mdtolink 0.1.5 → 0.1.7
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/dist/{api-D4MGz1n7.mjs → api-CPJjLxqz.mjs} +87 -12
- package/dist/{config-B5jPCcGo.mjs → config-cFx42NU7.mjs} +35 -6
- package/dist/{dist-DVBd1E-5.mjs → dist-BbvD4qtQ.mjs} +1 -1
- package/dist/domain-D5HsJ52R.mjs +165 -0
- package/dist/{format-DbYC9f36.mjs → format-CaRgIpjB.mjs} +5 -4
- package/dist/handle-C-teVKcx.mjs +82 -0
- package/dist/index.mjs +66 -12
- package/dist/{list-Dv3o-Yt-.mjs → list-5TKm4hrp.mjs} +9 -12
- package/dist/{login-DKrVl_-X.mjs → login-DOLV04ZV.mjs} +25 -20
- package/dist/{logout-2ajJT8D-.mjs → logout-t5CtUkc2.mjs} +2 -2
- package/dist/mcp.mjs +3 -3
- package/dist/{publish-S5e-jsL5.mjs → publish-DdAgmsVg.mjs} +47 -38
- package/dist/require-auth-m9LOildn.mjs +64 -0
- package/dist/{unpublish-DguElyLU.mjs → unpublish-DqwzN793.mjs} +8 -11
- package/package.json +7 -2
- /package/dist/{open-CZUGhT0Q.mjs → open-DQe1i6ko.mjs} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as SERVER_URL } from "./config-
|
|
2
|
+
import { n as SERVER_URL } from "./config-cFx42NU7.mjs";
|
|
3
3
|
|
|
4
4
|
//#region ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/core.js
|
|
5
5
|
/** A special constant with type `never` */
|
|
@@ -1297,7 +1297,7 @@ const $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => {
|
|
|
1297
1297
|
});
|
|
1298
1298
|
function isValidBase64URL(data) {
|
|
1299
1299
|
if (!base64url.test(data)) return false;
|
|
1300
|
-
const base64$1 = data.replace(/[-_]/g, (c$
|
|
1300
|
+
const base64$1 = data.replace(/[-_]/g, (c$6) => c$6 === "-" ? "+" : "/");
|
|
1301
1301
|
return isValidBase64(base64$1.padEnd(Math.ceil(base64$1.length / 4) * 4, "="));
|
|
1302
1302
|
}
|
|
1303
1303
|
const $ZodBase64URL = /* @__PURE__ */ $constructor("$ZodBase64URL", (inst, def) => {
|
|
@@ -7859,8 +7859,8 @@ const PaginationQuerySchema = object({
|
|
|
7859
7859
|
|
|
7860
7860
|
//#endregion
|
|
7861
7861
|
//#region ../../packages/contracts/src/contracts/billing.contract.ts
|
|
7862
|
-
const c$
|
|
7863
|
-
const billingContract = c$
|
|
7862
|
+
const c$5 = initContract();
|
|
7863
|
+
const billingContract = c$5.router({
|
|
7864
7864
|
getSubscription: {
|
|
7865
7865
|
method: "GET",
|
|
7866
7866
|
path: "/billing/subscription",
|
|
@@ -7940,13 +7940,13 @@ const DocumentListItemSchema = DocumentResponseSchema.omit({ content: true }).de
|
|
|
7940
7940
|
const CreateDocumentRequestSchema = object({
|
|
7941
7941
|
content: string().min(1).max(1e6).describe("Markdown content (max 1MB)"),
|
|
7942
7942
|
title: string().max(200).optional().describe("Optional title (max 200 chars)"),
|
|
7943
|
-
slug: string().min(1).max(100).regex(/^[a-z0-9-]+$/).optional().describe("Custom
|
|
7943
|
+
slug: string().min(1).max(100).regex(/^[a-z0-9-]+$/).optional().describe("Custom filename (Pro+ only, e.g., meeting-notes)"),
|
|
7944
7944
|
isPublic: boolean().default(true).describe("Whether the document is publicly accessible")
|
|
7945
7945
|
}).describe("Request body for creating a new document");
|
|
7946
7946
|
const UpdateDocumentRequestSchema = object({
|
|
7947
7947
|
content: string().min(1).max(1e6).optional().describe("Updated markdown content"),
|
|
7948
7948
|
title: string().max(200).optional().describe("Updated title"),
|
|
7949
|
-
slug: string().min(1).max(100).regex(/^[a-z0-9-]+$/).optional().describe("Updated
|
|
7949
|
+
slug: string().min(1).max(100).regex(/^[a-z0-9-]+$/).optional().describe("Updated filename (Pro+ only)"),
|
|
7950
7950
|
isPublic: boolean().optional().describe("Updated visibility")
|
|
7951
7951
|
}).describe("Request body for updating a document (all fields optional)");
|
|
7952
7952
|
const PublicDocumentResponseSchema = object({
|
|
@@ -7964,8 +7964,8 @@ const UsernameDocumentParamsSchema = object({
|
|
|
7964
7964
|
|
|
7965
7965
|
//#endregion
|
|
7966
7966
|
//#region ../../packages/contracts/src/contracts/document.contract.ts
|
|
7967
|
-
const c$
|
|
7968
|
-
const documentContract = c$
|
|
7967
|
+
const c$4 = initContract();
|
|
7968
|
+
const documentContract = c$4.router({
|
|
7969
7969
|
list: {
|
|
7970
7970
|
method: "GET",
|
|
7971
7971
|
path: "/documents",
|
|
@@ -7993,7 +7993,7 @@ const documentContract = c$3.router({
|
|
|
7993
7993
|
403: ErrorResponseSchema
|
|
7994
7994
|
},
|
|
7995
7995
|
summary: "Create document",
|
|
7996
|
-
description: "Publishes a new markdown document to a shareable URL. Free tier users get nanoid-based URLs with 7-day expiry. Pro+ users can set custom
|
|
7996
|
+
description: "Publishes a new markdown document to a shareable URL. Free tier users get nanoid-based URLs with 7-day expiry. Pro+ users can set custom filenames for user-scoped URLs (/@username/slug). Returns 403 if the user's plan document limit is reached."
|
|
7997
7997
|
},
|
|
7998
7998
|
get: {
|
|
7999
7999
|
method: "GET",
|
|
@@ -8019,7 +8019,7 @@ const documentContract = c$3.router({
|
|
|
8019
8019
|
404: ErrorResponseSchema
|
|
8020
8020
|
},
|
|
8021
8021
|
summary: "Update document",
|
|
8022
|
-
description: "Updates a document's content, title, slug, or visibility. All fields are optional — only provided fields are updated. Custom
|
|
8022
|
+
description: "Updates a document's content, title, slug, or visibility. All fields are optional — only provided fields are updated. Custom filenames require Pro+ plan. Returns 400 if the slug is already taken."
|
|
8023
8023
|
},
|
|
8024
8024
|
delete: {
|
|
8025
8025
|
method: "DELETE",
|
|
@@ -8035,7 +8035,7 @@ const documentContract = c$3.router({
|
|
|
8035
8035
|
description: "Soft-deletes a document by setting its status to 'deleted'. The document will no longer be accessible via its public URL. Requires authentication."
|
|
8036
8036
|
}
|
|
8037
8037
|
}, { pathPrefix: "/api" });
|
|
8038
|
-
const publicDocumentContract = c$
|
|
8038
|
+
const publicDocumentContract = c$4.router({
|
|
8039
8039
|
getBySlug: {
|
|
8040
8040
|
method: "GET",
|
|
8041
8041
|
path: "/d/:slug",
|
|
@@ -8058,10 +8058,84 @@ const publicDocumentContract = c$3.router({
|
|
|
8058
8058
|
410: ErrorResponseSchema
|
|
8059
8059
|
},
|
|
8060
8060
|
summary: "Get document by username and slug",
|
|
8061
|
-
description: "Retrieves a publicly shared document via a user-scoped URL (e.g. /@alice/my-doc). Available for Pro+ users who set custom
|
|
8061
|
+
description: "Retrieves a publicly shared document via a user-scoped URL (e.g. /@alice/my-doc). Available for Pro+ users who set custom filenames. Returns 410 if the document has expired. No authentication required."
|
|
8062
8062
|
}
|
|
8063
8063
|
}, { pathPrefix: "" });
|
|
8064
8064
|
|
|
8065
|
+
//#endregion
|
|
8066
|
+
//#region ../../packages/contracts/src/schemas/domain.ts
|
|
8067
|
+
const DomainResponseSchema = object({
|
|
8068
|
+
id: string().describe("Domain ID"),
|
|
8069
|
+
domain: string().describe("Domain name"),
|
|
8070
|
+
userId: string().describe("Owner user ID"),
|
|
8071
|
+
verified: boolean().describe("Whether domain DNS has been verified"),
|
|
8072
|
+
verifiedAt: string().datetime().nullable().describe("Verification timestamp"),
|
|
8073
|
+
cnameTarget: string().describe("CNAME target the domain should point to"),
|
|
8074
|
+
dnsProvider: string().nullable().describe("Detected DNS provider name"),
|
|
8075
|
+
dnsManagementUrl: string().nullable().describe("Direct link to DNS management page"),
|
|
8076
|
+
createdAt: string().datetime().describe("Creation timestamp")
|
|
8077
|
+
}).describe("Custom domain with verification status");
|
|
8078
|
+
const CreateDomainRequestSchema = object({ domain: string().min(1).max(253).regex(/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/, "Must be a valid domain name (e.g., docs.example.com)").describe("Domain name to add") }).describe("Request body for adding a custom domain");
|
|
8079
|
+
const VerifyDomainResponseSchema = object({
|
|
8080
|
+
verified: boolean().describe("Whether verification succeeded"),
|
|
8081
|
+
message: string().describe("Verification result message")
|
|
8082
|
+
}).describe("Domain verification result");
|
|
8083
|
+
|
|
8084
|
+
//#endregion
|
|
8085
|
+
//#region ../../packages/contracts/src/contracts/domain.contract.ts
|
|
8086
|
+
const c$3 = initContract();
|
|
8087
|
+
const domainContract = c$3.router({
|
|
8088
|
+
list: {
|
|
8089
|
+
method: "GET",
|
|
8090
|
+
path: "/domains",
|
|
8091
|
+
responses: {
|
|
8092
|
+
200: array(DomainResponseSchema),
|
|
8093
|
+
401: ErrorResponseSchema
|
|
8094
|
+
},
|
|
8095
|
+
summary: "List custom domains",
|
|
8096
|
+
description: "Returns all custom domains for the authenticated user."
|
|
8097
|
+
},
|
|
8098
|
+
create: {
|
|
8099
|
+
method: "POST",
|
|
8100
|
+
path: "/domains",
|
|
8101
|
+
body: CreateDomainRequestSchema,
|
|
8102
|
+
responses: {
|
|
8103
|
+
201: DomainResponseSchema,
|
|
8104
|
+
400: ErrorResponseSchema,
|
|
8105
|
+
401: ErrorResponseSchema,
|
|
8106
|
+
403: ErrorResponseSchema
|
|
8107
|
+
},
|
|
8108
|
+
summary: "Add custom domain",
|
|
8109
|
+
description: "Adds a custom domain for the authenticated user. Requires Publisher plan. Returns DNS verification instructions. The domain must be globally unique."
|
|
8110
|
+
},
|
|
8111
|
+
verify: {
|
|
8112
|
+
method: "POST",
|
|
8113
|
+
path: "/domains/:id/verify",
|
|
8114
|
+
pathParams: object({ id: string().describe("Domain ID") }),
|
|
8115
|
+
body: null,
|
|
8116
|
+
responses: {
|
|
8117
|
+
200: VerifyDomainResponseSchema,
|
|
8118
|
+
401: ErrorResponseSchema,
|
|
8119
|
+
404: ErrorResponseSchema
|
|
8120
|
+
},
|
|
8121
|
+
summary: "Verify domain DNS",
|
|
8122
|
+
description: "Checks DNS TXT record for the domain to verify ownership. Looks for a TXT record at _mdtolink-verification.{domain} matching the verification token."
|
|
8123
|
+
},
|
|
8124
|
+
delete: {
|
|
8125
|
+
method: "DELETE",
|
|
8126
|
+
path: "/domains/:id",
|
|
8127
|
+
pathParams: object({ id: string().describe("Domain ID") }),
|
|
8128
|
+
body: null,
|
|
8129
|
+
responses: {
|
|
8130
|
+
200: SuccessResponseSchema,
|
|
8131
|
+
401: ErrorResponseSchema,
|
|
8132
|
+
404: ErrorResponseSchema
|
|
8133
|
+
},
|
|
8134
|
+
summary: "Remove custom domain",
|
|
8135
|
+
description: "Removes a custom domain from the authenticated user's account."
|
|
8136
|
+
}
|
|
8137
|
+
}, { pathPrefix: "/api" });
|
|
8138
|
+
|
|
8065
8139
|
//#endregion
|
|
8066
8140
|
//#region ../../packages/contracts/src/contracts/health.contract.ts
|
|
8067
8141
|
const c$2 = initContract();
|
|
@@ -8151,6 +8225,7 @@ const c = initContract();
|
|
|
8151
8225
|
const apiContract = c.router({
|
|
8152
8226
|
billing: billingContract,
|
|
8153
8227
|
documents: documentContract,
|
|
8228
|
+
domains: domainContract,
|
|
8154
8229
|
health: healthContract,
|
|
8155
8230
|
users: userContract
|
|
8156
8231
|
});
|
|
@@ -7,19 +7,36 @@ import { homedir } from "node:os";
|
|
|
7
7
|
const CONFIG_DIR = join(homedir(), ".config", "mdtolink");
|
|
8
8
|
const TOKEN_PATH = join(CONFIG_DIR, "token.json");
|
|
9
9
|
const DOCUMENTS_PATH = join(CONFIG_DIR, "documents.json");
|
|
10
|
+
const DEFAULTS_PATH = join(CONFIG_DIR, "defaults.json");
|
|
10
11
|
const SERVER_URL = process.env.MDTOLINK_SERVER_URL || "https://api.mdtolink.com";
|
|
11
12
|
const APP_URL = process.env.MDTOLINK_APP_URL || "https://app.mdtolink.com";
|
|
12
|
-
async function
|
|
13
|
+
async function readTokenData() {
|
|
13
14
|
try {
|
|
14
15
|
const raw = await readFile(TOKEN_PATH, "utf-8");
|
|
15
|
-
return JSON.parse(raw)
|
|
16
|
+
return JSON.parse(raw);
|
|
16
17
|
} catch {
|
|
17
|
-
return
|
|
18
|
+
return {};
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
|
-
async function
|
|
21
|
+
async function writeTokenData(data) {
|
|
21
22
|
await mkdir(CONFIG_DIR, { recursive: true });
|
|
22
|
-
await writeFile(TOKEN_PATH, JSON.stringify(
|
|
23
|
+
await writeFile(TOKEN_PATH, JSON.stringify(data), { mode: 384 });
|
|
24
|
+
}
|
|
25
|
+
async function getToken() {
|
|
26
|
+
return (await readTokenData()).token ?? null;
|
|
27
|
+
}
|
|
28
|
+
async function storeToken(token) {
|
|
29
|
+
const data = await readTokenData();
|
|
30
|
+
data.token = token;
|
|
31
|
+
await writeTokenData(data);
|
|
32
|
+
}
|
|
33
|
+
async function getUsername() {
|
|
34
|
+
return (await readTokenData()).username ?? null;
|
|
35
|
+
}
|
|
36
|
+
async function storeUsername(username) {
|
|
37
|
+
const data = await readTokenData();
|
|
38
|
+
data.username = username;
|
|
39
|
+
await writeTokenData(data);
|
|
23
40
|
}
|
|
24
41
|
async function clearToken() {
|
|
25
42
|
try {
|
|
@@ -29,6 +46,18 @@ async function clearToken() {
|
|
|
29
46
|
async function isLoggedIn() {
|
|
30
47
|
return await getToken() !== null;
|
|
31
48
|
}
|
|
49
|
+
async function getDefaults() {
|
|
50
|
+
try {
|
|
51
|
+
const raw = await readFile(DEFAULTS_PATH, "utf-8");
|
|
52
|
+
return JSON.parse(raw);
|
|
53
|
+
} catch {
|
|
54
|
+
return {};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function setDefaults(defaults) {
|
|
58
|
+
await mkdir(CONFIG_DIR, { recursive: true });
|
|
59
|
+
await writeFile(DEFAULTS_PATH, JSON.stringify(defaults, null, " "), { mode: 384 });
|
|
60
|
+
}
|
|
32
61
|
async function getDocumentMap() {
|
|
33
62
|
try {
|
|
34
63
|
const raw = await readFile(DOCUMENTS_PATH, "utf-8");
|
|
@@ -58,4 +87,4 @@ async function findMappingBySlug(slug) {
|
|
|
58
87
|
}
|
|
59
88
|
|
|
60
89
|
//#endregion
|
|
61
|
-
export {
|
|
90
|
+
export { getDefaults as a, getUsername as c, setDefaults as d, setDocumentMapping as f, findMappingBySlug as i, isLoggedIn as l, storeUsername as m, SERVER_URL as n, getDocumentMap as o, storeToken as p, clearToken as r, getToken as s, APP_URL as t, removeDocumentMapping as u };
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./api-CPJjLxqz.mjs";
|
|
3
|
+
import { a as getDefaults, d as setDefaults } from "./config-cFx42NU7.mjs";
|
|
4
|
+
import { c as Ct, n as R, o as bt, r as Re, t as Je } from "./dist-BbvD4qtQ.mjs";
|
|
5
|
+
import { n as requireAuth } from "./require-auth-m9LOildn.mjs";
|
|
6
|
+
|
|
7
|
+
//#region src/cli/commands/domain.ts
|
|
8
|
+
async function domainList() {
|
|
9
|
+
const auth = await requireAuth();
|
|
10
|
+
if (!auth) return;
|
|
11
|
+
const spin = bt();
|
|
12
|
+
spin.start("Fetching domains...");
|
|
13
|
+
const result = await auth.api.domains.list({});
|
|
14
|
+
if (result.status !== 200) {
|
|
15
|
+
spin.stop("Failed to fetch domains.");
|
|
16
|
+
process.exitCode = 1;
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
spin.stop("Domains loaded.");
|
|
20
|
+
const domains = result.body;
|
|
21
|
+
if (domains.length === 0) {
|
|
22
|
+
R.info("No custom domains. Use `mdtl domain add <domain>` to add one.");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const defaults = await getDefaults();
|
|
26
|
+
for (const domain of domains) {
|
|
27
|
+
const verified = domain.verified ? "verified" : "unverified";
|
|
28
|
+
const isDefault = defaults.defaultDomain === domain.domain ? " (default)" : "";
|
|
29
|
+
R.info(`${domain.domain} [${verified}]${isDefault}`);
|
|
30
|
+
if (!domain.verified) {
|
|
31
|
+
R.info(" Add a CNAME record to verify and route your domain:");
|
|
32
|
+
R.info(` ${domain.domain} → ${domain.cnameTarget}`);
|
|
33
|
+
if (domain.dnsManagementUrl) R.info(` ${domain.dnsProvider} DNS: ${domain.dnsManagementUrl}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function domainAdd(domainName) {
|
|
38
|
+
const auth = await requireAuth();
|
|
39
|
+
if (!auth) return;
|
|
40
|
+
const spin = bt();
|
|
41
|
+
spin.start("Adding domain...");
|
|
42
|
+
const result = await auth.api.domains.create({ body: { domain: domainName } });
|
|
43
|
+
if (result.status === 201) {
|
|
44
|
+
const domain = result.body;
|
|
45
|
+
spin.stop("Domain added!");
|
|
46
|
+
R.success(`Added: ${domain.domain}`);
|
|
47
|
+
R.info("");
|
|
48
|
+
R.info("Add a CNAME record to verify and route your domain:");
|
|
49
|
+
R.info(` ${domain.domain} → ${domain.cnameTarget}`);
|
|
50
|
+
if (domain.dnsManagementUrl) {
|
|
51
|
+
R.info("");
|
|
52
|
+
R.info(`Open ${domain.dnsProvider ?? "your DNS provider"} to add the record:`);
|
|
53
|
+
R.info(` ${domain.dnsManagementUrl}`);
|
|
54
|
+
}
|
|
55
|
+
R.info("");
|
|
56
|
+
R.info(`Then run: mdtl domain verify ${domain.domain}`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
spin.stop("Failed to add domain.");
|
|
60
|
+
const body = result.body;
|
|
61
|
+
R.error(body.error);
|
|
62
|
+
process.exitCode = 1;
|
|
63
|
+
}
|
|
64
|
+
async function domainVerify(domainName) {
|
|
65
|
+
const auth = await requireAuth();
|
|
66
|
+
if (!auth) return;
|
|
67
|
+
const listResult = await auth.api.domains.list({});
|
|
68
|
+
if (listResult.status !== 200) {
|
|
69
|
+
R.error("Failed to fetch domains.");
|
|
70
|
+
process.exitCode = 1;
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const domain = listResult.body.find((d) => d.domain === domainName);
|
|
74
|
+
if (!domain) {
|
|
75
|
+
R.error(`Domain not found: ${domainName}`);
|
|
76
|
+
process.exitCode = 1;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (domain.verified) {
|
|
80
|
+
R.success(`${domainName} is already verified.`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const spin = bt();
|
|
84
|
+
spin.start("Checking DNS records...");
|
|
85
|
+
const result = await auth.api.domains.verify({ params: { id: domain.id } });
|
|
86
|
+
if (result.status !== 200) {
|
|
87
|
+
spin.stop("Verification failed.");
|
|
88
|
+
process.exitCode = 1;
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (result.body.verified) {
|
|
92
|
+
spin.stop("Verified!");
|
|
93
|
+
R.success(result.body.message);
|
|
94
|
+
} else {
|
|
95
|
+
spin.stop("Not verified yet.");
|
|
96
|
+
R.warning(result.body.message);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function domainRemove(domainName) {
|
|
100
|
+
const auth = await requireAuth();
|
|
101
|
+
if (!auth) return;
|
|
102
|
+
const listResult = await auth.api.domains.list({});
|
|
103
|
+
if (listResult.status !== 200) {
|
|
104
|
+
R.error("Failed to fetch domains.");
|
|
105
|
+
process.exitCode = 1;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const domain = listResult.body.find((d) => d.domain === domainName);
|
|
109
|
+
if (!domain) {
|
|
110
|
+
R.error(`Domain not found: ${domainName}`);
|
|
111
|
+
process.exitCode = 1;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const shouldDelete = await Re({ message: `Remove ${domainName}? This cannot be undone.` });
|
|
115
|
+
if (Ct(shouldDelete) || !shouldDelete) {
|
|
116
|
+
R.info("Cancelled.");
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if ((await auth.api.domains.delete({ params: { id: domain.id } })).status === 200) {
|
|
120
|
+
R.success(`Removed: ${domainName}`);
|
|
121
|
+
if ((await getDefaults()).defaultDomain === domainName) await setDefaults({ defaultDomain: void 0 });
|
|
122
|
+
} else {
|
|
123
|
+
R.error("Failed to remove domain.");
|
|
124
|
+
process.exitCode = 1;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async function domainDefault() {
|
|
128
|
+
const auth = await requireAuth();
|
|
129
|
+
if (!auth) return;
|
|
130
|
+
const listResult = await auth.api.domains.list({});
|
|
131
|
+
if (listResult.status !== 200) {
|
|
132
|
+
R.error("Failed to fetch domains.");
|
|
133
|
+
process.exitCode = 1;
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const verifiedDomains = listResult.body.filter((d) => d.verified);
|
|
137
|
+
if (verifiedDomains.length === 0) {
|
|
138
|
+
R.info("No verified domains. Add and verify a domain first.");
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const defaults = await getDefaults();
|
|
142
|
+
const selected = await Je({
|
|
143
|
+
message: "Select default domain:",
|
|
144
|
+
options: [{
|
|
145
|
+
value: "__none__",
|
|
146
|
+
label: "None (no default domain)"
|
|
147
|
+
}, ...verifiedDomains.map((d) => ({
|
|
148
|
+
value: d.domain,
|
|
149
|
+
label: d.domain,
|
|
150
|
+
hint: defaults.defaultDomain === d.domain ? "current default" : void 0
|
|
151
|
+
}))],
|
|
152
|
+
initialValue: defaults.defaultDomain ?? "__none__"
|
|
153
|
+
});
|
|
154
|
+
if (Ct(selected)) {
|
|
155
|
+
R.info("Cancelled.");
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const newDefault = selected === "__none__" ? void 0 : selected;
|
|
159
|
+
await setDefaults({ defaultDomain: newDefault });
|
|
160
|
+
if (newDefault) R.success(`Default domain set to: ${newDefault}`);
|
|
161
|
+
else R.success("Default domain cleared.");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
//#endregion
|
|
165
|
+
export { domainAdd, domainDefault, domainList, domainRemove, domainVerify };
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as APP_URL } from "./config-
|
|
2
|
+
import { t as APP_URL } from "./config-cFx42NU7.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/cli/lib/format.ts
|
|
5
|
-
function formatDocumentUrl(doc) {
|
|
5
|
+
function formatDocumentUrl(doc, username) {
|
|
6
|
+
if (doc.urlType === "user_scoped" && username) return `${APP_URL}/@${username}/${doc.slug}`;
|
|
6
7
|
return `${APP_URL}/d/${doc.slug}`;
|
|
7
8
|
}
|
|
8
|
-
function formatDocumentTable(items, total, offset) {
|
|
9
|
+
function formatDocumentTable(items, total, offset, username) {
|
|
9
10
|
if (items.length === 0) return "No documents found.";
|
|
10
11
|
const lines = [];
|
|
11
12
|
const header = padColumns([
|
|
@@ -21,7 +22,7 @@ function formatDocumentTable(items, total, offset) {
|
|
|
21
22
|
for (const doc of items) {
|
|
22
23
|
const title = doc.title || "(untitled)";
|
|
23
24
|
const created = new Date(doc.createdAt).toLocaleDateString();
|
|
24
|
-
const link = formatDocumentUrl(doc);
|
|
25
|
+
const link = formatDocumentUrl(doc, username);
|
|
25
26
|
lines.push(padColumns([
|
|
26
27
|
truncate(title, 30),
|
|
27
28
|
truncate(doc.slug, 20),
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./api-CPJjLxqz.mjs";
|
|
3
|
+
import { m as storeUsername, n as SERVER_URL } from "./config-cFx42NU7.mjs";
|
|
4
|
+
import { n as R, o as bt } from "./dist-BbvD4qtQ.mjs";
|
|
5
|
+
import { n as requireAuth } from "./require-auth-m9LOildn.mjs";
|
|
6
|
+
|
|
7
|
+
//#region src/cli/commands/handle.ts
|
|
8
|
+
async function handleShow() {
|
|
9
|
+
const auth = await requireAuth();
|
|
10
|
+
if (!auth) return;
|
|
11
|
+
const { api } = auth;
|
|
12
|
+
const result = await api.users.getMe({});
|
|
13
|
+
if (result.status !== 200) {
|
|
14
|
+
R.error("Failed to fetch profile.");
|
|
15
|
+
process.exitCode = 1;
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const username = result.body.username;
|
|
19
|
+
if (username) {
|
|
20
|
+
await storeUsername(username);
|
|
21
|
+
R.info(`Your handle: @${username}`);
|
|
22
|
+
} else R.info("No handle set. Use `mdtl handle set <name>` to claim one.");
|
|
23
|
+
}
|
|
24
|
+
async function handleSet(name) {
|
|
25
|
+
const auth = await requireAuth();
|
|
26
|
+
if (!auth) return;
|
|
27
|
+
const { token } = auth;
|
|
28
|
+
const handle = name.startsWith("@") ? name.slice(1) : name;
|
|
29
|
+
if (!/^[a-z0-9][a-z0-9_-]*$/.test(handle)) {
|
|
30
|
+
R.error("Invalid handle. Use lowercase letters, numbers, hyphens, and underscores. Must start with a letter or number.");
|
|
31
|
+
process.exitCode = 1;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (handle.length < 3 || handle.length > 30) {
|
|
35
|
+
R.error("Handle must be between 3 and 30 characters.");
|
|
36
|
+
process.exitCode = 1;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const spin = bt();
|
|
40
|
+
spin.start("Setting handle...");
|
|
41
|
+
const response = await fetch(`${SERVER_URL}/api/auth/update-user`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: {
|
|
44
|
+
"Content-Type": "application/json",
|
|
45
|
+
Authorization: `Bearer ${token}`
|
|
46
|
+
},
|
|
47
|
+
body: JSON.stringify({ username: handle })
|
|
48
|
+
});
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
const body = await response.json();
|
|
51
|
+
const message = typeof body.message === "string" ? body.message : "Failed to set handle. It may already be taken.";
|
|
52
|
+
spin.stop("Failed.");
|
|
53
|
+
R.error(message);
|
|
54
|
+
process.exitCode = 1;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
await storeUsername(handle);
|
|
58
|
+
spin.stop("Done!");
|
|
59
|
+
R.success(`Handle set to @${handle}`);
|
|
60
|
+
}
|
|
61
|
+
async function handleRemove() {
|
|
62
|
+
const auth = await requireAuth();
|
|
63
|
+
if (!auth) return;
|
|
64
|
+
const { token } = auth;
|
|
65
|
+
if (!(await fetch(`${SERVER_URL}/api/auth/update-user`, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers: {
|
|
68
|
+
"Content-Type": "application/json",
|
|
69
|
+
Authorization: `Bearer ${token}`
|
|
70
|
+
},
|
|
71
|
+
body: JSON.stringify({ username: "" })
|
|
72
|
+
})).ok) {
|
|
73
|
+
R.error("Failed to remove handle.");
|
|
74
|
+
process.exitCode = 1;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
await storeUsername("");
|
|
78
|
+
R.success("Handle removed.");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
export { handleRemove, handleSet, handleShow };
|
package/dist/index.mjs
CHANGED
|
@@ -3030,15 +3030,15 @@ const { program: program$1, createCommand, createArgument, createOption, Command
|
|
|
3030
3030
|
const program = new Command();
|
|
3031
3031
|
program.name("mdtolink").description("Publish markdown files to shareable URLs").version("0.1.0");
|
|
3032
3032
|
program.command("login").aliases(["auth", "signin"]).description("Authenticate with MDtolink").action(async () => {
|
|
3033
|
-
const { login } = await import("./login-
|
|
3033
|
+
const { login } = await import("./login-DOLV04ZV.mjs");
|
|
3034
3034
|
await login();
|
|
3035
3035
|
});
|
|
3036
3036
|
program.command("logout").aliases(["signout"]).description("Clear stored authentication token").action(async () => {
|
|
3037
|
-
const { logout } = await import("./logout-
|
|
3037
|
+
const { logout } = await import("./logout-t5CtUkc2.mjs");
|
|
3038
3038
|
await logout();
|
|
3039
3039
|
});
|
|
3040
|
-
program.command("publish").aliases(["p", "pub"]).description("Publish or update a markdown file").argument("<file>", "Path to markdown file").option("--slug <slug>", "Custom
|
|
3041
|
-
const { publish } = await import("./publish-
|
|
3040
|
+
program.command("publish").aliases(["p", "pub"]).description("Publish or update a markdown file").argument("<file>", "Path to markdown file").option("--slug <slug>", "Custom filename (Pro+ only, e.g., meeting-notes)").option("--title <title>", "Custom title (defaults to filename)").action(async (file, options) => {
|
|
3041
|
+
const { publish } = await import("./publish-DdAgmsVg.mjs");
|
|
3042
3042
|
await publish(file, options);
|
|
3043
3043
|
});
|
|
3044
3044
|
program.command("unpublish").aliases([
|
|
@@ -3046,28 +3046,70 @@ program.command("unpublish").aliases([
|
|
|
3046
3046
|
"remove",
|
|
3047
3047
|
"delete"
|
|
3048
3048
|
]).description("Remove a published document").argument("[file-or-slug]", "File path or document slug").action(async (fileOrSlug) => {
|
|
3049
|
-
const { unpublish } = await import("./unpublish-
|
|
3049
|
+
const { unpublish } = await import("./unpublish-DqwzN793.mjs");
|
|
3050
3050
|
await unpublish(fileOrSlug);
|
|
3051
3051
|
});
|
|
3052
3052
|
program.command("list").aliases(["ls", "l"]).description("List published documents").option("--limit <n>", "Number of documents to show", "20").option("--offset <n>", "Skip N documents", "0").action(async (options) => {
|
|
3053
|
-
const { list } = await import("./list-
|
|
3053
|
+
const { list } = await import("./list-5TKm4hrp.mjs");
|
|
3054
3054
|
await list({
|
|
3055
3055
|
limit: Number.parseInt(options.limit, 10),
|
|
3056
3056
|
offset: Number.parseInt(options.offset, 10)
|
|
3057
3057
|
});
|
|
3058
3058
|
});
|
|
3059
|
+
const handleCmd = program.command("handle").aliases(["h"]).description("Manage your handle (@username)");
|
|
3060
|
+
handleCmd.command("show").description("Show current handle").action(async () => {
|
|
3061
|
+
const { handleShow } = await import("./handle-C-teVKcx.mjs");
|
|
3062
|
+
await handleShow();
|
|
3063
|
+
});
|
|
3064
|
+
handleCmd.command("set").argument("<name>", "Handle to claim (e.g., david)").description("Set your handle").action(async (name) => {
|
|
3065
|
+
const { handleSet } = await import("./handle-C-teVKcx.mjs");
|
|
3066
|
+
await handleSet(name);
|
|
3067
|
+
});
|
|
3068
|
+
handleCmd.command("remove").description("Remove your handle").action(async () => {
|
|
3069
|
+
const { handleRemove } = await import("./handle-C-teVKcx.mjs");
|
|
3070
|
+
await handleRemove();
|
|
3071
|
+
});
|
|
3072
|
+
handleCmd.action(async () => {
|
|
3073
|
+
const { handleShow } = await import("./handle-C-teVKcx.mjs");
|
|
3074
|
+
await handleShow();
|
|
3075
|
+
});
|
|
3076
|
+
const domainCmd = program.command("domain").aliases(["dom"]).description("Manage custom domains");
|
|
3077
|
+
domainCmd.command("list").description("List your custom domains").action(async () => {
|
|
3078
|
+
const { domainList } = await import("./domain-D5HsJ52R.mjs");
|
|
3079
|
+
await domainList();
|
|
3080
|
+
});
|
|
3081
|
+
domainCmd.command("add").argument("<domain>", "Domain name (e.g., docs.example.com)").description("Add a custom domain").action(async (domain) => {
|
|
3082
|
+
const { domainAdd } = await import("./domain-D5HsJ52R.mjs");
|
|
3083
|
+
await domainAdd(domain);
|
|
3084
|
+
});
|
|
3085
|
+
domainCmd.command("verify").argument("<domain>", "Domain name to verify").description("Verify domain DNS ownership").action(async (domain) => {
|
|
3086
|
+
const { domainVerify } = await import("./domain-D5HsJ52R.mjs");
|
|
3087
|
+
await domainVerify(domain);
|
|
3088
|
+
});
|
|
3089
|
+
domainCmd.command("remove").argument("<domain>", "Domain name to remove").description("Remove a custom domain").action(async (domain) => {
|
|
3090
|
+
const { domainRemove } = await import("./domain-D5HsJ52R.mjs");
|
|
3091
|
+
await domainRemove(domain);
|
|
3092
|
+
});
|
|
3093
|
+
domainCmd.command("default").description("Set default custom domain").action(async () => {
|
|
3094
|
+
const { domainDefault } = await import("./domain-D5HsJ52R.mjs");
|
|
3095
|
+
await domainDefault();
|
|
3096
|
+
});
|
|
3097
|
+
domainCmd.action(async () => {
|
|
3098
|
+
const { domainList } = await import("./domain-D5HsJ52R.mjs");
|
|
3099
|
+
await domainList();
|
|
3100
|
+
});
|
|
3059
3101
|
program.command("commands").description("Show all available commands").action(() => {
|
|
3060
3102
|
printCommands();
|
|
3061
3103
|
});
|
|
3062
3104
|
program.argument("[file]", "Markdown file to publish (shorthand for `publish`)");
|
|
3063
|
-
program.option("--slug <slug>", "Custom
|
|
3105
|
+
program.option("--slug <slug>", "Custom filename (Pro+ only, e.g., meeting-notes)");
|
|
3064
3106
|
program.option("--title <title>", "Custom title (defaults to filename)");
|
|
3065
3107
|
program.action(async (file, options) => {
|
|
3066
|
-
if (!file) {
|
|
3108
|
+
if (!file || file === "help") {
|
|
3067
3109
|
program.help();
|
|
3068
3110
|
return;
|
|
3069
3111
|
}
|
|
3070
|
-
const { publish } = await import("./publish-
|
|
3112
|
+
const { publish } = await import("./publish-DdAgmsVg.mjs");
|
|
3071
3113
|
await publish(file, options);
|
|
3072
3114
|
});
|
|
3073
3115
|
program.addHelpText("after", () => {
|
|
@@ -3077,14 +3119,15 @@ program.addHelpText("after", () => {
|
|
|
3077
3119
|
Aliases:
|
|
3078
3120
|
publish p, pub login auth, signin
|
|
3079
3121
|
unpublish rm, remove logout signout
|
|
3080
|
-
list ls, l
|
|
3122
|
+
list ls, l handle h
|
|
3123
|
+
domain dom`;
|
|
3081
3124
|
});
|
|
3082
3125
|
function printCommands() {
|
|
3083
3126
|
console.log(`
|
|
3084
3127
|
mdtolink commands:
|
|
3085
3128
|
|
|
3086
3129
|
publish <file> Publish or update a markdown file
|
|
3087
|
-
--slug <
|
|
3130
|
+
--slug <name> Custom filename (Pro+ only, e.g., meeting-notes)
|
|
3088
3131
|
--title <title> Custom title (defaults to filename)
|
|
3089
3132
|
|
|
3090
3133
|
unpublish [target] Remove a published document
|
|
@@ -3092,6 +3135,16 @@ mdtolink commands:
|
|
|
3092
3135
|
--limit <n> Number of documents to show (default: 20)
|
|
3093
3136
|
--offset <n> Skip N documents (default: 0)
|
|
3094
3137
|
|
|
3138
|
+
handle Show your handle (@username)
|
|
3139
|
+
handle set <name> Set your handle (e.g., mdtl handle set david)
|
|
3140
|
+
handle remove Remove your handle
|
|
3141
|
+
|
|
3142
|
+
domain List your custom domains
|
|
3143
|
+
domain add <domain> Add a custom domain (Publisher only)
|
|
3144
|
+
domain verify <dom> Verify domain DNS ownership
|
|
3145
|
+
domain remove <dom> Remove a custom domain
|
|
3146
|
+
domain default Set default custom domain
|
|
3147
|
+
|
|
3095
3148
|
login Authenticate with MDtolink
|
|
3096
3149
|
logout Clear stored authentication token
|
|
3097
3150
|
commands Show this list
|
|
@@ -3102,7 +3155,8 @@ Shortcuts:
|
|
|
3102
3155
|
Aliases:
|
|
3103
3156
|
publish p, pub login auth, signin
|
|
3104
3157
|
unpublish rm, remove logout signout
|
|
3105
|
-
list ls, l
|
|
3158
|
+
list ls, l handle h
|
|
3159
|
+
domain dom
|
|
3106
3160
|
`);
|
|
3107
3161
|
}
|
|
3108
3162
|
await program.parseAsync();
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { t as formatDocumentTable } from "./format-
|
|
5
|
-
import {
|
|
2
|
+
import "./api-CPJjLxqz.mjs";
|
|
3
|
+
import "./config-cFx42NU7.mjs";
|
|
4
|
+
import { t as formatDocumentTable } from "./format-CaRgIpjB.mjs";
|
|
5
|
+
import { n as R, o as bt } from "./dist-BbvD4qtQ.mjs";
|
|
6
|
+
import { n as requireAuth } from "./require-auth-m9LOildn.mjs";
|
|
6
7
|
|
|
7
8
|
//#region src/cli/commands/list.ts
|
|
8
9
|
async function list(options) {
|
|
9
|
-
const
|
|
10
|
-
if (!
|
|
11
|
-
|
|
12
|
-
process.exitCode = 1;
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
const api = createApiClient(token);
|
|
10
|
+
const auth = await requireAuth();
|
|
11
|
+
if (!auth) return;
|
|
12
|
+
const { api, username } = auth;
|
|
16
13
|
const spin = bt();
|
|
17
14
|
spin.start("Fetching documents...");
|
|
18
15
|
try {
|
|
@@ -23,7 +20,7 @@ async function list(options) {
|
|
|
23
20
|
if (result.status === 200) {
|
|
24
21
|
spin.stop("Documents loaded.");
|
|
25
22
|
const { items, total, offset } = result.body;
|
|
26
|
-
const output = formatDocumentTable(items, total, offset);
|
|
23
|
+
const output = formatDocumentTable(items, total, offset, username);
|
|
27
24
|
R.info(output);
|
|
28
25
|
} else {
|
|
29
26
|
const body = result.body;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { t as createApiClient } from "./api-CPJjLxqz.mjs";
|
|
3
|
+
import { m as storeUsername, n as SERVER_URL, p as storeToken } from "./config-cFx42NU7.mjs";
|
|
4
|
+
import { i as We, n as R, o as bt } from "./dist-BbvD4qtQ.mjs";
|
|
4
5
|
|
|
5
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
6
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/client/broadcast-channel.mjs
|
|
6
7
|
const kBroadcastChannel = Symbol.for("better-auth:broadcast-channel");
|
|
7
8
|
const now$1 = () => Math.floor(Date.now() / 1e3);
|
|
8
9
|
var WindowBroadcastChannel = class {
|
|
@@ -46,7 +47,7 @@ function getGlobalBroadcastChannel(name = "better-auth.message") {
|
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
//#endregion
|
|
49
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
50
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/client/focus-manager.mjs
|
|
50
51
|
const kFocusManager = Symbol.for("better-auth:focus-manager");
|
|
51
52
|
var WindowFocusManager = class {
|
|
52
53
|
listeners = /* @__PURE__ */ new Set();
|
|
@@ -76,7 +77,7 @@ function getGlobalFocusManager() {
|
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
//#endregion
|
|
79
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
80
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/client/online-manager.mjs
|
|
80
81
|
const kOnlineManager = Symbol.for("better-auth:online-manager");
|
|
81
82
|
var WindowOnlineManager = class {
|
|
82
83
|
listeners = /* @__PURE__ */ new Set();
|
|
@@ -240,7 +241,7 @@ let onMount = ($store, initialize) => {
|
|
|
240
241
|
};
|
|
241
242
|
|
|
242
243
|
//#endregion
|
|
243
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
244
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/client/query.mjs
|
|
244
245
|
const isServer = () => typeof window === "undefined";
|
|
245
246
|
const useAuthQuery = (initializedAtom, path, $fetch, options) => {
|
|
246
247
|
const value = /* @__PURE__ */ atom({
|
|
@@ -334,7 +335,7 @@ const useAuthQuery = (initializedAtom, path, $fetch, options) => {
|
|
|
334
335
|
};
|
|
335
336
|
|
|
336
337
|
//#endregion
|
|
337
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
338
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/client/session-refresh.mjs
|
|
338
339
|
const now = () => Math.floor(Date.now() / 1e3);
|
|
339
340
|
/**
|
|
340
341
|
* Rate limit: don't refetch on focus if a session request was made within this many seconds
|
|
@@ -753,7 +754,7 @@ var BetterAuthError = class extends Error {
|
|
|
753
754
|
};
|
|
754
755
|
|
|
755
756
|
//#endregion
|
|
756
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
757
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/utils/url.mjs
|
|
757
758
|
function checkHasPath(url) {
|
|
758
759
|
try {
|
|
759
760
|
return (new URL(url).pathname.replace(/\/+$/, "") || "/") !== "/";
|
|
@@ -826,7 +827,7 @@ function getOrigin(url) {
|
|
|
826
827
|
}
|
|
827
828
|
|
|
828
829
|
//#endregion
|
|
829
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
830
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/client/fetch-plugins.mjs
|
|
830
831
|
const redirectPlugin = {
|
|
831
832
|
id: "redirect",
|
|
832
833
|
name: "Redirect",
|
|
@@ -842,7 +843,7 @@ const redirectPlugin = {
|
|
|
842
843
|
};
|
|
843
844
|
|
|
844
845
|
//#endregion
|
|
845
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
846
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/client/parser.mjs
|
|
846
847
|
const PROTO_POLLUTION_PATTERNS = {
|
|
847
848
|
proto: /"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/,
|
|
848
849
|
constructor: /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/,
|
|
@@ -913,7 +914,7 @@ function parseJSON(value, options = { strict: true }) {
|
|
|
913
914
|
}
|
|
914
915
|
|
|
915
916
|
//#endregion
|
|
916
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
917
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/client/session-atom.mjs
|
|
917
918
|
function getSessionAtom($fetch, options) {
|
|
918
919
|
const $signal = /* @__PURE__ */ atom(false);
|
|
919
920
|
const session = useAuthQuery($signal, "/get-session", $fetch, { method: "GET" });
|
|
@@ -1412,7 +1413,7 @@ var betterFetch = async (url, options) => {
|
|
|
1412
1413
|
};
|
|
1413
1414
|
|
|
1414
1415
|
//#endregion
|
|
1415
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
1416
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/client/config.mjs
|
|
1416
1417
|
const getClientConfig = (options, loadEnv) => {
|
|
1417
1418
|
const isCredentialsSupported = "credentials" in Request.prototype;
|
|
1418
1419
|
const baseURL = getBaseURL(options?.baseURL, options?.basePath, void 0, loadEnv) ?? "/api/auth";
|
|
@@ -1493,13 +1494,13 @@ const getClientConfig = (options, loadEnv) => {
|
|
|
1493
1494
|
};
|
|
1494
1495
|
|
|
1495
1496
|
//#endregion
|
|
1496
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
1497
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/utils/is-atom.mjs
|
|
1497
1498
|
function isAtom(value) {
|
|
1498
1499
|
return typeof value === "object" && value !== null && "get" in value && typeof value.get === "function" && "lc" in value && typeof value.lc === "number";
|
|
1499
1500
|
}
|
|
1500
1501
|
|
|
1501
1502
|
//#endregion
|
|
1502
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
1503
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/client/proxy.mjs
|
|
1503
1504
|
function getMethod(path, knownPathMethods, args) {
|
|
1504
1505
|
const method = knownPathMethods[path];
|
|
1505
1506
|
const { fetchOptions, query: _query, ...body } = args || {};
|
|
@@ -1574,7 +1575,7 @@ function createDynamicPathProxy(routes, client, knownPathMethods, atoms, atomLis
|
|
|
1574
1575
|
}
|
|
1575
1576
|
|
|
1576
1577
|
//#endregion
|
|
1577
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
1578
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/client/vanilla.mjs
|
|
1578
1579
|
function createAuthClient(options) {
|
|
1579
1580
|
const { pluginPathMethods, pluginsActions, pluginsAtoms, $fetch, atomListeners, $store } = getClientConfig(options);
|
|
1580
1581
|
const resolvedHooks = {};
|
|
@@ -1588,7 +1589,7 @@ function createAuthClient(options) {
|
|
|
1588
1589
|
}
|
|
1589
1590
|
|
|
1590
1591
|
//#endregion
|
|
1591
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
1592
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/plugins/access/access.mjs
|
|
1592
1593
|
function role(statements) {
|
|
1593
1594
|
return {
|
|
1594
1595
|
authorize(request, connector = "AND") {
|
|
@@ -1630,7 +1631,7 @@ function createAccessControl(s) {
|
|
|
1630
1631
|
}
|
|
1631
1632
|
|
|
1632
1633
|
//#endregion
|
|
1633
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
1634
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/plugins/admin/access/statement.mjs
|
|
1634
1635
|
const defaultStatements$1 = {
|
|
1635
1636
|
user: [
|
|
1636
1637
|
"create",
|
|
@@ -1674,7 +1675,7 @@ const userAc = defaultAc$1.newRole({
|
|
|
1674
1675
|
});
|
|
1675
1676
|
|
|
1676
1677
|
//#endregion
|
|
1677
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
1678
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/plugins/device-authorization/client.mjs
|
|
1678
1679
|
const deviceAuthorizationClient = () => {
|
|
1679
1680
|
return {
|
|
1680
1681
|
id: "device-authorization",
|
|
@@ -1690,7 +1691,7 @@ const deviceAuthorizationClient = () => {
|
|
|
1690
1691
|
};
|
|
1691
1692
|
|
|
1692
1693
|
//#endregion
|
|
1693
|
-
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@
|
|
1694
|
+
//#region ../../node_modules/.pnpm/better-auth@1.4.20_drizzle-kit@0.31.9_drizzle-orm@0.45.1_@opentelemetry+api@1.9.0_@type_a40a2e15f82eb076fc233026dff617a5/node_modules/better-auth/dist/plugins/organization/access/statement.mjs
|
|
1694
1695
|
const defaultStatements = {
|
|
1695
1696
|
organization: ["update", "delete"],
|
|
1696
1697
|
member: [
|
|
@@ -1784,6 +1785,10 @@ async function pollForToken(deviceCode, interval) {
|
|
|
1784
1785
|
const userName = session?.user?.name || "there";
|
|
1785
1786
|
R.success(`Authenticated successfully! Hello, ${userName}!`);
|
|
1786
1787
|
R.info("Token stored at ~/.config/mdtolink/token.json");
|
|
1788
|
+
try {
|
|
1789
|
+
const result = await createApiClient(data.access_token).users.getMe({});
|
|
1790
|
+
if (result.status === 200 && result.body.username) await storeUsername(result.body.username);
|
|
1791
|
+
} catch {}
|
|
1787
1792
|
return;
|
|
1788
1793
|
}
|
|
1789
1794
|
if (error) {
|
|
@@ -1824,7 +1829,7 @@ async function login() {
|
|
|
1824
1829
|
R.info(`Your code: ${user_code}`);
|
|
1825
1830
|
R.info(`Visit: ${verification_uri}`);
|
|
1826
1831
|
try {
|
|
1827
|
-
const { default: open } = await import("./open-
|
|
1832
|
+
const { default: open } = await import("./open-DQe1i6ko.mjs");
|
|
1828
1833
|
const urlToOpen = verification_uri_complete || verification_uri;
|
|
1829
1834
|
if (urlToOpen) {
|
|
1830
1835
|
await open(urlToOpen);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { l as isLoggedIn, r as clearToken } from "./config-cFx42NU7.mjs";
|
|
3
|
+
import { n as R } from "./dist-BbvD4qtQ.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/cli/commands/logout.ts
|
|
6
6
|
async function logout() {
|
package/dist/mcp.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { r as __toESM, t as __commonJSMin } from "./chunk-DrUt9iA_.mjs";
|
|
3
|
-
import { A as clone, C as meta$1, D as parseAsync, E as parse$1, M as normalizeParams, N as $constructor, O as safeParse$1, S as describe$1, T as $ZodType, _ as string, a as array, b as datetime, c as discriminatedUnion, d as looseObject, f as number, g as record, h as preprocess, i as _null, j as defineLazy, k as safeParseAsync$1, l as intersection, m as optional, n as ZodOptional, o as boolean, p as object$1, r as _enum, s as custom, t as createApiClient, u as literal, v as union, w as $ZodObject, x as toJSONSchema, y as unknown } from "./api-
|
|
4
|
-
import {
|
|
5
|
-
import { n as formatDocumentUrl } from "./format-
|
|
3
|
+
import { A as clone, C as meta$1, D as parseAsync, E as parse$1, M as normalizeParams, N as $constructor, O as safeParse$1, S as describe$1, T as $ZodType, _ as string, a as array, b as datetime, c as discriminatedUnion, d as looseObject, f as number, g as record, h as preprocess, i as _null, j as defineLazy, k as safeParseAsync$1, l as intersection, m as optional, n as ZodOptional, o as boolean, p as object$1, r as _enum, s as custom, t as createApiClient, u as literal, v as union, w as $ZodObject, x as toJSONSchema, y as unknown } from "./api-CPJjLxqz.mjs";
|
|
4
|
+
import { s as getToken } from "./config-cFx42NU7.mjs";
|
|
5
|
+
import { n as formatDocumentUrl } from "./format-CaRgIpjB.mjs";
|
|
6
6
|
import N from "node:process";
|
|
7
7
|
|
|
8
8
|
//#region ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/helpers/util.js
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import { n as formatDocumentUrl } from "./format-
|
|
5
|
-
import {
|
|
2
|
+
import "./api-CPJjLxqz.mjs";
|
|
3
|
+
import { f as setDocumentMapping, o as getDocumentMap } from "./config-cFx42NU7.mjs";
|
|
4
|
+
import { n as formatDocumentUrl } from "./format-CaRgIpjB.mjs";
|
|
5
|
+
import { n as R, o as bt } from "./dist-BbvD4qtQ.mjs";
|
|
6
|
+
import { n as requireAuth, t as promptReauth } from "./require-auth-m9LOildn.mjs";
|
|
6
7
|
import { basename, extname, resolve } from "node:path";
|
|
7
8
|
import { access, readFile } from "node:fs/promises";
|
|
8
9
|
|
|
@@ -16,22 +17,8 @@ async function publish(filePath, options) {
|
|
|
16
17
|
process.exitCode = 1;
|
|
17
18
|
return;
|
|
18
19
|
}
|
|
19
|
-
|
|
20
|
-
if (!
|
|
21
|
-
const shouldLogin = await Re({ message: "You are not logged in. Would you like to authorize now?" });
|
|
22
|
-
if (Ct(shouldLogin) || !shouldLogin) {
|
|
23
|
-
R.info("Publish cancelled. Run `mdtolink login` to authenticate.");
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
const { login } = await import("./login-DKrVl_-X.mjs");
|
|
27
|
-
await login();
|
|
28
|
-
token = await getToken();
|
|
29
|
-
if (!token) {
|
|
30
|
-
R.error("Authentication failed. Cannot publish.");
|
|
31
|
-
process.exitCode = 1;
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
20
|
+
const auth = await requireAuth();
|
|
21
|
+
if (!auth) return;
|
|
35
22
|
const content = await readFile(absolutePath, "utf-8");
|
|
36
23
|
if (content.trim().length === 0) {
|
|
37
24
|
R.error("File is empty.");
|
|
@@ -40,17 +27,36 @@ async function publish(filePath, options) {
|
|
|
40
27
|
}
|
|
41
28
|
const title = options.title ?? basename(absolutePath, extname(absolutePath));
|
|
42
29
|
const existingMapping = (await getDocumentMap())[absolutePath];
|
|
43
|
-
|
|
30
|
+
let { api, username } = auth;
|
|
44
31
|
const spin = bt();
|
|
45
32
|
if (existingMapping) {
|
|
46
33
|
spin.start("Updating document...");
|
|
47
|
-
await updateExisting(api, absolutePath, existingMapping.documentId, content, title, options.slug, spin)
|
|
34
|
+
if (await updateExisting(api, absolutePath, existingMapping.documentId, content, title, options.slug, spin, username)) {
|
|
35
|
+
const reauthed = await promptReauth();
|
|
36
|
+
if (!reauthed) return;
|
|
37
|
+
api = reauthed.api;
|
|
38
|
+
username = reauthed.username;
|
|
39
|
+
const retrySpin = bt();
|
|
40
|
+
retrySpin.start("Retrying update...");
|
|
41
|
+
await updateExisting(api, absolutePath, existingMapping.documentId, content, title, options.slug, retrySpin, username);
|
|
42
|
+
}
|
|
48
43
|
} else {
|
|
49
44
|
spin.start("Publishing document...");
|
|
50
|
-
await publishNew(api, absolutePath, content, title, options.slug, spin)
|
|
45
|
+
if (await publishNew(api, absolutePath, content, title, options.slug, spin, username)) {
|
|
46
|
+
const reauthed = await promptReauth();
|
|
47
|
+
if (!reauthed) return;
|
|
48
|
+
api = reauthed.api;
|
|
49
|
+
username = reauthed.username;
|
|
50
|
+
const retrySpin = bt();
|
|
51
|
+
retrySpin.start("Retrying publish...");
|
|
52
|
+
await publishNew(api, absolutePath, content, title, options.slug, retrySpin, username);
|
|
53
|
+
}
|
|
51
54
|
}
|
|
52
55
|
}
|
|
53
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Returns true if the caller should prompt re-auth and retry.
|
|
58
|
+
*/
|
|
59
|
+
async function updateExisting(api, absolutePath, documentId, content, title, slug, spin, username) {
|
|
54
60
|
try {
|
|
55
61
|
const result = await api.documents.update({
|
|
56
62
|
params: { id: documentId },
|
|
@@ -62,7 +68,7 @@ async function updateExisting(api, absolutePath, documentId, content, title, slu
|
|
|
62
68
|
});
|
|
63
69
|
if (result.status === 200) {
|
|
64
70
|
const doc = result.body;
|
|
65
|
-
const url = formatDocumentUrl(doc);
|
|
71
|
+
const url = formatDocumentUrl(doc, username);
|
|
66
72
|
await setDocumentMapping(absolutePath, {
|
|
67
73
|
documentId: doc.id,
|
|
68
74
|
slug: doc.slug,
|
|
@@ -71,32 +77,33 @@ async function updateExisting(api, absolutePath, documentId, content, title, slu
|
|
|
71
77
|
});
|
|
72
78
|
spin.stop("Document updated!");
|
|
73
79
|
R.success(`Updated: ${url}`);
|
|
74
|
-
return;
|
|
80
|
+
return false;
|
|
75
81
|
}
|
|
76
82
|
const body = result.body;
|
|
77
83
|
const errorMsg = body.message ?? body.error ?? "Unknown error";
|
|
78
84
|
spin.stop(`Update failed: ${errorMsg}`);
|
|
79
|
-
if (result.status === 401)
|
|
80
|
-
R.error("Session expired. Run `mdtolink login` to re-authenticate.");
|
|
81
|
-
process.exitCode = 1;
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
85
|
+
if (result.status === 401) return true;
|
|
84
86
|
if (result.status === 404) {
|
|
85
87
|
R.warning("Previous document no longer exists on server. Creating a new one...");
|
|
86
88
|
const newSpin = bt();
|
|
87
89
|
newSpin.start("Publishing document...");
|
|
88
|
-
await publishNew(api, absolutePath, content, title, slug, newSpin);
|
|
89
|
-
return;
|
|
90
|
+
await publishNew(api, absolutePath, content, title, slug, newSpin, username);
|
|
91
|
+
return false;
|
|
90
92
|
}
|
|
91
93
|
if (result.status === 403) R.info("Upgrade at https://mdtolink.com/pricing");
|
|
92
94
|
process.exitCode = 1;
|
|
95
|
+
return false;
|
|
93
96
|
} catch {
|
|
94
97
|
spin.stop("Update failed.");
|
|
95
98
|
R.error("Could not connect to server. Check MDTOLINK_SERVER_URL.");
|
|
96
99
|
process.exitCode = 1;
|
|
100
|
+
return false;
|
|
97
101
|
}
|
|
98
102
|
}
|
|
99
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Returns true if the caller should prompt re-auth and retry.
|
|
105
|
+
*/
|
|
106
|
+
async function publishNew(api, absolutePath, content, title, slug, spin, username) {
|
|
100
107
|
try {
|
|
101
108
|
const result = await api.documents.create({ body: {
|
|
102
109
|
content,
|
|
@@ -106,7 +113,7 @@ async function publishNew(api, absolutePath, content, title, slug, spin) {
|
|
|
106
113
|
} });
|
|
107
114
|
if (result.status === 201) {
|
|
108
115
|
const doc = result.body;
|
|
109
|
-
const url = formatDocumentUrl(doc);
|
|
116
|
+
const url = formatDocumentUrl(doc, username);
|
|
110
117
|
await setDocumentMapping(absolutePath, {
|
|
111
118
|
documentId: doc.id,
|
|
112
119
|
slug: doc.slug,
|
|
@@ -115,20 +122,22 @@ async function publishNew(api, absolutePath, content, title, slug, spin) {
|
|
|
115
122
|
});
|
|
116
123
|
spin.stop("Published!");
|
|
117
124
|
R.success(`Published: ${url}`);
|
|
118
|
-
return;
|
|
125
|
+
return false;
|
|
119
126
|
}
|
|
120
127
|
spin.stop("Publish failed.");
|
|
121
128
|
const body = result.body;
|
|
122
|
-
if (result.status === 401)
|
|
123
|
-
|
|
129
|
+
if (result.status === 401) return true;
|
|
130
|
+
if (result.status === 403) {
|
|
124
131
|
R.error(body.message ?? body.error);
|
|
125
132
|
R.info("Upgrade at https://mdtolink.com/pricing");
|
|
126
133
|
} else R.error(body.message ?? body.error);
|
|
127
134
|
process.exitCode = 1;
|
|
135
|
+
return false;
|
|
128
136
|
} catch {
|
|
129
137
|
spin.stop("Publish failed.");
|
|
130
138
|
R.error("Could not connect to server. Check MDTOLINK_SERVER_URL.");
|
|
131
139
|
process.exitCode = 1;
|
|
140
|
+
return false;
|
|
132
141
|
}
|
|
133
142
|
}
|
|
134
143
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as createApiClient } from "./api-CPJjLxqz.mjs";
|
|
3
|
+
import { c as getUsername, s as getToken } from "./config-cFx42NU7.mjs";
|
|
4
|
+
import { c as Ct, n as R, r as Re } from "./dist-BbvD4qtQ.mjs";
|
|
5
|
+
|
|
6
|
+
//#region src/cli/lib/require-auth.ts
|
|
7
|
+
/**
|
|
8
|
+
* Ensure the user is authenticated. If no token exists, prompts to login.
|
|
9
|
+
* Returns an auth context with API client, token, and username — or null if auth failed.
|
|
10
|
+
*/
|
|
11
|
+
async function requireAuth() {
|
|
12
|
+
let token = await getToken();
|
|
13
|
+
if (!token) {
|
|
14
|
+
const shouldLogin = await Re({ message: "You are not logged in. Would you like to authorize now?" });
|
|
15
|
+
if (Ct(shouldLogin) || !shouldLogin) {
|
|
16
|
+
R.info("Run `mdtolink login` to authenticate.");
|
|
17
|
+
process.exitCode = 1;
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const { login } = await import("./login-DOLV04ZV.mjs");
|
|
21
|
+
await login();
|
|
22
|
+
token = await getToken();
|
|
23
|
+
if (!token) {
|
|
24
|
+
R.error("Authentication failed.");
|
|
25
|
+
process.exitCode = 1;
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const username = await getUsername();
|
|
30
|
+
return {
|
|
31
|
+
api: createApiClient(token),
|
|
32
|
+
token,
|
|
33
|
+
username
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Prompt re-authentication on expired session (401).
|
|
38
|
+
* Returns a fresh auth context, or null if re-auth failed/declined.
|
|
39
|
+
*/
|
|
40
|
+
async function promptReauth() {
|
|
41
|
+
const shouldLogin = await Re({ message: "Session expired. Re-authenticate?" });
|
|
42
|
+
if (Ct(shouldLogin) || !shouldLogin) {
|
|
43
|
+
R.info("Run `mdtolink login` to re-authenticate.");
|
|
44
|
+
process.exitCode = 1;
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const { login } = await import("./login-DOLV04ZV.mjs");
|
|
48
|
+
await login();
|
|
49
|
+
const token = await getToken();
|
|
50
|
+
if (!token) {
|
|
51
|
+
R.error("Authentication failed.");
|
|
52
|
+
process.exitCode = 1;
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const username = await getUsername();
|
|
56
|
+
return {
|
|
57
|
+
api: createApiClient(token),
|
|
58
|
+
token,
|
|
59
|
+
username
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
export { requireAuth as n, promptReauth as t };
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import { a as
|
|
2
|
+
import "./api-CPJjLxqz.mjs";
|
|
3
|
+
import { i as findMappingBySlug, o as getDocumentMap, u as removeDocumentMapping } from "./config-cFx42NU7.mjs";
|
|
4
|
+
import { a as Ze, c as Ct, n as R, o as bt, r as Re, s as je } from "./dist-BbvD4qtQ.mjs";
|
|
5
|
+
import { n as requireAuth } from "./require-auth-m9LOildn.mjs";
|
|
5
6
|
import { resolve } from "node:path";
|
|
6
7
|
|
|
7
8
|
//#region src/cli/commands/unpublish.ts
|
|
8
9
|
async function unpublish(fileOrSlug) {
|
|
9
|
-
const
|
|
10
|
-
if (!
|
|
11
|
-
|
|
12
|
-
process.exitCode = 1;
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
const api = createApiClient(token);
|
|
10
|
+
const auth = await requireAuth();
|
|
11
|
+
if (!auth) return;
|
|
12
|
+
const { api } = auth;
|
|
16
13
|
if (fileOrSlug) await unpublishByArg(api, fileOrSlug);
|
|
17
14
|
else await unpublishInteractive(api);
|
|
18
15
|
}
|
|
@@ -75,7 +72,7 @@ async function unpublishInteractive(api) {
|
|
|
75
72
|
const slug = await Ze({
|
|
76
73
|
message: "Enter the document slug:",
|
|
77
74
|
validate: (val) => {
|
|
78
|
-
if (val.trim().length === 0) return "Slug cannot be empty.";
|
|
75
|
+
if (!val || val.trim().length === 0) return "Slug cannot be empty.";
|
|
79
76
|
}
|
|
80
77
|
});
|
|
81
78
|
if (Ct(slug)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mdtolink",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Publish markdown files to shareable URLs with one command",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -34,17 +34,22 @@
|
|
|
34
34
|
"@opentui/core": "^0.1.84",
|
|
35
35
|
"@ts-rest/core": "3.53.0-rc.1",
|
|
36
36
|
"@types/node": "22.19.13",
|
|
37
|
+
"@vitest/coverage-v8": "^3.2.3",
|
|
37
38
|
"better-auth": "^1.4.19",
|
|
38
39
|
"commander": "^14.0.3",
|
|
39
40
|
"open": "^10.1.0",
|
|
40
41
|
"tsdown": "^0.16.8",
|
|
41
42
|
"tsx": "^4.21.0",
|
|
42
43
|
"typescript": "5.9.3",
|
|
44
|
+
"vitest": "^3.2.3",
|
|
43
45
|
"@mdtolink/contracts": "0.0.1"
|
|
44
46
|
},
|
|
45
47
|
"scripts": {
|
|
46
48
|
"build": "tsdown",
|
|
47
49
|
"dev:tui": "bun run --watch src/index.ts",
|
|
48
|
-
"dev:cli": "tsx src/cli/index.ts"
|
|
50
|
+
"dev:cli": "tsx src/cli/index.ts",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"test:watch": "vitest",
|
|
53
|
+
"test:coverage": "vitest run --coverage"
|
|
49
54
|
}
|
|
50
55
|
}
|
|
File without changes
|