@nearform/fling 0.10.1 → 0.11.1
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 +3 -0
- package/dist/cli.js +2122 -549
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -181,33 +181,33 @@ function sharedVia(site) {
|
|
|
181
181
|
var describeSharedSite = (site) => `- ${site.name}: ${site.url} (shared by ${site.owner}, through ${sharedVia(site)}${site.reviewUrl ? `; review: ${site.reviewUrl}` : ""})`;
|
|
182
182
|
|
|
183
183
|
// ../../node_modules/.pnpm/@cfworker+json-schema@4.1.4/node_modules/@cfworker/json-schema/dist/esm/deep-compare-strict.js
|
|
184
|
-
function deepCompareStrict(
|
|
185
|
-
const typeofa = typeof
|
|
184
|
+
function deepCompareStrict(a3, b) {
|
|
185
|
+
const typeofa = typeof a3;
|
|
186
186
|
if (typeofa !== typeof b) {
|
|
187
187
|
return false;
|
|
188
188
|
}
|
|
189
|
-
const aIsArray = Array.isArray(
|
|
189
|
+
const aIsArray = Array.isArray(a3);
|
|
190
190
|
const bIsArray = Array.isArray(b);
|
|
191
191
|
if (aIsArray !== bIsArray) {
|
|
192
192
|
return false;
|
|
193
193
|
}
|
|
194
194
|
if (aIsArray) {
|
|
195
|
-
const length =
|
|
195
|
+
const length = a3.length;
|
|
196
196
|
if (length !== b.length) {
|
|
197
197
|
return false;
|
|
198
198
|
}
|
|
199
199
|
for (let i = 0; i < length; i++) {
|
|
200
|
-
if (!deepCompareStrict(
|
|
200
|
+
if (!deepCompareStrict(a3[i], b[i])) {
|
|
201
201
|
return false;
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
return true;
|
|
205
205
|
}
|
|
206
206
|
if (typeofa === "object") {
|
|
207
|
-
if (!
|
|
208
|
-
return
|
|
207
|
+
if (!a3 || !b) {
|
|
208
|
+
return a3 === b;
|
|
209
209
|
}
|
|
210
|
-
const aKeys = Object.keys(
|
|
210
|
+
const aKeys = Object.keys(a3);
|
|
211
211
|
const bKeys = Object.keys(b);
|
|
212
212
|
const length = aKeys.length;
|
|
213
213
|
if (length !== bKeys.length) {
|
|
@@ -217,13 +217,13 @@ function deepCompareStrict(a, b) {
|
|
|
217
217
|
if (!Object.prototype.hasOwnProperty.call(b, k)) {
|
|
218
218
|
return false;
|
|
219
219
|
}
|
|
220
|
-
if (!deepCompareStrict(
|
|
220
|
+
if (!deepCompareStrict(a3[k], b[k])) {
|
|
221
221
|
return false;
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
224
|
return true;
|
|
225
225
|
}
|
|
226
|
-
return
|
|
226
|
+
return a3 === b;
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
// ../../node_modules/.pnpm/@cfworker+json-schema@4.1.4/node_modules/@cfworker/json-schema/dist/esm/pointer.js
|
|
@@ -1084,10 +1084,10 @@ Known schemas:
|
|
|
1084
1084
|
const keywordLocation = `${schemaLocation}/contains`;
|
|
1085
1085
|
const errorsLength = errors.length;
|
|
1086
1086
|
let contained = 0;
|
|
1087
|
-
for (let
|
|
1088
|
-
const result = validate(instance[
|
|
1087
|
+
for (let j2 = 0; j2 < length; j2++) {
|
|
1088
|
+
const result = validate(instance[j2], $contains, draft, lookup, shortCircuit, recursiveAnchor, `${instanceLocation}/${j2}`, keywordLocation);
|
|
1089
1089
|
if (result.valid) {
|
|
1090
|
-
evaluated[
|
|
1090
|
+
evaluated[j2] = true;
|
|
1091
1091
|
contained++;
|
|
1092
1092
|
} else {
|
|
1093
1093
|
errors.push(...result.errors);
|
|
@@ -1139,23 +1139,23 @@ Known schemas:
|
|
|
1139
1139
|
}
|
|
1140
1140
|
}
|
|
1141
1141
|
if ($uniqueItems) {
|
|
1142
|
-
for (let
|
|
1143
|
-
const
|
|
1144
|
-
const ao = typeof
|
|
1142
|
+
for (let j2 = 0; j2 < length; j2++) {
|
|
1143
|
+
const a3 = instance[j2];
|
|
1144
|
+
const ao = typeof a3 === "object" && a3 !== null;
|
|
1145
1145
|
for (let k = 0; k < length; k++) {
|
|
1146
|
-
if (
|
|
1146
|
+
if (j2 === k) {
|
|
1147
1147
|
continue;
|
|
1148
1148
|
}
|
|
1149
1149
|
const b = instance[k];
|
|
1150
1150
|
const bo = typeof b === "object" && b !== null;
|
|
1151
|
-
if (
|
|
1151
|
+
if (a3 === b || ao && bo && deepCompareStrict(a3, b)) {
|
|
1152
1152
|
errors.push({
|
|
1153
1153
|
instanceLocation,
|
|
1154
1154
|
keyword: "uniqueItems",
|
|
1155
1155
|
keywordLocation: `${schemaLocation}/uniqueItems`,
|
|
1156
|
-
error: `Duplicate items at indexes ${
|
|
1156
|
+
error: `Duplicate items at indexes ${j2} and ${k}.`
|
|
1157
1157
|
});
|
|
1158
|
-
|
|
1158
|
+
j2 = Number.MAX_SAFE_INTEGER;
|
|
1159
1159
|
k = Number.MAX_SAFE_INTEGER;
|
|
1160
1160
|
}
|
|
1161
1161
|
}
|
|
@@ -1315,9 +1315,11 @@ function markdownHomePages(files) {
|
|
|
1315
1315
|
|
|
1316
1316
|
// ../../packages/shared/src/comments.ts
|
|
1317
1317
|
var COMMENT_MAX_CHARS = 4e3;
|
|
1318
|
+
var COMMENTS_PER_SITE_MAX = 1e3;
|
|
1318
1319
|
var COMMENT_PATH_MAX = 1024;
|
|
1319
1320
|
var FORM_ID_MAX = 40;
|
|
1320
1321
|
var RESPONSE_DATA_MAX_BYTES = 16 * 1024;
|
|
1322
|
+
var RESPONSES_PER_SITE_MAX = 1e4;
|
|
1321
1323
|
var CommentAuthorSchema = z3.discriminatedUnion("kind", [
|
|
1322
1324
|
z3.object({ kind: z3.literal("user"), email: z3.string() }),
|
|
1323
1325
|
z3.object({ kind: z3.literal("guest"), name: z3.string() })
|
|
@@ -1425,11 +1427,11 @@ function normalizeCommentPath(input) {
|
|
|
1425
1427
|
var RAW_QUERY = "?raw=1";
|
|
1426
1428
|
function commentThreads(comments) {
|
|
1427
1429
|
const threads = /* @__PURE__ */ new Map();
|
|
1428
|
-
for (const
|
|
1429
|
-
if (
|
|
1430
|
+
for (const c2 of comments) {
|
|
1431
|
+
if (c2.parentId === null) threads.set(c2.id, { comment: c2, replies: [] });
|
|
1430
1432
|
}
|
|
1431
|
-
for (const
|
|
1432
|
-
if (
|
|
1433
|
+
for (const c2 of comments) {
|
|
1434
|
+
if (c2.parentId !== null) threads.get(c2.parentId)?.replies.push(c2);
|
|
1433
1435
|
}
|
|
1434
1436
|
return [...threads.values()];
|
|
1435
1437
|
}
|
|
@@ -1604,15 +1606,15 @@ var FormsConfigSchema = z4.object({
|
|
|
1604
1606
|
}
|
|
1605
1607
|
});
|
|
1606
1608
|
var DATA_KEYWORDS = /* @__PURE__ */ new Set(["const", "enum", "default", "examples"]);
|
|
1607
|
-
function walkSchema(node,
|
|
1609
|
+
function walkSchema(node, at2, visit) {
|
|
1608
1610
|
if (Array.isArray(node)) {
|
|
1609
|
-
for (const [i, item] of node.entries()) walkSchema(item, `${
|
|
1611
|
+
for (const [i, item] of node.entries()) walkSchema(item, `${at2}/${i}`, visit);
|
|
1610
1612
|
return;
|
|
1611
1613
|
}
|
|
1612
1614
|
if (node === null || typeof node !== "object") return;
|
|
1613
1615
|
for (const [key, value] of Object.entries(node)) {
|
|
1614
|
-
visit(key, value,
|
|
1615
|
-
if (!DATA_KEYWORDS.has(key)) walkSchema(value, `${
|
|
1616
|
+
visit(key, value, at2);
|
|
1617
|
+
if (!DATA_KEYWORDS.has(key)) walkSchema(value, `${at2}/${key}`, visit);
|
|
1616
1618
|
}
|
|
1617
1619
|
}
|
|
1618
1620
|
function resolveLocalRef(root, ref) {
|
|
@@ -1620,8 +1622,8 @@ function resolveLocalRef(root, ref) {
|
|
|
1620
1622
|
if (fragment === "") return root;
|
|
1621
1623
|
if (!fragment.startsWith("/")) {
|
|
1622
1624
|
let found;
|
|
1623
|
-
walkSchema(root, "#", (key, value,
|
|
1624
|
-
if (key === "$anchor" && value === fragment && found === void 0) found =
|
|
1625
|
+
walkSchema(root, "#", (key, value, at2) => {
|
|
1626
|
+
if (key === "$anchor" && value === fragment && found === void 0) found = at2;
|
|
1625
1627
|
});
|
|
1626
1628
|
return found;
|
|
1627
1629
|
}
|
|
@@ -1651,19 +1653,19 @@ function checkFormSchema(schema) {
|
|
|
1651
1653
|
problems.push(`Not a valid JSON Schema: ${e.field ? `${e.field} ` : ""}${e.message}`);
|
|
1652
1654
|
}
|
|
1653
1655
|
}
|
|
1654
|
-
walkSchema(root, "#", (key, value,
|
|
1656
|
+
walkSchema(root, "#", (key, value, at2) => {
|
|
1655
1657
|
if (key === "$ref" && typeof value === "string") {
|
|
1656
1658
|
if (!value.startsWith("#")) {
|
|
1657
|
-
problems.push(`${
|
|
1659
|
+
problems.push(`${at2}: $ref "${value}" is remote; only local refs ("#/$defs/\u2026") are allowed`);
|
|
1658
1660
|
} else if (resolveLocalRef(root, value) === void 0) {
|
|
1659
|
-
problems.push(`${
|
|
1661
|
+
problems.push(`${at2}: $ref "${value}" points at nothing`);
|
|
1660
1662
|
}
|
|
1661
1663
|
}
|
|
1662
1664
|
if ((key === "$dynamicRef" || key === "$recursiveRef") && typeof value === "string") {
|
|
1663
|
-
problems.push(`${
|
|
1665
|
+
problems.push(`${at2}: ${key} is not supported; use $ref`);
|
|
1664
1666
|
}
|
|
1665
|
-
if (key === "$id" &&
|
|
1666
|
-
problems.push(`${
|
|
1667
|
+
if (key === "$id" && at2 !== "#" && typeof value === "string") {
|
|
1668
|
+
problems.push(`${at2}: $id is only allowed at the root`);
|
|
1667
1669
|
}
|
|
1668
1670
|
});
|
|
1669
1671
|
return problems;
|
|
@@ -1694,7 +1696,7 @@ function fieldErrors(units) {
|
|
|
1694
1696
|
if (WRAPPERS.has(u.keyword) && /subschema|does not match schema|do not match/i.test(u.error)) {
|
|
1695
1697
|
continue;
|
|
1696
1698
|
}
|
|
1697
|
-
if (choices.some((
|
|
1699
|
+
if (choices.some((c2) => u.keywordLocation.startsWith(c2))) continue;
|
|
1698
1700
|
let field = fieldOf(u.instanceLocation);
|
|
1699
1701
|
let message = u.error;
|
|
1700
1702
|
const missing = u.keyword === "required" && /"([^"]+)"/.exec(u.error);
|
|
@@ -1727,7 +1729,7 @@ function globRegExp(glob) {
|
|
|
1727
1729
|
const cached = globCache.get(glob);
|
|
1728
1730
|
if (cached) return cached;
|
|
1729
1731
|
const g = glob.replace(/^\/+/, "");
|
|
1730
|
-
let
|
|
1732
|
+
let re2 = "";
|
|
1731
1733
|
for (let i = 0; i < g.length; i++) {
|
|
1732
1734
|
const ch = g[i];
|
|
1733
1735
|
if (ch === "*") {
|
|
@@ -1735,21 +1737,21 @@ function globRegExp(glob) {
|
|
|
1735
1737
|
i++;
|
|
1736
1738
|
if (g[i + 1] === "/") {
|
|
1737
1739
|
i++;
|
|
1738
|
-
|
|
1739
|
-
} else
|
|
1740
|
-
} else
|
|
1741
|
-
} else if (ch === "?")
|
|
1742
|
-
else
|
|
1740
|
+
re2 += "(?:.*/)?";
|
|
1741
|
+
} else re2 += ".*";
|
|
1742
|
+
} else re2 += "[^/]*";
|
|
1743
|
+
} else if (ch === "?") re2 += "[^/]";
|
|
1744
|
+
else re2 += ch.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
1743
1745
|
}
|
|
1744
|
-
const out = new RegExp(`^${
|
|
1746
|
+
const out = new RegExp(`^${re2}$`);
|
|
1745
1747
|
globCache.set(glob, out);
|
|
1746
1748
|
return out;
|
|
1747
1749
|
}
|
|
1748
1750
|
function globMatches(glob, path3) {
|
|
1749
1751
|
const rel = path3.replace(/^\/+/, "");
|
|
1750
|
-
const
|
|
1752
|
+
const re2 = globRegExp(glob);
|
|
1751
1753
|
const names = rel === "" || rel.endsWith("/") ? [rel, rel.replace(/\/$/, ""), `${rel}index.html`] : [rel];
|
|
1752
|
-
return names.some((n) =>
|
|
1754
|
+
return names.some((n) => re2.test(n));
|
|
1753
1755
|
}
|
|
1754
1756
|
function formAppliesTo(form, path3) {
|
|
1755
1757
|
const globs = form.paths ?? [];
|
|
@@ -1805,7 +1807,7 @@ function formsSummaryLines(summary) {
|
|
|
1805
1807
|
const own = f.visibility === "own" ? ", each reviewer sees only their own" : "";
|
|
1806
1808
|
return `${summary.title} \xB7 ${f.title} (${f.id}): ${f.kind === "page" ? "one per reviewer per page" : "a comment type"}${where}${own}`;
|
|
1807
1809
|
}),
|
|
1808
|
-
...summary.warnings.map((
|
|
1810
|
+
...summary.warnings.map((w2) => `warning: ${w2}`)
|
|
1809
1811
|
];
|
|
1810
1812
|
}
|
|
1811
1813
|
function responseFields(form, data) {
|
|
@@ -1874,11 +1876,11 @@ function responsesCsv(rows, forms2 = []) {
|
|
|
1874
1876
|
for (const form of forms2) Object.keys(form.schema.properties ?? {}).forEach(add);
|
|
1875
1877
|
for (const row2 of rows) Object.keys(row2.data).forEach(add);
|
|
1876
1878
|
const fixed = ["id", "path", "formId", "author", "createdAt", "updatedAt", "versionId"];
|
|
1877
|
-
const header = [...fixed, ...columns.map((
|
|
1879
|
+
const header = [...fixed, ...columns.map((c2) => fixed.includes(c2) ? `data.${c2}` : c2)];
|
|
1878
1880
|
const lines = [header.map(csvCell).join(",")];
|
|
1879
1881
|
for (const row2 of rows) {
|
|
1880
1882
|
lines.push(
|
|
1881
|
-
[...fixed.map((k) => csvCell(row2[k])), ...columns.map((
|
|
1883
|
+
[...fixed.map((k) => csvCell(row2[k])), ...columns.map((c2) => csvCell(row2.data[c2]))].join(",")
|
|
1882
1884
|
);
|
|
1883
1885
|
}
|
|
1884
1886
|
return `${lines.join("\r\n")}\r
|
|
@@ -1893,8 +1895,8 @@ function progressLines(exported) {
|
|
|
1893
1895
|
return exported.progress.map((p) => {
|
|
1894
1896
|
const form = exported.forms.find((f) => f.id === p.form);
|
|
1895
1897
|
const done = p.pages.filter((page2) => (p.done[page2]?.length ?? 0) > 0).length;
|
|
1896
|
-
const
|
|
1897
|
-
const where = form?.kind === "comment" ? `${
|
|
1898
|
+
const count3 = exported.responses.filter((r) => r.formId === p.form).length;
|
|
1899
|
+
const where = form?.kind === "comment" ? `${count3} response${count3 === 1 ? "" : "s"} on ${Object.keys(p.done).length} of ${p.pages.length} pages` : `${done} / ${p.pages.length} page${p.pages.length === 1 ? "" : "s"} answered`;
|
|
1898
1900
|
return `${form?.title ?? p.form} (${p.form}): ${where}, ${p.reviewers.length} reviewer${p.reviewers.length === 1 ? "" : "s"}`;
|
|
1899
1901
|
});
|
|
1900
1902
|
}
|
|
@@ -1905,6 +1907,7 @@ var MAX_FILE_BYTES = 25 * 1024 * 1024;
|
|
|
1905
1907
|
var MAX_FILES = 5e3;
|
|
1906
1908
|
var MAX_PATH_LENGTH = 1024;
|
|
1907
1909
|
var MAX_PATH_FOLDER_LENGTH = 100;
|
|
1910
|
+
var MAX_PATHS_PER_SITE = 1e3;
|
|
1908
1911
|
|
|
1909
1912
|
// ../../packages/shared/src/manifest.ts
|
|
1910
1913
|
import { z as z5 } from "zod";
|
|
@@ -2066,7 +2069,7 @@ function scanForSecrets(text2, path3) {
|
|
|
2066
2069
|
findings.push({ path: path3, line, rule: rule.id });
|
|
2067
2070
|
}
|
|
2068
2071
|
}
|
|
2069
|
-
return findings.sort((
|
|
2072
|
+
return findings.sort((a3, b) => a3.line - b.line || a3.rule.localeCompare(b.rule));
|
|
2070
2073
|
}
|
|
2071
2074
|
var BINARY_EXTENSIONS = new Set(
|
|
2072
2075
|
"png jpg jpeg gif webp avif ico bmp tif tiff heic psd woff woff2 ttf otf eot mp3 mp4 m4a m4v mov webm ogg oga ogv wav flac aac avi mkv zip gz tgz br zst bz2 xz 7z rar wasm pdf glb gltf-binary bin dat".split(/\s+/).filter(Boolean)
|
|
@@ -2537,6 +2540,7 @@ var CLI_PACKAGE = "@nearform/fling";
|
|
|
2537
2540
|
var REPO_SLUG = "nearform/fling";
|
|
2538
2541
|
var DEFAULT_INSTALL_COMMAND = `npm install -g ${CLI_PACKAGE}`;
|
|
2539
2542
|
var REPO_URL = `https://github.com/${REPO_SLUG}`;
|
|
2543
|
+
var WHY_SITE_NAME = "why-fling";
|
|
2540
2544
|
|
|
2541
2545
|
// ../../packages/shared/src/forms-templates.ts
|
|
2542
2546
|
var FORM_TEMPLATE_NAMES = ["labels", "rubric", "compare", "issue", "survey"];
|
|
@@ -2779,6 +2783,1476 @@ function describeGroup(group) {
|
|
|
2779
2783
|
].join("\n");
|
|
2780
2784
|
}
|
|
2781
2785
|
|
|
2786
|
+
// ../../packages/shared/src/guide.ts
|
|
2787
|
+
import { z as z11 } from "zod";
|
|
2788
|
+
var GUIDE_PARTS = [
|
|
2789
|
+
{ id: "start", label: "Start" },
|
|
2790
|
+
{ id: "publish", label: "Publish" },
|
|
2791
|
+
{ id: "share", label: "Share" },
|
|
2792
|
+
{ id: "team-sites", label: "Team sites" },
|
|
2793
|
+
{ id: "feedback", label: "Feedback" },
|
|
2794
|
+
{ id: "admin", label: "Admin" },
|
|
2795
|
+
{ id: "run", label: "Run your own Fling" }
|
|
2796
|
+
];
|
|
2797
|
+
var PART_IDS = GUIDE_PARTS.map((p) => p.id);
|
|
2798
|
+
var GUIDE_ROUTE = "/guide";
|
|
2799
|
+
var GuideFrontmatterSchema = z11.object({
|
|
2800
|
+
title: z11.string().min(1),
|
|
2801
|
+
part: z11.enum(PART_IDS),
|
|
2802
|
+
/** its place within the part */
|
|
2803
|
+
order: z11.number().int(),
|
|
2804
|
+
/** one line: the nav's tooltip and what search matches besides the text */
|
|
2805
|
+
summary: z11.string().min(1),
|
|
2806
|
+
/** capabilities the page needs; it is hidden on an instance without any of them */
|
|
2807
|
+
requires: z11.array(z11.string().min(1)).default([]),
|
|
2808
|
+
/** `admin`: shown to the instance's admins only */
|
|
2809
|
+
audience: z11.enum(["everyone", "admin"]).default("everyone"),
|
|
2810
|
+
/** repository globs of the code the page describes (coarse: a directory, not a list of files) */
|
|
2811
|
+
sources: z11.array(z11.string().min(1)).min(1),
|
|
2812
|
+
/** the commit at which the page was last checked against its sources */
|
|
2813
|
+
verified: z11.string().regex(/^[0-9a-f]{7,40}$/, "a commit sha")
|
|
2814
|
+
});
|
|
2815
|
+
var instanceGuideUrl = (instance) => instance?.appOrigin && instance.capabilities?.guide === true ? `${instance.appOrigin}${GUIDE_ROUTE}` : void 0;
|
|
2816
|
+
|
|
2817
|
+
// ../../node_modules/.pnpm/marked@18.1.3/node_modules/marked/lib/marked.esm.js
|
|
2818
|
+
function H() {
|
|
2819
|
+
return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null };
|
|
2820
|
+
}
|
|
2821
|
+
var S = H();
|
|
2822
|
+
function se(a3) {
|
|
2823
|
+
S = a3;
|
|
2824
|
+
}
|
|
2825
|
+
var B = { exec: () => null };
|
|
2826
|
+
function D(a3) {
|
|
2827
|
+
let e = [];
|
|
2828
|
+
return (t) => {
|
|
2829
|
+
let n = Math.max(0, Math.min(3, t - 1)), s = e[n];
|
|
2830
|
+
return s || (s = a3(n), e[n] = s), s;
|
|
2831
|
+
};
|
|
2832
|
+
}
|
|
2833
|
+
function c(a3, e = "") {
|
|
2834
|
+
let t = typeof a3 == "string" ? a3 : a3.source, n = { replace: (s, r) => {
|
|
2835
|
+
let o = typeof r == "string" ? r : r.source;
|
|
2836
|
+
return o = o.replace(T.caret, "$1"), t = t.replace(s, o), n;
|
|
2837
|
+
}, getRegex: () => new RegExp(t, e) };
|
|
2838
|
+
return n;
|
|
2839
|
+
}
|
|
2840
|
+
var Te = ((a3 = "") => {
|
|
2841
|
+
try {
|
|
2842
|
+
return !!new RegExp("(?<=1)(?<!1)" + a3);
|
|
2843
|
+
} catch {
|
|
2844
|
+
return false;
|
|
2845
|
+
}
|
|
2846
|
+
})();
|
|
2847
|
+
var T = { codeRemoveIndent: /^(?: {0,3}\t| {1,4})/gm, outputLinkReplace: /\\([\[\]])/g, indentCodeCompensation: /^(\s+)(?:```)/, beginningSpace: /^\s+/, endingHash: /#$/, startingSpaceChar: /^ /, endingSpaceChar: / $/, endingSpaceTabChar: /[ \t]$/, nonSpaceChar: /[^ ]/, newLineCharGlobal: /\n/g, tabCharGlobal: /\t/g, leadingSpaceTab: /^[ \t]+/, multipleSpaceGlobal: /\s+/g, blankLine: /^[ \t]*$/, doubleBlankLine: /\n[ \t]*\n[ \t]*$/, blockquoteStart: /^ {0,3}>/, blockquoteSetextReplace: /\n {0,3}((?:=+|-+)[ \t]*)(?=\n|$)/g, blockquoteSetextReplace2: /^ {0,3}>[ \t]?/gm, blockquoteMarkerWhitespace: /^( {0,3}>)([ \t]+)/gm, listReplaceNesting: /^ {1,4}(?=( {4})*[^ ])/g, listIsTask: /^\[[ xX]\][ \t]+\S/, listReplaceTask: /^\[[ xX]\][ \t]+/, listTaskCheckbox: /\[[ xX]\]/, anyLine: /\n.*\n/, hrefBrackets: /^<(.*)>$/, tableDelimiter: /[:|]/, tableAlignChars: /^\||\| *$/g, tableRowBlankLine: /\n[ \t]*$/, tableAlignRight: /^ *-+: *$/, tableAlignCenter: /^ *:-+: *$/, tableAlignLeft: /^ *:-+ *$/, startATag: /^<a /i, endATag: /^<\/a>/i, startPreScriptTag: /^<(pre|code|kbd|script)(\s|>)/i, endPreScriptTag: /^<\/(pre|code|kbd|script)(\s|>)/i, startAngleBracket: /^</, endAngleBracket: />$/, pedanticHrefTitle: /^([^'"]*[^\s])\s+(['"])(.*)\2/, unicodeAlphaNumeric: /[\p{L}\p{N}]/u, numericCharacterReference: /&#(?:(\d{1,7})|[Xx]([A-Fa-f0-9]{1,6}));/, numericCharacterReferenceOrAmpersand: /&#(?:(\d{1,7})|[Xx]([A-Fa-f0-9]{1,6}));|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g, escapeTest: /[&<>"']/, escapeReplace: /[&<>"']/g, escapeTestNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/, escapeReplaceNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g, caret: /(^|[^\[])\^/g, percentDecode: /%25/g, findPipe: /\|/g, splitPipe: / \|/, slashPipe: /\\\|/g, carriageReturn: /\r\n|\r/g, spaceLine: /^ +$/gm, notSpaceStart: /^\S*/, endingNewline: /\n$/, listItemRegex: (a3) => new RegExp(`^( {0,3}${a3})((?:[ ][^\\n]*)?(?:\\n|$))`), nextBulletRegex: D((a3) => new RegExp(`^ {0,${a3}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`)), hrRegex: D((a3) => new RegExp(`^ {0,${a3}}((?:-[ ]*){3,}|(?:_[ ]*){3,}|(?:\\*[ ]*){3,})(?:\\n+|$)`)), fencesBeginRegex: D((a3) => new RegExp(`^ {0,${a3}}(?:\`\`\`|~~~)`)), headingBeginRegex: D((a3) => new RegExp(`^ {0,${a3}}#{1,6}(?:\\s|$)`)), pedanticHeadingBeginRegex: D((a3) => new RegExp(`^ {0,${a3}}#`)), htmlBeginRegex: D((a3) => new RegExp(`^ {0,${a3}}(?:</?(?:${K})(?: +|$|/?>)|<(?:(?:script|pre|style|textarea)(?:[\\s>]|$)|!--)|<\\?|<![A-Za-z]|<!\\[CDATA\\[)`, "i")), blockquoteBeginRegex: D((a3) => new RegExp(`^ {0,${a3}}>`)) };
|
|
2848
|
+
var ve = /^(?:[ \t]*(?:\n|$))+/;
|
|
2849
|
+
var Ze = /^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/;
|
|
2850
|
+
var He = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}(?:(?=`)\1`*|(?=~)\1~*) *(?=\n|$)|$)/;
|
|
2851
|
+
var W = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
|
|
2852
|
+
var je = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
|
|
2853
|
+
var oe = / {0,3}(?:[*+-]|\d{1,9}[.)])/;
|
|
2854
|
+
var Oe = /^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |fences|blockquote|heading|hr|html|table))+?)\n {0,3}(=+|-+)[ \t]*(?:\n+|$)/;
|
|
2855
|
+
var we = c(Oe).replace(/bull/g, oe).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}(?:\s|$)/).replace(/hr/g, / {0,3}(?:(?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/\|table/g, "").getRegex();
|
|
2856
|
+
var Ge = c(Oe).replace(/bull/g, oe).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}(?:\s|$)/).replace(/hr/g, / {0,3}(?:(?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/table/g, / {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex();
|
|
2857
|
+
var ae = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table|[ \t]+\n)[^\n]+)*)/;
|
|
2858
|
+
var Ne = /^[^\n]+/;
|
|
2859
|
+
var le = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\\n]|\n(?![ \t]*\n))+/;
|
|
2860
|
+
var Fe = c(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label", le).replace("title", /(?:"(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\\n]|\n(?!\n))*'|\((?:\\[\s\S]|[^()\\])*\))/).getRegex();
|
|
2861
|
+
var Qe = c(/^(bull)([ \t][^\n]*?)?(?:\n|$)/).replace(/bull/g, oe).getRegex();
|
|
2862
|
+
var K = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";
|
|
2863
|
+
var ue = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
|
|
2864
|
+
var Ue = c("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n*|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>[^\\n]*\\n*|$)|<![A-Z][\\s\\S]*?(?:>[^\\n]*\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>[^\\n]*\\n*|$)|</?(tag)(?:[ \\t]+|\\n|/?>|$)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!(?:script|pre|style|textarea)(?![a-z0-9-]))([a-z][a-z0-9-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</[a-z][a-z0-9-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))", "i").replace("comment", ue).replace("tag", K).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
|
|
2865
|
+
var Pe = (a3) => c(ae).replace("hr", W).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", a3).replace("html", " {0,3}(?:</?(?:tag)(?: +|\\n|/?>)|<(?:(?:script|pre|style|textarea)(?:[\\s>]|$)|!--)|<\\?|<![A-Za-z]|<!\\[CDATA\\[)").replace("tag", K).getRegex();
|
|
2866
|
+
var We = Pe(/ {0,3}(?:[*+-]|1[.)])[ \t]+[^ \t\n]/);
|
|
2867
|
+
var Ke = Pe(/ {0,3}(?:[*+-]|\d{1,9}[.)])(?:[ \t]|\n|$)/);
|
|
2868
|
+
var Xe = c(/^( {0,3}> ?(?:(?![ \t]*(?:\n|$))(paragraph)|[^\n]*)(?:\n|$))+/).replace("paragraph", Ke).getRegex();
|
|
2869
|
+
var pe = { blockquote: Xe, code: Ze, def: Fe, fences: He, heading: je, hr: W, html: Ue, lheading: we, list: Qe, newline: ve, paragraph: We, table: B, text: Ne };
|
|
2870
|
+
var xe = c("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr", W).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("blockquote", " {0,3}>").replace("code", "(?: {4}| {0,3} )[^\\n]").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", " {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html", " {0,3}(?:</?(?:tag)(?: +|\\n|/?>)|<(?:(?:script|pre|style|textarea)(?:[\\s>]|$)|!--)|<\\?|<![A-Za-z]|<!\\[CDATA\\[)").replace("tag", K).getRegex();
|
|
2871
|
+
var Ve = { ...pe, lheading: Ge, table: xe, paragraph: c(ae).replace("hr", W).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("table", xe).replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", " {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]").replace("html", " {0,3}(?:</?(?:tag)(?: +|\\n|/?>)|<(?:(?:script|pre|style|textarea)(?:[\\s>]|$)|!--)|<\\?|<![A-Za-z]|<!\\[CDATA\\[)").replace("tag", K).getRegex() };
|
|
2872
|
+
var Je = { ...pe, html: c(`^ *(?:comment(?: *\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1>(?: *\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?>(?: *\\n{2,}|\\s*$))`).replace("comment", ue).replace(/tag/g, "(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(), def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, heading: /^(#{1,6})(.*)(?:\n+|$)/, fences: B, lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, paragraph: c(ae).replace("hr", W).replace("heading", ` *#{1,6} *[^
|
|
2873
|
+
]`).replace("lheading", we).replace("|table", "").replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").replace("|tag", "").getRegex() };
|
|
2874
|
+
var Ye = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
|
|
2875
|
+
var et = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
|
|
2876
|
+
var Se = /^( {2,}|\\)\n(?!\s*$)[ \t]*/;
|
|
2877
|
+
var tt = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
|
|
2878
|
+
var $ = /[\p{P}\p{S}]/u;
|
|
2879
|
+
var j = /[\s\p{P}\p{S}]/u;
|
|
2880
|
+
var X = /[^\s\p{P}\p{S}]/u;
|
|
2881
|
+
var nt = c(/^((?![*_])punctSpace)/, "u").replace(/punctSpace/g, j).getRegex();
|
|
2882
|
+
var rt = /[\p{Pi}\p{Ps}"']/u;
|
|
2883
|
+
var ye = /(?!~)[\p{P}\p{S}]/u;
|
|
2884
|
+
var st = /(?!~)[\s\p{P}\p{S}]/u;
|
|
2885
|
+
var it = /(?:[^\s\p{P}\p{S}]|~)/u;
|
|
2886
|
+
var ot = c(/link|precode-code|html/, "g").replace("link", /\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-", Te ? "(?<!`)()" : "(^^|[^`])").replace("code", /(?<b>`+)[^`]+\k<b>(?!`)/).replace("html", /<(?! )[^<>]*?>/).getRegex();
|
|
2887
|
+
var _e = /^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/;
|
|
2888
|
+
var at = c(_e, "u").replace(/punct/g, $).getRegex();
|
|
2889
|
+
var lt = c(_e, "u").replace(/punct/g, ye).getRegex();
|
|
2890
|
+
var ut = /^(?:\*+(?:((?!\*)(?!openQuote)punct)|([^\s*]))?)|^_+(?:((?!_)(?!openQuote)punct)|([^\s_]))?/;
|
|
2891
|
+
var pt = c(ut, "u").replace(/openQuote/g, rt).replace(/punct/g, $).getRegex();
|
|
2892
|
+
var $e = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)";
|
|
2893
|
+
var ct = c($e, "gu").replace(/notPunctSpace/g, X).replace(/punctSpace/g, j).replace(/punct/g, $).getRegex();
|
|
2894
|
+
var ht = c($e, "gu").replace(/notPunctSpace/g, it).replace(/punctSpace/g, st).replace(/punct/g, ye).getRegex();
|
|
2895
|
+
var dt = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)[\\s](\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|(?:(?!\\*)punct|notPunctSpace)(\\*+)(?!\\*)(?=notPunctSpace)";
|
|
2896
|
+
var gt = c(dt, "gu").replace(/notPunctSpace/g, X).replace(/punctSpace/g, j).replace(/punct/g, $).getRegex();
|
|
2897
|
+
var kt = c("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)", "gu").replace(/notPunctSpace/g, X).replace(/punctSpace/g, j).replace(/punct/g, $).getRegex();
|
|
2898
|
+
var ft = "^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)[\\s](_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)|(?:(?!_)punct|notPunctSpace)(_+)(?!_)(?=notPunctSpace)";
|
|
2899
|
+
var mt = c(ft, "gu").replace(/notPunctSpace/g, X).replace(/punctSpace/g, j).replace(/punct/g, $).getRegex();
|
|
2900
|
+
var xt = c(/^~~?(?:((?!~)punct)|[^\s~])/, "u").replace(/punct/g, $).getRegex();
|
|
2901
|
+
var bt = "^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)";
|
|
2902
|
+
var Rt = c(bt, "gu").replace(/notPunctSpace/g, X).replace(/punctSpace/g, j).replace(/punct/g, $).getRegex();
|
|
2903
|
+
var Tt = c(/\\(punct)/, "gu").replace(/punct/g, $).getRegex();
|
|
2904
|
+
var Ot = c(/(`+)(?:[^`]|[^`][\s\S]*?[^`])\1(?!`)|`+|\\(punct)/, "gu").replace(/punct/g, $).getRegex();
|
|
2905
|
+
var wt = c(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme", /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email", /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex();
|
|
2906
|
+
var Pt = c(ue).replace("(?:-->|$)", "-->").getRegex();
|
|
2907
|
+
var St = c("^comment|^</[a-zA-Z][a-zA-Z0-9-]*\\s*>|^<[a-zA-Z][a-zA-Z0-9-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment", Pt).replace("attribute", /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex();
|
|
2908
|
+
var Le = /\[(?:\\[\s\S]|[^\[\]\\])*\]/;
|
|
2909
|
+
var re = c(/(?:\[(?:brackets|\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/).replace("brackets", Le).getRegex();
|
|
2910
|
+
var yt = c(/^!?\[(label)\]\([ \t\n]*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?[ \t\n]*\)/).replace("label", re).replace("href", /<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]+|(?=\))/).replace("title", /"(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\])*'|\((?:\\[\s\S]|[^)\\])*\)/).getRegex();
|
|
2911
|
+
var _t = c(/^!?\[(label)\]\[(ref)\]/).replace("label", re).replace("ref", le).getRegex();
|
|
2912
|
+
var $t = c(/^!?\[(ref)\](?:\[\])?/).replace("ref", le).getRegex();
|
|
2913
|
+
var be = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\]){1,999}/;
|
|
2914
|
+
var Lt = c(/(?:[^\[\]\\`]*(?:\[(?:brackets|\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\]))){0,999}?[^\[\]\\`]*?/).replace("brackets", Le).getRegex();
|
|
2915
|
+
var Ct = c("reflink|nolink(?!\\()", "g").replace("reflink", c(/^!?\[(label)\]\[(ref)\]/).replace("label", Lt).replace("ref", be).getRegex()).replace("nolink", c(/^!?\[(ref)\](?:\[\])?/).replace("ref", be).getRegex()).getRegex();
|
|
2916
|
+
var Re = /[hH][tT][tT][pP][sS]?|[fF][tT][pP]/;
|
|
2917
|
+
var It = /[A-Za-z0-9._+-]+@[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![\w-])/;
|
|
2918
|
+
var At = c(/(?:mailto:email|xmpp:email(?:\/[A-Za-z0-9@.]+)?)/).replace(/email/g, It).getRegex();
|
|
2919
|
+
var ce = { _backpedal: B, anyPunctuation: Tt, anyPunctuationOutsideCode: Ot, autolink: wt, blockSkip: ot, br: Se, code: et, del: B, delLDelim: B, delRDelim: B, emStrongLDelim: at, emStrongRDelimAst: ct, emStrongRDelimUnd: kt, escape: Ye, link: yt, nolink: $t, punctuation: nt, reflink: _t, reflinkSearch: Ct, tag: St, text: tt, url: B };
|
|
2920
|
+
var Et = { ...ce, emStrongLDelim: pt, emStrongRDelimAst: gt, emStrongRDelimUnd: mt, link: c(/^!?\[(label)\]\((.*?)\)/).replace("label", re).getRegex(), reflink: c(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", re).getRegex() };
|
|
2921
|
+
var ie = { ...ce, emStrongRDelimAst: ht, emStrongLDelim: lt, delLDelim: xt, delRDelim: Rt, url: c(/^emailProtocol|^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("emailProtocol", At).replace("protocol", Re).replace("email", /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![\w-])/).getRegex(), _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/, del: /^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/, text: c(/^(?:[^a-zA-Z0-9](?=emailProtocol)|(`+|~+|[^`~])(?:(?=[`~])|(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|wwwStart|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9](?=emailProtocol)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))))/).replace("protocol", Re).replace(/emailProtocol/g, /(?:mailto|xmpp):/).replace("wwwStart", Te ? "(?<![^\\s*_~(])www\\." : "www\\.").getRegex() };
|
|
2922
|
+
var zt = { ...ie, br: c(Se).replace("{2,}", "*").getRegex(), text: c(ie.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex() };
|
|
2923
|
+
var V = { normal: pe, gfm: Ve, pedantic: Je };
|
|
2924
|
+
var G = { normal: ce, gfm: ie, breaks: zt, pedantic: Et };
|
|
2925
|
+
var Mt = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
|
|
2926
|
+
var Ce = (a3) => Mt[a3];
|
|
2927
|
+
function P(a3, e) {
|
|
2928
|
+
if (e) {
|
|
2929
|
+
if (T.escapeTest.test(a3)) return a3.replace(T.escapeReplace, Ce);
|
|
2930
|
+
} else if (T.escapeTestNoEncode.test(a3)) return a3.replace(T.escapeReplaceNoEncode, Ce);
|
|
2931
|
+
return a3;
|
|
2932
|
+
}
|
|
2933
|
+
function Ie(a3) {
|
|
2934
|
+
return T.numericCharacterReference.test(a3) ? a3.replace(T.numericCharacterReferenceOrAmpersand, (e, t, n) => {
|
|
2935
|
+
if (t === void 0 && n === void 0) return "&";
|
|
2936
|
+
let s = t === void 0 ? Number.parseInt(n, 16) : Number.parseInt(t, 10);
|
|
2937
|
+
return s === 0 || s > 1114111 || s >= 55296 && s <= 57343 ? "\uFFFD" : s === 38 ? "&" : String.fromCodePoint(s);
|
|
2938
|
+
}) : a3;
|
|
2939
|
+
}
|
|
2940
|
+
function he(a3) {
|
|
2941
|
+
try {
|
|
2942
|
+
a3 = encodeURI(a3).replace(T.percentDecode, "%");
|
|
2943
|
+
} catch {
|
|
2944
|
+
return null;
|
|
2945
|
+
}
|
|
2946
|
+
return a3;
|
|
2947
|
+
}
|
|
2948
|
+
function de(a3, e) {
|
|
2949
|
+
let t = a3.replace(T.findPipe, (r, o, i) => {
|
|
2950
|
+
let l = false, p = o;
|
|
2951
|
+
for (; --p >= 0 && i[p] === "\\"; ) l = !l;
|
|
2952
|
+
return l ? "|" : " |";
|
|
2953
|
+
}), n = t.split(T.splitPipe), s = 0;
|
|
2954
|
+
if (n[0].trim() || n.shift(), n.length > 0 && !n.at(-1)?.trim() && n.pop(), e) if (n.length > e) n.splice(e);
|
|
2955
|
+
else for (; n.length < e; ) n.push("");
|
|
2956
|
+
for (; s < n.length; s++) n[s] = n[s].trim().replace(T.slashPipe, "|");
|
|
2957
|
+
return n;
|
|
2958
|
+
}
|
|
2959
|
+
function L(a3, e, t) {
|
|
2960
|
+
let n = a3.length;
|
|
2961
|
+
if (n === 0) return "";
|
|
2962
|
+
let s = 0;
|
|
2963
|
+
for (; s < n; ) {
|
|
2964
|
+
let r = a3.charAt(n - s - 1);
|
|
2965
|
+
if (r === e && !t) s++;
|
|
2966
|
+
else if (r !== e && t) s++;
|
|
2967
|
+
else break;
|
|
2968
|
+
}
|
|
2969
|
+
return a3.slice(0, n - s);
|
|
2970
|
+
}
|
|
2971
|
+
function ge(a3) {
|
|
2972
|
+
let e = a3.split(`
|
|
2973
|
+
`), t = e.length - 1;
|
|
2974
|
+
for (; t >= 0 && T.blankLine.test(e[t]); ) t--;
|
|
2975
|
+
return e.length - t <= 2 ? a3 : e.slice(0, t + 1).join(`
|
|
2976
|
+
`);
|
|
2977
|
+
}
|
|
2978
|
+
function F(a3) {
|
|
2979
|
+
return a3.trim().replace(T.multipleSpaceGlobal, " ").toLowerCase().toUpperCase().toLowerCase();
|
|
2980
|
+
}
|
|
2981
|
+
function ke(a3, e) {
|
|
2982
|
+
if (a3.indexOf(e[0]) === -1 && a3.indexOf(e[1]) === -1) return -1;
|
|
2983
|
+
let t = 0;
|
|
2984
|
+
for (let n = 0; n < a3.length; n++) if (a3[n] === "\\") n++;
|
|
2985
|
+
else if (a3[n] === e[0]) t++;
|
|
2986
|
+
else if (a3[n] === e[1] && (t--, t < 0)) return n;
|
|
2987
|
+
return t > 0 ? -2 : -1;
|
|
2988
|
+
}
|
|
2989
|
+
var N = /* @__PURE__ */ new WeakMap();
|
|
2990
|
+
function fe(a3) {
|
|
2991
|
+
let e = { "*": -1, _: -1 }, t = -1, n = a3.length;
|
|
2992
|
+
for (let s = 0; s < n; s++) {
|
|
2993
|
+
let r = a3[s];
|
|
2994
|
+
if (r !== "*" && r !== "_" && r !== "~") continue;
|
|
2995
|
+
let o = s === 0 ? `
|
|
2996
|
+
` : a3[s - 1], i = s + 1;
|
|
2997
|
+
for (; i < n && a3[i] === r; ) i++;
|
|
2998
|
+
o !== " " && o !== " " && o !== `
|
|
2999
|
+
` && o !== "\r" && o !== "\f" && (r === "~" ? t = s : e[r] = s), s = i - 1;
|
|
3000
|
+
}
|
|
3001
|
+
return { maskedSrc: a3, lastPossibleEmStrongCloserIndex: e, lastPossibleDelCloserIndex: t };
|
|
3002
|
+
}
|
|
3003
|
+
function Ae(a3, e) {
|
|
3004
|
+
let t = fe(e), n = N.get(a3);
|
|
3005
|
+
n ? n.push(t) : N.set(a3, [t]);
|
|
3006
|
+
}
|
|
3007
|
+
function Ee(a3) {
|
|
3008
|
+
let e = N.get(a3);
|
|
3009
|
+
e && (e.pop(), e.length === 0 && N.delete(a3));
|
|
3010
|
+
}
|
|
3011
|
+
function ze(a3, e, t) {
|
|
3012
|
+
let n = N.get(a3)?.at(-1);
|
|
3013
|
+
return n && n.maskedSrc === e ? n.lastPossibleEmStrongCloserIndex[t] : fe(e).lastPossibleEmStrongCloserIndex[t];
|
|
3014
|
+
}
|
|
3015
|
+
function Me(a3, e) {
|
|
3016
|
+
let t = N.get(a3)?.at(-1);
|
|
3017
|
+
return t && t.maskedSrc === e ? t.lastPossibleDelCloserIndex : fe(e).lastPossibleDelCloserIndex;
|
|
3018
|
+
}
|
|
3019
|
+
function J(a3, e = 0) {
|
|
3020
|
+
let t = e, n = "";
|
|
3021
|
+
for (let s of a3) if (s === " ") {
|
|
3022
|
+
let r = 4 - t % 4;
|
|
3023
|
+
n += " ".repeat(r), t += r;
|
|
3024
|
+
} else n += s, t++;
|
|
3025
|
+
return n;
|
|
3026
|
+
}
|
|
3027
|
+
function De(a3, e, t, n, s) {
|
|
3028
|
+
let r = e.href, o = e.title || null, i = a3[1].replace(s.other.outputLinkReplace, "$1"), l = a3[0].charAt(0) === "!", p = n.state.inLink, h = n.state.linkEmitted, u = n.state.inRawBlock;
|
|
3029
|
+
n.state.inLink = true, n.state.linkEmitted = false;
|
|
3030
|
+
let d = n.inlineTokens(i), k = n.state.linkEmitted;
|
|
3031
|
+
if (n.state.linkEmitted = h, n.state.inLink = p, !l) {
|
|
3032
|
+
if (k) {
|
|
3033
|
+
n.state.inRawBlock = u;
|
|
3034
|
+
return;
|
|
3035
|
+
}
|
|
3036
|
+
n.state.linkEmitted = true;
|
|
3037
|
+
}
|
|
3038
|
+
return { type: l ? "image" : "link", raw: t, href: r, title: o, text: i, tokens: d };
|
|
3039
|
+
}
|
|
3040
|
+
function Dt(a3, e, t) {
|
|
3041
|
+
let n = a3.match(t.other.indentCodeCompensation);
|
|
3042
|
+
if (n === null) return e;
|
|
3043
|
+
let s = n[1];
|
|
3044
|
+
return e.split(`
|
|
3045
|
+
`).map((r) => {
|
|
3046
|
+
let o = r.match(t.other.beginningSpace);
|
|
3047
|
+
if (o === null) return r;
|
|
3048
|
+
let [i] = o;
|
|
3049
|
+
return r.slice(Math.min(i.length, s.length));
|
|
3050
|
+
}).join(`
|
|
3051
|
+
`);
|
|
3052
|
+
}
|
|
3053
|
+
function Be(a3, e, t, n) {
|
|
3054
|
+
if (!e.includes("<")) return false;
|
|
3055
|
+
for (let s = 0; s < e.length; s++) {
|
|
3056
|
+
if (e[s] === "\\") {
|
|
3057
|
+
s++;
|
|
3058
|
+
continue;
|
|
3059
|
+
}
|
|
3060
|
+
if (e[s] === "`") {
|
|
3061
|
+
let i = n.inline.code.exec(e.slice(s));
|
|
3062
|
+
if (i) {
|
|
3063
|
+
s += i[0].length - 1;
|
|
3064
|
+
continue;
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3067
|
+
if (e[s] !== "<") continue;
|
|
3068
|
+
let r = a3.slice(t + s), o = n.inline.tag.exec(r) || n.inline.autolink.exec(r);
|
|
3069
|
+
if (o) {
|
|
3070
|
+
if (o[0].length > e.length - s) return true;
|
|
3071
|
+
s += o[0].length - 1;
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
return false;
|
|
3075
|
+
}
|
|
3076
|
+
var _ = class {
|
|
3077
|
+
options;
|
|
3078
|
+
rules;
|
|
3079
|
+
lexer;
|
|
3080
|
+
constructor(e) {
|
|
3081
|
+
this.options = e || S;
|
|
3082
|
+
}
|
|
3083
|
+
space(e) {
|
|
3084
|
+
let t = this.rules.block.newline.exec(e);
|
|
3085
|
+
if (t && t[0].length > 0) return { type: "space", raw: t[0] };
|
|
3086
|
+
}
|
|
3087
|
+
code(e) {
|
|
3088
|
+
let t = this.rules.block.code.exec(e);
|
|
3089
|
+
if (t) {
|
|
3090
|
+
let n = this.options.pedantic ? t[0] : ge(t[0]), s = n.replace(this.rules.other.codeRemoveIndent, "");
|
|
3091
|
+
return { type: "code", raw: n, codeBlockStyle: "indented", text: s };
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
fences(e) {
|
|
3095
|
+
let t = this.rules.block.fences.exec(e);
|
|
3096
|
+
if (t) {
|
|
3097
|
+
let n = t[0], s = Dt(n, t[3] || "", this.rules);
|
|
3098
|
+
return { type: "code", raw: n, lang: t[2] ? t[2].trim().replace(this.rules.inline.anyPunctuation, "$1") : t[2], text: s };
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
heading(e) {
|
|
3102
|
+
let t = this.rules.block.heading.exec(e);
|
|
3103
|
+
if (t) {
|
|
3104
|
+
let n = t[2].trim();
|
|
3105
|
+
if (this.rules.other.endingHash.test(n)) {
|
|
3106
|
+
let s = L(n, "#");
|
|
3107
|
+
(this.options.pedantic || !s || this.rules.other.endingSpaceTabChar.test(s)) && (n = s.trim());
|
|
3108
|
+
}
|
|
3109
|
+
return { type: "heading", raw: L(t[0], `
|
|
3110
|
+
`), depth: t[1].length, text: n, tokens: this.lexer.inline(n) };
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
hr(e) {
|
|
3114
|
+
let t = this.rules.block.hr.exec(e);
|
|
3115
|
+
if (t) return { type: "hr", raw: L(t[0], `
|
|
3116
|
+
`) };
|
|
3117
|
+
}
|
|
3118
|
+
blockquote(e) {
|
|
3119
|
+
let t = this.rules.block.blockquote.exec(e);
|
|
3120
|
+
if (t) {
|
|
3121
|
+
let n = L(t[0], `
|
|
3122
|
+
`).split(`
|
|
3123
|
+
`), s = "", r = "", o = [];
|
|
3124
|
+
for (; n.length > 0; ) {
|
|
3125
|
+
let i = false, l = [], p;
|
|
3126
|
+
for (p = 0; p < n.length; p++) if (this.rules.other.blockquoteStart.test(n[p])) l.push(n[p]), i = true;
|
|
3127
|
+
else if (!i) l.push(n[p]);
|
|
3128
|
+
else break;
|
|
3129
|
+
n = n.slice(p);
|
|
3130
|
+
let h = l.join(`
|
|
3131
|
+
`), u = h.replace(this.rules.other.blockquoteMarkerWhitespace, (g, b, m) => b + J(m, b.length)).replace(this.rules.other.blockquoteSetextReplace, `
|
|
3132
|
+
$1`).replace(this.rules.other.blockquoteSetextReplace2, "");
|
|
3133
|
+
s = s ? `${s}
|
|
3134
|
+
${h}` : h, r = r ? `${r}
|
|
3135
|
+
${u}` : u;
|
|
3136
|
+
let d = this.lexer.state.top;
|
|
3137
|
+
if (this.lexer.state.top = true, this.lexer.blockTokens(u, o, true), this.lexer.state.top = d, n.length === 0) break;
|
|
3138
|
+
let k = o.at(-1);
|
|
3139
|
+
if (k?.type === "code" || k?.type === "heading" || k?.type === "hr" || k?.type === "html" || k?.type === "table") break;
|
|
3140
|
+
if (k?.type === "blockquote") {
|
|
3141
|
+
let g = k, b = n.join(`
|
|
3142
|
+
`), m = g.raw + `
|
|
3143
|
+
` + b.replace(this.rules.other.blockquoteSetextReplace2, ""), f = this.blockquote(m);
|
|
3144
|
+
o[o.length - 1] = f;
|
|
3145
|
+
let y = m.substring(f.raw.length).replace(/^\n/, ""), R = y ? y.split(`
|
|
3146
|
+
`).length : 0, A = R ? n.slice(0, -R) : n;
|
|
3147
|
+
if (A.length > 0 && (s = `${s}
|
|
3148
|
+
${A.join(`
|
|
3149
|
+
`)}`), r = r.substring(0, r.length - g.text.length) + f.text, n = n.slice(A.length), n.length > 0 && this.rules.other.blockquoteStart.test(n[0])) continue;
|
|
3150
|
+
break;
|
|
3151
|
+
} else if (k?.type === "list") {
|
|
3152
|
+
let g = k, b = g.raw + `
|
|
3153
|
+
` + n.join(`
|
|
3154
|
+
`), m = this.list(b);
|
|
3155
|
+
o[o.length - 1] = m;
|
|
3156
|
+
let f = m.raw.length > g.raw.length ? b.slice(g.raw.length + 1, m.raw.length).split(`
|
|
3157
|
+
`).length : 0;
|
|
3158
|
+
if (f > 0) {
|
|
3159
|
+
let y = n.slice(0, f).join(`
|
|
3160
|
+
`);
|
|
3161
|
+
s = `${s}
|
|
3162
|
+
${y}`, r = `${r}
|
|
3163
|
+
${y}`;
|
|
3164
|
+
}
|
|
3165
|
+
n = n.slice(f);
|
|
3166
|
+
continue;
|
|
3167
|
+
}
|
|
3168
|
+
}
|
|
3169
|
+
return { type: "blockquote", raw: s, tokens: o, text: r };
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
list(e) {
|
|
3173
|
+
let t = this.rules.block.list.exec(e);
|
|
3174
|
+
if (t) {
|
|
3175
|
+
let n = e, s = () => n.length - e.length, r = t[1].trim(), o = r.length > 1, i = { type: "list", raw: "", ordered: o, start: o ? +r.slice(0, -1) : "", loose: false, items: [] };
|
|
3176
|
+
r = o ? `\\d{1,9}\\${r.slice(-1)}` : `\\${r}`, this.options.pedantic && (r = o ? r : "[*+-]");
|
|
3177
|
+
let l = this.rules.other.listItemRegex(r), p = false;
|
|
3178
|
+
for (; e; ) {
|
|
3179
|
+
let u = false, d = "";
|
|
3180
|
+
if (!(t = l.exec(e)) || this.rules.block.hr.test(e)) break;
|
|
3181
|
+
let k = s();
|
|
3182
|
+
e = e.substring(t[0].length);
|
|
3183
|
+
let g = t[2].split(`
|
|
3184
|
+
`, 1)[0], b = t[1].length, m = this.options.pedantic ? J(g, b) : g.replace(this.rules.other.leadingSpaceTab, (v) => J(v, b)), f = e.split(`
|
|
3185
|
+
`, 1)[0], y = !m.trim(), R = 0;
|
|
3186
|
+
if (this.options.pedantic ? (R = 2, d = m.trimStart()) : y ? R = b + 1 : (R = m.search(this.rules.other.nonSpaceChar), R = R > 4 ? 1 : R, d = m.slice(R), R += b), y && this.rules.other.blankLine.test(f) && (e = e.substring(f.length + 1), u = true), !u) {
|
|
3187
|
+
let v = this.rules.other.nextBulletRegex(R), Q = this.rules.other.hrRegex(R), ee = this.rules.other.fencesBeginRegex(R), te = this.options.pedantic ? this.rules.other.pedanticHeadingBeginRegex(R) : this.rules.other.headingBeginRegex(R), M = this.rules.other.htmlBeginRegex(R), ne = this.rules.other.blockquoteBeginRegex(R);
|
|
3188
|
+
for (; e; ) {
|
|
3189
|
+
let U = e.split(`
|
|
3190
|
+
`, 1)[0], Z;
|
|
3191
|
+
if (f = U, this.options.pedantic ? (f = f.replace(this.rules.other.listReplaceNesting, " "), Z = f) : Z = f.replace(this.rules.other.leadingSpaceTab, (me) => J(me)), ee.test(f) || te.test(f) || M.test(f) || ne.test(f) || v.test(f) || Q.test(f)) break;
|
|
3192
|
+
if (Z.search(this.rules.other.nonSpaceChar) >= R || !f.trim()) d += `
|
|
3193
|
+
` + Z.slice(R);
|
|
3194
|
+
else {
|
|
3195
|
+
if (y || m.replace(this.rules.other.tabCharGlobal, " ").search(this.rules.other.nonSpaceChar) >= 4 || ee.test(m) || te.test(m) || M.test(m) || Q.test(m)) break;
|
|
3196
|
+
let qe = !this.options.pedantic && /^ {0,3}(?:=+|-+) *$/.test(f) && this.rules.block.lheading.test(`${m}
|
|
3197
|
+
${f}`) ? ` ${Z.replace(/^ {0,3}/, "")}` : f;
|
|
3198
|
+
d += `
|
|
3199
|
+
` + qe;
|
|
3200
|
+
}
|
|
3201
|
+
y = !f.trim(), e = e.substring(U.length + 1), m = Z.slice(R);
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
let A = n.slice(k, s());
|
|
3205
|
+
i.loose || (p ? i.loose = true : this.rules.other.doubleBlankLine.test(A) && (p = true)), i.items.push({ type: "list_item", raw: A, task: !!this.options.gfm && this.rules.other.listIsTask.test(d), loose: false, text: d, tokens: [] });
|
|
3206
|
+
}
|
|
3207
|
+
let h = i.items.at(-1);
|
|
3208
|
+
if (h) h.raw = h.raw.trimEnd(), h.text = h.text.trimEnd();
|
|
3209
|
+
else return;
|
|
3210
|
+
i.raw = n.slice(0, s()).trimEnd();
|
|
3211
|
+
for (let u of i.items) if (this.lexer.state.top = false, u.tokens = this.lexer.blockTokens(u.text, []), !i.loose) {
|
|
3212
|
+
let d = u.tokens.filter((g) => g.type === "space"), k = d.length > 0 && d.some((g) => this.rules.other.anyLine.test(g.raw));
|
|
3213
|
+
i.loose = k;
|
|
3214
|
+
}
|
|
3215
|
+
for (let u of i.items) {
|
|
3216
|
+
let d = u.tokens[0];
|
|
3217
|
+
if (u.task && (d?.type === "text" || d?.type === "paragraph")) {
|
|
3218
|
+
u.text = u.text.replace(this.rules.other.listReplaceTask, ""), d.raw = d.raw.replace(this.rules.other.listReplaceTask, ""), d.text = d.text.replace(this.rules.other.listReplaceTask, "");
|
|
3219
|
+
for (let g = this.lexer.inlineQueue.length - 1; g >= 0; g--) if (this.rules.other.listIsTask.test(this.lexer.inlineQueue[g].src)) {
|
|
3220
|
+
this.lexer.inlineQueue[g].src = this.lexer.inlineQueue[g].src.replace(this.rules.other.listReplaceTask, "");
|
|
3221
|
+
break;
|
|
3222
|
+
}
|
|
3223
|
+
let k = this.rules.other.listTaskCheckbox.exec(u.raw);
|
|
3224
|
+
if (k) {
|
|
3225
|
+
let g = { type: "checkbox", raw: k[0] + " ", checked: k[0] !== "[ ]" };
|
|
3226
|
+
u.checked = g.checked, i.loose ? u.tokens[0] && ["paragraph", "text"].includes(u.tokens[0].type) && "tokens" in u.tokens[0] && u.tokens[0].tokens ? (u.tokens[0].raw = g.raw + u.tokens[0].raw, u.tokens[0].text = g.raw + u.tokens[0].text, u.tokens[0].tokens.unshift(g)) : u.tokens.unshift({ type: "paragraph", raw: g.raw, text: g.raw, tokens: [g] }) : u.tokens.unshift(g);
|
|
3227
|
+
}
|
|
3228
|
+
} else u.task && (u.task = false);
|
|
3229
|
+
}
|
|
3230
|
+
if (i.loose) for (let u of i.items) {
|
|
3231
|
+
u.loose = true;
|
|
3232
|
+
for (let d of u.tokens) d.type === "text" && (d.type = "paragraph");
|
|
3233
|
+
}
|
|
3234
|
+
return i;
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
html(e) {
|
|
3238
|
+
let t = this.rules.block.html.exec(e);
|
|
3239
|
+
if (t) {
|
|
3240
|
+
let n = ge(t[0]);
|
|
3241
|
+
return { type: "html", block: true, raw: n, pre: t[1] === "pre" || t[1] === "script" || t[1] === "style", text: n };
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
def(e) {
|
|
3245
|
+
let t = this.rules.block.def.exec(e);
|
|
3246
|
+
if (t) {
|
|
3247
|
+
if (!this.rules.other.startAngleBracket.test(t[2]) && ke(t[2], "()") !== -1) return;
|
|
3248
|
+
let n = F(t[1]), s = t[2] ? t[2].replace(this.rules.other.hrefBrackets, "$1").replace(this.rules.inline.anyPunctuation, "$1") : "", r = t[3] ? t[3].substring(1, t[3].length - 1).replace(this.rules.inline.anyPunctuation, "$1") : t[3];
|
|
3249
|
+
return { type: "def", tag: n, raw: L(t[0], `
|
|
3250
|
+
`), href: s, title: r };
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
table(e) {
|
|
3254
|
+
let t = this.rules.block.table.exec(e);
|
|
3255
|
+
if (!t || !this.rules.other.tableDelimiter.test(t[2])) return;
|
|
3256
|
+
let n = de(t[1]), s = t[2].replace(this.rules.other.tableAlignChars, "").split("|"), r = t[3]?.trim() ? t[3].replace(this.rules.other.tableRowBlankLine, "").split(`
|
|
3257
|
+
`) : [], o = { type: "table", raw: L(t[0], `
|
|
3258
|
+
`), header: [], align: [], rows: [] };
|
|
3259
|
+
if (n.length === s.length) {
|
|
3260
|
+
for (let i of s) this.rules.other.tableAlignRight.test(i) ? o.align.push("right") : this.rules.other.tableAlignCenter.test(i) ? o.align.push("center") : this.rules.other.tableAlignLeft.test(i) ? o.align.push("left") : o.align.push(null);
|
|
3261
|
+
for (let i = 0; i < n.length; i++) o.header.push({ text: n[i], tokens: this.lexer.inline(n[i]), header: true, align: o.align[i] });
|
|
3262
|
+
for (let i of r) o.rows.push(de(i, o.header.length).map((l, p) => ({ text: l, tokens: this.lexer.inline(l), header: false, align: o.align[p] })));
|
|
3263
|
+
return o;
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3266
|
+
lheading(e) {
|
|
3267
|
+
let t = this.rules.block.lheading.exec(e);
|
|
3268
|
+
if (t) {
|
|
3269
|
+
let n = t[1].trim();
|
|
3270
|
+
return { type: "heading", raw: L(t[0], `
|
|
3271
|
+
`), depth: t[2].charAt(0) === "=" ? 1 : 2, text: n, tokens: this.lexer.inline(n) };
|
|
3272
|
+
}
|
|
3273
|
+
}
|
|
3274
|
+
paragraph(e) {
|
|
3275
|
+
let t = this.rules.block.paragraph.exec(e);
|
|
3276
|
+
if (t) {
|
|
3277
|
+
let n = t[1].charAt(t[1].length - 1) === `
|
|
3278
|
+
` ? t[1].slice(0, -1) : t[1];
|
|
3279
|
+
return { type: "paragraph", raw: t[0], text: n, tokens: this.lexer.inline(n) };
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
text(e) {
|
|
3283
|
+
let t = this.rules.block.text.exec(e);
|
|
3284
|
+
if (t) return { type: "text", raw: t[0], text: t[0], tokens: this.lexer.inline(t[0]) };
|
|
3285
|
+
}
|
|
3286
|
+
escape(e) {
|
|
3287
|
+
let t = this.rules.inline.escape.exec(e);
|
|
3288
|
+
if (t) return { type: "escape", raw: t[0], text: t[1] };
|
|
3289
|
+
}
|
|
3290
|
+
tag(e) {
|
|
3291
|
+
let t = this.rules.inline.tag.exec(e);
|
|
3292
|
+
if (t) return !this.lexer.state.inLink && this.rules.other.startATag.test(t[0]) ? this.lexer.state.inLink = true : this.lexer.state.inLink && this.rules.other.endATag.test(t[0]) && (this.lexer.state.inLink = false), !this.lexer.state.inRawBlock && this.rules.other.startPreScriptTag.test(t[0]) ? this.lexer.state.inRawBlock = true : this.lexer.state.inRawBlock && this.rules.other.endPreScriptTag.test(t[0]) && (this.lexer.state.inRawBlock = false), { type: "html", raw: t[0], inLink: this.lexer.state.inLink, inRawBlock: this.lexer.state.inRawBlock, block: false, text: t[0] };
|
|
3293
|
+
}
|
|
3294
|
+
link(e) {
|
|
3295
|
+
if (this.lexer.state.linkParenPossible === false) return;
|
|
3296
|
+
let t = this.rules.inline.link.exec(e);
|
|
3297
|
+
if (t) {
|
|
3298
|
+
let n = t[0].charAt(0) === "!" ? 2 : 1;
|
|
3299
|
+
if (!this.options.pedantic && Be(e, t[1], n, this.rules)) return;
|
|
3300
|
+
let s = t[2].trim();
|
|
3301
|
+
if (!this.options.pedantic && this.rules.other.startAngleBracket.test(s)) {
|
|
3302
|
+
if (!this.rules.other.endAngleBracket.test(s)) return;
|
|
3303
|
+
let l = L(s.slice(0, -1), "\\");
|
|
3304
|
+
if ((s.length - l.length) % 2 === 0) return;
|
|
3305
|
+
} else {
|
|
3306
|
+
let l = ke(t[2], "()");
|
|
3307
|
+
if (l === -2) return;
|
|
3308
|
+
if (l > -1) {
|
|
3309
|
+
let h = (t[0].indexOf("!") === 0 ? 5 : 4) + t[1].length + l;
|
|
3310
|
+
t[2] = t[2].substring(0, l), t[0] = t[0].substring(0, h).trim(), t[3] = "";
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
let r = L(t[0].slice(0, -1), "\\");
|
|
3314
|
+
if ((t[0].length - r.length) % 2 === 0) return;
|
|
3315
|
+
let o = t[2], i = "";
|
|
3316
|
+
if (this.options.pedantic) {
|
|
3317
|
+
let l = this.rules.other.pedanticHrefTitle.exec(o);
|
|
3318
|
+
l && (o = l[1], i = l[3]);
|
|
3319
|
+
} else i = t[3] ? t[3].slice(1, -1) : "";
|
|
3320
|
+
return o = o.trim(), this.rules.other.startAngleBracket.test(o) && (this.options.pedantic && !this.rules.other.endAngleBracket.test(s) ? o = o.slice(1) : o = o.slice(1, -1)), De(t, { href: o && o.replace(this.rules.inline.anyPunctuation, "$1"), title: i && i.replace(this.rules.inline.anyPunctuation, "$1") }, t[0], this.lexer, this.rules);
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
reflink(e, t) {
|
|
3324
|
+
let n;
|
|
3325
|
+
if ((n = this.rules.inline.reflink.exec(e)) || (n = this.rules.inline.nolink.exec(e))) {
|
|
3326
|
+
let s = n[0].charAt(0) === "!" ? 2 : 1;
|
|
3327
|
+
if (!this.options.pedantic && Be(e, n[1], s, this.rules)) return;
|
|
3328
|
+
let r = t[F(n[2] || n[1])];
|
|
3329
|
+
if (!r) {
|
|
3330
|
+
let o = n[0].charAt(0);
|
|
3331
|
+
return { type: "text", raw: o, text: o };
|
|
3332
|
+
}
|
|
3333
|
+
return De(n, r, n[0], this.lexer, this.rules);
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
emStrong(e, t, n = "") {
|
|
3337
|
+
let s = this.rules.inline.emStrongLDelim.exec(e);
|
|
3338
|
+
if (!s || !s[1] && !s[2] && !s[3] && !s[4]) return;
|
|
3339
|
+
let r = s[0][0], o = n === r, i = t.length - e.length, l = i;
|
|
3340
|
+
for (; !this.options.pedantic && l > 0 && t[l - 1] === r; ) l--;
|
|
3341
|
+
let p = [...t.slice(Math.max(0, l - 2), l)].at(-1) ?? "", h = p === "*" || p === "_" || !!this.rules.inline.punctuation.exec(p);
|
|
3342
|
+
l < i && (n = p);
|
|
3343
|
+
let u = l < i ? h : !!this.rules.inline.punctuation.exec(n);
|
|
3344
|
+
if (s[4] && n.match(this.rules.other.unicodeAlphaNumeric)) return;
|
|
3345
|
+
let d = s[1] || s[3] || "";
|
|
3346
|
+
if (!d || !n || u) {
|
|
3347
|
+
let k = [...s[0]].length - 1, g, b, m = k, f = 0, y = i - l + k, R = !this.options.pedantic && !!p.trim() && (!!d || r === "*" && !h);
|
|
3348
|
+
if (r !== "*" && r !== "_") return;
|
|
3349
|
+
let A = r === "*" ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd, v = ze(this, t, r), Q = t.length - e.length + k;
|
|
3350
|
+
if (v < Q) return;
|
|
3351
|
+
t = t.slice(-1 * e.length + k);
|
|
3352
|
+
let ee = v - Q;
|
|
3353
|
+
for (A.lastIndex = 0; (s = A.exec(t)) !== null && !(s.index > ee); ) {
|
|
3354
|
+
if (g = s[1] || s[2] || s[3] || s[4] || s[5] || s[6], !g) continue;
|
|
3355
|
+
if (b = [...g].length, s[3] || s[4]) {
|
|
3356
|
+
m += b;
|
|
3357
|
+
continue;
|
|
3358
|
+
} else if (s[5] || s[6] || R) {
|
|
3359
|
+
if (o && (s[5] || s[6])) break;
|
|
3360
|
+
if (y % 3 && !((y + b) % 3)) {
|
|
3361
|
+
f += b;
|
|
3362
|
+
continue;
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
if (m -= b, m > 0) continue;
|
|
3366
|
+
b = Math.min(b, b + m + f);
|
|
3367
|
+
let te = [...s[0]][0].length, M = e.slice(0, k + s.index + te + b);
|
|
3368
|
+
if (Math.min(k, b) % 2) {
|
|
3369
|
+
let U = M.slice(1, -1);
|
|
3370
|
+
return { type: "em", raw: M, text: U, tokens: this.lexer.inlineTokens(U) };
|
|
3371
|
+
}
|
|
3372
|
+
let ne = M.slice(2, -2);
|
|
3373
|
+
return { type: "strong", raw: M, text: ne, tokens: this.lexer.inlineTokens(ne) };
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
codespan(e) {
|
|
3378
|
+
let t = this.rules.inline.code.exec(e);
|
|
3379
|
+
if (t) {
|
|
3380
|
+
let n = t[2].replace(this.rules.other.newLineCharGlobal, " "), s = this.rules.other.nonSpaceChar.test(n), r = this.rules.other.startingSpaceChar.test(n) && this.rules.other.endingSpaceChar.test(n);
|
|
3381
|
+
return s && r && (n = n.substring(1, n.length - 1)), { type: "codespan", raw: t[0], text: n };
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
br(e) {
|
|
3385
|
+
let t = this.rules.inline.br.exec(e);
|
|
3386
|
+
if (t) return { type: "br", raw: t[0] };
|
|
3387
|
+
}
|
|
3388
|
+
del(e, t, n = "") {
|
|
3389
|
+
let s = this.rules.inline.delLDelim.exec(e);
|
|
3390
|
+
if (!s) return;
|
|
3391
|
+
if (!(s[1] || "") || !n || this.rules.inline.punctuation.exec(n)) {
|
|
3392
|
+
let o = [...s[0]].length - 1, i, l, p = o, h = this.rules.inline.delRDelim, u = Me(this, t), d = t.length - e.length + o;
|
|
3393
|
+
if (u < d) return;
|
|
3394
|
+
t = t.slice(-1 * e.length + o);
|
|
3395
|
+
let k = u - d;
|
|
3396
|
+
for (h.lastIndex = 0; (s = h.exec(t)) !== null && !(s.index > k); ) {
|
|
3397
|
+
if (i = s[1] || s[2] || s[3] || s[4] || s[5] || s[6], !i || (l = [...i].length, l !== o)) continue;
|
|
3398
|
+
if (s[3] || s[4]) {
|
|
3399
|
+
p += l;
|
|
3400
|
+
continue;
|
|
3401
|
+
}
|
|
3402
|
+
if (p -= l, p > 0) continue;
|
|
3403
|
+
l = Math.min(l, l + p);
|
|
3404
|
+
let g = [...s[0]][0].length, b = e.slice(0, o + s.index + g + l), m = b.slice(o, -o);
|
|
3405
|
+
return { type: "del", raw: b, text: m, tokens: this.lexer.inlineTokens(m) };
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
autolink(e) {
|
|
3410
|
+
let t = this.rules.inline.autolink.exec(e);
|
|
3411
|
+
if (t) {
|
|
3412
|
+
let n, s;
|
|
3413
|
+
return t[2] === "@" ? (n = t[1], s = "mailto:" + n) : (n = t[1], s = n), { type: "link", raw: t[0], text: n, href: s, autolink: true, tokens: [{ type: "text", raw: n, text: n }] };
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
url(e) {
|
|
3417
|
+
let t;
|
|
3418
|
+
if (t = this.rules.inline.url.exec(e)) {
|
|
3419
|
+
let n, s;
|
|
3420
|
+
if (t[2] === "@") n = t[0], s = "mailto:" + n;
|
|
3421
|
+
else {
|
|
3422
|
+
let r;
|
|
3423
|
+
do
|
|
3424
|
+
r = t[0], t[0] = this.rules.inline._backpedal.exec(t[0])?.[0] ?? "";
|
|
3425
|
+
while (r !== t[0]);
|
|
3426
|
+
n = t[0], t[1] === "www." ? s = "http://" + t[0] : s = t[0];
|
|
3427
|
+
}
|
|
3428
|
+
return { type: "link", raw: t[0], text: n, href: s, autolink: true, tokens: [{ type: "text", raw: n, text: n }] };
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
inlineText(e) {
|
|
3432
|
+
let t = this.rules.inline.text.exec(e);
|
|
3433
|
+
if (t) {
|
|
3434
|
+
let n = this.lexer.state.inRawBlock;
|
|
3435
|
+
return { type: "text", raw: t[0], text: n ? t[0] : Ie(t[0]), escaped: n };
|
|
3436
|
+
}
|
|
3437
|
+
}
|
|
3438
|
+
};
|
|
3439
|
+
var O = class a {
|
|
3440
|
+
tokens;
|
|
3441
|
+
options;
|
|
3442
|
+
state;
|
|
3443
|
+
inlineQueue;
|
|
3444
|
+
tokenizer;
|
|
3445
|
+
constructor(e) {
|
|
3446
|
+
this.tokens = [], this.tokens.links = /* @__PURE__ */ Object.create(null), this.options = e || S, this.options.tokenizer = this.options.tokenizer || new _(), this.tokenizer = this.options.tokenizer, this.tokenizer.options = this.options, this.tokenizer.lexer = this, this.inlineQueue = [], this.state = { inLink: false, inRawBlock: false, linkEmitted: false, linkParenPossible: true, top: true };
|
|
3447
|
+
let t = { other: T, block: V.normal, inline: G.normal };
|
|
3448
|
+
this.options.pedantic ? (t.block = V.pedantic, t.inline = G.pedantic) : this.options.gfm && (t.block = V.gfm, this.options.breaks ? t.inline = G.breaks : t.inline = G.gfm), this.tokenizer.rules = t;
|
|
3449
|
+
}
|
|
3450
|
+
static get rules() {
|
|
3451
|
+
return { block: V, inline: G };
|
|
3452
|
+
}
|
|
3453
|
+
static lex(e, t) {
|
|
3454
|
+
return new a(t).lex(e);
|
|
3455
|
+
}
|
|
3456
|
+
static lexInline(e, t) {
|
|
3457
|
+
return new a(t).inlineTokens(e);
|
|
3458
|
+
}
|
|
3459
|
+
lex(e) {
|
|
3460
|
+
e = e.replace(T.carriageReturn, `
|
|
3461
|
+
`), this.blockTokens(e, this.tokens);
|
|
3462
|
+
for (let t = 0; t < this.inlineQueue.length; t++) {
|
|
3463
|
+
let n = this.inlineQueue[t];
|
|
3464
|
+
this.state.inRawBlock = false, this.inlineTokens(n.src, n.tokens);
|
|
3465
|
+
}
|
|
3466
|
+
return this.inlineQueue = [], this.tokens;
|
|
3467
|
+
}
|
|
3468
|
+
blockTokens(e, t = [], n = false) {
|
|
3469
|
+
this.tokenizer.lexer = this, this.options.pedantic && (e = e.replace(T.tabCharGlobal, " ").replace(T.spaceLine, ""));
|
|
3470
|
+
let s = 1 / 0;
|
|
3471
|
+
for (; e; ) {
|
|
3472
|
+
if (e.length < s) s = e.length;
|
|
3473
|
+
else {
|
|
3474
|
+
this.infiniteLoopError(e.charCodeAt(0));
|
|
3475
|
+
break;
|
|
3476
|
+
}
|
|
3477
|
+
let r;
|
|
3478
|
+
if (this.options.extensions?.block?.some((i) => (r = i.call({ lexer: this }, e, t)) ? (e = e.substring(r.raw.length), t.push(r), true) : false)) continue;
|
|
3479
|
+
if (r = this.tokenizer.space(e)) {
|
|
3480
|
+
e = e.substring(r.raw.length);
|
|
3481
|
+
let i = t.at(-1);
|
|
3482
|
+
r.raw.length === 1 && i !== void 0 ? i.raw += `
|
|
3483
|
+
` : t.push(r);
|
|
3484
|
+
continue;
|
|
3485
|
+
}
|
|
3486
|
+
if (r = this.tokenizer.code(e)) {
|
|
3487
|
+
e = e.substring(r.raw.length);
|
|
3488
|
+
let i = t.at(-1);
|
|
3489
|
+
i?.type === "paragraph" || i?.type === "text" ? (i.raw += (i.raw.endsWith(`
|
|
3490
|
+
`) ? "" : `
|
|
3491
|
+
`) + r.raw, i.text += `
|
|
3492
|
+
` + r.text, this.inlineQueue.at(-1).src = i.text) : t.push(r);
|
|
3493
|
+
continue;
|
|
3494
|
+
}
|
|
3495
|
+
if (r = this.tokenizer.fences(e)) {
|
|
3496
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
3497
|
+
continue;
|
|
3498
|
+
}
|
|
3499
|
+
if (r = this.tokenizer.heading(e)) {
|
|
3500
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
3501
|
+
continue;
|
|
3502
|
+
}
|
|
3503
|
+
if (r = this.tokenizer.hr(e)) {
|
|
3504
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
3505
|
+
continue;
|
|
3506
|
+
}
|
|
3507
|
+
if (r = this.tokenizer.blockquote(e)) {
|
|
3508
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
3509
|
+
continue;
|
|
3510
|
+
}
|
|
3511
|
+
if (r = this.tokenizer.list(e)) {
|
|
3512
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
3513
|
+
continue;
|
|
3514
|
+
}
|
|
3515
|
+
if (r = this.tokenizer.html(e)) {
|
|
3516
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
3517
|
+
continue;
|
|
3518
|
+
}
|
|
3519
|
+
if (r = this.tokenizer.def(e)) {
|
|
3520
|
+
e = e.substring(r.raw.length);
|
|
3521
|
+
let i = t.at(-1);
|
|
3522
|
+
i?.type === "paragraph" || i?.type === "text" ? (i.raw += (i.raw.endsWith(`
|
|
3523
|
+
`) ? "" : `
|
|
3524
|
+
`) + r.raw, i.text += `
|
|
3525
|
+
` + r.raw, this.inlineQueue.at(-1).src = i.text) : (this.tokens.links[r.tag] || (this.tokens.links[r.tag] = { href: r.href, title: r.title }), t.push(r));
|
|
3526
|
+
continue;
|
|
3527
|
+
}
|
|
3528
|
+
if (r = this.tokenizer.table(e)) {
|
|
3529
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
3530
|
+
continue;
|
|
3531
|
+
}
|
|
3532
|
+
if (r = this.tokenizer.lheading(e)) {
|
|
3533
|
+
e = e.substring(r.raw.length), t.push(r);
|
|
3534
|
+
continue;
|
|
3535
|
+
}
|
|
3536
|
+
let o = e;
|
|
3537
|
+
if (this.options.extensions?.startBlock) {
|
|
3538
|
+
let i = 1 / 0, l = e.slice(1), p;
|
|
3539
|
+
this.options.extensions.startBlock.forEach((h) => {
|
|
3540
|
+
p = h.call({ lexer: this }, l), typeof p == "number" && p >= 0 && (i = Math.min(i, p));
|
|
3541
|
+
}), i < 1 / 0 && i >= 0 && (o = e.substring(0, i + 1));
|
|
3542
|
+
}
|
|
3543
|
+
if (this.state.top && (r = this.tokenizer.paragraph(o))) {
|
|
3544
|
+
let i = t.at(-1);
|
|
3545
|
+
n && i?.type === "paragraph" ? (i.raw += (i.raw.endsWith(`
|
|
3546
|
+
`) ? "" : `
|
|
3547
|
+
`) + r.raw, i.text += `
|
|
3548
|
+
` + r.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = i.text) : t.push(r), n = o.length !== e.length, e = e.substring(r.raw.length);
|
|
3549
|
+
continue;
|
|
3550
|
+
}
|
|
3551
|
+
if (r = this.tokenizer.text(e)) {
|
|
3552
|
+
e = e.substring(r.raw.length);
|
|
3553
|
+
let i = t.at(-1);
|
|
3554
|
+
i?.type === "text" ? (i.raw += (i.raw.endsWith(`
|
|
3555
|
+
`) ? "" : `
|
|
3556
|
+
`) + r.raw, i.text += `
|
|
3557
|
+
` + r.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = i.text) : t.push(r);
|
|
3558
|
+
continue;
|
|
3559
|
+
}
|
|
3560
|
+
if (e) {
|
|
3561
|
+
this.infiniteLoopError(e.charCodeAt(0));
|
|
3562
|
+
break;
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
return this.state.top = true, t;
|
|
3566
|
+
}
|
|
3567
|
+
inline(e, t = []) {
|
|
3568
|
+
return this.inlineQueue.push({ src: e, tokens: t }), t;
|
|
3569
|
+
}
|
|
3570
|
+
linkInText(e) {
|
|
3571
|
+
if (!e.includes("[")) return false;
|
|
3572
|
+
let t = this.tokenizer.rules.inline.link;
|
|
3573
|
+
for (let n of e.matchAll(this.tokenizer.rules.inline.blockSkip)) if (t.test(n[0]) && e.charAt(n.index - 1) !== "!") return true;
|
|
3574
|
+
for (let n of e.matchAll(this.tokenizer.rules.inline.reflinkSearch)) {
|
|
3575
|
+
let s = n[0], r = s.lastIndexOf("[");
|
|
3576
|
+
if (!(s.charAt(0) === "!" || !Object.hasOwn(this.tokens.links, F(s.slice(r + 1, -1)))) && !(r > 1 && this.linkInText(s.slice(1, r - 1)))) return true;
|
|
3577
|
+
}
|
|
3578
|
+
return false;
|
|
3579
|
+
}
|
|
3580
|
+
inlineTokens(e, t = []) {
|
|
3581
|
+
this.tokenizer.lexer = this;
|
|
3582
|
+
let n = this.state.linkParenPossible;
|
|
3583
|
+
this.state.linkParenPossible = n && e.includes(")");
|
|
3584
|
+
try {
|
|
3585
|
+
return this.#e(e, t);
|
|
3586
|
+
} finally {
|
|
3587
|
+
this.state.linkParenPossible = n;
|
|
3588
|
+
}
|
|
3589
|
+
}
|
|
3590
|
+
#e(e, t) {
|
|
3591
|
+
let n = e.includes("*") || e.includes("_") || e.includes("~") || this.options.hooks?.emStrongMask || this.tokenizer.emStrong !== _.prototype.emStrong || this.tokenizer.del !== _.prototype.del ? this.#n(e) : e;
|
|
3592
|
+
Ae(this.tokenizer, n);
|
|
3593
|
+
try {
|
|
3594
|
+
return this.#t(e, n, t);
|
|
3595
|
+
} finally {
|
|
3596
|
+
Ee(this.tokenizer);
|
|
3597
|
+
}
|
|
3598
|
+
}
|
|
3599
|
+
#t(e, t, n) {
|
|
3600
|
+
let s = false, r = "", o = 1 / 0;
|
|
3601
|
+
for (; e; ) {
|
|
3602
|
+
if (e.length < o) o = e.length;
|
|
3603
|
+
else {
|
|
3604
|
+
this.infiniteLoopError(e.charCodeAt(0));
|
|
3605
|
+
break;
|
|
3606
|
+
}
|
|
3607
|
+
s || (r = ""), s = false;
|
|
3608
|
+
let i;
|
|
3609
|
+
if (this.options.extensions?.inline?.some((p) => (i = p.call({ lexer: this }, e, n)) ? (e = e.substring(i.raw.length), n.push(i), true) : false)) continue;
|
|
3610
|
+
if (i = this.tokenizer.escape(e)) {
|
|
3611
|
+
e = e.substring(i.raw.length), n.push(i);
|
|
3612
|
+
continue;
|
|
3613
|
+
}
|
|
3614
|
+
if (i = this.tokenizer.tag(e)) {
|
|
3615
|
+
e = e.substring(i.raw.length), n.push(i);
|
|
3616
|
+
continue;
|
|
3617
|
+
}
|
|
3618
|
+
if (i = this.tokenizer.link(e)) {
|
|
3619
|
+
e = e.substring(i.raw.length), n.push(i);
|
|
3620
|
+
continue;
|
|
3621
|
+
}
|
|
3622
|
+
if (i = this.tokenizer.reflink(e, this.tokens.links)) {
|
|
3623
|
+
e = e.substring(i.raw.length);
|
|
3624
|
+
let p = n.at(-1);
|
|
3625
|
+
i.type === "text" && p?.type === "text" ? (p.raw += i.raw, p.text += i.text) : n.push(i);
|
|
3626
|
+
continue;
|
|
3627
|
+
}
|
|
3628
|
+
if (i = this.tokenizer.emStrong(e, t, r)) {
|
|
3629
|
+
e = e.substring(i.raw.length), n.push(i);
|
|
3630
|
+
continue;
|
|
3631
|
+
}
|
|
3632
|
+
if (i = this.tokenizer.codespan(e)) {
|
|
3633
|
+
e = e.substring(i.raw.length), n.push(i);
|
|
3634
|
+
continue;
|
|
3635
|
+
}
|
|
3636
|
+
if (i = this.tokenizer.br(e)) {
|
|
3637
|
+
e = e.substring(i.raw.length), n.push(i);
|
|
3638
|
+
continue;
|
|
3639
|
+
}
|
|
3640
|
+
if (i = this.tokenizer.del(e, t, r)) {
|
|
3641
|
+
e = e.substring(i.raw.length), n.push(i);
|
|
3642
|
+
continue;
|
|
3643
|
+
}
|
|
3644
|
+
if (i = this.tokenizer.autolink(e)) {
|
|
3645
|
+
e = e.substring(i.raw.length), n.push(i);
|
|
3646
|
+
continue;
|
|
3647
|
+
}
|
|
3648
|
+
if (!this.state.inLink && (i = this.tokenizer.url(e))) {
|
|
3649
|
+
e = e.substring(i.raw.length), n.push(i);
|
|
3650
|
+
continue;
|
|
3651
|
+
}
|
|
3652
|
+
let l = e;
|
|
3653
|
+
if (this.options.extensions?.startInline) {
|
|
3654
|
+
let p = 1 / 0, h = e.slice(1), u;
|
|
3655
|
+
this.options.extensions.startInline.forEach((d) => {
|
|
3656
|
+
u = d.call({ lexer: this }, h), typeof u == "number" && u >= 0 && (p = Math.min(p, u));
|
|
3657
|
+
}), p < 1 / 0 && p >= 0 && (l = e.substring(0, p + 1));
|
|
3658
|
+
}
|
|
3659
|
+
if (i = this.tokenizer.inlineText(l)) {
|
|
3660
|
+
e = e.substring(i.raw.length), i.raw.slice(-1) !== "_" && (r = i.raw.slice(-1)), s = true;
|
|
3661
|
+
let p = n.at(-1);
|
|
3662
|
+
p?.type === "text" ? (p.raw += i.raw, p.text += i.text) : n.push(i);
|
|
3663
|
+
continue;
|
|
3664
|
+
}
|
|
3665
|
+
if (e) {
|
|
3666
|
+
this.infiniteLoopError(e.charCodeAt(0));
|
|
3667
|
+
break;
|
|
3668
|
+
}
|
|
3669
|
+
}
|
|
3670
|
+
return n;
|
|
3671
|
+
}
|
|
3672
|
+
#n(e) {
|
|
3673
|
+
let t = e;
|
|
3674
|
+
if (this.tokens.links && e.includes("[")) {
|
|
3675
|
+
let n = this.tokenizer.rules.inline.reflinkSearch, s = (r) => {
|
|
3676
|
+
let o = r.lastIndexOf("[");
|
|
3677
|
+
if (!Object.hasOwn(this.tokens.links, F(r.slice(o + 1, -1)))) return r;
|
|
3678
|
+
if (o > 1 && r.charAt(0) !== "!") {
|
|
3679
|
+
let i = r.slice(1, o - 1);
|
|
3680
|
+
if (this.linkInText(i)) return "[" + i.replace(n, s) + "][" + "a".repeat(r.length - o - 2) + "]";
|
|
3681
|
+
}
|
|
3682
|
+
return "[" + "a".repeat(r.length - 2) + "]";
|
|
3683
|
+
};
|
|
3684
|
+
t = t.replace(n, s);
|
|
3685
|
+
}
|
|
3686
|
+
return t = t.replace(this.tokenizer.rules.inline.anyPunctuationOutsideCode, (n, s, r) => r ? "+".repeat(n.length) : s ? s + n.slice(s.length, -s.length).replace(/`/g, "+") + s : n), t = t.replace(this.tokenizer.rules.inline.blockSkip, (n, s, r) => {
|
|
3687
|
+
let o = r ? r.length : 0;
|
|
3688
|
+
return n.slice(0, o) + "[" + "a".repeat(n.length - o - 2) + "]";
|
|
3689
|
+
}), t = this.options.hooks?.emStrongMask?.call({ lexer: this }, t) ?? t, t;
|
|
3690
|
+
}
|
|
3691
|
+
infiniteLoopError(e) {
|
|
3692
|
+
let t = "Infinite loop on byte: " + e;
|
|
3693
|
+
if (this.options.silent) console.error(t);
|
|
3694
|
+
else throw new Error(t);
|
|
3695
|
+
}
|
|
3696
|
+
};
|
|
3697
|
+
var C = class {
|
|
3698
|
+
options;
|
|
3699
|
+
parser;
|
|
3700
|
+
constructor(e) {
|
|
3701
|
+
this.options = e || S;
|
|
3702
|
+
}
|
|
3703
|
+
space(e) {
|
|
3704
|
+
return "";
|
|
3705
|
+
}
|
|
3706
|
+
code({ text: e, lang: t, escaped: n }) {
|
|
3707
|
+
let s = (t || "").match(T.notSpaceStart)?.[0], r = e ? e.replace(T.endingNewline, "") + `
|
|
3708
|
+
` : "";
|
|
3709
|
+
return s ? '<pre><code class="language-' + P(s) + '">' + (n ? r : P(r, true)) + `</code></pre>
|
|
3710
|
+
` : "<pre><code>" + (n ? r : P(r, true)) + `</code></pre>
|
|
3711
|
+
`;
|
|
3712
|
+
}
|
|
3713
|
+
blockquote({ tokens: e }) {
|
|
3714
|
+
return `<blockquote>
|
|
3715
|
+
${this.parser.parse(e)}</blockquote>
|
|
3716
|
+
`;
|
|
3717
|
+
}
|
|
3718
|
+
html({ text: e }) {
|
|
3719
|
+
return e;
|
|
3720
|
+
}
|
|
3721
|
+
def(e) {
|
|
3722
|
+
return "";
|
|
3723
|
+
}
|
|
3724
|
+
heading({ tokens: e, depth: t }) {
|
|
3725
|
+
return `<h${t}>${this.parser.parseInline(e)}</h${t}>
|
|
3726
|
+
`;
|
|
3727
|
+
}
|
|
3728
|
+
hr(e) {
|
|
3729
|
+
return `<hr>
|
|
3730
|
+
`;
|
|
3731
|
+
}
|
|
3732
|
+
list(e) {
|
|
3733
|
+
let t = e.ordered, n = e.start, s = "";
|
|
3734
|
+
for (let i = 0; i < e.items.length; i++) {
|
|
3735
|
+
let l = e.items[i];
|
|
3736
|
+
s += this.listitem(l);
|
|
3737
|
+
}
|
|
3738
|
+
let r = t ? "ol" : "ul", o = t && n !== 1 ? ' start="' + n + '"' : "";
|
|
3739
|
+
return "<" + r + o + `>
|
|
3740
|
+
` + s + "</" + r + `>
|
|
3741
|
+
`;
|
|
3742
|
+
}
|
|
3743
|
+
listitem(e) {
|
|
3744
|
+
return `<li>${this.parser.parse(e.tokens)}</li>
|
|
3745
|
+
`;
|
|
3746
|
+
}
|
|
3747
|
+
checkbox({ checked: e }) {
|
|
3748
|
+
return "<input " + (e ? 'checked="" ' : "") + 'disabled="" type="checkbox"> ';
|
|
3749
|
+
}
|
|
3750
|
+
paragraph({ tokens: e }) {
|
|
3751
|
+
return `<p>${this.parser.parseInline(e)}</p>
|
|
3752
|
+
`;
|
|
3753
|
+
}
|
|
3754
|
+
table(e) {
|
|
3755
|
+
let t = "", n = "";
|
|
3756
|
+
for (let r = 0; r < e.header.length; r++) n += this.tablecell(e.header[r]);
|
|
3757
|
+
t += this.tablerow({ text: n });
|
|
3758
|
+
let s = "";
|
|
3759
|
+
for (let r = 0; r < e.rows.length; r++) {
|
|
3760
|
+
let o = e.rows[r];
|
|
3761
|
+
n = "";
|
|
3762
|
+
for (let i = 0; i < o.length; i++) n += this.tablecell(o[i]);
|
|
3763
|
+
s += this.tablerow({ text: n });
|
|
3764
|
+
}
|
|
3765
|
+
return s && (s = `<tbody>${s}</tbody>`), `<table>
|
|
3766
|
+
<thead>
|
|
3767
|
+
` + t + `</thead>
|
|
3768
|
+
` + s + `</table>
|
|
3769
|
+
`;
|
|
3770
|
+
}
|
|
3771
|
+
tablerow({ text: e }) {
|
|
3772
|
+
return `<tr>
|
|
3773
|
+
${e}</tr>
|
|
3774
|
+
`;
|
|
3775
|
+
}
|
|
3776
|
+
tablecell(e) {
|
|
3777
|
+
let t = this.parser.parseInline(e.tokens), n = e.header ? "th" : "td";
|
|
3778
|
+
return (e.align ? `<${n} align="${e.align}">` : `<${n}>`) + t + `</${n}>
|
|
3779
|
+
`;
|
|
3780
|
+
}
|
|
3781
|
+
strong({ tokens: e }) {
|
|
3782
|
+
return `<strong>${this.parser.parseInline(e)}</strong>`;
|
|
3783
|
+
}
|
|
3784
|
+
em({ tokens: e }) {
|
|
3785
|
+
return `<em>${this.parser.parseInline(e)}</em>`;
|
|
3786
|
+
}
|
|
3787
|
+
codespan({ text: e }) {
|
|
3788
|
+
return `<code>${P(e, true)}</code>`;
|
|
3789
|
+
}
|
|
3790
|
+
br(e) {
|
|
3791
|
+
return "<br>";
|
|
3792
|
+
}
|
|
3793
|
+
del({ tokens: e }) {
|
|
3794
|
+
return `<del>${this.parser.parseInline(e)}</del>`;
|
|
3795
|
+
}
|
|
3796
|
+
link({ href: e, title: t, text: n, tokens: s, autolink: r }) {
|
|
3797
|
+
let o = r ? P(n, true) : this.parser.parseInline(s), i = he(e);
|
|
3798
|
+
if (i === null) return o;
|
|
3799
|
+
e = P(i, r);
|
|
3800
|
+
let l = '<a href="' + e + '"';
|
|
3801
|
+
return t && (l += ' title="' + P(t) + '"'), l += ">" + o + "</a>", l;
|
|
3802
|
+
}
|
|
3803
|
+
image({ href: e, title: t, text: n, tokens: s }) {
|
|
3804
|
+
s && (n = this.parser.parseInline(s, this.parser.textRenderer));
|
|
3805
|
+
let r = he(e);
|
|
3806
|
+
if (r === null) return P(n);
|
|
3807
|
+
e = r;
|
|
3808
|
+
let o = `<img src="${P(e)}" alt="${P(n)}"`;
|
|
3809
|
+
return t && (o += ` title="${P(t)}"`), o += ">", o;
|
|
3810
|
+
}
|
|
3811
|
+
text(e) {
|
|
3812
|
+
return "tokens" in e && e.tokens ? this.parser.parseInline(e.tokens) : "escaped" in e && e.escaped ? e.text : P(e.text);
|
|
3813
|
+
}
|
|
3814
|
+
};
|
|
3815
|
+
var E = class {
|
|
3816
|
+
parser;
|
|
3817
|
+
strong({ text: e, tokens: t }) {
|
|
3818
|
+
return t ? this.parser.parseInline(t, this) : e;
|
|
3819
|
+
}
|
|
3820
|
+
em({ text: e, tokens: t }) {
|
|
3821
|
+
return t ? this.parser.parseInline(t, this) : e;
|
|
3822
|
+
}
|
|
3823
|
+
codespan({ text: e }) {
|
|
3824
|
+
return e;
|
|
3825
|
+
}
|
|
3826
|
+
del({ text: e, tokens: t }) {
|
|
3827
|
+
return t ? this.parser.parseInline(t, this) : e;
|
|
3828
|
+
}
|
|
3829
|
+
html({ text: e }) {
|
|
3830
|
+
return e;
|
|
3831
|
+
}
|
|
3832
|
+
text({ text: e }) {
|
|
3833
|
+
return e;
|
|
3834
|
+
}
|
|
3835
|
+
link({ text: e, tokens: t }) {
|
|
3836
|
+
return t ? this.parser.parseInline(t, this) : e;
|
|
3837
|
+
}
|
|
3838
|
+
image({ text: e, tokens: t }) {
|
|
3839
|
+
return t ? this.parser.parseInline(t, this) : e;
|
|
3840
|
+
}
|
|
3841
|
+
br() {
|
|
3842
|
+
return "";
|
|
3843
|
+
}
|
|
3844
|
+
checkbox({ raw: e }) {
|
|
3845
|
+
return e;
|
|
3846
|
+
}
|
|
3847
|
+
};
|
|
3848
|
+
var w = class a2 {
|
|
3849
|
+
options;
|
|
3850
|
+
renderer;
|
|
3851
|
+
textRenderer;
|
|
3852
|
+
constructor(e) {
|
|
3853
|
+
this.options = e || S, this.options.renderer = this.options.renderer || new C(), this.renderer = this.options.renderer, this.renderer.options = this.options, this.renderer.parser = this, this.textRenderer = new E(), this.textRenderer.parser = this;
|
|
3854
|
+
}
|
|
3855
|
+
static parse(e, t) {
|
|
3856
|
+
return new a2(t).parse(e);
|
|
3857
|
+
}
|
|
3858
|
+
static parseInline(e, t) {
|
|
3859
|
+
return new a2(t).parseInline(e);
|
|
3860
|
+
}
|
|
3861
|
+
parse(e) {
|
|
3862
|
+
this.renderer.parser = this;
|
|
3863
|
+
let t = "";
|
|
3864
|
+
for (let n = 0; n < e.length; n++) {
|
|
3865
|
+
let s = e[n];
|
|
3866
|
+
if (this.options.extensions?.renderers?.[s.type]) {
|
|
3867
|
+
let o = s, i = this.options.extensions.renderers[o.type].call({ parser: this }, o);
|
|
3868
|
+
if (i !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "checkbox", "html", "def", "paragraph", "text"].includes(o.type)) {
|
|
3869
|
+
t += i || "";
|
|
3870
|
+
continue;
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
let r = s;
|
|
3874
|
+
switch (r.type) {
|
|
3875
|
+
case "space": {
|
|
3876
|
+
t += this.renderer.space(r);
|
|
3877
|
+
break;
|
|
3878
|
+
}
|
|
3879
|
+
case "hr": {
|
|
3880
|
+
t += this.renderer.hr(r);
|
|
3881
|
+
break;
|
|
3882
|
+
}
|
|
3883
|
+
case "heading": {
|
|
3884
|
+
t += this.renderer.heading(r);
|
|
3885
|
+
break;
|
|
3886
|
+
}
|
|
3887
|
+
case "code": {
|
|
3888
|
+
t += this.renderer.code(r);
|
|
3889
|
+
break;
|
|
3890
|
+
}
|
|
3891
|
+
case "table": {
|
|
3892
|
+
t += this.renderer.table(r);
|
|
3893
|
+
break;
|
|
3894
|
+
}
|
|
3895
|
+
case "blockquote": {
|
|
3896
|
+
t += this.renderer.blockquote(r);
|
|
3897
|
+
break;
|
|
3898
|
+
}
|
|
3899
|
+
case "list": {
|
|
3900
|
+
t += this.renderer.list(r);
|
|
3901
|
+
break;
|
|
3902
|
+
}
|
|
3903
|
+
case "checkbox": {
|
|
3904
|
+
t += this.renderer.checkbox(r);
|
|
3905
|
+
break;
|
|
3906
|
+
}
|
|
3907
|
+
case "html": {
|
|
3908
|
+
t += this.renderer.html(r);
|
|
3909
|
+
break;
|
|
3910
|
+
}
|
|
3911
|
+
case "def": {
|
|
3912
|
+
t += this.renderer.def(r);
|
|
3913
|
+
break;
|
|
3914
|
+
}
|
|
3915
|
+
case "paragraph": {
|
|
3916
|
+
t += this.renderer.paragraph(r);
|
|
3917
|
+
break;
|
|
3918
|
+
}
|
|
3919
|
+
case "text": {
|
|
3920
|
+
t += this.renderer.text(r);
|
|
3921
|
+
break;
|
|
3922
|
+
}
|
|
3923
|
+
default: {
|
|
3924
|
+
let o = 'Token with "' + r.type + '" type was not found.';
|
|
3925
|
+
if (this.options.silent) return console.error(o), "";
|
|
3926
|
+
throw new Error(o);
|
|
3927
|
+
}
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3930
|
+
return t;
|
|
3931
|
+
}
|
|
3932
|
+
parseInline(e, t = this.renderer) {
|
|
3933
|
+
this.renderer.parser = this;
|
|
3934
|
+
let n = "";
|
|
3935
|
+
for (let s = 0; s < e.length; s++) {
|
|
3936
|
+
let r = e[s];
|
|
3937
|
+
if (this.options.extensions?.renderers?.[r.type]) {
|
|
3938
|
+
let i = this.options.extensions.renderers[r.type].call({ parser: this }, r);
|
|
3939
|
+
if (i !== false || !["escape", "html", "link", "image", "checkbox", "strong", "em", "codespan", "br", "del", "text"].includes(r.type)) {
|
|
3940
|
+
n += i || "";
|
|
3941
|
+
continue;
|
|
3942
|
+
}
|
|
3943
|
+
}
|
|
3944
|
+
let o = r;
|
|
3945
|
+
switch (o.type) {
|
|
3946
|
+
case "escape": {
|
|
3947
|
+
n += t.text(o);
|
|
3948
|
+
break;
|
|
3949
|
+
}
|
|
3950
|
+
case "html": {
|
|
3951
|
+
n += t.html(o);
|
|
3952
|
+
break;
|
|
3953
|
+
}
|
|
3954
|
+
case "link": {
|
|
3955
|
+
n += t.link(o);
|
|
3956
|
+
break;
|
|
3957
|
+
}
|
|
3958
|
+
case "image": {
|
|
3959
|
+
n += t.image(o);
|
|
3960
|
+
break;
|
|
3961
|
+
}
|
|
3962
|
+
case "checkbox": {
|
|
3963
|
+
n += t.checkbox(o);
|
|
3964
|
+
break;
|
|
3965
|
+
}
|
|
3966
|
+
case "strong": {
|
|
3967
|
+
n += t.strong(o);
|
|
3968
|
+
break;
|
|
3969
|
+
}
|
|
3970
|
+
case "em": {
|
|
3971
|
+
n += t.em(o);
|
|
3972
|
+
break;
|
|
3973
|
+
}
|
|
3974
|
+
case "codespan": {
|
|
3975
|
+
n += t.codespan(o);
|
|
3976
|
+
break;
|
|
3977
|
+
}
|
|
3978
|
+
case "br": {
|
|
3979
|
+
n += t.br(o);
|
|
3980
|
+
break;
|
|
3981
|
+
}
|
|
3982
|
+
case "del": {
|
|
3983
|
+
n += t.del(o);
|
|
3984
|
+
break;
|
|
3985
|
+
}
|
|
3986
|
+
case "text": {
|
|
3987
|
+
n += t.text(o);
|
|
3988
|
+
break;
|
|
3989
|
+
}
|
|
3990
|
+
default: {
|
|
3991
|
+
let i = 'Token with "' + o.type + '" type was not found.';
|
|
3992
|
+
if (this.options.silent) return console.error(i), "";
|
|
3993
|
+
throw new Error(i);
|
|
3994
|
+
}
|
|
3995
|
+
}
|
|
3996
|
+
}
|
|
3997
|
+
return n;
|
|
3998
|
+
}
|
|
3999
|
+
};
|
|
4000
|
+
var I = class {
|
|
4001
|
+
options;
|
|
4002
|
+
block;
|
|
4003
|
+
constructor(e) {
|
|
4004
|
+
this.options = e || S;
|
|
4005
|
+
}
|
|
4006
|
+
static passThroughHooks = /* @__PURE__ */ new Set(["preprocess", "postprocess", "processAllTokens", "emStrongMask"]);
|
|
4007
|
+
static passThroughHooksRespectAsync = /* @__PURE__ */ new Set(["preprocess", "postprocess", "processAllTokens"]);
|
|
4008
|
+
preprocess(e) {
|
|
4009
|
+
return e;
|
|
4010
|
+
}
|
|
4011
|
+
postprocess(e) {
|
|
4012
|
+
return e;
|
|
4013
|
+
}
|
|
4014
|
+
processAllTokens(e) {
|
|
4015
|
+
return e;
|
|
4016
|
+
}
|
|
4017
|
+
emStrongMask(e) {
|
|
4018
|
+
return e;
|
|
4019
|
+
}
|
|
4020
|
+
provideLexer(e = this.block) {
|
|
4021
|
+
return e ? O.lex : O.lexInline;
|
|
4022
|
+
}
|
|
4023
|
+
provideParser(e = this.block) {
|
|
4024
|
+
return e ? w.parse : w.parseInline;
|
|
4025
|
+
}
|
|
4026
|
+
};
|
|
4027
|
+
function z12(a3, e) {
|
|
4028
|
+
if (Array.isArray(e)) for (let t = 0; t < e.length; t++) a3.push(e[t]);
|
|
4029
|
+
else a3.push(e);
|
|
4030
|
+
}
|
|
4031
|
+
var Y = class {
|
|
4032
|
+
defaults = H();
|
|
4033
|
+
options = this.setOptions;
|
|
4034
|
+
parse = this.parseMarkdown(true);
|
|
4035
|
+
parseInline = this.parseMarkdown(false);
|
|
4036
|
+
Parser = w;
|
|
4037
|
+
Renderer = C;
|
|
4038
|
+
TextRenderer = E;
|
|
4039
|
+
Lexer = O;
|
|
4040
|
+
Tokenizer = _;
|
|
4041
|
+
Hooks = I;
|
|
4042
|
+
constructor(...e) {
|
|
4043
|
+
this.use(...e);
|
|
4044
|
+
}
|
|
4045
|
+
walkTokens(e, t) {
|
|
4046
|
+
let n = [];
|
|
4047
|
+
for (let s of e) switch (z12(n, t.call(this, s)), s.type) {
|
|
4048
|
+
case "table": {
|
|
4049
|
+
let r = s;
|
|
4050
|
+
for (let o of r.header) z12(n, this.walkTokens(o.tokens, t));
|
|
4051
|
+
for (let o of r.rows) for (let i of o) z12(n, this.walkTokens(i.tokens, t));
|
|
4052
|
+
break;
|
|
4053
|
+
}
|
|
4054
|
+
case "list": {
|
|
4055
|
+
let r = s;
|
|
4056
|
+
z12(n, this.walkTokens(r.items, t));
|
|
4057
|
+
break;
|
|
4058
|
+
}
|
|
4059
|
+
default: {
|
|
4060
|
+
let r = s;
|
|
4061
|
+
this.defaults.extensions?.childTokens?.[r.type] ? this.defaults.extensions.childTokens[r.type].forEach((o) => {
|
|
4062
|
+
let i = r[o].flat(1 / 0);
|
|
4063
|
+
z12(n, this.walkTokens(i, t));
|
|
4064
|
+
}) : r.tokens && z12(n, this.walkTokens(r.tokens, t));
|
|
4065
|
+
}
|
|
4066
|
+
}
|
|
4067
|
+
return n;
|
|
4068
|
+
}
|
|
4069
|
+
use(...e) {
|
|
4070
|
+
let t = this.defaults.extensions || { renderers: /* @__PURE__ */ Object.create(null), childTokens: /* @__PURE__ */ Object.create(null) };
|
|
4071
|
+
return e.forEach((n) => {
|
|
4072
|
+
let s = { ...n };
|
|
4073
|
+
if (s.async = this.defaults.async || s.async || false, n.extensions && (n.extensions.forEach((r) => {
|
|
4074
|
+
if (!r.name) throw new Error("extension name required");
|
|
4075
|
+
if ("renderer" in r) {
|
|
4076
|
+
let o = t.renderers[r.name];
|
|
4077
|
+
o ? t.renderers[r.name] = function(...i) {
|
|
4078
|
+
let l = r.renderer.apply(this, i);
|
|
4079
|
+
return l === false && (l = o.apply(this, i)), l;
|
|
4080
|
+
} : t.renderers[r.name] = r.renderer;
|
|
4081
|
+
}
|
|
4082
|
+
if ("tokenizer" in r) {
|
|
4083
|
+
if (!r.level || r.level !== "block" && r.level !== "inline") throw new Error("extension level must be 'block' or 'inline'");
|
|
4084
|
+
let o = t[r.level];
|
|
4085
|
+
o ? o.unshift(r.tokenizer) : t[r.level] = [r.tokenizer], r.start && (r.level === "block" ? t.startBlock ? t.startBlock.push(r.start) : t.startBlock = [r.start] : r.level === "inline" && (t.startInline ? t.startInline.push(r.start) : t.startInline = [r.start]));
|
|
4086
|
+
}
|
|
4087
|
+
"childTokens" in r && r.childTokens && (t.childTokens[r.name] = r.childTokens);
|
|
4088
|
+
}), s.extensions = t), n.renderer) {
|
|
4089
|
+
let r = this.defaults.renderer || new C(this.defaults);
|
|
4090
|
+
for (let o in n.renderer) {
|
|
4091
|
+
if (!(o in r)) throw new Error(`renderer '${o}' does not exist`);
|
|
4092
|
+
if (["options", "parser"].includes(o)) continue;
|
|
4093
|
+
let i = o, l = n.renderer[i], p = r[i];
|
|
4094
|
+
r[i] = (...h) => {
|
|
4095
|
+
let u = l.apply(r, h);
|
|
4096
|
+
return u === false && (u = p.apply(r, h)), u === false ? "" : u ?? "";
|
|
4097
|
+
};
|
|
4098
|
+
}
|
|
4099
|
+
s.renderer = r;
|
|
4100
|
+
}
|
|
4101
|
+
if (n.tokenizer) {
|
|
4102
|
+
let r = this.defaults.tokenizer || new _(this.defaults);
|
|
4103
|
+
for (let o in n.tokenizer) {
|
|
4104
|
+
if (!(o in r)) throw new Error(`tokenizer '${o}' does not exist`);
|
|
4105
|
+
if (["options", "rules", "lexer"].includes(o)) continue;
|
|
4106
|
+
let i = o, l = n.tokenizer[i], p = r[i];
|
|
4107
|
+
r[i] = (...h) => {
|
|
4108
|
+
let u = l.apply(r, h);
|
|
4109
|
+
return u === false && (u = p.apply(r, h)), u;
|
|
4110
|
+
};
|
|
4111
|
+
}
|
|
4112
|
+
s.tokenizer = r;
|
|
4113
|
+
}
|
|
4114
|
+
if (n.hooks) {
|
|
4115
|
+
let r = this.defaults.hooks || new I();
|
|
4116
|
+
for (let o in n.hooks) {
|
|
4117
|
+
if (!(o in r)) throw new Error(`hook '${o}' does not exist`);
|
|
4118
|
+
if (["options", "block"].includes(o)) continue;
|
|
4119
|
+
let i = o, l = n.hooks[i], p = r[i];
|
|
4120
|
+
I.passThroughHooks.has(o) ? r[i] = (h) => {
|
|
4121
|
+
if (r.options.async && I.passThroughHooksRespectAsync.has(o)) return (async () => {
|
|
4122
|
+
let d = await l.call(r, h);
|
|
4123
|
+
return p.call(r, d);
|
|
4124
|
+
})();
|
|
4125
|
+
let u = l.call(r, h);
|
|
4126
|
+
return p.call(r, u);
|
|
4127
|
+
} : r[i] = (...h) => {
|
|
4128
|
+
if (r.options.async) return (async () => {
|
|
4129
|
+
let d = await l.apply(r, h);
|
|
4130
|
+
return d === false && (d = await p.apply(r, h)), d;
|
|
4131
|
+
})();
|
|
4132
|
+
let u = l.apply(r, h);
|
|
4133
|
+
return u === false && (u = p.apply(r, h)), u;
|
|
4134
|
+
};
|
|
4135
|
+
}
|
|
4136
|
+
s.hooks = r;
|
|
4137
|
+
}
|
|
4138
|
+
if (n.walkTokens) {
|
|
4139
|
+
let r = this.defaults.walkTokens, o = n.walkTokens;
|
|
4140
|
+
s.walkTokens = function(i) {
|
|
4141
|
+
let l = [];
|
|
4142
|
+
return z12(l, o.call(this, i)), r && z12(l, r.call(this, i)), l;
|
|
4143
|
+
};
|
|
4144
|
+
}
|
|
4145
|
+
this.defaults = { ...this.defaults, ...s };
|
|
4146
|
+
}), this;
|
|
4147
|
+
}
|
|
4148
|
+
setOptions(e) {
|
|
4149
|
+
return this.defaults = { ...this.defaults, ...e }, this;
|
|
4150
|
+
}
|
|
4151
|
+
lexer(e, t) {
|
|
4152
|
+
return O.lex(e, t ?? this.defaults);
|
|
4153
|
+
}
|
|
4154
|
+
parser(e, t) {
|
|
4155
|
+
return w.parse(e, t ?? this.defaults);
|
|
4156
|
+
}
|
|
4157
|
+
parseMarkdown(e) {
|
|
4158
|
+
return (n, s) => {
|
|
4159
|
+
let r = { ...s }, o = { ...this.defaults, ...r }, i = this.onError(!!o.silent, !!o.async);
|
|
4160
|
+
if (this.defaults.async === true && r.async === false) return i(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));
|
|
4161
|
+
if (typeof n > "u" || n === null) return i(new Error("marked(): input parameter is undefined or null"));
|
|
4162
|
+
if (typeof n != "string") return i(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(n) + ", string expected"));
|
|
4163
|
+
if (o.hooks && (o.hooks.options = o, o.hooks.block = e), o.async) return (async () => {
|
|
4164
|
+
let l = o.hooks ? await o.hooks.preprocess(n) : n, h = await (o.hooks ? await o.hooks.provideLexer(e) : e ? O.lex : O.lexInline)(l, o), u = o.hooks ? await o.hooks.processAllTokens(h) : h;
|
|
4165
|
+
o.walkTokens && await Promise.all(this.walkTokens(u, o.walkTokens));
|
|
4166
|
+
let k = await (o.hooks ? await o.hooks.provideParser(e) : e ? w.parse : w.parseInline)(u, o);
|
|
4167
|
+
return o.hooks ? await o.hooks.postprocess(k) : k;
|
|
4168
|
+
})().catch(i);
|
|
4169
|
+
try {
|
|
4170
|
+
o.hooks && (n = o.hooks.preprocess(n));
|
|
4171
|
+
let p = (o.hooks ? o.hooks.provideLexer(e) : e ? O.lex : O.lexInline)(n, o);
|
|
4172
|
+
o.hooks && (p = o.hooks.processAllTokens(p)), o.walkTokens && this.walkTokens(p, o.walkTokens);
|
|
4173
|
+
let u = (o.hooks ? o.hooks.provideParser(e) : e ? w.parse : w.parseInline)(p, o);
|
|
4174
|
+
return o.hooks && (u = o.hooks.postprocess(u)), u;
|
|
4175
|
+
} catch (l) {
|
|
4176
|
+
return i(l);
|
|
4177
|
+
}
|
|
4178
|
+
};
|
|
4179
|
+
}
|
|
4180
|
+
onError(e, t) {
|
|
4181
|
+
return (n) => {
|
|
4182
|
+
if (n.message += `
|
|
4183
|
+
Please report this to https://github.com/markedjs/marked.`, e) {
|
|
4184
|
+
let s = "<p>An error occurred:</p><pre>" + P(n.message + "", true) + "</pre>";
|
|
4185
|
+
return t ? Promise.resolve(s) : s;
|
|
4186
|
+
}
|
|
4187
|
+
if (t) return Promise.reject(n);
|
|
4188
|
+
throw n;
|
|
4189
|
+
};
|
|
4190
|
+
}
|
|
4191
|
+
};
|
|
4192
|
+
var q = new Y();
|
|
4193
|
+
function x(a3, e) {
|
|
4194
|
+
return q.parse(a3, e);
|
|
4195
|
+
}
|
|
4196
|
+
x.options = x.setOptions = function(a3) {
|
|
4197
|
+
return q.setOptions(a3), x.defaults = q.defaults, se(x.defaults), x;
|
|
4198
|
+
};
|
|
4199
|
+
x.getDefaults = H;
|
|
4200
|
+
x.defaults = S;
|
|
4201
|
+
function Bt(...a3) {
|
|
4202
|
+
return q.use(...a3), x.defaults = q.defaults, se(x.defaults), x;
|
|
4203
|
+
}
|
|
4204
|
+
x.use = Bt;
|
|
4205
|
+
x.walkTokens = function(a3, e) {
|
|
4206
|
+
return q.walkTokens(a3, e);
|
|
4207
|
+
};
|
|
4208
|
+
x.parseInline = q.parseInline;
|
|
4209
|
+
x.Parser = w;
|
|
4210
|
+
x.parser = w.parse;
|
|
4211
|
+
x.Renderer = C;
|
|
4212
|
+
x.TextRenderer = E;
|
|
4213
|
+
x.Lexer = O;
|
|
4214
|
+
x.lexer = O.lex;
|
|
4215
|
+
x.Tokenizer = _;
|
|
4216
|
+
x.Hooks = I;
|
|
4217
|
+
x.parse = x;
|
|
4218
|
+
var _n = x.options;
|
|
4219
|
+
var $n = x.setOptions;
|
|
4220
|
+
var Ln = x.walkTokens;
|
|
4221
|
+
var Cn = x.parseInline;
|
|
4222
|
+
var An = w.parse;
|
|
4223
|
+
var En = O.lex;
|
|
4224
|
+
|
|
4225
|
+
// ../../packages/shared/src/markdown.ts
|
|
4226
|
+
var MAX_RENDERED_MARKDOWN = 200;
|
|
4227
|
+
var MAX_MARKDOWN_BYTES = 2 * 1024 * 1024;
|
|
4228
|
+
var STYLE = `
|
|
4229
|
+
:root{color-scheme:light dark;--fg:light-dark(#1f2328,#e6edf3);--muted:light-dark(#59636e,#9198a1);--bg:light-dark(#fff,#0d1117);--line:light-dark(#d1d9e0,#3d444d);--code:light-dark(#f6f8fa,#151b23);--link:light-dark(#0969da,#4493f8)}
|
|
4230
|
+
*{box-sizing:border-box}
|
|
4231
|
+
body{margin:0;background:var(--bg);color:var(--fg);font:16px/1.6 system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif}
|
|
4232
|
+
.fling-md-header,main{max-width:64rem;margin:0 auto;padding-inline:clamp(1rem,4vw,2rem)}
|
|
4233
|
+
.fling-md-header{padding-block:.75rem;display:flex;gap:1rem;justify-content:space-between;font-size:.8125rem;color:var(--muted);border-bottom:1px solid var(--line)}
|
|
4234
|
+
.fling-md-header span{overflow-wrap:anywhere}
|
|
4235
|
+
main{padding-block:1.5rem 4rem;overflow-wrap:break-word}
|
|
4236
|
+
a{color:var(--link)}
|
|
4237
|
+
h1,h2,h3,h4,h5,h6{line-height:1.25;margin:1.75em 0 .6em}
|
|
4238
|
+
h1:first-child,h2:first-child{margin-top:0}
|
|
4239
|
+
h1,h2{padding-bottom:.3em;border-bottom:1px solid var(--line)}
|
|
4240
|
+
code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,"Liberation Mono",monospace;font-size:.875em}
|
|
4241
|
+
:not(pre)>code{background:var(--code);padding:.15em .35em;border-radius:4px}
|
|
4242
|
+
pre{background:var(--code);padding:1rem;border-radius:6px;overflow:auto;line-height:1.45}
|
|
4243
|
+
blockquote{margin:1em 0;padding:0 1em;color:var(--muted);border-left:.25em solid var(--line)}
|
|
4244
|
+
table{border-collapse:collapse;display:block;max-width:100%;overflow:auto;margin:1em 0}
|
|
4245
|
+
th,td{border:1px solid var(--line);padding:.4em .8em}
|
|
4246
|
+
th{background:var(--code)}
|
|
4247
|
+
img,video{max-width:100%;height:auto}
|
|
4248
|
+
hr{border:0;border-top:1px solid var(--line);margin:2em 0}
|
|
4249
|
+
li.task-list-item{list-style:none}
|
|
4250
|
+
li.task-list-item input{margin:0 .4em 0 -1.4em;vertical-align:middle}
|
|
4251
|
+
`.trim().replace(/\n/g, "");
|
|
4252
|
+
|
|
4253
|
+
// ../../packages/shared/src/mcp-tools.ts
|
|
4254
|
+
import { z as z15 } from "zod";
|
|
4255
|
+
|
|
2782
4256
|
// ../../packages/shared/src/site-labels.ts
|
|
2783
4257
|
var SITE_NAME_MAX = 50;
|
|
2784
4258
|
var SHARE_TOKEN_LENGTH = 20;
|
|
@@ -2813,56 +4287,56 @@ function siteUrl(label, sitesDomain, protocol = "https:") {
|
|
|
2813
4287
|
}
|
|
2814
4288
|
|
|
2815
4289
|
// ../../packages/shared/src/instance.ts
|
|
2816
|
-
import { z as
|
|
4290
|
+
import { z as z13 } from "zod";
|
|
2817
4291
|
var INSTANCE_METADATA_PATH = "/.well-known/fling";
|
|
2818
4292
|
var RELEASE_HEADER = "Fling-Release";
|
|
2819
4293
|
var HEX_COLOR_RE = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
2820
|
-
var color =
|
|
2821
|
-
var SignInProviderSchema =
|
|
4294
|
+
var color = z13.string().regex(HEX_COLOR_RE);
|
|
4295
|
+
var SignInProviderSchema = z13.looseObject({
|
|
2822
4296
|
/** `google` or `oidc` today; clients pass it back as is. */
|
|
2823
|
-
id:
|
|
4297
|
+
id: z13.string().min(1),
|
|
2824
4298
|
/** "Sign in with <displayName>". */
|
|
2825
|
-
displayName:
|
|
2826
|
-
issuer:
|
|
4299
|
+
displayName: z13.string().min(1),
|
|
4300
|
+
issuer: z13.string().optional()
|
|
2827
4301
|
});
|
|
2828
|
-
var InstanceAuthSchema =
|
|
2829
|
-
kind:
|
|
2830
|
-
displayName:
|
|
2831
|
-
issuer:
|
|
2832
|
-
providers:
|
|
2833
|
-
emailDomains:
|
|
2834
|
-
invitedEmails:
|
|
4302
|
+
var InstanceAuthSchema = z13.looseObject({
|
|
4303
|
+
kind: z13.string().min(1),
|
|
4304
|
+
displayName: z13.string().min(1),
|
|
4305
|
+
issuer: z13.string().optional(),
|
|
4306
|
+
providers: z13.array(SignInProviderSchema).optional(),
|
|
4307
|
+
emailDomains: z13.array(z13.string()).default([]),
|
|
4308
|
+
invitedEmails: z13.boolean().optional()
|
|
2835
4309
|
});
|
|
2836
|
-
var BrandColorsSchema =
|
|
4310
|
+
var BrandColorsSchema = z13.looseObject({
|
|
2837
4311
|
primary: color.optional(),
|
|
2838
4312
|
primaryContent: color.optional(),
|
|
2839
4313
|
accent: color.optional(),
|
|
2840
4314
|
ink: color.optional(),
|
|
2841
4315
|
highlight: color.optional()
|
|
2842
4316
|
});
|
|
2843
|
-
var InstanceBrandSchema =
|
|
4317
|
+
var InstanceBrandSchema = z13.looseObject({
|
|
2844
4318
|
/** https: or data: URL of the logo mark shown before the name (light theme). */
|
|
2845
|
-
logoUrl:
|
|
4319
|
+
logoUrl: z13.string().optional(),
|
|
2846
4320
|
/** The same for the dark theme; defaults to `logoUrl`. */
|
|
2847
|
-
logoDarkUrl:
|
|
2848
|
-
faviconUrl:
|
|
4321
|
+
logoDarkUrl: z13.string().optional(),
|
|
4322
|
+
faviconUrl: z13.string().optional(),
|
|
2849
4323
|
colors: BrandColorsSchema.default({})
|
|
2850
4324
|
});
|
|
2851
|
-
var InstanceMetadataSchema =
|
|
2852
|
-
version:
|
|
4325
|
+
var InstanceMetadataSchema = z13.looseObject({
|
|
4326
|
+
version: z13.number().int().min(1),
|
|
2853
4327
|
/** Display name, e.g. "Fling". */
|
|
2854
|
-
name:
|
|
4328
|
+
name: z13.string().min(1),
|
|
2855
4329
|
/** e.g. `https://fling.example.test` (no trailing slash) */
|
|
2856
|
-
appOrigin:
|
|
4330
|
+
appOrigin: z13.string().url(),
|
|
2857
4331
|
/** host[:port] sites hang off: a site is `<name>.<sitesDomain>` */
|
|
2858
|
-
sitesDomain:
|
|
2859
|
-
siteScheme:
|
|
4332
|
+
sitesDomain: z13.string().min(1),
|
|
4333
|
+
siteScheme: z13.enum(["http", "https"]),
|
|
2860
4334
|
auth: InstanceAuthSchema,
|
|
2861
4335
|
brand: InstanceBrandSchema.default({ colors: {} }),
|
|
2862
4336
|
/** Feature flags: a client hides what is missing or false. */
|
|
2863
|
-
capabilities:
|
|
4337
|
+
capabilities: z13.record(z13.string(), z13.boolean()).default({}),
|
|
2864
4338
|
/** How to install the CLI, e.g. `npm install -g <package>`. */
|
|
2865
|
-
installCommand:
|
|
4339
|
+
installCommand: z13.string().min(1),
|
|
2866
4340
|
/**
|
|
2867
4341
|
* The access level a new site gets when its first deploy names none (`SITE_DEFAULT_ACCESS`).
|
|
2868
4342
|
* Missing (older servers) or unknown: `members` (`defaultAccessOf`).
|
|
@@ -2872,8 +4346,59 @@ var InstanceMetadataSchema = z11.looseObject({
|
|
|
2872
4346
|
* The Fling release the server runs, e.g. `0.7.0` (the root package.json's version, built in).
|
|
2873
4347
|
* Missing on servers built before releases were stamped.
|
|
2874
4348
|
*/
|
|
2875
|
-
release:
|
|
4349
|
+
release: z13.string().min(1).optional().catch(void 0)
|
|
2876
4350
|
});
|
|
4351
|
+
var CORE_CAPABILITIES = {
|
|
4352
|
+
/** the remote MCP connector at `/mcp` */
|
|
4353
|
+
remoteMcp: true,
|
|
4354
|
+
shareLinks: true,
|
|
4355
|
+
publicSites: true,
|
|
4356
|
+
archive: true,
|
|
4357
|
+
rollback: true,
|
|
4358
|
+
/** a private site can be limited to listed people (its audience) */
|
|
4359
|
+
audiences: true,
|
|
4360
|
+
/** named lists of people (groups.ts) that any member can use in an audience */
|
|
4361
|
+
groups: true,
|
|
4362
|
+
/** the five access levels (access.ts), `only_me` among them, set with `access` */
|
|
4363
|
+
accessLevels: true,
|
|
4364
|
+
/** a site's owners and publishers, people and groups (site-roles.ts), set with `owners`/`publishers` */
|
|
4365
|
+
siteRoles: true,
|
|
4366
|
+
/** a deploy can publish one top-level folder of a site, as its Path (`DeployRequest.path`) */
|
|
4367
|
+
pathPublish: true,
|
|
4368
|
+
/**
|
|
4369
|
+
* Paths: top-level folders of a site with their own versions, rollback, owners and publishers
|
|
4370
|
+
* (`/api/sites/:name/paths…`, `fling paths`, `fling_paths`); a home page with a Paths block lists
|
|
4371
|
+
* them, as does `/_fling-paths.json`
|
|
4372
|
+
*/
|
|
4373
|
+
paths: true,
|
|
4374
|
+
/** Markdown files are served rendered as pages (GitHub-flavoured), their source at `?raw=1` */
|
|
4375
|
+
markdown: true,
|
|
4376
|
+
/**
|
|
4377
|
+
* whoever can see a site signed in may download its files (`GET /api/sites/:name/pull`,
|
|
4378
|
+
* `fling pull`, `fling_read_files`), and a deploy can build on the version pulled, sending only
|
|
4379
|
+
* what changed (`DeployRequest.base`)
|
|
4380
|
+
*/
|
|
4381
|
+
pull: true,
|
|
4382
|
+
/**
|
|
4383
|
+
* a live preview of each site's home page on its site page, and a thumbnail of it in the site
|
|
4384
|
+
* lists, taken by its owners' and publishers' browsers (thumbnails.ts)
|
|
4385
|
+
*/
|
|
4386
|
+
thumbnails: true,
|
|
4387
|
+
/** the user guide in the web app at `/guide` (guide.ts), readable signed out */
|
|
4388
|
+
guide: true
|
|
4389
|
+
};
|
|
4390
|
+
var CONFIGURED_CAPABILITIES = [
|
|
4391
|
+
"comments",
|
|
4392
|
+
"forms",
|
|
4393
|
+
"live",
|
|
4394
|
+
"notifications",
|
|
4395
|
+
"email",
|
|
4396
|
+
"invites"
|
|
4397
|
+
];
|
|
4398
|
+
var CAPABILITY_NAMES = [
|
|
4399
|
+
...Object.keys(CORE_CAPABILITIES),
|
|
4400
|
+
...CONFIGURED_CAPABILITIES
|
|
4401
|
+
];
|
|
2877
4402
|
var defaultAccessOf = (instance) => instance?.defaultAccess ?? LEGACY_DEFAULT_ACCESS;
|
|
2878
4403
|
function instanceSitesPattern(instance) {
|
|
2879
4404
|
return `${instance.siteScheme}://<name>.${instance.sitesDomain}`;
|
|
@@ -2896,128 +4421,11 @@ function instanceMetadataUrl(serverUrl) {
|
|
|
2896
4421
|
return `${serverUrl.replace(/\/+$/, "")}${INSTANCE_METADATA_PATH}`;
|
|
2897
4422
|
}
|
|
2898
4423
|
|
|
2899
|
-
// ../../packages/shared/src/kvs.ts
|
|
2900
|
-
import { z as z12 } from "zod";
|
|
2901
|
-
|
|
2902
|
-
// ../../packages/shared/src/route-keys.ts
|
|
2903
|
-
var SITE_PASS_TTL_SECONDS = 5 * 60;
|
|
2904
|
-
|
|
2905
|
-
// ../../packages/shared/src/kvs.ts
|
|
2906
|
-
var KvsSiteValueSchema = z12.object({
|
|
2907
|
-
/** siteId — S3 prefix is `sites/<id>/<v>/` */
|
|
2908
|
-
id: z12.string(),
|
|
2909
|
-
/** current versionId */
|
|
2910
|
-
v: z12.string(),
|
|
2911
|
-
vis: z12.enum(["private", "public"]),
|
|
2912
|
-
/** serve /index.html for unknown extensionless paths */
|
|
2913
|
-
spa: z12.boolean(),
|
|
2914
|
-
/** present when the site is restricted (private with an audience): the edge wants a site pass */
|
|
2915
|
-
r: z12.literal(1).optional(),
|
|
2916
|
-
/** present when the site has live Paths: a request's first folder may be one (`path:` keys) */
|
|
2917
|
-
p: z12.literal(1).optional(),
|
|
2918
|
-
/**
|
|
2919
|
-
* the rendered home page and Paths listing (`sites/<id>/_rendered/<i>.html|json`), served for
|
|
2920
|
-
* `/`, `/index.html` and PATHS_JSON_PATH instead of the version's own index.html
|
|
2921
|
-
*/
|
|
2922
|
-
i: z12.string().optional(),
|
|
2923
|
-
/** present when the current version's Markdown files have rendered pages (markdown.ts) */
|
|
2924
|
-
m: z12.literal(1).optional()
|
|
2925
|
-
});
|
|
2926
|
-
var KvsPathValueSchema = z12.object({
|
|
2927
|
-
id: z12.string(),
|
|
2928
|
-
v: z12.string(),
|
|
2929
|
-
/** as on a site's value: its current version's Markdown has rendered pages */
|
|
2930
|
-
m: z12.literal(1).optional()
|
|
2931
|
-
});
|
|
2932
|
-
|
|
2933
|
-
// ../../packages/shared/src/listing.ts
|
|
2934
|
-
var LISTING_GENERATOR_META = "fling-listing";
|
|
2935
|
-
var escapeHtml = (s) => s.replace(
|
|
2936
|
-
/[&<>"']/g,
|
|
2937
|
-
(c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]
|
|
2938
|
-
);
|
|
2939
|
-
var hrefFor = (path3) => path3.split("/").map(encodeURIComponent).join("/");
|
|
2940
|
-
function isHtmlPath(path3) {
|
|
2941
|
-
return /\.html?$/i.test(path3);
|
|
2942
|
-
}
|
|
2943
|
-
function extractHtmlTitle(html) {
|
|
2944
|
-
const match = /<title[^>]*>([\s\S]*?)<\/title>/i.exec(html.slice(0, 65536));
|
|
2945
|
-
const title = match?.[1]?.replace(/<[^>]*>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/\s+/g, " ").trim();
|
|
2946
|
-
return title ? title : null;
|
|
2947
|
-
}
|
|
2948
|
-
function renderHtmlListing(siteName2, entries) {
|
|
2949
|
-
const pages = entries.filter((e) => isHtmlPath(e.path) && e.path.toLowerCase() !== "index.html").sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
2950
|
-
const groups2 = /* @__PURE__ */ new Map();
|
|
2951
|
-
for (const page2 of pages) {
|
|
2952
|
-
const slash = page2.path.lastIndexOf("/");
|
|
2953
|
-
const folder = slash === -1 ? "" : page2.path.slice(0, slash);
|
|
2954
|
-
groups2.set(folder, [...groups2.get(folder) ?? [], page2]);
|
|
2955
|
-
}
|
|
2956
|
-
const sections = [...groups2.entries()].sort(([a], [b]) => a === "" ? -1 : b === "" ? 1 : a < b ? -1 : 1).map(([folder, items]) => {
|
|
2957
|
-
const heading = folder ? `<h2>${escapeHtml(folder)}/</h2>` : "";
|
|
2958
|
-
const rows = items.map((item) => {
|
|
2959
|
-
const file = item.path.slice(item.path.lastIndexOf("/") + 1);
|
|
2960
|
-
const label = item.title ? escapeHtml(item.title) : escapeHtml(file);
|
|
2961
|
-
const sub = item.title ? `<span class="file">${escapeHtml(file)}</span>` : "";
|
|
2962
|
-
return `<li><a href="${hrefFor(item.path)}">${label}</a>${sub}</li>`;
|
|
2963
|
-
}).join("\n");
|
|
2964
|
-
return `${heading}<ul>
|
|
2965
|
-
${rows}
|
|
2966
|
-
</ul>`;
|
|
2967
|
-
}).join("\n");
|
|
2968
|
-
const body = pages.length ? sections : '<p class="empty">No HTML pages in this fling.</p>';
|
|
2969
|
-
const count2 = `${pages.length} page${pages.length === 1 ? "" : "s"}`;
|
|
2970
|
-
return `<!doctype html>
|
|
2971
|
-
<html lang="en">
|
|
2972
|
-
<head>
|
|
2973
|
-
<meta charset="utf-8">
|
|
2974
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
2975
|
-
<meta name="generator" content="${LISTING_GENERATOR_META}">
|
|
2976
|
-
<title>${escapeHtml(siteName2)}</title>
|
|
2977
|
-
<style>
|
|
2978
|
-
:root { color-scheme: light dark; --fg: #000e38; --muted: #5b6480; --bg: #f7f8fb; --card: #fff;
|
|
2979
|
-
--line: #e3e6ef; --accent: #166bff; --green: #00e5a4; }
|
|
2980
|
-
@media (prefers-color-scheme: dark) { :root { --fg: #eef1f8; --muted: #9aa3bd; --bg: #000e38;
|
|
2981
|
-
--card: #0b1a4a; --line: #1d2c5e; --accent: #6ea2ff; } }
|
|
2982
|
-
* { box-sizing: border-box; }
|
|
2983
|
-
body { margin: 0; font: 16px/1.5 Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
2984
|
-
color: var(--fg); background: var(--bg); }
|
|
2985
|
-
main { max-width: 760px; margin: 0 auto; padding: 48px 20px 64px; }
|
|
2986
|
-
header { border-left: 4px solid var(--green); padding-left: 14px; margin-bottom: 28px; }
|
|
2987
|
-
h1 { margin: 0; font-size: 1.6rem; }
|
|
2988
|
-
header p, .file, footer { color: var(--muted); font-size: .875rem; }
|
|
2989
|
-
header p { margin: 4px 0 0; }
|
|
2990
|
-
h2 { font-size: .95rem; margin: 28px 0 8px; color: var(--muted); font-weight: 600; }
|
|
2991
|
-
ul { list-style: none; margin: 0; padding: 0; background: var(--card); border: 1px solid var(--line);
|
|
2992
|
-
border-radius: 10px; overflow: hidden; }
|
|
2993
|
-
li { padding: 12px 16px; border-top: 1px solid var(--line); display: flex; gap: 12px;
|
|
2994
|
-
justify-content: space-between; align-items: baseline; flex-wrap: wrap; }
|
|
2995
|
-
li:first-child { border-top: 0; }
|
|
2996
|
-
a { color: var(--accent); text-decoration: none; font-weight: 500; }
|
|
2997
|
-
a:hover { text-decoration: underline; }
|
|
2998
|
-
.empty { color: var(--muted); }
|
|
2999
|
-
footer { margin-top: 40px; }
|
|
3000
|
-
</style>
|
|
3001
|
-
</head>
|
|
3002
|
-
<body>
|
|
3003
|
-
<main>
|
|
3004
|
-
<header><h1>${escapeHtml(siteName2)}</h1><p>${count2}</p></header>
|
|
3005
|
-
${body}
|
|
3006
|
-
<footer>Flung with Fling</footer>
|
|
3007
|
-
</main>
|
|
3008
|
-
</body>
|
|
3009
|
-
</html>
|
|
3010
|
-
`;
|
|
3011
|
-
}
|
|
3012
|
-
|
|
3013
|
-
// ../../packages/shared/src/mcp-tools.ts
|
|
3014
|
-
import { z as z14 } from "zod";
|
|
3015
|
-
|
|
3016
4424
|
// ../../packages/shared/src/notifications.ts
|
|
3017
|
-
import { z as
|
|
4425
|
+
import { z as z14 } from "zod";
|
|
3018
4426
|
var CHANNEL_IDS = ["email"];
|
|
3019
|
-
var ChannelIdSchema =
|
|
3020
|
-
var DeliverySchema =
|
|
4427
|
+
var ChannelIdSchema = z14.enum(CHANNEL_IDS);
|
|
4428
|
+
var DeliverySchema = z14.enum(["on", "off"]);
|
|
3021
4429
|
var EVENT_KEYS = [
|
|
3022
4430
|
"site.shared",
|
|
3023
4431
|
"site.shared_via_group",
|
|
@@ -3027,7 +4435,7 @@ var EVENT_KEYS = [
|
|
|
3027
4435
|
"comment.created",
|
|
3028
4436
|
"comment.reply"
|
|
3029
4437
|
];
|
|
3030
|
-
var EventKeySchema =
|
|
4438
|
+
var EventKeySchema = z14.enum(EVENT_KEYS);
|
|
3031
4439
|
var EVENT_CATALOGUE = [
|
|
3032
4440
|
{
|
|
3033
4441
|
key: "site.shared",
|
|
@@ -3091,95 +4499,96 @@ var EVENT_CATALOGUE = [
|
|
|
3091
4499
|
}
|
|
3092
4500
|
];
|
|
3093
4501
|
var BY_KEY = new Map(EVENT_CATALOGUE.map((e) => [e.key, e]));
|
|
3094
|
-
var NotificationPreferencesUpdateSchema =
|
|
3095
|
-
muted:
|
|
3096
|
-
cells:
|
|
4502
|
+
var NotificationPreferencesUpdateSchema = z14.object({
|
|
4503
|
+
muted: z14.boolean().optional(),
|
|
4504
|
+
cells: z14.partialRecord(EventKeySchema, z14.partialRecord(ChannelIdSchema, DeliverySchema.nullable())).optional()
|
|
3097
4505
|
});
|
|
3098
|
-
var EventDefinitionSchema =
|
|
3099
|
-
key:
|
|
3100
|
-
title:
|
|
3101
|
-
description:
|
|
3102
|
-
section:
|
|
3103
|
-
defaults:
|
|
3104
|
-
coolDown:
|
|
3105
|
-
capability:
|
|
4506
|
+
var EventDefinitionSchema = z14.looseObject({
|
|
4507
|
+
key: z14.string(),
|
|
4508
|
+
title: z14.string(),
|
|
4509
|
+
description: z14.string(),
|
|
4510
|
+
section: z14.string(),
|
|
4511
|
+
defaults: z14.record(z14.string(), DeliverySchema),
|
|
4512
|
+
coolDown: z14.boolean(),
|
|
4513
|
+
capability: z14.string().optional()
|
|
3106
4514
|
});
|
|
3107
|
-
var NotificationSettingsSchema =
|
|
3108
|
-
channels:
|
|
3109
|
-
events:
|
|
3110
|
-
muted:
|
|
3111
|
-
cells:
|
|
3112
|
-
overrides:
|
|
4515
|
+
var NotificationSettingsSchema = z14.looseObject({
|
|
4516
|
+
channels: z14.array(z14.string()),
|
|
4517
|
+
events: z14.array(EventDefinitionSchema),
|
|
4518
|
+
muted: z14.boolean(),
|
|
4519
|
+
cells: z14.record(z14.string(), z14.record(z14.string(), DeliverySchema)),
|
|
4520
|
+
overrides: z14.record(z14.string(), z14.record(z14.string(), DeliverySchema)).default({})
|
|
3113
4521
|
});
|
|
3114
|
-
var SentNotificationSchema =
|
|
3115
|
-
id:
|
|
3116
|
-
channel:
|
|
4522
|
+
var SentNotificationSchema = z14.looseObject({
|
|
4523
|
+
id: z14.string(),
|
|
4524
|
+
channel: z14.string(),
|
|
3117
4525
|
/** the events it told them about (several when folded) */
|
|
3118
|
-
eventKeys:
|
|
3119
|
-
subject:
|
|
4526
|
+
eventKeys: z14.array(z14.string()),
|
|
4527
|
+
subject: z14.string(),
|
|
3120
4528
|
/** the provider's message id, when it gave one */
|
|
3121
|
-
providerId:
|
|
3122
|
-
sentAt:
|
|
4529
|
+
providerId: z14.string().nullable(),
|
|
4530
|
+
sentAt: z14.string()
|
|
3123
4531
|
});
|
|
3124
|
-
var SentNotificationListSchema =
|
|
3125
|
-
var MailCountsSchema =
|
|
3126
|
-
sent:
|
|
3127
|
-
retrying:
|
|
3128
|
-
givenUp:
|
|
3129
|
-
suppressed:
|
|
3130
|
-
dropped:
|
|
4532
|
+
var SentNotificationListSchema = z14.object({ sent: z14.array(SentNotificationSchema) });
|
|
4533
|
+
var MailCountsSchema = z14.object({
|
|
4534
|
+
sent: z14.number(),
|
|
4535
|
+
retrying: z14.number(),
|
|
4536
|
+
givenUp: z14.number(),
|
|
4537
|
+
suppressed: z14.number(),
|
|
4538
|
+
dropped: z14.number()
|
|
3131
4539
|
});
|
|
3132
|
-
var MailAdminSchema =
|
|
3133
|
-
config:
|
|
3134
|
-
driver:
|
|
3135
|
-
from:
|
|
3136
|
-
fromName:
|
|
3137
|
-
replyTo:
|
|
3138
|
-
configurationSet:
|
|
4540
|
+
var MailAdminSchema = z14.object({
|
|
4541
|
+
config: z14.object({
|
|
4542
|
+
driver: z14.string(),
|
|
4543
|
+
from: z14.string(),
|
|
4544
|
+
fromName: z14.string(),
|
|
4545
|
+
replyTo: z14.string().nullable(),
|
|
4546
|
+
configurationSet: z14.string().nullable(),
|
|
3139
4547
|
/** outside invitations are on (`INVITES`) */
|
|
3140
|
-
invites:
|
|
4548
|
+
invites: z14.boolean()
|
|
3141
4549
|
}),
|
|
3142
|
-
health:
|
|
4550
|
+
health: z14.object({
|
|
3143
4551
|
/** the first hour counted (UTC, `2026-10-28T14`) */
|
|
3144
|
-
since:
|
|
4552
|
+
since: z14.string(),
|
|
3145
4553
|
/** the hours with any activity, oldest first */
|
|
3146
|
-
hours:
|
|
4554
|
+
hours: z14.array(MailCountsSchema.extend({ hour: z14.string() })),
|
|
3147
4555
|
totals: MailCountsSchema,
|
|
3148
4556
|
/** the latest failed sends, newest first */
|
|
3149
|
-
failures:
|
|
3150
|
-
|
|
3151
|
-
at:
|
|
3152
|
-
batchId:
|
|
3153
|
-
eventKeys:
|
|
3154
|
-
reason:
|
|
3155
|
-
detail:
|
|
4557
|
+
failures: z14.array(
|
|
4558
|
+
z14.object({
|
|
4559
|
+
at: z14.string(),
|
|
4560
|
+
batchId: z14.string(),
|
|
4561
|
+
eventKeys: z14.array(z14.string()),
|
|
4562
|
+
reason: z14.string(),
|
|
4563
|
+
detail: z14.string().nullable()
|
|
3156
4564
|
})
|
|
3157
4565
|
)
|
|
3158
4566
|
}),
|
|
3159
4567
|
/** test emails this admin may still send this hour, of `limit` */
|
|
3160
|
-
tests:
|
|
4568
|
+
tests: z14.object({ remaining: z14.number(), limit: z14.number() })
|
|
3161
4569
|
});
|
|
3162
|
-
var MailTestRequestSchema =
|
|
3163
|
-
to:
|
|
4570
|
+
var MailTestRequestSchema = z14.object({
|
|
4571
|
+
to: z14.string().trim().toLowerCase().min(3).max(254)
|
|
3164
4572
|
});
|
|
3165
|
-
var MailTestResultSchema =
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
ok:
|
|
3169
|
-
reason:
|
|
3170
|
-
detail:
|
|
3171
|
-
error:
|
|
4573
|
+
var MailTestResultSchema = z14.discriminatedUnion("ok", [
|
|
4574
|
+
z14.object({ ok: z14.literal(true), providerId: z14.string().nullable(), subject: z14.string() }),
|
|
4575
|
+
z14.object({
|
|
4576
|
+
ok: z14.literal(false),
|
|
4577
|
+
reason: z14.string(),
|
|
4578
|
+
detail: z14.string().nullable(),
|
|
4579
|
+
error: z14.string()
|
|
3172
4580
|
})
|
|
3173
4581
|
]);
|
|
3174
|
-
var
|
|
4582
|
+
var MAIL_TESTS_PER_HOUR = 10;
|
|
4583
|
+
var CellChangeSchema = z14.object({
|
|
3175
4584
|
event: EventKeySchema,
|
|
3176
4585
|
channel: ChannelIdSchema,
|
|
3177
|
-
value:
|
|
4586
|
+
value: z14.enum(["on", "off", "default"])
|
|
3178
4587
|
});
|
|
3179
4588
|
function preferencesUpdateOf(change) {
|
|
3180
4589
|
const cells = {};
|
|
3181
|
-
for (const
|
|
3182
|
-
cells[
|
|
4590
|
+
for (const c2 of change.cells ?? []) {
|
|
4591
|
+
cells[c2.event] = { ...cells[c2.event], [c2.channel]: c2.value === "default" ? null : c2.value };
|
|
3183
4592
|
}
|
|
3184
4593
|
return {
|
|
3185
4594
|
...change.muted === void 0 ? {} : { muted: change.muted },
|
|
@@ -3225,28 +4634,28 @@ function matchesQuery(row2, query) {
|
|
|
3225
4634
|
}
|
|
3226
4635
|
return true;
|
|
3227
4636
|
}
|
|
3228
|
-
function compareRows(
|
|
3229
|
-
const
|
|
4637
|
+
function compareRows(a3, b, sort) {
|
|
4638
|
+
const x2 = String(a3.folder);
|
|
3230
4639
|
const y = String(b.folder);
|
|
3231
|
-
const xs =
|
|
4640
|
+
const xs = x2.match(/\d+|\D+/g) || [];
|
|
3232
4641
|
const ys = y.match(/\d+|\D+/g) || [];
|
|
3233
4642
|
let byFolder = 0;
|
|
3234
4643
|
for (let i = 0; i < xs.length && i < ys.length && byFolder === 0; i++) {
|
|
3235
4644
|
const p = xs[i];
|
|
3236
|
-
const
|
|
3237
|
-
if (/^\d/.test(p) && /^\d/.test(
|
|
4645
|
+
const q2 = ys[i];
|
|
4646
|
+
if (/^\d/.test(p) && /^\d/.test(q2)) {
|
|
3238
4647
|
const pn = p.replace(/^0+/, "");
|
|
3239
|
-
const qn =
|
|
4648
|
+
const qn = q2.replace(/^0+/, "");
|
|
3240
4649
|
byFolder = pn.length - qn.length || (pn < qn ? -1 : pn > qn ? 1 : 0);
|
|
3241
4650
|
} else {
|
|
3242
4651
|
const pl = p.toLowerCase();
|
|
3243
|
-
const ql =
|
|
4652
|
+
const ql = q2.toLowerCase();
|
|
3244
4653
|
byFolder = pl < ql ? -1 : pl > ql ? 1 : 0;
|
|
3245
4654
|
}
|
|
3246
4655
|
}
|
|
3247
4656
|
if (byFolder === 0) byFolder = xs.length - ys.length;
|
|
3248
|
-
if (byFolder === 0) byFolder =
|
|
3249
|
-
const byTime = (Date.parse(
|
|
4657
|
+
if (byFolder === 0) byFolder = x2 < y ? -1 : x2 > y ? 1 : 0;
|
|
4658
|
+
const byTime = (Date.parse(a3.updated) || 0) - (Date.parse(b.updated) || 0);
|
|
3250
4659
|
if (sort === "folder") return byFolder;
|
|
3251
4660
|
if (sort === "folder-desc") return -byFolder;
|
|
3252
4661
|
if (sort === "oldest") return byTime || byFolder;
|
|
@@ -3474,7 +4883,7 @@ var ESCAPES = {
|
|
|
3474
4883
|
'"': """,
|
|
3475
4884
|
"'": "'"
|
|
3476
4885
|
};
|
|
3477
|
-
var esc = (value) => value.replace(/[&<>"']/g, (
|
|
4886
|
+
var esc = (value) => value.replace(/[&<>"']/g, (c2) => ESCAPES[c2] ?? c2);
|
|
3478
4887
|
var BASE_CSS = `:root{color-scheme:light dark;--bg:#f7f7f8;--fg:#1c1c21;--muted:#5d5d68;--card:#fff;--line:#e2e2e7;--fling-paths-accent:#2f5fc4}
|
|
3479
4888
|
@media (prefers-color-scheme:dark){:root{--bg:#141417;--fg:#ececf0;--muted:#a0a0ab;--card:#1d1d22;--line:#2e2e35;--fling-paths-accent:#8ab0ff}}
|
|
3480
4889
|
*{box-sizing:border-box}
|
|
@@ -3654,9 +5063,9 @@ function describeReadFiles(name, result) {
|
|
|
3654
5063
|
// ../../packages/shared/src/site-sort.ts
|
|
3655
5064
|
var SITE_SORTS = ["updated", "created", "name"];
|
|
3656
5065
|
var DEFAULT_SITE_SORT = "updated";
|
|
3657
|
-
var byName = (
|
|
5066
|
+
var byName = (a3, b) => a3.name < b.name ? -1 : a3.name > b.name ? 1 : 0;
|
|
3658
5067
|
function sortSites(sites, sort = DEFAULT_SITE_SORT) {
|
|
3659
|
-
const newest = (key) => (
|
|
5068
|
+
const newest = (key) => (a3, b) => Date.parse(b[key]) - Date.parse(a3[key]) || byName(a3, b);
|
|
3660
5069
|
const compare = sort === "name" ? byName : newest(sort === "created" ? "createdAt" : "updatedAt");
|
|
3661
5070
|
return [...sites].sort(compare);
|
|
3662
5071
|
}
|
|
@@ -3684,21 +5093,23 @@ function mcpWording(instance) {
|
|
|
3684
5093
|
signIn: `their ${instance.auth.displayName} account`,
|
|
3685
5094
|
reviewPattern: instance.appOrigin ? reviewUrl(instance.appOrigin, "<name>") : GENERIC_REVIEW,
|
|
3686
5095
|
defaultAccess: defaultAccessOf(instance),
|
|
3687
|
-
invites: instance.capabilities?.invites === true
|
|
5096
|
+
invites: instance.capabilities?.invites === true,
|
|
5097
|
+
...instanceGuideUrl(instance) ? { guide: instanceGuideUrl(instance) } : {}
|
|
3688
5098
|
};
|
|
3689
5099
|
}
|
|
3690
|
-
var
|
|
3691
|
-
var
|
|
3692
|
-
var
|
|
5100
|
+
var GUIDE_NOTE = (w2) => w2.guide ? `When the user asks how to do something with ${w2.name} (connect an assistant, share a site, team sites, comments), answer, then point them at its guide, ${w2.guide}, which covers every feature by assistant, command line and web app.` : void 0;
|
|
5101
|
+
var addressRule = (w2) => w2.invites ? `Each address must be one that can sign in to ${w2.name}, or one from outside it, which is invited as a reviewer (a guest who signs in with an emailed link and sees only what is shared with them; a few a day per person, else \`too_many_invites\`).` : `Each address must be one that can sign in to ${w2.name}.`;
|
|
5102
|
+
var defaultAccessPhrase = (w2) => w2.defaultAccess === "members" ? `open to ${w2.privateAudience}` : w2.defaultAccess === "only_me" ? "visible only to the user" : "given the Fling's default (only the user, unless the Fling is set up otherwise)";
|
|
5103
|
+
var ACCESS_NOTE = (w2) => "Before publishing a new site, ask the user who should be able to open it, unless they already said, and pass `access`: `only_me` (only the user), `members` (" + w2.privateAudience + `), \`groups\` or \`people\` (only the groups in \`groups\`, by slug, and the addresses in \`emails\`; one site may name both), or \`public\` (anyone, no sign-in; only if the user asks). Without \`access\` a new site is ${defaultAccessPhrase(w2)}. Re-publishing never changes who can open an existing site: use fling_set_access for that. Share links (fling_share) open a site to anyone who has them.`;
|
|
3693
5104
|
var NAME_REQUIRED = 'Publishing needs a name: if the user did not give one, propose a short descriptive one (e.g. "q3-report") and confirm it with them first (fling_check_name tells you whether it is free). If the name is taken by someone else the call fails with free suggestions \u2014 offer those to the user and retry with the one they pick.';
|
|
3694
5105
|
var INLINE_ONLY = "If you created the content in this conversation, pass it directly \u2014 never pass file paths from your sandbox (this server cannot read them) and never try to curl/upload from your sandbox.";
|
|
3695
5106
|
var NEVER_PUBLISHED = "Fling never publishes dotfiles, gitignored files, secret files (keys, certs, credentials) or files that contain secrets (API keys, tokens, private keys, passwords in database URLs); it stops and tells you which file and line. Remove the secret (or leave the file out) and retry \u2014 there is no way to override this.";
|
|
3696
5107
|
var ENCODING = '`encoding` is "utf8" (default, for text: HTML, CSS, JS, SVG, JSON, Markdown\u2026) or "base64" (binary: images, fonts, PDFs).';
|
|
3697
5108
|
var LIST_HTML = "If the files have no root index.html but do include HTML pages, the call does not publish: it reports how many HTML pages there are and asks you to check with the user. Ask them whether to generate an index.html listing those pages (retry with `listHtml: true`) or to publish without one (`listHtml: false` \u2014 the site root will 404, the pages still work at their own paths), then retry.";
|
|
3698
|
-
var listHtml =
|
|
5109
|
+
var listHtml = z15.boolean().optional().describe(
|
|
3699
5110
|
"Only matters when there is no root index.html: true \u2192 generate an index.html linking every HTML page; false \u2192 publish without one (root 404s). Omit until the user has decided"
|
|
3700
5111
|
);
|
|
3701
|
-
var siteName =
|
|
5112
|
+
var siteName = z15.string().min(1).max(200).describe('Site name, e.g. "q3-report"');
|
|
3702
5113
|
function describePublishHints(hints) {
|
|
3703
5114
|
if (!hints?.length) return "";
|
|
3704
5115
|
return `
|
|
@@ -3707,33 +5118,33 @@ Worth doing:
|
|
|
3707
5118
|
}
|
|
3708
5119
|
var PATH_PUBLISH_NOTE = `With \`path\` (one top-level folder, e.g. "PAY-412"), the files are published as that folder's Path: they go to <site>/PAY-412/\u2026 (give their paths relative to the folder, its page being "index.html"), and the rest of the site is untouched. A Path has its own versions, rollback, owners and publishers, and is made on first use (you own it). Use it for one plan, spec, report or week's page on a shared team site; teammates publishing other Paths never collide. fling_paths lists a site's Paths. The site's home page lists them by default when it has no index.html, or as a custom page with a Paths block (fling_paths_template); an index.html without a block lists none: settle which with the user (see fling_paths).`;
|
|
3709
5120
|
var PULL_NOTE = "To change a site that is already published (fix a typo, update a page, add one), start from what is live, not from scratch: read its files with fling_read_files, then call fling_publish with `base` (the `versionId` it returned) and only the files you changed or added, plus `remove` for files to delete; every other file stays as it is. If someone published the site in between, it fails with base_changed: read the files again and redo the changes, rather than publishing without `base` over theirs.";
|
|
3710
|
-
var base =
|
|
5121
|
+
var base = z15.string().min(1).max(100).optional().describe(
|
|
3711
5122
|
"The versionId fling_read_files returned: publish only what changed on top of it. `files` then holds only the files you changed or added, and every other file of the site is kept. Fails with base_changed if the site has changed since. Not with `path`"
|
|
3712
5123
|
);
|
|
3713
|
-
var remove =
|
|
3714
|
-
var publishPath =
|
|
5124
|
+
var remove = z15.array(z15.string().min(1).max(1024)).max(MAX_FILES).optional().describe("With `base`: the paths of the files to delete from the site");
|
|
5125
|
+
var publishPath = z15.string().min(1).max(1024).optional().describe(
|
|
3715
5126
|
'Publish as the Path at this top-level folder of the site, e.g. "PAY-412" (served at <site>/PAY-412/); the rest of the site is untouched. File paths are relative to it. Omit to publish the site itself'
|
|
3716
5127
|
);
|
|
3717
|
-
var sitePath =
|
|
5128
|
+
var sitePath = z15.string().min(1).max(1024).describe(
|
|
3718
5129
|
'Site-relative path with forward slashes, e.g. "index.html", "css/app.css", "img/logo.png". The root page must be "index.html". No dotfiles (".env", ".well-known/\u2026")'
|
|
3719
5130
|
);
|
|
3720
|
-
var emails =
|
|
3721
|
-
var groupSlugs =
|
|
5131
|
+
var emails = z15.array(z15.string().min(3).max(254)).max(AUDIENCE_EMAILS_MAX);
|
|
5132
|
+
var groupSlugs = z15.array(z15.string().min(1).max(100)).max(AUDIENCE_GROUPS_MAX);
|
|
3722
5133
|
var roleChange = {
|
|
3723
|
-
add:
|
|
3724
|
-
remove:
|
|
3725
|
-
set:
|
|
3726
|
-
addGroups:
|
|
3727
|
-
removeGroups:
|
|
3728
|
-
setGroups:
|
|
5134
|
+
add: z15.array(z15.string().min(3).max(254)).max(PUBLISHER_EMAILS_MAX).optional(),
|
|
5135
|
+
remove: z15.array(z15.string().min(3).max(254)).max(PUBLISHER_EMAILS_MAX).optional(),
|
|
5136
|
+
set: z15.array(z15.string().min(3).max(254)).max(PUBLISHER_EMAILS_MAX).optional(),
|
|
5137
|
+
addGroups: z15.array(z15.string().min(1).max(100)).max(PUBLISHER_GROUPS_MAX).optional(),
|
|
5138
|
+
removeGroups: z15.array(z15.string().min(1).max(100)).max(PUBLISHER_GROUPS_MAX).optional(),
|
|
5139
|
+
setGroups: z15.array(z15.string().min(1).max(100)).max(PUBLISHER_GROUPS_MAX).optional()
|
|
3729
5140
|
};
|
|
3730
|
-
var groupSlug =
|
|
3731
|
-
var members =
|
|
3732
|
-
var groupName =
|
|
3733
|
-
var commentPath =
|
|
3734
|
-
var commentId =
|
|
3735
|
-
var formsConfig =
|
|
3736
|
-
var formId =
|
|
5141
|
+
var groupSlug = z15.string().min(1).max(100).describe(`The group's slug, e.g. "design"`);
|
|
5142
|
+
var members = z15.array(z15.string().min(3).max(254)).max(GROUP_MEMBERS_MAX);
|
|
5143
|
+
var groupName = z15.string().min(1).max(GROUP_NAME_MAX);
|
|
5144
|
+
var commentPath = z15.string().max(1024);
|
|
5145
|
+
var commentId = z15.string().min(1).max(100);
|
|
5146
|
+
var formsConfig = z15.record(z15.string(), z15.unknown());
|
|
5147
|
+
var formId = z15.string().min(1).max(40);
|
|
3737
5148
|
var TEMPLATES_LIST = FORM_TEMPLATE_NAMES.map(
|
|
3738
5149
|
(n) => `\`${n}\` (${FORM_TEMPLATE_DESCRIPTIONS[n]})`
|
|
3739
5150
|
).join(", ");
|
|
@@ -3800,23 +5211,23 @@ function describePathsCheck(check2) {
|
|
|
3800
5211
|
return [
|
|
3801
5212
|
head,
|
|
3802
5213
|
...check2.errors.map((e) => `- Error: ${e}`),
|
|
3803
|
-
...check2.warnings.map((
|
|
5214
|
+
...check2.warnings.map((w2) => `- Warning: ${w2}`),
|
|
3804
5215
|
...check2.ok ? ["Publish it as the site's root index.html (without `path`)."] : []
|
|
3805
5216
|
].join("\n");
|
|
3806
5217
|
}
|
|
3807
|
-
var pathFolder =
|
|
3808
|
-
var encoding =
|
|
3809
|
-
var spa =
|
|
5218
|
+
var pathFolder = z15.string().min(1).max(MAX_PATH_FOLDER_LENGTH + 2);
|
|
5219
|
+
var encoding = z15.enum(["utf8", "base64"]).optional().describe('How `content` is encoded: "utf8" (default) for text, "base64" for binary files');
|
|
5220
|
+
var spa = z15.boolean().optional().describe(
|
|
3810
5221
|
"Single-page app: serve index.html for unknown paths (client-side routing). Omit to keep the current setting"
|
|
3811
5222
|
);
|
|
3812
|
-
function mcpToolsFor(
|
|
3813
|
-
const NAME_RULES = `Site names are 1-${SITE_NAME_MAX} chars of lowercase letters, digits and single hyphens, and are one global namespace (first come, first served): the site is served at ${
|
|
3814
|
-
const VISIBILITY = ACCESS_NOTE(
|
|
3815
|
-
const isPublic =
|
|
5223
|
+
function mcpToolsFor(w2) {
|
|
5224
|
+
const NAME_RULES = `Site names are 1-${SITE_NAME_MAX} chars of lowercase letters, digits and single hyphens, and are one global namespace (first come, first served): the site is served at ${w2.sitesPattern}.`;
|
|
5225
|
+
const VISIBILITY = ACCESS_NOTE(w2);
|
|
5226
|
+
const isPublic = z15.boolean().optional().describe(
|
|
3816
5227
|
"Prefer `access` (a new site) or fling_set_access (an existing one). true \u2192 anyone can view; false \u2192 private. Omit to keep the current setting"
|
|
3817
5228
|
);
|
|
3818
|
-
const access3 =
|
|
3819
|
-
`Who can open a new site: only_me, members (${
|
|
5229
|
+
const access3 = z15.enum(ACCESS_LEVELS).optional().describe(
|
|
5230
|
+
`Who can open a new site: only_me, members (${w2.privateAudience}), groups, people or public. Ask the user before the first publish; omit for the default (${defaultAccessPhrase(w2)}). Ignored when the site already exists`
|
|
3820
5231
|
);
|
|
3821
5232
|
const accessEmails = emails.optional().describe('With access "people" (or "groups"): the addresses that may open it');
|
|
3822
5233
|
const accessGroups = groupSlugs.optional().describe('With access "groups" (or "people"): the groups, by slug, whose members may open it');
|
|
@@ -3824,7 +5235,7 @@ function mcpToolsFor(w) {
|
|
|
3824
5235
|
whoami: tool({
|
|
3825
5236
|
name: "fling_whoami",
|
|
3826
5237
|
title: "Who am I",
|
|
3827
|
-
description: `Show the signed-in user that ${
|
|
5238
|
+
description: `Show the signed-in user that ${w2.name} acts as.`,
|
|
3828
5239
|
inputSchema: {},
|
|
3829
5240
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
3830
5241
|
}),
|
|
@@ -3833,9 +5244,9 @@ function mcpToolsFor(w) {
|
|
|
3833
5244
|
title: "List sites",
|
|
3834
5245
|
description: "List the user's Fling sites with URL, visibility and share link. With `shared: true`, list instead the restricted sites other people have shared with the user (by address or through a group they're in), with URL, review link and owner.",
|
|
3835
5246
|
inputSchema: {
|
|
3836
|
-
archived:
|
|
3837
|
-
shared:
|
|
3838
|
-
sort:
|
|
5247
|
+
archived: z15.boolean().optional().describe("List archived sites instead of live ones"),
|
|
5248
|
+
shared: z15.boolean().optional().describe("List the sites others have shared with the user instead of the user's own"),
|
|
5249
|
+
sort: z15.enum(SITE_SORTS).optional().describe(
|
|
3839
5250
|
"Order: updated (last updated, newest first; the default), created (newest first) or name (A\u2013Z)"
|
|
3840
5251
|
)
|
|
3841
5252
|
},
|
|
@@ -3859,7 +5270,7 @@ function mcpToolsFor(w) {
|
|
|
3859
5270
|
description: "List the files in a site's current version (or in `versionId`, from fling_info): path, size and content type, sorted by path. Use it to check what was actually published \u2014 e.g. when the user sees a 404, confirm the page exists at that path and that there is a root index.html (without one the site root 404s).",
|
|
3860
5271
|
inputSchema: {
|
|
3861
5272
|
name: siteName,
|
|
3862
|
-
versionId:
|
|
5273
|
+
versionId: z15.string().min(1).max(100).optional().describe("Version id (from fling_info); omit for the version being served"),
|
|
3863
5274
|
path: pathFolder.optional().describe(
|
|
3864
5275
|
"One of the site's Paths, its folder (e.g. \"PAY-412\"): list that Path's version (ids from fling_info with this `path`) instead; its files are under the folder"
|
|
3865
5276
|
)
|
|
@@ -3872,10 +5283,10 @@ function mcpToolsFor(w) {
|
|
|
3872
5283
|
description: `Read the files of a site's current version (or \`versionId\`), with their content inline (text as utf8, anything else base64), to change some of them and publish again. Returns up to ${MCP_READ_MAX_BYTES / 1024 / 1024} MB a call, in path order: when there is more, pass the returned \`cursor\` for the next files, or name the files you need in \`paths\` (fling_files lists them). It returns the \`versionId\` to pass to fling_publish as \`base\`. Anyone who can open the site may read it; publishing needs an owner or publisher. ${PULL_NOTE}`,
|
|
3873
5284
|
inputSchema: {
|
|
3874
5285
|
name: siteName,
|
|
3875
|
-
paths:
|
|
3876
|
-
path:
|
|
3877
|
-
cursor:
|
|
3878
|
-
versionId:
|
|
5286
|
+
paths: z15.array(z15.string().min(1).max(1024)).max(MAX_FILES).optional().describe('Only these files (site paths, e.g. "index.html"); omit for all of them'),
|
|
5287
|
+
path: z15.string().min(1).max(1024).optional().describe('The files of this Path of the site, e.g. "PAY-412" (paths relative to it)'),
|
|
5288
|
+
cursor: z15.string().max(20).optional().describe("From the previous call, for the next files"),
|
|
5289
|
+
versionId: z15.string().min(1).max(100).optional().describe("Version id (from fling_info); omit for the version being served")
|
|
3879
5290
|
},
|
|
3880
5291
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
3881
5292
|
}),
|
|
@@ -3883,7 +5294,7 @@ function mcpToolsFor(w) {
|
|
|
3883
5294
|
name: "fling_check_name",
|
|
3884
5295
|
title: "Check a site name",
|
|
3885
5296
|
description: "Check whether a site name can be used before publishing: `available` (a new site), `yours` (publishing updates the user's existing site), `taken` (someone else's \u2014 free `suggestions` are returned) or `invalid`. " + NAME_RULES,
|
|
3886
|
-
inputSchema: { name:
|
|
5297
|
+
inputSchema: { name: z15.string().min(1).max(200).describe("Site name to check") },
|
|
3887
5298
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
3888
5299
|
}),
|
|
3889
5300
|
publish: tool({
|
|
@@ -3892,10 +5303,10 @@ function mcpToolsFor(w) {
|
|
|
3892
5303
|
description: `Publish a static site to Fling in one call and get back its URL. Pass every file of the site inline in \`files\` (whole site, up to ${MCP_PUBLISH_MAX_BYTES / 1024 / 1024} MB decoded in total; bigger sites: fling_upload_begin / fling_upload_file / fling_upload_finish). ${INLINE_ONLY} ${ENCODING} Publishing replaces the whole site with exactly these files (it is not a patch: include unchanged files too), unless \`path\` or \`base\` is given; publishing identical content again is a no-op. ${PATH_PUBLISH_NOTE} ${PULL_NOTE} ${NAME_REQUIRED} ${NAME_RULES} ${VISIBILITY} ${LIST_HTML} ${NEVER_PUBLISHED} The result includes \`warnings\`. Share the returned URL with the user; fling_files shows exactly which files the site has. To collect labels, ratings, scores or eval judgements from reviewers, pass \`forms\` (or include ${FORMS_FILE} among the files): see fling_forms_template.`,
|
|
3893
5304
|
inputSchema: {
|
|
3894
5305
|
name: siteName,
|
|
3895
|
-
files:
|
|
3896
|
-
|
|
5306
|
+
files: z15.array(
|
|
5307
|
+
z15.object({
|
|
3897
5308
|
path: sitePath,
|
|
3898
|
-
content:
|
|
5309
|
+
content: z15.string().describe("The file content, encoded as `encoding` says"),
|
|
3899
5310
|
encoding
|
|
3900
5311
|
})
|
|
3901
5312
|
).max(MAX_FILES).describe(
|
|
@@ -3938,11 +5349,11 @@ function mcpToolsFor(w) {
|
|
|
3938
5349
|
title: "Upload a file (chunked)",
|
|
3939
5350
|
description: `Add one file to a chunked upload started with fling_upload_begin. Sending the same path again replaces it. A file larger than ${MCP_UPLOAD_CHUNK_MAX_CHARS / 1024 / 1024} MB of content can span calls: send the first part normally, then the following parts in order with \`append: true\` (same path and encoding; send appends one at a time, not in parallel). ${ENCODING} ${NEVER_PUBLISHED}`,
|
|
3940
5351
|
inputSchema: {
|
|
3941
|
-
uploadId:
|
|
5352
|
+
uploadId: z15.string().min(1).max(100).describe("From fling_upload_begin"),
|
|
3942
5353
|
path: sitePath,
|
|
3943
|
-
content:
|
|
5354
|
+
content: z15.string().max(MCP_UPLOAD_CHUNK_MAX_CHARS).describe("The file content (or the next part of it, with `append`)"),
|
|
3944
5355
|
encoding,
|
|
3945
|
-
append:
|
|
5356
|
+
append: z15.boolean().optional().describe("Append this content to the file sent earlier with the same path")
|
|
3946
5357
|
},
|
|
3947
5358
|
annotations: { destructiveHint: false, openWorldHint: false }
|
|
3948
5359
|
}),
|
|
@@ -3951,7 +5362,7 @@ function mcpToolsFor(w) {
|
|
|
3951
5362
|
title: "Finish a chunked upload",
|
|
3952
5363
|
description: `Publish everything sent with fling_upload_file as the new version of the site and return its URL. The site becomes exactly the uploaded files (with \`path\`, that Path does; with \`base\`, plus the rest of that version). ${LIST_HTML} The upload stays open, so just call fling_upload_finish again with \`listHtml\`. The result includes \`warnings\`.`,
|
|
3953
5364
|
inputSchema: {
|
|
3954
|
-
uploadId:
|
|
5365
|
+
uploadId: z15.string().min(1).max(100).describe("From fling_upload_begin"),
|
|
3955
5366
|
listHtml
|
|
3956
5367
|
},
|
|
3957
5368
|
annotations: { destructiveHint: false, openWorldHint: true }
|
|
@@ -3962,18 +5373,18 @@ function mcpToolsFor(w) {
|
|
|
3962
5373
|
description: "Get or create a public share link for a site: anyone with the link can view it without signing in (use it to show a private site to someone who cannot sign in). `refresh` replaces the link (the old one stops working); `revoke` removes it.",
|
|
3963
5374
|
inputSchema: {
|
|
3964
5375
|
name: siteName,
|
|
3965
|
-
refresh:
|
|
3966
|
-
revoke:
|
|
5376
|
+
refresh: z15.boolean().optional().describe("Rotate the link"),
|
|
5377
|
+
revoke: z15.boolean().optional().describe("Remove the link")
|
|
3967
5378
|
},
|
|
3968
5379
|
annotations: { destructiveHint: false, openWorldHint: true }
|
|
3969
5380
|
}),
|
|
3970
5381
|
setAccess: tool({
|
|
3971
5382
|
name: "fling_set_access",
|
|
3972
5383
|
title: "Set who can open a site",
|
|
3973
|
-
description: "Set a site's access level: `only_me` (only the user), `members` (" +
|
|
5384
|
+
description: "Set a site's access level: `only_me` (only the user), `members` (" + w2.privateAudience + `), \`groups\` and \`people\` (only the user, the groups in \`groups\` by slug and the addresses in \`emails\`; both levels take both, and replace the whole audience), or \`public\` (anyone can open the site; its review page and comments still need sign-in). Only change it when the user asks. ${addressRule(w2)} Share links still open the site to anyone who has them. Someone who loses access is shut out within 5 minutes; people and groups added are told by email when the instance sends it.`,
|
|
3974
5385
|
inputSchema: {
|
|
3975
5386
|
name: siteName,
|
|
3976
|
-
access:
|
|
5387
|
+
access: z15.enum(ACCESS_LEVELS).describe("only_me, members, groups, people or public"),
|
|
3977
5388
|
emails: emails.optional().describe("For groups or people: the addresses that may open it"),
|
|
3978
5389
|
groups: groupSlugs.optional().describe("For groups or people: the groups (slugs, fling_groups) whose members may")
|
|
3979
5390
|
},
|
|
@@ -3982,14 +5393,14 @@ function mcpToolsFor(w) {
|
|
|
3982
5393
|
setVisibility: tool({
|
|
3983
5394
|
name: "fling_set_visibility",
|
|
3984
5395
|
title: "Set visibility",
|
|
3985
|
-
description: `Make a site private or public (anyone can open the site; its review page and comments still need sign-in). Making it private gives it back the access it had before (only the user, ${
|
|
3986
|
-
inputSchema: { name: siteName, visibility:
|
|
5396
|
+
description: `Make a site private or public (anyone can open the site; its review page and comments still need sign-in). Making it private gives it back the access it had before (only the user, ${w2.privateAudience}, or its audience). fling_set_access sets any level.`,
|
|
5397
|
+
inputSchema: { name: siteName, visibility: z15.enum(["private", "public"]) },
|
|
3987
5398
|
annotations: { idempotentHint: true, openWorldHint: true }
|
|
3988
5399
|
}),
|
|
3989
5400
|
setAudience: tool({
|
|
3990
5401
|
name: "fling_set_audience",
|
|
3991
5402
|
title: "Set who can see a private site",
|
|
3992
|
-
description: `Limit a private site to listed people and groups (its audience), or open it again to ${
|
|
5403
|
+
description: `Limit a private site to listed people and groups (its audience), or open it again to ${w2.privateAudience}; fling_set_access does the same for whole levels, including only the user. \`add\` and \`remove\` change the addresses and \`set\` replaces them; \`addGroups\`, \`removeGroups\` and \`setGroups\` do the same for groups, by slug (fling_groups lists them); \`clear\` empties both (then every signed-in member can see it again). The owner always sees the site. ${addressRule(w2)} The audience only applies while the site is private (fling_set_visibility); share links still open it to anyone. Removing someone takes up to 5 minutes to shut them out. fling_info shows the audience.`,
|
|
3993
5404
|
inputSchema: {
|
|
3994
5405
|
name: siteName,
|
|
3995
5406
|
add: emails.optional().describe("Addresses to let in"),
|
|
@@ -3998,14 +5409,14 @@ function mcpToolsFor(w) {
|
|
|
3998
5409
|
addGroups: groupSlugs.optional().describe("Groups (slugs) to let in"),
|
|
3999
5410
|
removeGroups: groupSlugs.optional().describe("Groups (slugs) to take out"),
|
|
4000
5411
|
setGroups: groupSlugs.optional().describe("Replace the groups with exactly these slugs"),
|
|
4001
|
-
clear:
|
|
5412
|
+
clear: z15.boolean().optional().describe("Empty the audience (addresses and groups): every signed-in member sees it")
|
|
4002
5413
|
},
|
|
4003
5414
|
annotations: { idempotentHint: true, openWorldHint: false }
|
|
4004
5415
|
}),
|
|
4005
5416
|
setOwners: tool({
|
|
4006
5417
|
name: "fling_set_owners",
|
|
4007
5418
|
title: "Set a site's owners",
|
|
4008
|
-
description: `Change who owns a site: people and groups who may do everything the user can with it (publish, roll back, change its access and settings, its owners and publishers, archive and delete it). Only owners change it, and only when the user asks. \`add\` and \`remove\` change the addresses and \`set\` replaces them; \`addGroups\`, \`removeGroups\` and \`setGroups\` do the same for groups, by slug (fling_groups). Only members of ${
|
|
5419
|
+
description: `Change who owns a site: people and groups who may do everything the user can with it (publish, roll back, change its access and settings, its owners and publishers, archive and delete it). Only owners change it, and only when the user asks. \`add\` and \`remove\` change the addresses and \`set\` replaces them; \`addGroups\`, \`removeGroups\` and \`setGroups\` do the same for groups, by slug (fling_groups). Only members of ${w2.name} may be owners, never guests; a site keeps at least one person (address) as an owner, and has at most ${OWNER_EMAILS_MAX} addresses. Naming a group trusts whoever manages it. fling_info shows the owners and publishers.`,
|
|
4009
5420
|
inputSchema: {
|
|
4010
5421
|
name: siteName,
|
|
4011
5422
|
add: roleChange.add.describe("Addresses to make owners"),
|
|
@@ -4022,7 +5433,7 @@ function mcpToolsFor(w) {
|
|
|
4022
5433
|
setPublishers: tool({
|
|
4023
5434
|
name: "fling_set_publishers",
|
|
4024
5435
|
title: "Set a site's publishers",
|
|
4025
|
-
description: `Change who publishes a site without owning it: people and groups who may deploy new versions and roll back, but not change its access or settings, add owners or delete it. Only the site's owners change it, and only when the user asks. \`add\` and \`remove\` change the addresses and \`set\` replaces them; \`addGroups\`, \`removeGroups\` and \`setGroups\` do the same for groups, by slug (fling_groups). Only members of ${
|
|
5436
|
+
description: `Change who publishes a site without owning it: people and groups who may deploy new versions and roll back, but not change its access or settings, add owners or delete it. Only the site's owners change it, and only when the user asks. \`add\` and \`remove\` change the addresses and \`set\` replaces them; \`addGroups\`, \`removeGroups\` and \`setGroups\` do the same for groups, by slug (fling_groups). Only members of ${w2.name} may publish, never guests. Someone who is also an owner stays an owner. fling_info shows the owners and publishers.`,
|
|
4026
5437
|
inputSchema: {
|
|
4027
5438
|
name: siteName,
|
|
4028
5439
|
add: roleChange.add.describe("Addresses to make publishers"),
|
|
@@ -4039,9 +5450,9 @@ function mcpToolsFor(w) {
|
|
|
4039
5450
|
groups: tool({
|
|
4040
5451
|
name: "fling_groups",
|
|
4041
5452
|
title: "List groups",
|
|
4042
|
-
description: `List the groups on ${
|
|
5453
|
+
description: `List the groups on ${w2.name}: named lists of people (a team) that any member can use in a site's audience (fling_set_audience \`addGroups\`). Each has a slug, a name, a size and an owner; \`mine\` lists only the user's own. \`members\` lists only the groups of exactly those people: use it before making a group, or to swap a list of addresses in an audience for a group that already holds them.`,
|
|
4043
5454
|
inputSchema: {
|
|
4044
|
-
mine:
|
|
5455
|
+
mine: z15.boolean().optional().describe("Only the groups the user owns"),
|
|
4045
5456
|
members: members.optional().describe("Only the groups whose members are exactly these addresses")
|
|
4046
5457
|
},
|
|
4047
5458
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
@@ -4056,7 +5467,7 @@ function mcpToolsFor(w) {
|
|
|
4056
5467
|
groupCreate: tool({
|
|
4057
5468
|
name: "fling_group_create",
|
|
4058
5469
|
title: "Create a group",
|
|
4059
|
-
description: `Create a group the user owns: a named list of people that anyone signed in to ${
|
|
5470
|
+
description: `Create a group the user owns: a named list of people that anyone signed in to ${w2.name} can see and use in a site's audience, but only the user can change. The slug is ${GROUP_SLUG_RULES}, unique on ${w2.name}; at most ${GROUP_MEMBERS_MAX} members. ${addressRule(w2)}`,
|
|
4060
5471
|
inputSchema: {
|
|
4061
5472
|
slug: groupSlug,
|
|
4062
5473
|
name: groupName.describe('Its display name, e.g. "Design team"'),
|
|
@@ -4067,7 +5478,7 @@ function mcpToolsFor(w) {
|
|
|
4067
5478
|
groupMembers: tool({
|
|
4068
5479
|
name: "fling_group_members",
|
|
4069
5480
|
title: "Change who is in a group",
|
|
4070
|
-
description: `Add people to a group the user owns, or take them out. Every site whose audience names the group follows: someone taken out is shut out within 5 minutes. ${addressRule(
|
|
5481
|
+
description: `Add people to a group the user owns, or take them out. Every site whose audience names the group follows: someone taken out is shut out within 5 minutes. ${addressRule(w2)}`,
|
|
4071
5482
|
inputSchema: {
|
|
4072
5483
|
slug: groupSlug,
|
|
4073
5484
|
add: members.optional().describe("Addresses to add"),
|
|
@@ -4088,7 +5499,7 @@ function mcpToolsFor(w) {
|
|
|
4088
5499
|
description: "Permanently delete a group the user owns. Sites whose audience names it keep their restriction, and anyone it let in loses access (a site limited to it alone is left to its owner). Cannot be undone \u2014 confirm with the user first and pass `confirm: true`.",
|
|
4089
5500
|
inputSchema: {
|
|
4090
5501
|
slug: groupSlug,
|
|
4091
|
-
confirm:
|
|
5502
|
+
confirm: z15.literal(true).describe("Must be true: the user has confirmed the deletion")
|
|
4092
5503
|
},
|
|
4093
5504
|
annotations: { destructiveHint: true, openWorldHint: false }
|
|
4094
5505
|
}),
|
|
@@ -4098,7 +5509,7 @@ function mcpToolsFor(w) {
|
|
|
4098
5509
|
description: "Archive a site (it stops being served and is hidden from lists, but its name, files and versions are kept) or, with `unarchive`, bring it back. Prefer this over deleting.",
|
|
4099
5510
|
inputSchema: {
|
|
4100
5511
|
name: siteName,
|
|
4101
|
-
unarchive:
|
|
5512
|
+
unarchive: z15.boolean().optional().describe("Restore an archived site")
|
|
4102
5513
|
},
|
|
4103
5514
|
annotations: { idempotentHint: true, openWorldHint: false }
|
|
4104
5515
|
}),
|
|
@@ -4108,28 +5519,28 @@ function mcpToolsFor(w) {
|
|
|
4108
5519
|
description: "Permanently delete a site and every version of it, freeing its name. Cannot be undone \u2014 confirm with the user first and pass `confirm: true`. Consider fling_archive instead.",
|
|
4109
5520
|
inputSchema: {
|
|
4110
5521
|
name: siteName,
|
|
4111
|
-
confirm:
|
|
5522
|
+
confirm: z15.literal(true).describe("Must be true: the user has confirmed the deletion")
|
|
4112
5523
|
},
|
|
4113
5524
|
annotations: { destructiveHint: true, openWorldHint: false }
|
|
4114
5525
|
}),
|
|
4115
5526
|
commentsList: tool({
|
|
4116
5527
|
name: "fling_comments_list",
|
|
4117
5528
|
title: "List comments",
|
|
4118
|
-
description: `List the comments people left on a site while reviewing it (${
|
|
5529
|
+
description: `List the comments people left on a site while reviewing it (${w2.reviewPattern}), as threads: each has the page path it is about, the version the site was serving when it was written, its replies, and whether it is resolved. Anyone signed in to ${w2.name} can comment on a site they can open. Resolved threads are left out unless \`includeResolved\`. Use it to act on feedback: fix the site, republish, then resolve the threads with fling_comment_resolve.`,
|
|
4119
5530
|
inputSchema: {
|
|
4120
5531
|
name: siteName,
|
|
4121
5532
|
path: commentPath.optional().describe('Only this page, e.g. "/" or "/docs/"'),
|
|
4122
|
-
includeResolved:
|
|
5533
|
+
includeResolved: z15.boolean().optional().describe("Include resolved threads")
|
|
4123
5534
|
},
|
|
4124
5535
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
4125
5536
|
}),
|
|
4126
5537
|
commentAdd: tool({
|
|
4127
5538
|
name: "fling_comment_add",
|
|
4128
5539
|
title: "Add a comment",
|
|
4129
|
-
description: `Comment on a page of a site (shown on its review page, ${
|
|
5540
|
+
description: `Comment on a page of a site (shown on its review page, ${w2.reviewPattern}), or reply to a thread (\`replyTo\`: a thread id from fling_comments_list). Comments are signed with the user's name, so only write one the user asked for.`,
|
|
4130
5541
|
inputSchema: {
|
|
4131
5542
|
name: siteName,
|
|
4132
|
-
body:
|
|
5543
|
+
body: z15.string().min(1).max(COMMENT_MAX_CHARS).describe("The comment (plain text)"),
|
|
4133
5544
|
path: commentPath.optional().describe('The page it is about (default "/"); ignored for a reply'),
|
|
4134
5545
|
replyTo: commentId.optional().describe("Reply to this thread instead of starting one")
|
|
4135
5546
|
},
|
|
@@ -4142,7 +5553,7 @@ function mcpToolsFor(w) {
|
|
|
4142
5553
|
inputSchema: {
|
|
4143
5554
|
name: siteName,
|
|
4144
5555
|
id: commentId.describe("The thread id"),
|
|
4145
|
-
reopen:
|
|
5556
|
+
reopen: z15.boolean().optional().describe("Reopen a resolved thread")
|
|
4146
5557
|
},
|
|
4147
5558
|
annotations: { idempotentHint: true, openWorldHint: false }
|
|
4148
5559
|
}),
|
|
@@ -4168,8 +5579,8 @@ function mcpToolsFor(w) {
|
|
|
4168
5579
|
title: "Start a forms config",
|
|
4169
5580
|
description: `A starter forms config to adapt, for structured feedback on a site's review page: ${TEMPLATES_LIST}. Ask the user what they want collected first, then change the template's options, wording and \`paths\` to fit, check it with fling_forms_check and publish it as \`forms\`. ${FORMS_FORMAT}`,
|
|
4170
5581
|
inputSchema: {
|
|
4171
|
-
template:
|
|
4172
|
-
title:
|
|
5582
|
+
template: z15.enum(FORM_TEMPLATE_NAMES).describe("Which starter"),
|
|
5583
|
+
title: z15.string().min(1).max(FORMS_TITLE_MAX).optional().describe(`The config's title, what the review page calls the forms (e.g. "Evals")`)
|
|
4173
5584
|
},
|
|
4174
5585
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
4175
5586
|
}),
|
|
@@ -4179,7 +5590,7 @@ function mcpToolsFor(w) {
|
|
|
4179
5590
|
description: `Check a forms config before publishing it, as a publish will: the envelope, each schema against JSON Schema 2020-12, the limits and the globs. With \`paths\` (the site's files, e.g. ["index.html", "interviews/1.html"]) it also says which pages each form applies to and warns about globs that match none. Returns \`ok\`, the \`errors\` (each saying where) and a summary. ${FORMS_FORMAT}`,
|
|
4180
5591
|
inputSchema: {
|
|
4181
5592
|
forms: formsConfig.describe("The forms config to check"),
|
|
4182
|
-
paths:
|
|
5593
|
+
paths: z15.array(z15.string().min(1).max(1024)).max(MAX_FILES).optional().describe(
|
|
4183
5594
|
"The site's file paths (or page paths), to see which pages each form applies to"
|
|
4184
5595
|
)
|
|
4185
5596
|
},
|
|
@@ -4204,25 +5615,25 @@ function mcpToolsFor(w) {
|
|
|
4204
5615
|
name: siteName,
|
|
4205
5616
|
path: commentPath.describe('The page, e.g. "/" or "/interviews/1.html"'),
|
|
4206
5617
|
formId: formId.describe("The form (its id, from fling_forms)"),
|
|
4207
|
-
data:
|
|
4208
|
-
quote:
|
|
5618
|
+
data: z15.record(z15.string(), z15.unknown()).describe("The answers, keyed by schema property"),
|
|
5619
|
+
quote: z15.string().min(1).max(ANCHOR_QUOTE_MAX).optional().describe("A comment-kind form: the text on the page the response is about")
|
|
4209
5620
|
},
|
|
4210
5621
|
annotations: { destructiveHint: false, openWorldHint: true }
|
|
4211
5622
|
}),
|
|
4212
5623
|
notifications: tool({
|
|
4213
5624
|
name: "fling_notifications",
|
|
4214
5625
|
title: "Notification settings",
|
|
4215
|
-
description: `Show what ${
|
|
5626
|
+
description: `Show what ${w2.name} tells the user about and how: each event (a site shared with them, added to a group, a comment on their site, a reply in their thread\u2026) with its key and, per channel (email), whether it is on or off, marking the ones the user chose themselves; and whether everything is muted. Use it before fling_notifications_set, or when the user asks why they get (or do not get) emails.`,
|
|
4216
5627
|
inputSchema: {},
|
|
4217
5628
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
4218
5629
|
}),
|
|
4219
5630
|
notificationsSet: tool({
|
|
4220
5631
|
name: "fling_notifications_set",
|
|
4221
5632
|
title: "Change notification settings",
|
|
4222
|
-
description: `Change what ${
|
|
5633
|
+
description: `Change what ${w2.name} tells the user about: \`muted: true\` stops everything (false turns it back on, with their choices kept), and \`cells\` turns single events on or off per channel, or back to the default (\`value: "default"\`). Event keys come from fling_notifications. Only change what the user asked for. Returns the settings after the change.`,
|
|
4223
5634
|
inputSchema: {
|
|
4224
|
-
muted:
|
|
4225
|
-
cells:
|
|
5635
|
+
muted: z15.boolean().optional().describe("true: send nothing at all; false: unmute"),
|
|
5636
|
+
cells: z15.array(CellChangeSchema).max(50).optional().describe(
|
|
4226
5637
|
'Events to change: `{ event, channel, value }`, value "on", "off" or "default"'
|
|
4227
5638
|
)
|
|
4228
5639
|
},
|
|
@@ -4240,8 +5651,8 @@ function mcpToolsFor(w) {
|
|
|
4240
5651
|
title: "Start a Paths home page",
|
|
4241
5652
|
description: `A starter home page (index.html) for a site with Paths, with its Paths block in place: Fling fills it with the site's live Paths. Templates: ${PATHS_TEMPLATES_LIST}. Use it when the user wants a custom home page listing their Paths rather than the default one. Adapt it freely (wording, layout, styling) while keeping the block, check it with fling_paths_check, then publish it as the site root (without \`path\`). Needs no sign-in. ${PATHS_HOME_CHOICE} ${PATHS_BLOCK_FORMAT}`,
|
|
4242
5653
|
inputSchema: {
|
|
4243
|
-
template:
|
|
4244
|
-
title:
|
|
5654
|
+
template: z15.enum(PATHS_TEMPLATE_NAMES).describe("Which starter"),
|
|
5655
|
+
title: z15.string().min(1).max(200).optional().describe(`The page's title and heading (e.g. "Payments plans")`)
|
|
4245
5656
|
},
|
|
4246
5657
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
4247
5658
|
}),
|
|
@@ -4250,7 +5661,7 @@ function mcpToolsFor(w) {
|
|
|
4250
5661
|
title: "Check a Paths home page",
|
|
4251
5662
|
description: `Check a site's home page (index.html) before publishing it, for the Paths block Fling fills with the site's Paths: whether there is one, bare or template, its options, and warnings (unknown options or placeholders, an unclosed template, an item without a link). Returns \`ok\`, \`errors\` and \`warnings\`. Use it on every custom home page for a site with Paths. Needs no sign-in. ${PATHS_HOME_CHOICE} ${PATHS_BLOCK_FORMAT}`,
|
|
4252
5663
|
inputSchema: {
|
|
4253
|
-
html:
|
|
5664
|
+
html: z15.string().min(1).max(MCP_PUBLISH_MAX_BYTES).describe("The page, as HTML")
|
|
4254
5665
|
},
|
|
4255
5666
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
4256
5667
|
}),
|
|
@@ -4260,7 +5671,7 @@ function mcpToolsFor(w) {
|
|
|
4260
5671
|
description: "Point a site at an earlier version (ids from fling_info). Instant; nothing is uploaded. With `path`, roll back only that Path (ids from fling_info with the same `path`); the rest of the site and its other Paths stay as they are.",
|
|
4261
5672
|
inputSchema: {
|
|
4262
5673
|
name: siteName,
|
|
4263
|
-
versionId:
|
|
5674
|
+
versionId: z15.string().min(1).max(100).describe("Version id to serve"),
|
|
4264
5675
|
path: pathFolder.optional().describe(
|
|
4265
5676
|
`One of the site's Paths, its folder (e.g. "PAY-412"): roll back only that Path`
|
|
4266
5677
|
)
|
|
@@ -4270,8 +5681,8 @@ function mcpToolsFor(w) {
|
|
|
4270
5681
|
};
|
|
4271
5682
|
}
|
|
4272
5683
|
var mcpTools = mcpToolsFor(mcpWording());
|
|
4273
|
-
var NOTIFICATIONS_NOTE = (
|
|
4274
|
-
var COMMENTS_NOTE = (
|
|
5684
|
+
var NOTIFICATIONS_NOTE = (w2) => `${w2.name} emails people when a site is shared with them, they are made an owner or publisher of one, they are added to a group, or someone comments on their site or replies in their thread. fling_notifications shows what the user hears about; change it with fling_notifications_set only when they ask.`;
|
|
5685
|
+
var COMMENTS_NOTE = (w2, opts = {}) => `People review sites at ${w2.reviewPattern} and leave comments on its pages. Publishing returns this review link (\`reviewUrl\`): it is the one to share when the user wants feedback; reviewers sign in to use it. fling_comments_list shows the comments; after acting on feedback, resolve the threads with fling_comment_resolve. Only post (fling_comment_add) or delete (fling_comment_delete) comments when the user asks.` + (opts.forms ? " To collect labels, ratings, scores or eval judgements, add a form (fling_forms_template) rather than asking reviewers to type codes in comments: their answers are then checked and exported as data." : "");
|
|
4275
5686
|
var shareForFeedback = (reviewPage2, instanceName, forms2 = false) => `Share for feedback: ${reviewPage2} (reviewers sign in to ${instanceName} to see the site${forms2 ? ", comment and answer its forms" : " and comment"}).`;
|
|
4276
5687
|
var MCP_FILES_LISTED = 200;
|
|
4277
5688
|
function describeVersionFiles(name, files, opts) {
|
|
@@ -4295,13 +5706,13 @@ function describeVersionFiles(name, files, opts) {
|
|
|
4295
5706
|
return lines.join("\n");
|
|
4296
5707
|
}
|
|
4297
5708
|
function looksLikeCodedLabels(threads) {
|
|
4298
|
-
const short = threads.map((t) => t.comment).filter((
|
|
5709
|
+
const short = threads.map((t) => t.comment).filter((c2) => !c2.response && c2.body.trim().length <= 40);
|
|
4299
5710
|
if (short.length < 5 || short.length * 2 < threads.length) return false;
|
|
4300
5711
|
const key = (body) => body.trim().toLowerCase().replace(/[\s.!]+$/g, "");
|
|
4301
5712
|
const counts = /* @__PURE__ */ new Map();
|
|
4302
|
-
for (const
|
|
4303
|
-
const repeated = short.filter((
|
|
4304
|
-
return repeated.length * 2 >= short.length && new Set(repeated.map((
|
|
5713
|
+
for (const c2 of short) counts.set(key(c2.body), (counts.get(key(c2.body)) ?? 0) + 1);
|
|
5714
|
+
const repeated = short.filter((c2) => (counts.get(key(c2.body)) ?? 0) > 1);
|
|
5715
|
+
return repeated.length * 2 >= short.length && new Set(repeated.map((c2) => c2.path)).size >= 3;
|
|
4305
5716
|
}
|
|
4306
5717
|
var CODED_LABELS_NOTE = "These comments look like labels typed by hand (short, repeated across pages). For the next round, suggest a form to the user (fling_forms_template, e.g. `labels`): reviewers then pick from readable options, every page gets one answer per reviewer, and fling_responses_list exports them as data.";
|
|
4307
5718
|
function describeComments(list, opts = {}) {
|
|
@@ -4312,10 +5723,10 @@ function describeComments(list, opts = {}) {
|
|
|
4312
5723
|
const version = (id) => id === null ? "" : id === list.site.currentVersionId ? ", current version" : `, version ${id}`;
|
|
4313
5724
|
const head = `${threads.length} ${opts.includeResolved ? "" : "open "}thread${threads.length === 1 ? "" : "s"} on ${name}` + (hidden ? ` (${hidden} resolved not shown)` : "") + (opts.reviewUrl ? `. Review page: ${opts.reviewUrl}` : "");
|
|
4314
5725
|
const blocks = threads.map(
|
|
4315
|
-
({ comment:
|
|
4316
|
-
`- [${
|
|
4317
|
-
...
|
|
4318
|
-
` ${
|
|
5726
|
+
({ comment: c2, replies }) => [
|
|
5727
|
+
`- [${c2.id}] ${c2.resolvedAt ? "RESOLVED " : ""}${c2.path}${version(c2.versionId)} \u2014 ${authorLabel(c2.author)}, ${c2.updatedAt ?? c2.createdAt}` + (c2.response ? ` (response to form "${c2.response.formId}")` : "") + ":",
|
|
5728
|
+
...c2.anchor?.quote ? [` > ${c2.anchor.quote.replace(/\n/g, " ")}`] : [],
|
|
5729
|
+
` ${c2.body.replace(/\n/g, "\n ")}`,
|
|
4319
5730
|
...replies.map(
|
|
4320
5731
|
(r) => ` - [${r.id}] ${authorLabel(r.author)}, ${r.createdAt}: ${r.body.replace(/\n/g, "\n ")}`
|
|
4321
5732
|
)
|
|
@@ -4325,6 +5736,163 @@ function describeComments(list, opts = {}) {
|
|
|
4325
5736
|
return [head, ...blocks, ...note].join("\n");
|
|
4326
5737
|
}
|
|
4327
5738
|
|
|
5739
|
+
// ../../packages/shared/src/route-keys.ts
|
|
5740
|
+
var SITE_PASS_TTL_SECONDS = 5 * 60;
|
|
5741
|
+
|
|
5742
|
+
// ../../packages/shared/src/guide-facts.ts
|
|
5743
|
+
var mb = (bytes) => `${bytes / (1024 * 1024)} MB`;
|
|
5744
|
+
var count2 = (n) => n.toLocaleString("en-GB");
|
|
5745
|
+
var PINNED_GUIDE_FACTS = {
|
|
5746
|
+
/** the oldest Node the CLI runs on (apps/cli/package.json `engines.node`) */
|
|
5747
|
+
"node-version": "22",
|
|
5748
|
+
/** how long the audit log keeps an entry (`AUDIT_TTL_DAYS`) */
|
|
5749
|
+
"audit-days": "180 days",
|
|
5750
|
+
/** how long an admin's impersonation lasts (`IMPERSONATION_TTL_SECONDS`) */
|
|
5751
|
+
"impersonation-ttl": "an hour",
|
|
5752
|
+
/** how long an invitation's sign-in link works (`INVITATION_LINK_TTL_SECONDS`) */
|
|
5753
|
+
"invite-link-ttl": "7 days",
|
|
5754
|
+
/** new outside addresses one person may invite a day, unless the instance says otherwise (`INVITES_PER_DAY`) */
|
|
5755
|
+
"invites-per-day": "20",
|
|
5756
|
+
/** how long an address that bounced or complained gets no mail (`SUPPRESSION_MS`) */
|
|
5757
|
+
"suppression-days": "30 days"
|
|
5758
|
+
};
|
|
5759
|
+
var GUIDE_FACTS = {
|
|
5760
|
+
"max-deploy": mb(MAX_DEPLOY_BYTES),
|
|
5761
|
+
"max-file": mb(MAX_FILE_BYTES),
|
|
5762
|
+
"max-files": count2(MAX_FILES),
|
|
5763
|
+
"max-inline": mb(MCP_PUBLISH_MAX_BYTES),
|
|
5764
|
+
"max-paths": count2(MAX_PATHS_PER_SITE),
|
|
5765
|
+
"max-folder": count2(MAX_PATH_FOLDER_LENGTH),
|
|
5766
|
+
"site-name-max": count2(SITE_NAME_MAX),
|
|
5767
|
+
"mail-tests-per-hour": count2(MAIL_TESTS_PER_HOUR),
|
|
5768
|
+
"markdown-max-size": mb(MAX_MARKDOWN_BYTES),
|
|
5769
|
+
"markdown-max-files": count2(MAX_RENDERED_MARKDOWN),
|
|
5770
|
+
"access-revoke-delay": `${SITE_PASS_TTL_SECONDS / 60} minutes`,
|
|
5771
|
+
"audience-emails-max": count2(AUDIENCE_EMAILS_MAX),
|
|
5772
|
+
"audience-groups-max": count2(AUDIENCE_GROUPS_MAX),
|
|
5773
|
+
"group-members-max": count2(GROUP_MEMBERS_MAX),
|
|
5774
|
+
"owner-emails-max": count2(OWNER_EMAILS_MAX),
|
|
5775
|
+
"publisher-emails-max": count2(PUBLISHER_EMAILS_MAX),
|
|
5776
|
+
"comments-max": count2(COMMENTS_PER_SITE_MAX),
|
|
5777
|
+
"comment-max-chars": count2(COMMENT_MAX_CHARS),
|
|
5778
|
+
"forms-max": count2(FORMS_MAX),
|
|
5779
|
+
"responses-max": count2(RESPONSES_PER_SITE_MAX),
|
|
5780
|
+
"cli-package": CLI_PACKAGE,
|
|
5781
|
+
"repo-slug": REPO_SLUG,
|
|
5782
|
+
"repo-url": REPO_URL,
|
|
5783
|
+
"why-site": WHY_SITE_NAME,
|
|
5784
|
+
...PINNED_GUIDE_FACTS
|
|
5785
|
+
};
|
|
5786
|
+
|
|
5787
|
+
// ../../packages/shared/src/kvs.ts
|
|
5788
|
+
import { z as z16 } from "zod";
|
|
5789
|
+
var KvsSiteValueSchema = z16.object({
|
|
5790
|
+
/** siteId — S3 prefix is `sites/<id>/<v>/` */
|
|
5791
|
+
id: z16.string(),
|
|
5792
|
+
/** current versionId */
|
|
5793
|
+
v: z16.string(),
|
|
5794
|
+
vis: z16.enum(["private", "public"]),
|
|
5795
|
+
/** serve /index.html for unknown extensionless paths */
|
|
5796
|
+
spa: z16.boolean(),
|
|
5797
|
+
/** present when the site is restricted (private with an audience): the edge wants a site pass */
|
|
5798
|
+
r: z16.literal(1).optional(),
|
|
5799
|
+
/** present when the site has live Paths: a request's first folder may be one (`path:` keys) */
|
|
5800
|
+
p: z16.literal(1).optional(),
|
|
5801
|
+
/**
|
|
5802
|
+
* the rendered home page and Paths listing (`sites/<id>/_rendered/<i>.html|json`), served for
|
|
5803
|
+
* `/`, `/index.html` and PATHS_JSON_PATH instead of the version's own index.html
|
|
5804
|
+
*/
|
|
5805
|
+
i: z16.string().optional(),
|
|
5806
|
+
/** present when the current version's Markdown files have rendered pages (markdown.ts) */
|
|
5807
|
+
m: z16.literal(1).optional()
|
|
5808
|
+
});
|
|
5809
|
+
var KvsPathValueSchema = z16.object({
|
|
5810
|
+
id: z16.string(),
|
|
5811
|
+
v: z16.string(),
|
|
5812
|
+
/** as on a site's value: its current version's Markdown has rendered pages */
|
|
5813
|
+
m: z16.literal(1).optional()
|
|
5814
|
+
});
|
|
5815
|
+
|
|
5816
|
+
// ../../packages/shared/src/listing.ts
|
|
5817
|
+
var LISTING_GENERATOR_META = "fling-listing";
|
|
5818
|
+
var escapeHtml = (s) => s.replace(
|
|
5819
|
+
/[&<>"']/g,
|
|
5820
|
+
(c2) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c2]
|
|
5821
|
+
);
|
|
5822
|
+
var hrefFor = (path3) => path3.split("/").map(encodeURIComponent).join("/");
|
|
5823
|
+
function isHtmlPath(path3) {
|
|
5824
|
+
return /\.html?$/i.test(path3);
|
|
5825
|
+
}
|
|
5826
|
+
function extractHtmlTitle(html) {
|
|
5827
|
+
const match = /<title[^>]*>([\s\S]*?)<\/title>/i.exec(html.slice(0, 65536));
|
|
5828
|
+
const title = match?.[1]?.replace(/<[^>]*>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/\s+/g, " ").trim();
|
|
5829
|
+
return title ? title : null;
|
|
5830
|
+
}
|
|
5831
|
+
function renderHtmlListing(siteName2, entries) {
|
|
5832
|
+
const pages = entries.filter((e) => isHtmlPath(e.path) && e.path.toLowerCase() !== "index.html").sort((a3, b) => a3.path < b.path ? -1 : a3.path > b.path ? 1 : 0);
|
|
5833
|
+
const groups2 = /* @__PURE__ */ new Map();
|
|
5834
|
+
for (const page2 of pages) {
|
|
5835
|
+
const slash = page2.path.lastIndexOf("/");
|
|
5836
|
+
const folder = slash === -1 ? "" : page2.path.slice(0, slash);
|
|
5837
|
+
groups2.set(folder, [...groups2.get(folder) ?? [], page2]);
|
|
5838
|
+
}
|
|
5839
|
+
const sections = [...groups2.entries()].sort(([a3], [b]) => a3 === "" ? -1 : b === "" ? 1 : a3 < b ? -1 : 1).map(([folder, items]) => {
|
|
5840
|
+
const heading = folder ? `<h2>${escapeHtml(folder)}/</h2>` : "";
|
|
5841
|
+
const rows = items.map((item) => {
|
|
5842
|
+
const file = item.path.slice(item.path.lastIndexOf("/") + 1);
|
|
5843
|
+
const label = item.title ? escapeHtml(item.title) : escapeHtml(file);
|
|
5844
|
+
const sub = item.title ? `<span class="file">${escapeHtml(file)}</span>` : "";
|
|
5845
|
+
return `<li><a href="${hrefFor(item.path)}">${label}</a>${sub}</li>`;
|
|
5846
|
+
}).join("\n");
|
|
5847
|
+
return `${heading}<ul>
|
|
5848
|
+
${rows}
|
|
5849
|
+
</ul>`;
|
|
5850
|
+
}).join("\n");
|
|
5851
|
+
const body = pages.length ? sections : '<p class="empty">No HTML pages in this fling.</p>';
|
|
5852
|
+
const count3 = `${pages.length} page${pages.length === 1 ? "" : "s"}`;
|
|
5853
|
+
return `<!doctype html>
|
|
5854
|
+
<html lang="en">
|
|
5855
|
+
<head>
|
|
5856
|
+
<meta charset="utf-8">
|
|
5857
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
5858
|
+
<meta name="generator" content="${LISTING_GENERATOR_META}">
|
|
5859
|
+
<title>${escapeHtml(siteName2)}</title>
|
|
5860
|
+
<style>
|
|
5861
|
+
:root { color-scheme: light dark; --fg: #000e38; --muted: #5b6480; --bg: #f7f8fb; --card: #fff;
|
|
5862
|
+
--line: #e3e6ef; --accent: #166bff; --green: #00e5a4; }
|
|
5863
|
+
@media (prefers-color-scheme: dark) { :root { --fg: #eef1f8; --muted: #9aa3bd; --bg: #000e38;
|
|
5864
|
+
--card: #0b1a4a; --line: #1d2c5e; --accent: #6ea2ff; } }
|
|
5865
|
+
* { box-sizing: border-box; }
|
|
5866
|
+
body { margin: 0; font: 16px/1.5 Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
5867
|
+
color: var(--fg); background: var(--bg); }
|
|
5868
|
+
main { max-width: 760px; margin: 0 auto; padding: 48px 20px 64px; }
|
|
5869
|
+
header { border-left: 4px solid var(--green); padding-left: 14px; margin-bottom: 28px; }
|
|
5870
|
+
h1 { margin: 0; font-size: 1.6rem; }
|
|
5871
|
+
header p, .file, footer { color: var(--muted); font-size: .875rem; }
|
|
5872
|
+
header p { margin: 4px 0 0; }
|
|
5873
|
+
h2 { font-size: .95rem; margin: 28px 0 8px; color: var(--muted); font-weight: 600; }
|
|
5874
|
+
ul { list-style: none; margin: 0; padding: 0; background: var(--card); border: 1px solid var(--line);
|
|
5875
|
+
border-radius: 10px; overflow: hidden; }
|
|
5876
|
+
li { padding: 12px 16px; border-top: 1px solid var(--line); display: flex; gap: 12px;
|
|
5877
|
+
justify-content: space-between; align-items: baseline; flex-wrap: wrap; }
|
|
5878
|
+
li:first-child { border-top: 0; }
|
|
5879
|
+
a { color: var(--accent); text-decoration: none; font-weight: 500; }
|
|
5880
|
+
a:hover { text-decoration: underline; }
|
|
5881
|
+
.empty { color: var(--muted); }
|
|
5882
|
+
footer { margin-top: 40px; }
|
|
5883
|
+
</style>
|
|
5884
|
+
</head>
|
|
5885
|
+
<body>
|
|
5886
|
+
<main>
|
|
5887
|
+
<header><h1>${escapeHtml(siteName2)}</h1><p>${count3}</p></header>
|
|
5888
|
+
${body}
|
|
5889
|
+
<footer>Flung with Fling</footer>
|
|
5890
|
+
</main>
|
|
5891
|
+
</body>
|
|
5892
|
+
</html>
|
|
5893
|
+
`;
|
|
5894
|
+
}
|
|
5895
|
+
|
|
4328
5896
|
// ../../packages/shared/src/ready.ts
|
|
4329
5897
|
var READY_TIMEOUT_MS = 15e3;
|
|
4330
5898
|
var NOT_READY_NOTE = "it can take a few more seconds to appear everywhere; reload if you see a 404";
|
|
@@ -4373,109 +5941,109 @@ function readinessWaitDisabled(env) {
|
|
|
4373
5941
|
}
|
|
4374
5942
|
|
|
4375
5943
|
// ../../packages/shared/src/review-bridge.ts
|
|
4376
|
-
import { z as
|
|
4377
|
-
var tag = { fling:
|
|
4378
|
-
var path =
|
|
4379
|
-
var hash =
|
|
4380
|
-
var BridgePinSchema =
|
|
4381
|
-
id:
|
|
4382
|
-
n:
|
|
5944
|
+
import { z as z17 } from "zod";
|
|
5945
|
+
var tag = { fling: z17.literal("review") };
|
|
5946
|
+
var path = z17.string().max(COMMENT_PATH_MAX);
|
|
5947
|
+
var hash = z17.string().max(COMMENT_PATH_MAX);
|
|
5948
|
+
var BridgePinSchema = z17.object({
|
|
5949
|
+
id: z17.string(),
|
|
5950
|
+
n: z17.number().int().min(1),
|
|
4383
5951
|
anchor: CommentAnchorSchema,
|
|
4384
|
-
selected:
|
|
4385
|
-
resolved:
|
|
5952
|
+
selected: z17.boolean(),
|
|
5953
|
+
resolved: z17.boolean()
|
|
4386
5954
|
});
|
|
4387
|
-
var BridgeCursorSchema =
|
|
4388
|
-
id:
|
|
4389
|
-
name:
|
|
4390
|
-
colour:
|
|
5955
|
+
var BridgeCursorSchema = z17.object({
|
|
5956
|
+
id: z17.string(),
|
|
5957
|
+
name: z17.string().max(100),
|
|
5958
|
+
colour: z17.string().max(32),
|
|
4391
5959
|
anchor: CommentAnchorSchema
|
|
4392
5960
|
});
|
|
4393
|
-
var ShellMessageSchema =
|
|
4394
|
-
|
|
5961
|
+
var ShellMessageSchema = z17.discriminatedUnion("type", [
|
|
5962
|
+
z17.object({ ...tag, type: z17.literal("ready") }),
|
|
4395
5963
|
/** the frame is on `path` (normalised, see normalizeCommentPath) with fragment `hash` ('' or '#…') */
|
|
4396
|
-
|
|
5964
|
+
z17.object({ ...tag, type: z17.literal("location"), path, hash, title: z17.string().max(300) }),
|
|
4397
5965
|
/** a pin placed while placing: a click (a spot) or a drag (a box) */
|
|
4398
|
-
|
|
5966
|
+
z17.object({ ...tag, type: z17.literal("pinPlaced"), anchor: CommentAnchorSchema }),
|
|
4399
5967
|
/** the reviewer selected text in the page: an anchor on it, with its quote */
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
5968
|
+
z17.object({ ...tag, type: z17.literal("textSelected"), anchor: CommentAnchorSchema }),
|
|
5969
|
+
z17.object({ ...tag, type: z17.literal("pinCancelled") }),
|
|
5970
|
+
z17.object({ ...tag, type: z17.literal("pinClicked"), id: z17.string() }),
|
|
4403
5971
|
/** this reviewer's pointer on the page; null when it left the frame */
|
|
4404
|
-
|
|
5972
|
+
z17.object({ ...tag, type: z17.literal("cursor"), anchor: CommentAnchorSchema.nullable() }),
|
|
4405
5973
|
/** a link or form to another origin, stopped: the frame stays on the site */
|
|
4406
|
-
|
|
4407
|
-
|
|
5974
|
+
z17.object({ ...tag, type: z17.literal("blocked"), href: z17.string().max(2048) }),
|
|
5975
|
+
z17.object({ ...tag, type: z17.literal("escape") }),
|
|
4408
5976
|
/** preview mode: the thumbnail the page asked for, a PNG of the frame's viewport of `versionId` */
|
|
4409
|
-
|
|
5977
|
+
z17.object({
|
|
4410
5978
|
...tag,
|
|
4411
|
-
type:
|
|
4412
|
-
png:
|
|
4413
|
-
versionId:
|
|
5979
|
+
type: z17.literal("captured"),
|
|
5980
|
+
png: z17.instanceof(Blob),
|
|
5981
|
+
versionId: z17.string().max(100)
|
|
4414
5982
|
}),
|
|
4415
5983
|
/** preview mode: no thumbnail could be drawn (CAPTURE_STALE: the host serves another version) */
|
|
4416
|
-
|
|
5984
|
+
z17.object({ ...tag, type: z17.literal("captureFailed"), reason: z17.string().max(300) })
|
|
4417
5985
|
]);
|
|
4418
|
-
var PageMessageSchema =
|
|
5986
|
+
var PageMessageSchema = z17.discriminatedUnion("type", [
|
|
4419
5987
|
/** load `path` (site-relative, may carry `?query` and `#hash`) in the frame */
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
5988
|
+
z17.object({ ...tag, type: z17.literal("navigate"), path: z17.string().max(COMMENT_PATH_MAX * 2) }),
|
|
5989
|
+
z17.object({ ...tag, type: z17.literal("reload") }),
|
|
5990
|
+
z17.object({ ...tag, type: z17.literal("placing"), on: z17.boolean() }),
|
|
4423
5991
|
/** the pins on the frame's current page */
|
|
4424
|
-
|
|
5992
|
+
z17.object({ ...tag, type: z17.literal("pins"), pins: z17.array(BridgePinSchema) }),
|
|
4425
5993
|
/** scroll the pin into view and draw attention to it */
|
|
4426
|
-
|
|
4427
|
-
|
|
5994
|
+
z17.object({ ...tag, type: z17.literal("focusPin"), id: z17.string() }),
|
|
5995
|
+
z17.object({ ...tag, type: z17.literal("cursors"), cursors: z17.array(BridgeCursorSchema) }),
|
|
4428
5996
|
/**
|
|
4429
5997
|
* preview mode: once the page has loaded and settled, draw it as a thumbnail (`captured`), only
|
|
4430
5998
|
* if the sites host serves `versionId` (the site's current version, as the API says)
|
|
4431
5999
|
*/
|
|
4432
|
-
|
|
6000
|
+
z17.object({ ...tag, type: z17.literal("capture"), versionId: z17.string().max(100) })
|
|
4433
6001
|
]);
|
|
4434
6002
|
|
|
4435
6003
|
// ../../packages/shared/src/review-live.ts
|
|
4436
|
-
import { z as
|
|
6004
|
+
import { z as z18 } from "zod";
|
|
4437
6005
|
var LIVE_PICTURE_MAX = 1024;
|
|
4438
|
-
var LivePeerSchema =
|
|
4439
|
-
id:
|
|
4440
|
-
name:
|
|
4441
|
-
colour:
|
|
6006
|
+
var LivePeerSchema = z18.object({
|
|
6007
|
+
id: z18.string(),
|
|
6008
|
+
name: z18.string().max(100),
|
|
6009
|
+
colour: z18.string().max(32),
|
|
4442
6010
|
/** their profile picture (https), when sign-in gave one; else clients show initials */
|
|
4443
|
-
picture:
|
|
6011
|
+
picture: z18.string().max(LIVE_PICTURE_MAX).optional()
|
|
4444
6012
|
});
|
|
4445
|
-
var LiveTicketSchema =
|
|
4446
|
-
url:
|
|
4447
|
-
ticket:
|
|
6013
|
+
var LiveTicketSchema = z18.object({
|
|
6014
|
+
url: z18.string(),
|
|
6015
|
+
ticket: z18.string(),
|
|
4448
6016
|
/** seconds the ticket is good for: connect before then */
|
|
4449
|
-
expiresIn:
|
|
6017
|
+
expiresIn: z18.number().int()
|
|
4450
6018
|
});
|
|
4451
|
-
var path2 =
|
|
4452
|
-
var hash2 =
|
|
4453
|
-
var LiveClientMessageSchema =
|
|
4454
|
-
|
|
6019
|
+
var path2 = z18.string().max(COMMENT_PATH_MAX);
|
|
6020
|
+
var hash2 = z18.string().max(COMMENT_PATH_MAX);
|
|
6021
|
+
var LiveClientMessageSchema = z18.discriminatedUnion("type", [
|
|
6022
|
+
z18.object({ type: z18.literal("hello") }),
|
|
4455
6023
|
/** where this peer's pointer is; `anchor` null when it left the page */
|
|
4456
|
-
|
|
4457
|
-
type:
|
|
6024
|
+
z18.object({
|
|
6025
|
+
type: z18.literal("cursor"),
|
|
4458
6026
|
path: path2,
|
|
4459
6027
|
hash: hash2,
|
|
4460
6028
|
anchor: CommentAnchorSchema.nullable()
|
|
4461
6029
|
}),
|
|
4462
|
-
|
|
6030
|
+
z18.object({ type: z18.literal("ping") })
|
|
4463
6031
|
]);
|
|
4464
|
-
var LiveServerMessageSchema =
|
|
6032
|
+
var LiveServerMessageSchema = z18.discriminatedUnion("type", [
|
|
4465
6033
|
/** the answer to `hello`: who this connection is, and who else is in the room */
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
type:
|
|
4471
|
-
peerId:
|
|
6034
|
+
z18.object({ type: z18.literal("welcome"), you: LivePeerSchema, peers: z18.array(LivePeerSchema) }),
|
|
6035
|
+
z18.object({ type: z18.literal("join"), peer: LivePeerSchema }),
|
|
6036
|
+
z18.object({ type: z18.literal("leave"), peerId: z18.string() }),
|
|
6037
|
+
z18.object({
|
|
6038
|
+
type: z18.literal("cursor"),
|
|
6039
|
+
peerId: z18.string(),
|
|
4472
6040
|
path: path2,
|
|
4473
6041
|
hash: hash2,
|
|
4474
6042
|
anchor: CommentAnchorSchema.nullable()
|
|
4475
6043
|
}),
|
|
4476
6044
|
/** the site's comments changed: refetch them */
|
|
4477
|
-
|
|
4478
|
-
|
|
6045
|
+
z18.object({ type: z18.literal("comments") }),
|
|
6046
|
+
z18.object({ type: z18.literal("pong") })
|
|
4479
6047
|
]);
|
|
4480
6048
|
|
|
4481
6049
|
// src/cli.ts
|
|
@@ -4529,7 +6097,7 @@ function exitCodeFor(error) {
|
|
|
4529
6097
|
// package.json
|
|
4530
6098
|
var package_default = {
|
|
4531
6099
|
name: "@nearform/fling",
|
|
4532
|
-
version: "0.
|
|
6100
|
+
version: "0.11.1",
|
|
4533
6101
|
license: "MIT",
|
|
4534
6102
|
description: "Fling a folder of static files at a Fling server and get a link back. CLI + MCP server.",
|
|
4535
6103
|
type: "module",
|
|
@@ -4753,7 +6321,7 @@ function describeCause(cause) {
|
|
|
4753
6321
|
import { chmod, mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
4754
6322
|
import { homedir } from "node:os";
|
|
4755
6323
|
import { delimiter, join } from "node:path";
|
|
4756
|
-
import { z as
|
|
6324
|
+
import { z as z19 } from "zod";
|
|
4757
6325
|
var CONFIG_DIR_NAME = ".fling";
|
|
4758
6326
|
var CONFIG_FILE_NAME = "config.json";
|
|
4759
6327
|
var ENV = {
|
|
@@ -4770,14 +6338,14 @@ var ENV = {
|
|
|
4770
6338
|
/** Set by CI systems; the update check stays quiet there too. */
|
|
4771
6339
|
ci: "CI"
|
|
4772
6340
|
};
|
|
4773
|
-
var serverEntrySchema =
|
|
6341
|
+
var serverEntrySchema = z19.object({
|
|
4774
6342
|
/** What the server said about itself at login. A copy this CLI can't read is just refetched. */
|
|
4775
6343
|
instance: InstanceMetadataSchema.optional().catch(void 0),
|
|
4776
|
-
apiKey:
|
|
4777
|
-
user:
|
|
4778
|
-
email:
|
|
4779
|
-
name:
|
|
4780
|
-
userSlug:
|
|
6344
|
+
apiKey: z19.string().min(1).optional().catch(void 0),
|
|
6345
|
+
user: z19.object({
|
|
6346
|
+
email: z19.string().optional(),
|
|
6347
|
+
name: z19.string().optional(),
|
|
6348
|
+
userSlug: z19.string().optional()
|
|
4781
6349
|
}).optional().catch(void 0)
|
|
4782
6350
|
});
|
|
4783
6351
|
function systemLocateOptions(env = process.env) {
|
|
@@ -5268,9 +6836,9 @@ function colourAt(t) {
|
|
|
5268
6836
|
const scaled = Math.min(Math.max(t, 0), 1) * (STOPS.length - 1);
|
|
5269
6837
|
const i = Math.min(Math.floor(scaled), STOPS.length - 2);
|
|
5270
6838
|
const f = scaled - i;
|
|
5271
|
-
const
|
|
6839
|
+
const a3 = STOPS[i];
|
|
5272
6840
|
const b = STOPS[i + 1];
|
|
5273
|
-
return [0, 1, 2].map((k) => Math.round(
|
|
6841
|
+
return [0, 1, 2].map((k) => Math.round(a3[k] + (b[k] - a3[k]) * f));
|
|
5274
6842
|
}
|
|
5275
6843
|
function gradient(text2, width = text2.length, offset = 0) {
|
|
5276
6844
|
if (chalk2.level === 0) return text2;
|
|
@@ -5435,8 +7003,8 @@ function requireClient(ctx) {
|
|
|
5435
7003
|
}
|
|
5436
7004
|
|
|
5437
7005
|
// src/sites.ts
|
|
5438
|
-
import { z as
|
|
5439
|
-
var ShareResponseSchema2 =
|
|
7006
|
+
import { z as z20 } from "zod";
|
|
7007
|
+
var ShareResponseSchema2 = z20.looseObject({ shareUrl: z20.string() });
|
|
5440
7008
|
var sitePath2 = (name) => `/api/sites/${encodeURIComponent(name)}`;
|
|
5441
7009
|
function whoami(client) {
|
|
5442
7010
|
return client.request("GET", "/api/me", { schema: MeSchema });
|
|
@@ -5904,9 +7472,9 @@ function commentsClient(ctx) {
|
|
|
5904
7472
|
return requireClient(ctx);
|
|
5905
7473
|
}
|
|
5906
7474
|
var reviewPage = (ctx, name, path3) => reviewUrl(ctx.config.instance?.appOrigin ?? ctx.config.serverUrl ?? "", name, path3);
|
|
5907
|
-
function describe(
|
|
5908
|
-
const version =
|
|
5909
|
-
return `${chalk6.bold(authorLabel(
|
|
7475
|
+
function describe(c2, currentVersionId) {
|
|
7476
|
+
const version = c2.versionId === null ? "" : c2.versionId === currentVersionId ? "" : chalk6.dim(` (on version ${c2.versionId})`);
|
|
7477
|
+
return `${chalk6.bold(authorLabel(c2.author))} ${chalk6.dim(formatDate(c2.createdAt))}${version}`;
|
|
5910
7478
|
}
|
|
5911
7479
|
async function runComments(ctx, name, opts) {
|
|
5912
7480
|
const list = await listComments(commentsClient(ctx), name, { path: opts.path });
|
|
@@ -5916,17 +7484,17 @@ async function runComments(ctx, name, opts) {
|
|
|
5916
7484
|
ctx.out.data({ ...list, reviewUrl: reviewPage(ctx, name) }, () => {
|
|
5917
7485
|
const lines = [];
|
|
5918
7486
|
let lastPath = null;
|
|
5919
|
-
for (const { comment:
|
|
5920
|
-
(
|
|
7487
|
+
for (const { comment: c2, replies } of threads.sort(
|
|
7488
|
+
(a3, b) => a3.comment.path.localeCompare(b.comment.path)
|
|
5921
7489
|
)) {
|
|
5922
|
-
if (
|
|
5923
|
-
lines.push("", chalk6.bold.underline(
|
|
5924
|
-
lastPath =
|
|
5925
|
-
}
|
|
5926
|
-
const state =
|
|
5927
|
-
lines.push(`${chalk6.dim(
|
|
5928
|
-
if (
|
|
5929
|
-
lines.push(...
|
|
7490
|
+
if (c2.path !== lastPath) {
|
|
7491
|
+
lines.push("", chalk6.bold.underline(c2.path));
|
|
7492
|
+
lastPath = c2.path;
|
|
7493
|
+
}
|
|
7494
|
+
const state = c2.resolvedAt ? chalk6.green(" \u2713 resolved") : "";
|
|
7495
|
+
lines.push(`${chalk6.dim(c2.id)}${state} ${describe(c2, list.site.currentVersionId)}`);
|
|
7496
|
+
if (c2.anchor?.quote) lines.push(chalk6.dim(` > ${c2.anchor.quote}`));
|
|
7497
|
+
lines.push(...c2.body.split("\n").map((l) => ` ${l}`));
|
|
5930
7498
|
for (const r of replies) {
|
|
5931
7499
|
lines.push(` ${chalk6.dim("\u21B3")} ${describe(r, list.site.currentVersionId)}`);
|
|
5932
7500
|
lines.push(...r.body.split("\n").map((l) => ` ${l}`));
|
|
@@ -6016,7 +7584,7 @@ async function rootIsIgnored(top, root) {
|
|
|
6016
7584
|
const rel = relative(top, root);
|
|
6017
7585
|
if (!rel || rel.startsWith("..")) return false;
|
|
6018
7586
|
const segments = rel.split(sep);
|
|
6019
|
-
const candidates = segments.map((
|
|
7587
|
+
const candidates = segments.map((_2, i) => `${segments.slice(0, i + 1).join("/")}/`);
|
|
6020
7588
|
const out = await git(top, ["check-ignore", "--stdin", "-z"], `${candidates.join("\0")}\0`);
|
|
6021
7589
|
return out !== null && out.split("\0").some(Boolean);
|
|
6022
7590
|
}
|
|
@@ -6175,7 +7743,7 @@ async function buildManifest(dir) {
|
|
|
6175
7743
|
async function walk2(realDir, relDir) {
|
|
6176
7744
|
await gitIgnore.enterDir(realDir, relDir);
|
|
6177
7745
|
const entries = await readdir(realDir, { withFileTypes: true });
|
|
6178
|
-
entries.sort((
|
|
7746
|
+
entries.sort((a3, b) => a3.name < b.name ? -1 : a3.name > b.name ? 1 : 0);
|
|
6179
7747
|
for (const entry of entries) {
|
|
6180
7748
|
const rel = relDir ? `${relDir}/${entry.name}` : entry.name;
|
|
6181
7749
|
if (entry.name.startsWith(".")) {
|
|
@@ -6267,7 +7835,7 @@ async function buildManifest(dir) {
|
|
|
6267
7835
|
if (findings.length > 0) {
|
|
6268
7836
|
throw new SecretsFoundError(
|
|
6269
7837
|
findings.sort(
|
|
6270
|
-
(
|
|
7838
|
+
(a3, b) => a3.path < b.path ? -1 : a3.path > b.path ? 1 : a3.line - b.line || a3.rule.localeCompare(b.rule)
|
|
6271
7839
|
)
|
|
6272
7840
|
);
|
|
6273
7841
|
}
|
|
@@ -6325,13 +7893,13 @@ async function withHtmlListing(local, siteName2) {
|
|
|
6325
7893
|
contentType: contentTypeFor("index.html")
|
|
6326
7894
|
};
|
|
6327
7895
|
const files = [...local.files.filter((f) => f.path !== "index.html"), index].sort(
|
|
6328
|
-
(
|
|
7896
|
+
(a3, b) => a3.path < b.path ? -1 : a3.path > b.path ? 1 : 0
|
|
6329
7897
|
);
|
|
6330
7898
|
return {
|
|
6331
7899
|
...local,
|
|
6332
7900
|
files,
|
|
6333
7901
|
totalBytes: files.reduce((n, f) => n + f.size, 0),
|
|
6334
|
-
warnings: local.warnings.filter((
|
|
7902
|
+
warnings: local.warnings.filter((w2) => w2 !== NO_INDEX_WARNING)
|
|
6335
7903
|
};
|
|
6336
7904
|
}
|
|
6337
7905
|
async function loadIgnore(root) {
|
|
@@ -6450,7 +8018,7 @@ async function nameTakenError(client, name, body) {
|
|
|
6450
8018
|
const raw = body?.error?.suggestions;
|
|
6451
8019
|
let suggestions = Array.isArray(raw) ? raw.filter((s) => typeof s === "string") : [];
|
|
6452
8020
|
if (suggestions.length === 0) {
|
|
6453
|
-
suggestions = await checkName(client, name).then((
|
|
8021
|
+
suggestions = await checkName(client, name).then((c2) => c2.suggestions).catch(() => []);
|
|
6454
8022
|
}
|
|
6455
8023
|
return new NameTakenError(name, suggestions);
|
|
6456
8024
|
}
|
|
@@ -6793,7 +8361,7 @@ function zipDotEntry(name) {
|
|
|
6793
8361
|
async function extractZip(data, dest, skippedDotfiles = []) {
|
|
6794
8362
|
const unsafe = [];
|
|
6795
8363
|
let declared = 0;
|
|
6796
|
-
let
|
|
8364
|
+
let count3 = 0;
|
|
6797
8365
|
let entries;
|
|
6798
8366
|
try {
|
|
6799
8367
|
entries = unzipSync(data, {
|
|
@@ -6808,7 +8376,7 @@ async function extractZip(data, dest, skippedDotfiles = []) {
|
|
|
6808
8376
|
if (dot && !skippedDotfiles.includes(dot)) skippedDotfiles.push(dot);
|
|
6809
8377
|
return false;
|
|
6810
8378
|
}
|
|
6811
|
-
|
|
8379
|
+
count3++;
|
|
6812
8380
|
declared += file.originalSize;
|
|
6813
8381
|
if (file.originalSize > MAX_FILE_BYTES)
|
|
6814
8382
|
throw new CliError(
|
|
@@ -6818,7 +8386,7 @@ async function extractZip(data, dest, skippedDotfiles = []) {
|
|
|
6818
8386
|
throw new CliError(
|
|
6819
8387
|
`The zip expands to more than ${formatBytes(MAX_DEPLOY_BYTES)}, the limit per deploy`
|
|
6820
8388
|
);
|
|
6821
|
-
if (
|
|
8389
|
+
if (count3 > MAX_FILES) throw new CliError(`The zip has more than ${MAX_FILES} files`);
|
|
6822
8390
|
return true;
|
|
6823
8391
|
}
|
|
6824
8392
|
});
|
|
@@ -6855,7 +8423,7 @@ async function extractZip(data, dest, skippedDotfiles = []) {
|
|
|
6855
8423
|
}
|
|
6856
8424
|
return written.sort();
|
|
6857
8425
|
}
|
|
6858
|
-
var escapeHtml3 = (s) => s.replace(/[&<>"']/g, (
|
|
8426
|
+
var escapeHtml3 = (s) => s.replace(/[&<>"']/g, (c2) => `&#${c2.charCodeAt(0)};`);
|
|
6859
8427
|
function wrapperPage(file) {
|
|
6860
8428
|
const href = escapeHtml3(encodeURIComponent(file));
|
|
6861
8429
|
const title = escapeHtml3(file);
|
|
@@ -6893,22 +8461,22 @@ function wrapperPage(file) {
|
|
|
6893
8461
|
import { createHash as createHash3 } from "node:crypto";
|
|
6894
8462
|
import { mkdir as mkdir3, readdir as readdir2, readFile as readFile7, rm as rm2, stat as stat4, writeFile as writeFile3 } from "node:fs/promises";
|
|
6895
8463
|
import { dirname as dirname2, join as join6 } from "node:path";
|
|
6896
|
-
import { z as
|
|
8464
|
+
import { z as z21 } from "zod";
|
|
6897
8465
|
var SITE_LINK_FILE = ".fling-site.json";
|
|
6898
8466
|
var DOWNLOAD_CONCURRENCY = 8;
|
|
6899
8467
|
var DOWNLOAD_RETRIES = 3;
|
|
6900
|
-
var SiteLinkSchema =
|
|
8468
|
+
var SiteLinkSchema = z21.object({
|
|
6901
8469
|
/** the Fling it was pulled from */
|
|
6902
|
-
server:
|
|
6903
|
-
name:
|
|
8470
|
+
server: z21.string(),
|
|
8471
|
+
name: z21.string(),
|
|
6904
8472
|
/** the version pulled, or the one the last deploy made */
|
|
6905
|
-
versionId:
|
|
8473
|
+
versionId: z21.string(),
|
|
6906
8474
|
/** a pull of one of the site's Paths (its folder): the folder is that Path */
|
|
6907
|
-
path:
|
|
8475
|
+
path: z21.string().optional(),
|
|
6908
8476
|
/** every file pulled (or deployed), by site path: its SHA-256 */
|
|
6909
|
-
files:
|
|
8477
|
+
files: z21.record(z21.string(), z21.string()),
|
|
6910
8478
|
/** the SHA-256 of the fling.forms.json pulled (or deployed); absent when the version had none */
|
|
6911
|
-
forms:
|
|
8479
|
+
forms: z21.string().optional()
|
|
6912
8480
|
});
|
|
6913
8481
|
async function readSiteLink(dir) {
|
|
6914
8482
|
let raw;
|
|
@@ -6951,11 +8519,11 @@ var linkAfter = (link, versionId, local, forms2) => {
|
|
|
6951
8519
|
const { forms: _was, ...rest } = link;
|
|
6952
8520
|
return { ...rest, versionId, files: siteFiles(link, local), ...forms2 ? { forms: forms2 } : {} };
|
|
6953
8521
|
};
|
|
6954
|
-
function describeChanges(
|
|
8522
|
+
function describeChanges(c2) {
|
|
6955
8523
|
const parts = [
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
8524
|
+
c2.changed.length ? `${c2.changed.length} changed` : "",
|
|
8525
|
+
c2.added.length ? `${c2.added.length} added` : "",
|
|
8526
|
+
c2.removed.length ? `${c2.removed.length} removed` : ""
|
|
6959
8527
|
].filter(Boolean);
|
|
6960
8528
|
return parts.length ? parts.join(", ") : "no changes";
|
|
6961
8529
|
}
|
|
@@ -7413,7 +8981,7 @@ var manifest_default = {
|
|
|
7413
8981
|
manifest_version: "0.3",
|
|
7414
8982
|
name: "fling",
|
|
7415
8983
|
display_name: "Fling",
|
|
7416
|
-
version: "0.
|
|
8984
|
+
version: "0.11.1",
|
|
7417
8985
|
description: "Publish HTML pages, zips and folders from your computer to Fling and get a link back.",
|
|
7418
8986
|
long_description: "Fling hosts static sites at https://<name>.<your sites domain> (private to people signed in to your Fling unless you make them public or share a link).\n\nThis extension runs on your computer, so Claude can publish:\n\n- content it created in the conversation (sent inline \u2014 no sandbox uploads),\n- a file you downloaded or Claude Desktop saved, by name: it looks in Downloads, Desktop, Documents/Claude and Claude Desktop's output folders,\n- a single .html file, a .zip of a site, or a folder with index.html.\n\nIt works with every Fling you sign in to: the one you downloaded it from is added on start, Claude can sign in to another with the fling_login tool, and the logins are shared with the fling CLI (`fling login <address>`). When several Flings are set up, Claude settles with you which one a conversation uses and names it on every call.",
|
|
7419
8987
|
author: {
|
|
@@ -7658,23 +9226,23 @@ function parseSemver(input) {
|
|
|
7658
9226
|
if (!m) return null;
|
|
7659
9227
|
return { core: [Number(m[1]), Number(m[2]), Number(m[3])], pre: m[4] ? m[4].split(".") : [] };
|
|
7660
9228
|
}
|
|
7661
|
-
function compareSemver(
|
|
9229
|
+
function compareSemver(a3, b) {
|
|
7662
9230
|
for (let i = 0; i < 3; i++) {
|
|
7663
|
-
const d = (
|
|
9231
|
+
const d = (a3.core[i] ?? 0) - (b.core[i] ?? 0);
|
|
7664
9232
|
if (d !== 0) return d;
|
|
7665
9233
|
}
|
|
7666
|
-
if (!
|
|
7667
|
-
for (let i = 0; i < Math.max(
|
|
7668
|
-
const
|
|
9234
|
+
if (!a3.pre.length || !b.pre.length) return b.pre.length - a3.pre.length;
|
|
9235
|
+
for (let i = 0; i < Math.max(a3.pre.length, b.pre.length); i++) {
|
|
9236
|
+
const x2 = a3.pre[i];
|
|
7669
9237
|
const y = b.pre[i];
|
|
7670
|
-
if (
|
|
9238
|
+
if (x2 === void 0) return -1;
|
|
7671
9239
|
if (y === void 0) return 1;
|
|
7672
|
-
if (
|
|
7673
|
-
const xn = /^\d+$/.test(
|
|
9240
|
+
if (x2 === y) continue;
|
|
9241
|
+
const xn = /^\d+$/.test(x2);
|
|
7674
9242
|
const yn = /^\d+$/.test(y);
|
|
7675
|
-
if (xn && yn) return Number(
|
|
9243
|
+
if (xn && yn) return Number(x2) - Number(y);
|
|
7676
9244
|
if (xn !== yn) return xn ? -1 : 1;
|
|
7677
|
-
return
|
|
9245
|
+
return x2 < y ? -1 : 1;
|
|
7678
9246
|
}
|
|
7679
9247
|
return 0;
|
|
7680
9248
|
}
|
|
@@ -7755,7 +9323,7 @@ async function runChecks(deps) {
|
|
|
7755
9323
|
]);
|
|
7756
9324
|
return groups2.flat();
|
|
7757
9325
|
}
|
|
7758
|
-
var doctorExitCode = (checks) => checks.some((
|
|
9326
|
+
var doctorExitCode = (checks) => checks.some((c2) => c2.status === "problem") ? 1 : 0;
|
|
7759
9327
|
function systemDoctorDeps(store, fetch2, runClaude2, findClaudeDesktop2) {
|
|
7760
9328
|
const { env, home, platform } = systemLocateOptions();
|
|
7761
9329
|
return {
|
|
@@ -7780,7 +9348,7 @@ function systemDoctorDeps(store, fetch2, runClaude2, findClaudeDesktop2) {
|
|
|
7780
9348
|
}
|
|
7781
9349
|
var SYMBOL = { ok: "\u2714", warning: "\u25B2", problem: "\u2716" };
|
|
7782
9350
|
function describeChecks(checks) {
|
|
7783
|
-
return checks.map((
|
|
9351
|
+
return checks.map((c2) => `${SYMBOL[c2.status]} ${c2.message}${c2.fix ? ` \u2014 fix: ${c2.fix}` : ""}`).join("\n");
|
|
7784
9352
|
}
|
|
7785
9353
|
async function cliChecks(d) {
|
|
7786
9354
|
const checks = [
|
|
@@ -7967,7 +9535,7 @@ async function serverChecks(d) {
|
|
|
7967
9535
|
return perServer.flat();
|
|
7968
9536
|
}
|
|
7969
9537
|
async function oneServer(d, url, label, apiKey) {
|
|
7970
|
-
const
|
|
9538
|
+
const at2 = (id, check2) => ({
|
|
7971
9539
|
area: "server",
|
|
7972
9540
|
id,
|
|
7973
9541
|
server: url,
|
|
@@ -7978,7 +9546,7 @@ async function oneServer(d, url, label, apiKey) {
|
|
|
7978
9546
|
instance = await fetchInstance(url, d.fetch);
|
|
7979
9547
|
} catch (error) {
|
|
7980
9548
|
return [
|
|
7981
|
-
|
|
9549
|
+
at2("server.metadata", {
|
|
7982
9550
|
status: "problem",
|
|
7983
9551
|
message: `${label}: ${error.message}`,
|
|
7984
9552
|
fix: `Check the address and your connection; if the Fling moved: ${BIN_NAME} login <its new address>`
|
|
@@ -7986,15 +9554,15 @@ async function oneServer(d, url, label, apiKey) {
|
|
|
7986
9554
|
];
|
|
7987
9555
|
}
|
|
7988
9556
|
const checks = [
|
|
7989
|
-
|
|
9557
|
+
at2("server.metadata", { status: "ok", message: `${label}: ${instance.name} answers` })
|
|
7990
9558
|
];
|
|
7991
9559
|
const newer = newerRelease(instance.release, d.version);
|
|
7992
9560
|
checks.push(
|
|
7993
|
-
newer ?
|
|
9561
|
+
newer ? at2("server.release", {
|
|
7994
9562
|
status: "warning",
|
|
7995
9563
|
message: `${label} runs Fling ${newer}, newer than this CLI (${d.version})`,
|
|
7996
9564
|
fix: UPDATE_COMMAND
|
|
7997
|
-
}) :
|
|
9565
|
+
}) : at2("server.release", {
|
|
7998
9566
|
status: "ok",
|
|
7999
9567
|
message: instance.release ? `${label} runs Fling ${instance.release}` : `${label} does not say which release it runs`
|
|
8000
9568
|
})
|
|
@@ -8002,7 +9570,7 @@ async function oneServer(d, url, label, apiKey) {
|
|
|
8002
9570
|
const login = `${BIN_NAME} login ${url}`;
|
|
8003
9571
|
if (!apiKey) {
|
|
8004
9572
|
checks.push(
|
|
8005
|
-
|
|
9573
|
+
at2("server.signedIn", { status: "problem", message: `${label}: not signed in`, fix: login })
|
|
8006
9574
|
);
|
|
8007
9575
|
} else {
|
|
8008
9576
|
try {
|
|
@@ -8014,18 +9582,18 @@ async function oneServer(d, url, label, apiKey) {
|
|
|
8014
9582
|
});
|
|
8015
9583
|
const me = await client.request("GET", "/api/me");
|
|
8016
9584
|
checks.push(
|
|
8017
|
-
|
|
9585
|
+
at2("server.signedIn", {
|
|
8018
9586
|
status: "ok",
|
|
8019
9587
|
message: `${label}: signed in${me?.email ? ` as ${me.email}` : ""}`
|
|
8020
9588
|
})
|
|
8021
9589
|
);
|
|
8022
9590
|
} catch (error) {
|
|
8023
9591
|
checks.push(
|
|
8024
|
-
exitCodeFor(error) === 2 ?
|
|
9592
|
+
exitCodeFor(error) === 2 ? at2("server.signedIn", {
|
|
8025
9593
|
status: "problem",
|
|
8026
9594
|
message: `${label}: the API key is not accepted`,
|
|
8027
9595
|
fix: login
|
|
8028
|
-
}) :
|
|
9596
|
+
}) : at2("server.signedIn", {
|
|
8029
9597
|
status: "warning",
|
|
8030
9598
|
message: `${label}: could not check the sign-in (${error.message})`,
|
|
8031
9599
|
fix: `${BIN_NAME} whoami --server ${url}`
|
|
@@ -8035,7 +9603,7 @@ async function oneServer(d, url, label, apiKey) {
|
|
|
8035
9603
|
}
|
|
8036
9604
|
const on = Object.entries(instance.capabilities).filter(([, v]) => v === true).map(([k]) => k).sort();
|
|
8037
9605
|
checks.push(
|
|
8038
|
-
|
|
9606
|
+
at2("server.capabilities", {
|
|
8039
9607
|
status: "ok",
|
|
8040
9608
|
message: `${label}: ${on.length ? on.join(", ") : "no optional features"}`
|
|
8041
9609
|
})
|
|
@@ -8118,21 +9686,21 @@ async function claudeDesktopChecks(d) {
|
|
|
8118
9686
|
if (!app) return [];
|
|
8119
9687
|
const dataDir = claudeDesktopDataDir(d.platform, d.env, d.home);
|
|
8120
9688
|
const ext = dataDir ? await desktopExtensionStatus(dataDir) : null;
|
|
8121
|
-
const
|
|
9689
|
+
const at2 = (check2) => ({
|
|
8122
9690
|
area: "claudeDesktop",
|
|
8123
9691
|
id: "claudeDesktop.extension",
|
|
8124
9692
|
...check2
|
|
8125
9693
|
});
|
|
8126
9694
|
if (!ext)
|
|
8127
9695
|
return [
|
|
8128
|
-
|
|
9696
|
+
at2({
|
|
8129
9697
|
status: "ok",
|
|
8130
9698
|
message: `Claude Desktop is installed (${app}); the extension could not be looked up`
|
|
8131
9699
|
})
|
|
8132
9700
|
];
|
|
8133
9701
|
if (!ext.installed)
|
|
8134
9702
|
return [
|
|
8135
|
-
|
|
9703
|
+
at2({
|
|
8136
9704
|
status: "warning",
|
|
8137
9705
|
message: "The Fling extension is not installed in Claude Desktop",
|
|
8138
9706
|
fix: `${BIN_NAME} setup (it opens fling.mcpb in Claude Desktop)`
|
|
@@ -8149,11 +9717,11 @@ async function claudeDesktopChecks(d) {
|
|
|
8149
9717
|
});
|
|
8150
9718
|
const behind = ext.version ? newerRelease(d.version, ext.version) : null;
|
|
8151
9719
|
checks.push(
|
|
8152
|
-
behind ?
|
|
9720
|
+
behind ? at2({
|
|
8153
9721
|
status: "warning",
|
|
8154
9722
|
message: `The Claude Desktop extension is ${ext.version}, older than this CLI (${d.version})`,
|
|
8155
9723
|
fix: `${BIN_NAME} setup`
|
|
8156
|
-
}) :
|
|
9724
|
+
}) : at2({
|
|
8157
9725
|
status: "ok",
|
|
8158
9726
|
message: `The Claude Desktop extension is installed${ext.version ? ` (${ext.version})` : ""} (${DESKTOP_EXTENSION_ID})`
|
|
8159
9727
|
})
|
|
@@ -8182,13 +9750,13 @@ async function runDoctor(ctx, deps) {
|
|
|
8182
9750
|
function render(checks) {
|
|
8183
9751
|
const lines = [];
|
|
8184
9752
|
let area;
|
|
8185
|
-
for (const
|
|
8186
|
-
if (
|
|
8187
|
-
area =
|
|
8188
|
-
lines.push(`${lines.length ? "\n" : ""}${chalk8.bold(AREAS[
|
|
9753
|
+
for (const c2 of checks) {
|
|
9754
|
+
if (c2.area !== area) {
|
|
9755
|
+
area = c2.area;
|
|
9756
|
+
lines.push(`${lines.length ? "\n" : ""}${chalk8.bold(AREAS[c2.area])}`);
|
|
8189
9757
|
}
|
|
8190
|
-
const message =
|
|
8191
|
-
lines.push(`${SYMBOLS[
|
|
9758
|
+
const message = c2.status === "problem" ? chalk8.red(c2.message) : c2.message;
|
|
9759
|
+
lines.push(`${SYMBOLS[c2.status]} ${message}${c2.fix ? chalk8.dim(` \u2014 fix: ${c2.fix}`) : ""}`);
|
|
8192
9760
|
}
|
|
8193
9761
|
return lines.join("\n");
|
|
8194
9762
|
}
|
|
@@ -8618,7 +10186,7 @@ async function runPathsCheck(ctx, path3) {
|
|
|
8618
10186
|
});
|
|
8619
10187
|
}
|
|
8620
10188
|
const check2 = checkPathsIndex(html);
|
|
8621
|
-
for (const
|
|
10189
|
+
for (const w2 of check2.warnings) ctx.log.warn(w2);
|
|
8622
10190
|
if (!check2.ok) {
|
|
8623
10191
|
if (ctx.json) ctx.out.data({ path: file, ...check2 }, () => "");
|
|
8624
10192
|
throw new CliError(`${shown2(file)} has no Paths block:
|
|
@@ -8725,9 +10293,13 @@ async function runSetup(baseCtx, opts, deps = {}) {
|
|
|
8725
10293
|
results.claudeCode = await stepClaudeCode(after, run, scope, ask, fancy);
|
|
8726
10294
|
results.claudeDesktop = await stepClaudeDesktop(after, deps, ask, fancy);
|
|
8727
10295
|
const failed = Object.values(results).includes("failed");
|
|
10296
|
+
const guide = instanceGuideUrl(
|
|
10297
|
+
login.serverUrl ? (await ctx.store.resolve({ serverUrl: login.serverUrl })).instance : void 0
|
|
10298
|
+
);
|
|
8728
10299
|
if (fancy)
|
|
8729
10300
|
outro(
|
|
8730
|
-
failed ? chalk14.yellow("Setup finished with problems \u2014 see above, then run `fling setup` again.") : `You're set. Try ${chalk14.bold(`${ctx.binName} deploy ./dist`)}, or ask Claude to \u201Cfling this\u201D
|
|
10301
|
+
failed ? chalk14.yellow("Setup finished with problems \u2014 see above, then run `fling setup` again.") : `You're set. Try ${chalk14.bold(`${ctx.binName} deploy ./dist`)}, or ask Claude to \u201Cfling this\u201D.${guide ? `
|
|
10302
|
+
How everything works: ${chalk14.underline(guide)}` : ""}`,
|
|
8731
10303
|
{ output: process.stderr }
|
|
8732
10304
|
);
|
|
8733
10305
|
ctx.out.data(results, () => "");
|
|
@@ -9076,7 +10648,7 @@ async function runAccess(ctx, name, opts) {
|
|
|
9076
10648
|
const client = requireClient(ctx);
|
|
9077
10649
|
const site = changesAudience(change) ? await setAudience(client, name, change) : await getAudience(client, name);
|
|
9078
10650
|
const warnings = audienceWarnings(site);
|
|
9079
|
-
for (const
|
|
10651
|
+
for (const w2 of warnings) ctx.log.warn(w2);
|
|
9080
10652
|
ctx.out.data({ ...site, warnings }, () => describeAudience(site, membersOf(ctx)));
|
|
9081
10653
|
}
|
|
9082
10654
|
async function runSetLevel(ctx, name, level, opts) {
|
|
@@ -9093,7 +10665,7 @@ async function runSetLevel(ctx, name, level, opts) {
|
|
|
9093
10665
|
}
|
|
9094
10666
|
const site = await setAccess(requireClient(ctx), name, level);
|
|
9095
10667
|
const warnings = audienceWarnings(site);
|
|
9096
|
-
for (const
|
|
10668
|
+
for (const w2 of warnings) ctx.log.warn(w2);
|
|
9097
10669
|
ctx.out.data({ ...site, warnings }, () => describeAudience(site, membersOf(ctx)));
|
|
9098
10670
|
}
|
|
9099
10671
|
async function runRoles(ctx, which, name, opts) {
|
|
@@ -9169,7 +10741,7 @@ import { tmpdir as tmpdir3 } from "node:os";
|
|
|
9169
10741
|
import { basename as basename3, dirname as dirname4, join as join13, resolve as resolvePath } from "node:path";
|
|
9170
10742
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9171
10743
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9172
|
-
import { z as
|
|
10744
|
+
import { z as z22 } from "zod";
|
|
9173
10745
|
|
|
9174
10746
|
// src/locate.ts
|
|
9175
10747
|
import { lstat, readdir as readdir3, readFile as readFile12, realpath as realpath4, stat as stat9 } from "node:fs/promises";
|
|
@@ -9331,9 +10903,9 @@ function withoutDuplicateSuffix(name) {
|
|
|
9331
10903
|
return name.replace(/ \(\d+\)(?=\.[^.]+$|$)/, "");
|
|
9332
10904
|
}
|
|
9333
10905
|
function namesMatch(candidate, wanted) {
|
|
9334
|
-
const
|
|
10906
|
+
const a3 = candidate.toLowerCase();
|
|
9335
10907
|
const b = wanted.toLowerCase();
|
|
9336
|
-
return
|
|
10908
|
+
return a3 === b || withoutDuplicateSuffix(a3) === withoutDuplicateSuffix(b);
|
|
9337
10909
|
}
|
|
9338
10910
|
var splitSegments = (path3) => path3.split(/[\\/]+/).filter((s) => s !== "" && s !== "." && s !== "~");
|
|
9339
10911
|
function suffixScore(path3, wanted) {
|
|
@@ -9397,8 +10969,8 @@ async function resolveInput(input, opts) {
|
|
|
9397
10969
|
return void 0;
|
|
9398
10970
|
});
|
|
9399
10971
|
if (found.length === 0) throw notFound(input, roots);
|
|
9400
|
-
found.sort((
|
|
9401
|
-
const strip = ({ score: _s, mtimeMs: _m, isDirectory: _d, ...
|
|
10972
|
+
found.sort((a3, b) => b.score - a3.score || b.mtimeMs - a3.mtimeMs);
|
|
10973
|
+
const strip = ({ score: _s, mtimeMs: _m, isDirectory: _d, ...c2 }) => c2;
|
|
9402
10974
|
const [best, ...rest] = found;
|
|
9403
10975
|
return {
|
|
9404
10976
|
path: best.path,
|
|
@@ -9455,7 +11027,7 @@ async function findFiles(opts, find = {}) {
|
|
|
9455
11027
|
});
|
|
9456
11028
|
return void 0;
|
|
9457
11029
|
});
|
|
9458
|
-
const files = [...found.values()].sort((
|
|
11030
|
+
const files = [...found.values()].sort((a3, b) => b.mtimeMs - a3.mtimeMs).slice(0, find.limit ?? 20).map(({ mtimeMs: _m, ...c2 }) => c2);
|
|
9459
11031
|
return { files, searched: roots, complete };
|
|
9460
11032
|
}
|
|
9461
11033
|
|
|
@@ -9582,8 +11154,8 @@ ${listing(servers)}`,
|
|
|
9582
11154
|
// src/mcp.ts
|
|
9583
11155
|
var LOGIN_HINT = `Not logged in to Fling. Call fling_login (it opens the browser to sign in), or ask the user to run \`${NPX_COMMAND} login\` in a terminal (in Claude Code: \`! ${NPX_COMMAND} login\`), then try again.`;
|
|
9584
11156
|
var NO_SERVER_HINT = `No Fling server is set up on this computer. Ask the user for their Fling's address, then call fling_login with it as \`server\` (or ask them to run \`${NPX_COMMAND} login <url>\` in a terminal; in Claude Code: \`! ${NPX_COMMAND} login <url>\`), then try again.`;
|
|
9585
|
-
var mcpLocalInstructions = (
|
|
9586
|
-
`${
|
|
11157
|
+
var mcpLocalInstructions = (w2, opts = {}) => [
|
|
11158
|
+
`${w2.name} publishes static sites (HTML/CSS/JS, images, documents) at ${w2.sitesPattern}. This server runs on the user's computer.`,
|
|
9587
11159
|
...opts.newerRelease ? [mcpUpdateNote(opts.newerRelease)] : [],
|
|
9588
11160
|
...[serversInstructions(opts.servers ?? [])].filter((p) => p !== void 0),
|
|
9589
11161
|
"Content you created in this conversation (an HTML page, a report, a small app): call fling_publish with every file inline (text as utf8, binary as base64). Never pass file paths from your sandbox (e.g. /mnt/user-data/outputs/\u2026, /sessions/\u2026) \u2014 this computer cannot see them \u2014 and never curl or upload from the sandbox.",
|
|
@@ -9593,12 +11165,13 @@ var mcpLocalInstructions = (w, opts = {}) => [
|
|
|
9593
11165
|
"When there is no index.html but there are HTML pages, fling_deploy and fling_publish do not publish: ask the user whether to generate an index page listing the pages (`listHtml: true`) or publish without one (`listHtml: false`, the root URL 404s), then retry.",
|
|
9594
11166
|
NEVER_PUBLISHED,
|
|
9595
11167
|
"Not logged in? Call fling_login, let the user finish signing in in the browser, then retry.",
|
|
9596
|
-
`${ACCESS_NOTE(
|
|
9597
|
-
...opts.comments ? [COMMENTS_NOTE(
|
|
11168
|
+
`${ACCESS_NOTE(w2)} Use fling_share for a link people who cannot sign in can open. ${opts.comments ? "Always give the user the links that come back: the review link first, as the one to share for feedback, then the site URL." : "Always give the user the URL that comes back."}`,
|
|
11169
|
+
...opts.comments ? [COMMENTS_NOTE(w2, { forms: opts.forms })] : [],
|
|
9598
11170
|
...opts.comments && opts.forms ? [
|
|
9599
|
-
`${FORMS_NOTE(
|
|
11171
|
+
`${FORMS_NOTE(w2)} A folder deployed with fling_deploy takes its forms from a ${FORMS_FILE} at its top.`
|
|
9600
11172
|
] : [],
|
|
9601
|
-
...opts.notifications ? [NOTIFICATIONS_NOTE(
|
|
11173
|
+
...opts.notifications ? [NOTIFICATIONS_NOTE(w2)] : [],
|
|
11174
|
+
...[GUIDE_NOTE(w2)].filter((p) => p !== void 0)
|
|
9602
11175
|
].join("\n\n");
|
|
9603
11176
|
var PUBLISHING_TOOLS = /* @__PURE__ */ new Set(["fling_publish", "fling_deploy"]);
|
|
9604
11177
|
function newestRelease(servers) {
|
|
@@ -9620,7 +11193,7 @@ function createMcpServer(deps = {}) {
|
|
|
9620
11193
|
const several = servers.length > 1;
|
|
9621
11194
|
const wording = mcpWording(several ? null : servers[0]?.instance);
|
|
9622
11195
|
const mcpTools2 = mcpToolsFor(wording);
|
|
9623
|
-
const serverArg =
|
|
11196
|
+
const serverArg = z22.string().min(1).max(500).optional().describe(serverArgDescription(servers));
|
|
9624
11197
|
const note = serverToolNote(servers);
|
|
9625
11198
|
const serverTool = (def, description = def.description) => ({
|
|
9626
11199
|
title: def.title,
|
|
@@ -9930,13 +11503,13 @@ ${formsHint2}` : ""),
|
|
|
9930
11503
|
title: "Deploy a file or folder from this computer",
|
|
9931
11504
|
description: `Fling something that is on the user's computer and return its stable URL (${wording.sitesPattern}): a folder of static files (e.g. a build output like dist/), a single .html file (served as the site's index.html), a .zip of a site (extracted; a single top-level folder is unwrapped), or any other single file (.pdf, .svg, .png\u2026, served next to a generated page that shows it). \`path\` can be absolute, relative to the working directory, or just a file name ("Pitch Deck.html"): names are looked up, newest first, in Downloads, Desktop, Documents/Claude and Claude Desktop output folders, and the result says where the file was found. Never pass paths from your own sandbox (/mnt/user-data/\u2026, /sessions/\u2026): for content you created, use fling_publish. Without \`name\`, a name is generated: from the file name for files ("Pitch Deck (1).html" \u2192 pitch-deck), from the project and folder for folders (~/work/rocketpod/docs \u2192 rocketpod-docs). Site names are one global namespace, first come first served \u2014 confirm the name with the user first (fling_check_name with \`path\` shows the generated one). If the name is taken it fails with free suggestions \u2014 ask the user to pick one, then retry with \`name\`. If there is no index.html but there are HTML pages, it does not deploy: ask the user whether to generate an index page listing them (\`listHtml: true\`) or deploy without one (\`listHtml: false\`), then retry. Re-deploying identical content is a no-op. ${ACCESS_NOTE(wording)} ${PATH_PUBLISH_NOTE.replace("With `path`", "With `sitePath`")} A folder made by fling_pull publishes to the site and Fling it was pulled from, on the version pulled: only what changed is sent, and if someone published the site since, it stops (base_changed) rather than replace their work; \`force: true\` replaces it anyway (only when the user says so). A ${FORMS_FILE} at the top of the folder is never published: it is the site's forms, for structured feedback (labels, ratings, scores, eval judgements) on the review page; \`forms\` passes one inline instead (fling_forms_template). ${NEVER_PUBLISHED}${note}`,
|
|
9932
11505
|
inputSchema: {
|
|
9933
|
-
path:
|
|
11506
|
+
path: z22.string().min(1).describe(
|
|
9934
11507
|
"File or folder on this computer: absolute, relative to the working directory, or just its name (looked up in Downloads, Desktop and Claude output folders)"
|
|
9935
11508
|
),
|
|
9936
|
-
name:
|
|
11509
|
+
name: z22.string().optional().describe(
|
|
9937
11510
|
"Site name (lowercase letters, digits, single hyphens; max 50). Defaults to a name generated from the file or folder"
|
|
9938
11511
|
),
|
|
9939
|
-
sitePath:
|
|
11512
|
+
sitePath: z22.string().min(1).max(1024).optional().describe(
|
|
9940
11513
|
'Publish as the Path at this top-level folder of the site, e.g. "PAY-412" (served at <site>/PAY-412/); the rest of the site is untouched. Needs `name`. Omit to publish the site itself'
|
|
9941
11514
|
),
|
|
9942
11515
|
spa: spa2,
|
|
@@ -9945,7 +11518,7 @@ ${formsHint2}` : ""),
|
|
|
9945
11518
|
groups: groups2,
|
|
9946
11519
|
public: isPublic,
|
|
9947
11520
|
listHtml: listHtml2,
|
|
9948
|
-
force:
|
|
11521
|
+
force: z22.boolean().optional().describe(
|
|
9949
11522
|
"A folder made by fling_pull: publish it without a base, replacing whatever is live even if someone published since. Only when the user says so"
|
|
9950
11523
|
),
|
|
9951
11524
|
forms: formsArg.describe(
|
|
@@ -10011,15 +11584,15 @@ ${formsHint2}` : ""),
|
|
|
10011
11584
|
title: "Download a site's files to change them",
|
|
10012
11585
|
description: `Download a site's files into a folder on this computer, to change some or all of them and publish again: by default ~/Documents/Claude/fling/<name>. Then edit the files there and call fling_deploy with the folder: it publishes on the version pulled, sending only what changed. Anyone who can open the site may pull it; publishing needs an owner or publisher. \`path\` pulls one folder of the site (its files at the top of the folder); deploying it keeps the rest of the site. If the folder is not empty it stops, unless \`force\` (it then writes over what is there). When fling_deploy says base_changed, someone published in between: pull again into another folder and redo the changes there.` + note,
|
|
10013
11586
|
inputSchema: {
|
|
10014
|
-
name:
|
|
10015
|
-
dir:
|
|
11587
|
+
name: z22.string().min(1).max(200).describe("Site name"),
|
|
11588
|
+
dir: z22.string().min(1).optional().describe(
|
|
10016
11589
|
"Folder to write the files to (absolute, or relative to the working directory). Default ~/Documents/Claude/fling/<name>"
|
|
10017
11590
|
),
|
|
10018
|
-
versionId:
|
|
11591
|
+
versionId: z22.string().min(1).max(100).optional().describe(
|
|
10019
11592
|
"Another version than the live one (owners and publishers; ids from fling_info)"
|
|
10020
11593
|
),
|
|
10021
|
-
path:
|
|
10022
|
-
force:
|
|
11594
|
+
path: z22.string().min(1).max(1024).optional().describe('Only this Path of the site, e.g. "PAY-412"'),
|
|
11595
|
+
force: z22.boolean().optional().describe("Write into the folder even if it is not empty"),
|
|
10023
11596
|
server: serverArg
|
|
10024
11597
|
},
|
|
10025
11598
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
@@ -10079,7 +11652,7 @@ ${formsHint2}` : ""),
|
|
|
10079
11652
|
const files = [
|
|
10080
11653
|
...read,
|
|
10081
11654
|
...tooLarge.map(({ url: _url, ...f }) => ({ ...f, tooLarge: true }))
|
|
10082
|
-
].sort((
|
|
11655
|
+
].sort((a3, b) => a3.path < b.path ? -1 : a3.path > b.path ? 1 : 0);
|
|
10083
11656
|
const result = {
|
|
10084
11657
|
name: args.name,
|
|
10085
11658
|
versionId: pulled.versionId,
|
|
@@ -10097,9 +11670,9 @@ ${formsHint2}` : ""),
|
|
|
10097
11670
|
title: "Find files to fling",
|
|
10098
11671
|
description: "List recent things on this computer that could be flung, newest first: .html/.htm and .zip files, and folders containing an index.html, from the working directory, Downloads, Desktop, Documents/Claude, ~/Claude and Claude Desktop output folders. Each has its path, where it was found, size and modified time. Use it when the user refers to a file they downloaded or that Claude Desktop saved, then pass the chosen path (or name) to fling_deploy.",
|
|
10099
11672
|
inputSchema: {
|
|
10100
|
-
query:
|
|
10101
|
-
limit:
|
|
10102
|
-
days:
|
|
11673
|
+
query: z22.string().optional().describe('Only names containing this text (case-insensitive), e.g. "deck"'),
|
|
11674
|
+
limit: z22.number().int().min(1).max(100).optional().describe("Max results (default 20)"),
|
|
11675
|
+
days: z22.number().int().min(1).max(3650).optional().describe("Only things modified in the last N days (default 14)")
|
|
10103
11676
|
},
|
|
10104
11677
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
10105
11678
|
},
|
|
@@ -10171,8 +11744,8 @@ ${JSON.stringify(data, null, 2)}`);
|
|
|
10171
11744
|
...serverTool(mcpTools2.checkName),
|
|
10172
11745
|
description: `${mcpTools2.checkName.description} Pass \`path\` instead of \`name\` to see the name fling_deploy would generate for a file or folder on this computer (same lookup as fling_deploy), so you can confirm it with the user.${note}`,
|
|
10173
11746
|
inputSchema: {
|
|
10174
|
-
name:
|
|
10175
|
-
path:
|
|
11747
|
+
name: z22.string().min(1).max(200).optional().describe("Site name to check"),
|
|
11748
|
+
path: z22.string().optional().describe("File or folder whose generated default name to check (path or file name)"),
|
|
10176
11749
|
server: serverArg
|
|
10177
11750
|
}
|
|
10178
11751
|
},
|
|
@@ -10213,7 +11786,7 @@ ${JSON.stringify(data, null, 2)}`);
|
|
|
10213
11786
|
title: "Sign in to Fling",
|
|
10214
11787
|
description: `Sign the user in to ${several ? "a Fling" : wording.name}: opens their browser to sign in with ${wording.signIn} and stores the key on this computer (shared with the fling CLI). Waits up to ~30 seconds; if sign-in is not finished by then, it keeps waiting in the background for up to 5 minutes \u2014 tell the user to finish signing in in the browser, then retry what you were doing. Call it when another tool says the user is not logged in. Pass \`server\` (its address) to sign in to another Fling, including one not set up on this computer yet: it is remembered, and becomes the current one only when none is.` + note,
|
|
10215
11788
|
inputSchema: {
|
|
10216
|
-
server:
|
|
11789
|
+
server: z22.string().min(1).max(500).optional().describe(
|
|
10217
11790
|
`The Fling to sign in to: its address (e.g. "https://fling.example.com"), or the host of one set up on this computer. ${several ? `Required while several Flings are set up (${servers.map((s) => serverLabel(s.url)).join(", ")})` : `Omit it to use ${servers[0] ? serverLabel(servers[0].url) : "the one this computer knows"}`}`
|
|
10218
11791
|
)
|
|
10219
11792
|
},
|
|
@@ -10320,7 +11893,7 @@ ${JSON.stringify({ ok, checks }, null, 2)}`);
|
|
|
10320
11893
|
title: "List the Flings on this computer",
|
|
10321
11894
|
description: `List the Flings set up on this computer, read now: each one's address, name, who is signed in (or "signed out") and which is current, the user's usual one. Call it when unsure which Fling the user means or which exist; the list may have changed since this conversation started. Pass \`use\` to make one the current Fling, the same as running \`${NPX_COMMAND} use <server>\`: it changes the default of the fling CLI too, so only do it when the user asks. It does not replace passing \`server\` to the other tools while several Flings are set up.`,
|
|
10322
11895
|
inputSchema: {
|
|
10323
|
-
use:
|
|
11896
|
+
use: z22.string().min(1).max(500).optional().describe(
|
|
10324
11897
|
"Make this Fling current (address, host or unique part of it), like `fling use`"
|
|
10325
11898
|
)
|
|
10326
11899
|
},
|