@aeptus/aexeo-emdash 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/admin.js ADDED
@@ -0,0 +1,492 @@
1
+ // src/admin/Facts.tsx
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ var PLUGIN_ID = "aexeo-seogeo";
5
+ var API_BASE = "/_emdash/api";
6
+ function Facts() {
7
+ const [data, setData] = useState(null);
8
+ const [loadError, setLoadError] = useState(null);
9
+ const [draft, setDraft] = useState("");
10
+ const [validation, setValidation] = useState(null);
11
+ const [busy, setBusy] = useState(null);
12
+ const [toast, setToast] = useState(null);
13
+ const loadCurrent = useCallback(async () => {
14
+ setLoadError(null);
15
+ try {
16
+ const res = await callRoute("data", {});
17
+ setData(res);
18
+ const stored = res.manifest;
19
+ if (stored !== null) {
20
+ setDraft(JSON.stringify(stored, null, 2));
21
+ }
22
+ } catch (err) {
23
+ setLoadError(err instanceof Error ? err.message : String(err));
24
+ }
25
+ }, []);
26
+ useEffect(() => {
27
+ void loadCurrent();
28
+ }, [loadCurrent]);
29
+ const onCopyPrompt = useCallback(async () => {
30
+ setBusy("prompt");
31
+ setToast(null);
32
+ try {
33
+ const res = await callRoute("prompt", {});
34
+ await navigator.clipboard.writeText(res.prompt);
35
+ setToast(
36
+ "Prompt copied to clipboard \u2014 paste it into Claude/GPT, answer the LLM's questions, then come back and paste the resulting JSON below."
37
+ );
38
+ } catch (err) {
39
+ setToast(
40
+ `Failed to generate prompt: ${err instanceof Error ? err.message : String(err)}`
41
+ );
42
+ } finally {
43
+ setBusy(null);
44
+ }
45
+ }, []);
46
+ const onValidate = useCallback(async () => {
47
+ setBusy("validate");
48
+ setToast(null);
49
+ setValidation(null);
50
+ try {
51
+ const res = await callRoute("validate", {
52
+ manifest_json: draft
53
+ });
54
+ setValidation(res);
55
+ } catch (err) {
56
+ setToast(
57
+ `Validation failed: ${err instanceof Error ? err.message : String(err)}`
58
+ );
59
+ } finally {
60
+ setBusy(null);
61
+ }
62
+ }, [draft]);
63
+ const onSave = useCallback(async () => {
64
+ setBusy("save");
65
+ setToast(null);
66
+ try {
67
+ await callRoute("save", { manifest_json: draft });
68
+ setToast("Manifest saved. Site truth score will reflect it on next refresh.");
69
+ await loadCurrent();
70
+ } catch (err) {
71
+ setToast(
72
+ `Save failed: ${err instanceof Error ? err.message : String(err)}`
73
+ );
74
+ } finally {
75
+ setBusy(null);
76
+ }
77
+ }, [draft, loadCurrent]);
78
+ const validationOk = validation !== null && validation.validation.valid && validation.validation.errors.length === 0 && validation.assessment.mismatches.filter((m) => m.severity === "error").length === 0;
79
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6 p-4", children: [
80
+ /* @__PURE__ */ jsxs("header", { children: [
81
+ /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold", children: "Truth manifest" }),
82
+ /* @__PURE__ */ jsxs("p", { className: "mt-1 text-sm text-kumo-subtle", children: [
83
+ "Author a ",
84
+ /* @__PURE__ */ jsx("code", { children: "facts.json" }),
85
+ " using your LLM of choice. The plugin frames the question, validates the answer, and stores the result. Read",
86
+ " ",
87
+ /* @__PURE__ */ jsx(
88
+ "a",
89
+ {
90
+ href: "https://github.com/schiste/Aexeo/blob/main/docs/facts-manifest.md",
91
+ target: "_blank",
92
+ rel: "noopener noreferrer",
93
+ className: "text-kumo-link hover:underline",
94
+ children: "the authoring guide"
95
+ }
96
+ ),
97
+ " ",
98
+ "for the philosophy behind this flow."
99
+ ] })
100
+ ] }),
101
+ loadError !== null && /* @__PURE__ */ jsxs("div", { className: "rounded border border-red-500/40 bg-red-500/10 p-3 text-sm text-red-700", children: [
102
+ "Failed to load manifest state: ",
103
+ loadError
104
+ ] }),
105
+ /* @__PURE__ */ jsxs("section", { className: "rounded border border-kumo-line p-3", children: [
106
+ /* @__PURE__ */ jsx("h2", { className: "text-sm font-medium", children: "Status" }),
107
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm", children: data === null ? "Loading\u2026" : data.present ? "\u2713 A truth manifest is stored. Editing the JSON below replaces it on Save." : "No truth manifest stored. Generate the prompt below to author one." })
108
+ ] }),
109
+ /* @__PURE__ */ jsxs("section", { className: "space-y-3 rounded border border-kumo-line p-3", children: [
110
+ /* @__PURE__ */ jsx("h2", { className: "text-sm font-medium", children: "1. Generate authoring prompt" }),
111
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-kumo-subtle", children: "Copies a populated prompt to your clipboard. Paste it into Claude/GPT/etc., answer the LLM's questions, and bring the resulting JSON back here." }),
112
+ /* @__PURE__ */ jsx(
113
+ "button",
114
+ {
115
+ type: "button",
116
+ onClick: () => void onCopyPrompt(),
117
+ disabled: busy !== null,
118
+ className: "rounded bg-kumo-brand px-3 py-1.5 text-sm font-medium text-white hover:bg-kumo-brand/90 disabled:opacity-50",
119
+ children: busy === "prompt" ? "Copying\u2026" : "Copy prompt"
120
+ }
121
+ )
122
+ ] }),
123
+ /* @__PURE__ */ jsxs("section", { className: "space-y-3 rounded border border-kumo-line p-3", children: [
124
+ /* @__PURE__ */ jsx("h2", { className: "text-sm font-medium", children: "2. Paste & validate" }),
125
+ /* @__PURE__ */ jsx(
126
+ "textarea",
127
+ {
128
+ value: draft,
129
+ onChange: (e) => setDraft(e.target.value),
130
+ spellCheck: false,
131
+ rows: 16,
132
+ placeholder: '{ "version": 1, "organization": { ... }, ... }',
133
+ className: "w-full rounded border border-kumo-line bg-kumo-tint p-2 font-mono text-xs"
134
+ }
135
+ ),
136
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
137
+ /* @__PURE__ */ jsx(
138
+ "button",
139
+ {
140
+ type: "button",
141
+ onClick: () => void onValidate(),
142
+ disabled: busy !== null || draft.trim().length === 0,
143
+ className: "rounded border border-kumo-line px-3 py-1.5 text-sm hover:bg-kumo-tint disabled:opacity-50",
144
+ children: busy === "validate" ? "Validating\u2026" : "Validate"
145
+ }
146
+ ),
147
+ /* @__PURE__ */ jsx(
148
+ "button",
149
+ {
150
+ type: "button",
151
+ onClick: () => void onSave(),
152
+ disabled: busy !== null || !validationOk,
153
+ title: validationOk ? "Save to KV" : "Run Validate first; only valid manifests can be saved.",
154
+ className: "rounded bg-kumo-brand px-3 py-1.5 text-sm font-medium text-white hover:bg-kumo-brand/90 disabled:opacity-50",
155
+ children: busy === "save" ? "Saving\u2026" : "Save"
156
+ }
157
+ )
158
+ ] })
159
+ ] }),
160
+ toast !== null && /* @__PURE__ */ jsx("div", { className: "rounded border border-kumo-line bg-kumo-tint p-3 text-sm", children: toast }),
161
+ validation !== null && /* @__PURE__ */ jsx(ValidationReport, { result: validation })
162
+ ] });
163
+ }
164
+ function ValidationReport({
165
+ result
166
+ }) {
167
+ const errMismatches = result.assessment.mismatches.filter(
168
+ (m) => m.severity === "error"
169
+ );
170
+ const warnMismatches = result.assessment.mismatches.filter(
171
+ (m) => m.severity === "warning"
172
+ );
173
+ return /* @__PURE__ */ jsxs("section", { className: "space-y-3 rounded border border-kumo-line p-3", children: [
174
+ /* @__PURE__ */ jsx("h2", { className: "text-sm font-medium", children: "Validation result" }),
175
+ /* @__PURE__ */ jsxs("div", { className: "text-sm", children: [
176
+ /* @__PURE__ */ jsxs("div", { children: [
177
+ "Shape:",
178
+ " ",
179
+ /* @__PURE__ */ jsx("strong", { children: result.validation.valid ? "valid" : "invalid" }),
180
+ " ",
181
+ "\xB7 org",
182
+ " ",
183
+ result.validation.organization_present ? "present" : "missing",
184
+ " \xB7",
185
+ " ",
186
+ result.validation.product_count,
187
+ " products \xB7",
188
+ " ",
189
+ result.validation.preferred_term_count,
190
+ " preferred terms \xB7",
191
+ " ",
192
+ result.validation.forbidden_term_count,
193
+ " forbidden terms"
194
+ ] }),
195
+ /* @__PURE__ */ jsxs("div", { children: [
196
+ "Score: ",
197
+ /* @__PURE__ */ jsx("strong", { children: result.assessment.score }),
198
+ "/",
199
+ result.assessment.score_ceiling,
200
+ " \xB7 source =",
201
+ " ",
202
+ /* @__PURE__ */ jsx("code", { children: result.assessment.structured_truth_source }),
203
+ " \xB7",
204
+ " ",
205
+ result.assessment.pages_analyzed,
206
+ " pages,",
207
+ " ",
208
+ result.assessment.pages_with_schema,
209
+ " with schema.org"
210
+ ] })
211
+ ] }),
212
+ result.validation.errors.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded border border-red-500/40 bg-red-500/10 p-2 text-sm", children: [
213
+ /* @__PURE__ */ jsx("strong", { children: "Schema errors:" }),
214
+ /* @__PURE__ */ jsx("ul", { className: "mt-1 list-disc pl-5", children: result.validation.errors.map((e, i) => /* @__PURE__ */ jsx("li", { children: e }, i)) })
215
+ ] }),
216
+ result.validation.warnings.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded border border-yellow-500/40 bg-yellow-500/10 p-2 text-sm", children: [
217
+ /* @__PURE__ */ jsx("strong", { children: "Schema warnings:" }),
218
+ /* @__PURE__ */ jsx("ul", { className: "mt-1 list-disc pl-5", children: result.validation.warnings.map((w, i) => /* @__PURE__ */ jsx("li", { children: w }, i)) })
219
+ ] }),
220
+ errMismatches.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded border border-red-500/40 bg-red-500/10 p-2 text-sm", children: [
221
+ /* @__PURE__ */ jsx("strong", { children: "Mismatches with site (errors):" }),
222
+ /* @__PURE__ */ jsx(MismatchList, { items: errMismatches })
223
+ ] }),
224
+ warnMismatches.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded border border-yellow-500/40 bg-yellow-500/10 p-2 text-sm", children: [
225
+ /* @__PURE__ */ jsx("strong", { children: "Mismatches with site (warnings):" }),
226
+ /* @__PURE__ */ jsx(MismatchList, { items: warnMismatches })
227
+ ] }),
228
+ result.validation.errors.length === 0 && result.assessment.mismatches.length === 0 && /* @__PURE__ */ jsxs("div", { className: "rounded border border-green-500/40 bg-green-500/10 p-2 text-sm", children: [
229
+ "\u2713 Manifest is valid and agrees with on-page schema.org. Click",
230
+ " ",
231
+ "Save to persist."
232
+ ] })
233
+ ] });
234
+ }
235
+ function MismatchList({
236
+ items
237
+ }) {
238
+ return /* @__PURE__ */ jsx("ul", { className: "mt-1 list-disc pl-5", children: items.map((m, i) => /* @__PURE__ */ jsxs("li", { children: [
239
+ /* @__PURE__ */ jsx("code", { className: "text-xs", children: m.route }),
240
+ " \xB7 ",
241
+ m.field,
242
+ ": expected",
243
+ " ",
244
+ /* @__PURE__ */ jsx("code", { className: "text-xs", children: m.expected }),
245
+ ", observed",
246
+ " ",
247
+ /* @__PURE__ */ jsx("code", { className: "text-xs", children: m.observed }),
248
+ " ",
249
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-kumo-subtle", children: [
250
+ "(",
251
+ m.source,
252
+ ")"
253
+ ] })
254
+ ] }, i)) });
255
+ }
256
+ async function callRoute(kind, extra) {
257
+ const res = await fetch(`${API_BASE}/plugins/${PLUGIN_ID}/facts`, {
258
+ method: "POST",
259
+ headers: {
260
+ "Content-Type": "application/json",
261
+ "X-EmDash-Request": "1"
262
+ },
263
+ body: JSON.stringify({ kind, ...extra })
264
+ });
265
+ const body = await res.json();
266
+ if (body.error !== void 0) {
267
+ throw new Error(`${body.error.code}: ${body.error.message}`);
268
+ }
269
+ if (body.data === void 0) {
270
+ throw new Error(`Empty response (HTTP ${res.status})`);
271
+ }
272
+ return body.data;
273
+ }
274
+
275
+ // src/admin/Findings.tsx
276
+ import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
277
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
278
+ var PLUGIN_ID2 = "aexeo-seogeo";
279
+ var API_BASE2 = "/_emdash/api";
280
+ function Findings() {
281
+ const [state, setState] = useState2({
282
+ loading: true,
283
+ error: null,
284
+ payload: null
285
+ });
286
+ const [refreshing, setRefreshing] = useState2(false);
287
+ const [toast, setToast] = useState2(null);
288
+ const load = useCallback2(async () => {
289
+ setState((s) => ({ ...s, loading: true, error: null }));
290
+ try {
291
+ const res = await fetch(`${API_BASE2}/plugins/${PLUGIN_ID2}/data`, {
292
+ method: "POST",
293
+ headers: csrfHeaders(),
294
+ body: "{}"
295
+ });
296
+ const body = await res.json();
297
+ const payload2 = unwrap(body, res);
298
+ setState({ loading: false, error: null, payload: payload2 });
299
+ } catch (err) {
300
+ setState({
301
+ loading: false,
302
+ error: err instanceof Error ? err.message : String(err),
303
+ payload: null
304
+ });
305
+ }
306
+ }, []);
307
+ const refresh = useCallback2(async () => {
308
+ setRefreshing(true);
309
+ setToast(null);
310
+ try {
311
+ const res = await fetch(`${API_BASE2}/plugins/${PLUGIN_ID2}/refresh`, {
312
+ method: "POST",
313
+ headers: csrfHeaders(),
314
+ body: "{}"
315
+ });
316
+ const body = await res.json();
317
+ const data = unwrap(body, res);
318
+ setState({ loading: false, error: null, payload: data.payload });
319
+ if (data.summary) {
320
+ const { documentsScanned, routesUpdated, totalFindings, errors } = data.summary;
321
+ if (errors.length > 0) {
322
+ setToast(`Refresh completed with ${errors.length} errors: ${errors.join(" \u2022 ")}`);
323
+ } else {
324
+ setToast(
325
+ `Refreshed ${routesUpdated} routes (${totalFindings} findings across ${documentsScanned} documents)`
326
+ );
327
+ }
328
+ }
329
+ } catch (err) {
330
+ setToast(
331
+ `Refresh failed: ${err instanceof Error ? err.message : String(err)}`
332
+ );
333
+ } finally {
334
+ setRefreshing(false);
335
+ }
336
+ }, []);
337
+ useEffect2(() => {
338
+ void load();
339
+ }, [load]);
340
+ if (state.loading && state.payload === null) {
341
+ return /* @__PURE__ */ jsx2("div", { className: "p-4 text-sm text-kumo-subtle", children: "Loading findings\u2026" });
342
+ }
343
+ if (state.error !== null) {
344
+ return /* @__PURE__ */ jsxs2("div", { className: "p-4", children: [
345
+ /* @__PURE__ */ jsx2("h1", { className: "text-xl font-semibold", children: "SEO findings" }),
346
+ /* @__PURE__ */ jsxs2("p", { className: "mt-2 rounded border border-red-500/40 bg-red-500/10 p-3 text-sm text-red-700", children: [
347
+ "Failed to load: ",
348
+ state.error
349
+ ] }),
350
+ /* @__PURE__ */ jsx2(
351
+ "button",
352
+ {
353
+ type: "button",
354
+ onClick: () => void load(),
355
+ className: "mt-3 rounded border border-kumo-line px-3 py-1.5 text-sm hover:bg-kumo-tint",
356
+ children: "Retry"
357
+ }
358
+ )
359
+ ] });
360
+ }
361
+ const payload = state.payload;
362
+ if (payload === null) {
363
+ return /* @__PURE__ */ jsx2("div", { className: "p-4 text-sm text-kumo-subtle", children: "No data." });
364
+ }
365
+ const routesByPath = /* @__PURE__ */ new Map();
366
+ for (const route of payload.routes) {
367
+ routesByPath.set(route.route, route);
368
+ }
369
+ return /* @__PURE__ */ jsxs2("div", { className: "space-y-4 p-4", children: [
370
+ /* @__PURE__ */ jsxs2("header", { className: "flex items-center justify-between gap-4", children: [
371
+ /* @__PURE__ */ jsxs2("div", { children: [
372
+ /* @__PURE__ */ jsx2("h1", { className: "text-xl font-semibold", children: "SEO findings" }),
373
+ /* @__PURE__ */ jsx2("p", { className: "mt-1 text-sm text-kumo-subtle", children: payload.totals.findings === 0 ? /* @__PURE__ */ jsx2(Fragment, { children: "No findings yet \u2014 click Refresh to evaluate the site." }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
374
+ payload.totals.findings,
375
+ " findings across ",
376
+ payload.totals.routes,
377
+ " routes \u2014",
378
+ " ",
379
+ payload.totals.errors,
380
+ " errors, ",
381
+ payload.totals.warnings,
382
+ " warnings."
383
+ ] }) })
384
+ ] }),
385
+ /* @__PURE__ */ jsx2(
386
+ "button",
387
+ {
388
+ type: "button",
389
+ onClick: () => void refresh(),
390
+ disabled: refreshing,
391
+ className: "rounded bg-kumo-brand px-3 py-1.5 text-sm font-medium text-white hover:bg-kumo-brand/90 disabled:opacity-50",
392
+ children: refreshing ? "Refreshing\u2026" : "Refresh"
393
+ }
394
+ )
395
+ ] }),
396
+ toast !== null && /* @__PURE__ */ jsx2("div", { className: "rounded border border-kumo-line bg-kumo-tint p-3 text-sm", children: toast }),
397
+ payload.sitewideFindings.length > 0 && /* @__PURE__ */ jsxs2("section", { className: "rounded border border-kumo-line p-3", children: [
398
+ /* @__PURE__ */ jsx2("h2", { className: "text-sm font-medium", children: "Sitewide" }),
399
+ /* @__PURE__ */ jsx2("ul", { className: "mt-2 space-y-1 text-sm", children: payload.sitewideFindings.map((finding, i) => /* @__PURE__ */ jsxs2("li", { className: "flex items-start gap-2", children: [
400
+ /* @__PURE__ */ jsx2(SeverityBadge, { severity: finding.severity }),
401
+ /* @__PURE__ */ jsx2("code", { className: "font-mono text-xs", children: finding.rule_id }),
402
+ /* @__PURE__ */ jsx2("span", { className: "flex-1", children: finding.message })
403
+ ] }, i)) })
404
+ ] }),
405
+ payload.findings.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "text-sm text-kumo-subtle", children: payload.totals.documentsIndexed === 0 ? "No documents indexed \u2014 click Refresh to do an initial sweep." : "All indexed documents are clean." }) : /* @__PURE__ */ jsx2("div", { className: "overflow-x-auto rounded border border-kumo-line", children: /* @__PURE__ */ jsxs2("table", { className: "w-full text-left text-sm", children: [
406
+ /* @__PURE__ */ jsx2("thead", { className: "bg-kumo-tint", children: /* @__PURE__ */ jsxs2("tr", { children: [
407
+ /* @__PURE__ */ jsx2("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Route" }),
408
+ /* @__PURE__ */ jsx2("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Rule" }),
409
+ /* @__PURE__ */ jsx2("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Severity" }),
410
+ /* @__PURE__ */ jsx2("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Message" })
411
+ ] }) }),
412
+ /* @__PURE__ */ jsx2("tbody", { children: payload.findings.map((finding, i) => {
413
+ const routeInfo = routesByPath.get(finding.route);
414
+ return /* @__PURE__ */ jsxs2("tr", { className: "border-t border-kumo-line", children: [
415
+ /* @__PURE__ */ jsx2("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx2(RouteLinks, { finding, info: routeInfo }) }),
416
+ /* @__PURE__ */ jsx2("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx2("code", { className: "rounded bg-kumo-tint px-1.5 py-0.5 font-mono text-xs", children: finding.rule_id }) }),
417
+ /* @__PURE__ */ jsx2("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx2(SeverityBadge, { severity: finding.severity }) }),
418
+ /* @__PURE__ */ jsx2("td", { className: "px-3 py-2 align-top", children: finding.message })
419
+ ] }, i);
420
+ }) })
421
+ ] }) })
422
+ ] });
423
+ }
424
+ function RouteLinks({
425
+ finding,
426
+ info
427
+ }) {
428
+ if (info === void 0) {
429
+ return /* @__PURE__ */ jsx2("span", { className: "font-mono text-xs", children: finding.route });
430
+ }
431
+ return /* @__PURE__ */ jsxs2("span", { className: "space-x-2", children: [
432
+ info.editUrl !== "" ? /* @__PURE__ */ jsx2(
433
+ "a",
434
+ {
435
+ href: info.editUrl,
436
+ className: "font-mono text-xs text-kumo-link hover:underline",
437
+ children: finding.route
438
+ }
439
+ ) : /* @__PURE__ */ jsx2("span", { className: "font-mono text-xs", children: finding.route }),
440
+ info.publishedUrl !== "" && /* @__PURE__ */ jsx2(
441
+ "a",
442
+ {
443
+ href: info.publishedUrl,
444
+ target: "_blank",
445
+ rel: "noopener noreferrer",
446
+ className: "text-xs text-kumo-link hover:underline",
447
+ children: "live \u2197"
448
+ }
449
+ ),
450
+ info.status !== "" && info.status !== "published" && /* @__PURE__ */ jsx2("span", { className: "text-xs text-kumo-subtle", children: info.status })
451
+ ] });
452
+ }
453
+ function SeverityBadge({ severity }) {
454
+ const classes = severity === "error" ? "bg-red-500/10 text-red-700 border-red-500/40" : severity === "warning" ? "bg-yellow-500/10 text-yellow-800 border-yellow-500/40" : "bg-kumo-tint text-kumo-subtle border-kumo-line";
455
+ return /* @__PURE__ */ jsx2(
456
+ "span",
457
+ {
458
+ className: `inline-block rounded border px-1.5 py-0.5 text-xs font-medium ${classes}`,
459
+ children: severity
460
+ }
461
+ );
462
+ }
463
+ function csrfHeaders() {
464
+ return {
465
+ "Content-Type": "application/json",
466
+ // emdash's apiFetch wrapper sets this on every mutation;
467
+ // mirroring it here so the plugin's REST endpoints get past the
468
+ // server's CSRF check the same way emdash's own admin does.
469
+ "X-EmDash-Request": "1"
470
+ };
471
+ }
472
+ function unwrap(body, res) {
473
+ if (body.error !== void 0) {
474
+ throw new Error(`${body.error.code}: ${body.error.message}`);
475
+ }
476
+ if (body.data === void 0) {
477
+ throw new Error(`Empty response (HTTP ${res.status})`);
478
+ }
479
+ return body.data;
480
+ }
481
+
482
+ // src/admin.tsx
483
+ var pages = {
484
+ "/findings": Findings,
485
+ // /facts is the truth-manifest authoring page. Block Kit can't render
486
+ // a textarea or copy-to-clipboard button, so this path goes through
487
+ // the React adminEntry. Same mechanism as /findings.
488
+ "/facts": Facts
489
+ };
490
+ export {
491
+ pages
492
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"configured.d.ts","sourceRoot":"","sources":["../src/configured.ts"],"names":[],"mappings":"AA6EA,MAAM,WAAW,uBAAuB;IACtC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAE,uBAA4B,GAAG,OAAO,CAmD3E;AAID,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"configured.d.ts","sourceRoot":"","sources":["../src/configured.ts"],"names":[],"mappings":"AAiFA,MAAM,WAAW,uBAAuB;IACtC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAE,uBAA4B,GAAG,OAAO,CAkF3E;AAID,eAAe,YAAY,CAAC"}