@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/CHANGELOG.md +121 -1
- package/dist/adapter.d.ts +12 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/admin/Facts.d.ts +3 -0
- package/dist/admin/Facts.d.ts.map +1 -0
- package/dist/admin/Findings.d.ts +3 -0
- package/dist/admin/Findings.d.ts.map +1 -0
- package/dist/admin.d.ts +7 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/admin.js +492 -0
- package/dist/configured.d.ts.map +1 -1
- package/dist/configured.js +456 -21
- package/dist/data-route.d.ts +49 -0
- package/dist/data-route.d.ts.map +1 -0
- package/dist/facts-route.d.ts +7 -0
- package/dist/facts-route.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -2
- package/dist/plugin.d.ts +13 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/sandbox-entry.js +47 -8
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/wasm-init.d.ts +3 -1
- package/dist/wasm-init.d.ts.map +1 -1
- package/package.json +16 -4
- package/wasm/aexeo_emdash_bridge.d.ts +16 -1
- package/wasm/aexeo_emdash_bridge.js +1 -1
- package/wasm/aexeo_emdash_bridge_bg.d.ts +12 -3
- package/wasm/aexeo_emdash_bridge_bg.js +65 -2
- package/wasm/aexeo_emdash_bridge_bg.wasm +0 -0
- package/wasm/aexeo_emdash_bridge_bg.wasm.d.ts +13 -11
package/dist/configured.js
CHANGED
|
@@ -5,7 +5,7 @@ var __export = (target, all) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
// src/adapter.ts
|
|
8
|
-
function
|
|
8
|
+
function adaptContentItem(content) {
|
|
9
9
|
const route = deriveRoute(content);
|
|
10
10
|
const title = stringOrEmpty(
|
|
11
11
|
content.seo?.title ?? content.data["title"] ?? content.slug ?? content.id
|
|
@@ -29,7 +29,16 @@ function contentItemToEmdashDocument(content) {
|
|
|
29
29
|
if (body !== null) {
|
|
30
30
|
document.body = body;
|
|
31
31
|
}
|
|
32
|
-
return
|
|
32
|
+
return {
|
|
33
|
+
document,
|
|
34
|
+
meta: {
|
|
35
|
+
id: content.id,
|
|
36
|
+
collection: content.type,
|
|
37
|
+
slug: content.slug,
|
|
38
|
+
status: content.status,
|
|
39
|
+
title
|
|
40
|
+
}
|
|
41
|
+
};
|
|
33
42
|
}
|
|
34
43
|
function deriveRoute(content) {
|
|
35
44
|
if (typeof content.slug === "string" && content.slug.length > 0) {
|
|
@@ -65,9 +74,11 @@ function isPortableTextArray(value) {
|
|
|
65
74
|
|
|
66
75
|
// src/plugin.ts
|
|
67
76
|
async function handleAfterSaveConfigured(event, ctx, evaluator) {
|
|
68
|
-
const
|
|
77
|
+
const adapted = adaptContentItem(event.content);
|
|
78
|
+
const document = adapted.document;
|
|
69
79
|
const { kv, log } = ctx;
|
|
70
|
-
|
|
80
|
+
const stored = { document, meta: adapted.meta };
|
|
81
|
+
await kv.set(documentKey(document.route), stored);
|
|
71
82
|
const result = await evaluator([document]);
|
|
72
83
|
if (!result.ok) {
|
|
73
84
|
log?.error?.(`afterSave evaluator failure (${result.reason})`, {
|
|
@@ -94,6 +105,7 @@ async function evaluateAndPersistAll(ctx, options) {
|
|
|
94
105
|
errors: []
|
|
95
106
|
};
|
|
96
107
|
const documents = [];
|
|
108
|
+
const adaptedByRoute = /* @__PURE__ */ new Map();
|
|
97
109
|
const documentRoutes = /* @__PURE__ */ new Set();
|
|
98
110
|
for (const collection of collections) {
|
|
99
111
|
let cursor;
|
|
@@ -104,9 +116,13 @@ async function evaluateAndPersistAll(ctx, options) {
|
|
|
104
116
|
...cursor === void 0 ? {} : { cursor }
|
|
105
117
|
});
|
|
106
118
|
for (const item of page.items) {
|
|
107
|
-
const
|
|
108
|
-
documents.push(document);
|
|
109
|
-
documentRoutes.add(document.route);
|
|
119
|
+
const adapted = adaptContentItem(item);
|
|
120
|
+
documents.push(adapted.document);
|
|
121
|
+
documentRoutes.add(adapted.document.route);
|
|
122
|
+
adaptedByRoute.set(adapted.document.route, {
|
|
123
|
+
document: adapted.document,
|
|
124
|
+
meta: adapted.meta
|
|
125
|
+
});
|
|
110
126
|
}
|
|
111
127
|
cursor = page.hasMore ? page.cursor : void 0;
|
|
112
128
|
} catch (err) {
|
|
@@ -117,8 +133,8 @@ async function evaluateAndPersistAll(ctx, options) {
|
|
|
117
133
|
} while (cursor !== void 0);
|
|
118
134
|
}
|
|
119
135
|
summary.documentsScanned = documents.length;
|
|
120
|
-
for (const
|
|
121
|
-
await kv.set(documentKey(document.route),
|
|
136
|
+
for (const stored of adaptedByRoute.values()) {
|
|
137
|
+
await kv.set(documentKey(stored.document.route), stored);
|
|
122
138
|
}
|
|
123
139
|
const result = await options.evaluator(documents);
|
|
124
140
|
if (!result.ok) {
|
|
@@ -153,9 +169,39 @@ function documentKey(route) {
|
|
|
153
169
|
const normalized = route === "" || route === "/" ? "/" : route;
|
|
154
170
|
return `document:${normalized}`;
|
|
155
171
|
}
|
|
172
|
+
var FACTS_KEY = "facts:current";
|
|
173
|
+
async function readStoredFacts(kv) {
|
|
174
|
+
const stored = await kv.get(FACTS_KEY);
|
|
175
|
+
return stored === void 0 ? null : stored;
|
|
176
|
+
}
|
|
156
177
|
async function readAllDocuments(kv) {
|
|
178
|
+
return (await readAllStoredDocuments(kv)).map((s) => s.document);
|
|
179
|
+
}
|
|
180
|
+
async function readAllStoredDocuments(kv) {
|
|
157
181
|
const entries = await kv.list("document:");
|
|
158
|
-
|
|
182
|
+
const out = [];
|
|
183
|
+
for (const entry of entries) {
|
|
184
|
+
const value = entry.value;
|
|
185
|
+
if (value === null || typeof value !== "object") continue;
|
|
186
|
+
if ("document" in value && "meta" in value) {
|
|
187
|
+
out.push(value);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if ("route" in value) {
|
|
191
|
+
const document = value;
|
|
192
|
+
out.push({
|
|
193
|
+
document,
|
|
194
|
+
meta: {
|
|
195
|
+
id: document.route,
|
|
196
|
+
collection: "",
|
|
197
|
+
slug: null,
|
|
198
|
+
status: "",
|
|
199
|
+
title: document.title ?? ""
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return out;
|
|
159
205
|
}
|
|
160
206
|
async function readFindings(kv, route) {
|
|
161
207
|
const stored = await kv.get(findingsKey(route));
|
|
@@ -172,7 +218,9 @@ __export(aexeo_emdash_bridge_bg_exports, {
|
|
|
172
218
|
__wbg_set_wasm: () => __wbg_set_wasm,
|
|
173
219
|
__wbindgen_init_externref_table: () => __wbindgen_init_externref_table,
|
|
174
220
|
evaluateDocuments: () => evaluateDocuments,
|
|
175
|
-
|
|
221
|
+
generateFactsPrompt: () => generateFactsPrompt,
|
|
222
|
+
scoreIntelligence: () => scoreIntelligence,
|
|
223
|
+
validateFactsManifest: () => validateFactsManifest
|
|
176
224
|
});
|
|
177
225
|
function evaluateDocuments(documents_json, config_json) {
|
|
178
226
|
let deferred4_0;
|
|
@@ -197,13 +245,13 @@ function evaluateDocuments(documents_json, config_json) {
|
|
|
197
245
|
wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
|
|
198
246
|
}
|
|
199
247
|
}
|
|
200
|
-
function
|
|
248
|
+
function generateFactsPrompt(documents_json) {
|
|
201
249
|
let deferred3_0;
|
|
202
250
|
let deferred3_1;
|
|
203
251
|
try {
|
|
204
252
|
const ptr0 = passStringToWasm0(documents_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
205
253
|
const len0 = WASM_VECTOR_LEN;
|
|
206
|
-
const ret = wasm.
|
|
254
|
+
const ret = wasm.generateFactsPrompt(ptr0, len0);
|
|
207
255
|
var ptr2 = ret[0];
|
|
208
256
|
var len2 = ret[1];
|
|
209
257
|
if (ret[3]) {
|
|
@@ -218,6 +266,52 @@ function scoreIntelligence(documents_json) {
|
|
|
218
266
|
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
|
|
219
267
|
}
|
|
220
268
|
}
|
|
269
|
+
function scoreIntelligence(documents_json, manifest_json) {
|
|
270
|
+
let deferred4_0;
|
|
271
|
+
let deferred4_1;
|
|
272
|
+
try {
|
|
273
|
+
const ptr0 = passStringToWasm0(documents_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
274
|
+
const len0 = WASM_VECTOR_LEN;
|
|
275
|
+
var ptr1 = isLikeNone(manifest_json) ? 0 : passStringToWasm0(manifest_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
276
|
+
var len1 = WASM_VECTOR_LEN;
|
|
277
|
+
const ret = wasm.scoreIntelligence(ptr0, len0, ptr1, len1);
|
|
278
|
+
var ptr3 = ret[0];
|
|
279
|
+
var len3 = ret[1];
|
|
280
|
+
if (ret[3]) {
|
|
281
|
+
ptr3 = 0;
|
|
282
|
+
len3 = 0;
|
|
283
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
284
|
+
}
|
|
285
|
+
deferred4_0 = ptr3;
|
|
286
|
+
deferred4_1 = len3;
|
|
287
|
+
return getStringFromWasm0(ptr3, len3);
|
|
288
|
+
} finally {
|
|
289
|
+
wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function validateFactsManifest(manifest_json, documents_json) {
|
|
293
|
+
let deferred4_0;
|
|
294
|
+
let deferred4_1;
|
|
295
|
+
try {
|
|
296
|
+
const ptr0 = passStringToWasm0(manifest_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
297
|
+
const len0 = WASM_VECTOR_LEN;
|
|
298
|
+
const ptr1 = passStringToWasm0(documents_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
299
|
+
const len1 = WASM_VECTOR_LEN;
|
|
300
|
+
const ret = wasm.validateFactsManifest(ptr0, len0, ptr1, len1);
|
|
301
|
+
var ptr3 = ret[0];
|
|
302
|
+
var len3 = ret[1];
|
|
303
|
+
if (ret[3]) {
|
|
304
|
+
ptr3 = 0;
|
|
305
|
+
len3 = 0;
|
|
306
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
307
|
+
}
|
|
308
|
+
deferred4_0 = ptr3;
|
|
309
|
+
deferred4_1 = len3;
|
|
310
|
+
return getStringFromWasm0(ptr3, len3);
|
|
311
|
+
} finally {
|
|
312
|
+
wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
221
315
|
function __wbg_Error_960c155d3d49e4c2(arg0, arg1) {
|
|
222
316
|
const ret = Error(getStringFromWasm0(arg0, arg1));
|
|
223
317
|
return ret;
|
|
@@ -333,11 +427,306 @@ async function evaluateDocuments2(documentsJson, configJson) {
|
|
|
333
427
|
ensureInitialized();
|
|
334
428
|
return evaluateDocuments(documentsJson, configJson);
|
|
335
429
|
}
|
|
336
|
-
async function scoreIntelligence2(documentsJson) {
|
|
430
|
+
async function scoreIntelligence2(documentsJson, manifestJson) {
|
|
431
|
+
ensureInitialized();
|
|
432
|
+
return scoreIntelligence(documentsJson, manifestJson ?? void 0);
|
|
433
|
+
}
|
|
434
|
+
async function generateFactsPrompt2(documentsJson) {
|
|
435
|
+
ensureInitialized();
|
|
436
|
+
return generateFactsPrompt(documentsJson);
|
|
437
|
+
}
|
|
438
|
+
async function validateFactsManifest2(manifestJson, documentsJson) {
|
|
337
439
|
ensureInitialized();
|
|
338
|
-
return
|
|
440
|
+
return validateFactsManifest(manifestJson, documentsJson);
|
|
339
441
|
}
|
|
340
442
|
|
|
443
|
+
// src/data-route.ts
|
|
444
|
+
async function handleDataRoute(ctx, options) {
|
|
445
|
+
let summary = null;
|
|
446
|
+
if (options.refresh) {
|
|
447
|
+
summary = await evaluateAndPersistAll(ctx, {
|
|
448
|
+
collections: options.collections,
|
|
449
|
+
evaluator: options.evaluator
|
|
450
|
+
});
|
|
451
|
+
await persistManifestStateFindings(ctx);
|
|
452
|
+
}
|
|
453
|
+
const payload = await buildFindingsPayload(ctx);
|
|
454
|
+
return { payload, summary };
|
|
455
|
+
}
|
|
456
|
+
async function buildFindingsPayload(ctx) {
|
|
457
|
+
const stored = await readAllStoredDocuments(ctx.kv);
|
|
458
|
+
const documents = /* @__PURE__ */ new Map();
|
|
459
|
+
for (const entry of stored) {
|
|
460
|
+
documents.set(entry.document.route, entry);
|
|
461
|
+
}
|
|
462
|
+
const entries = await ctx.kv.list(
|
|
463
|
+
"findings:"
|
|
464
|
+
);
|
|
465
|
+
const findings = [];
|
|
466
|
+
const sitewide = [];
|
|
467
|
+
const perRoute = /* @__PURE__ */ new Map();
|
|
468
|
+
for (const entry of entries) {
|
|
469
|
+
if (entry.value === null) continue;
|
|
470
|
+
const route = entry.key.replace(/^findings:/, "");
|
|
471
|
+
if (route === "*") {
|
|
472
|
+
sitewide.push(...entry.value.findings);
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
let bucket = perRoute.get(route);
|
|
476
|
+
if (bucket === void 0) {
|
|
477
|
+
bucket = { findings: [], errors: 0, warnings: 0 };
|
|
478
|
+
perRoute.set(route, bucket);
|
|
479
|
+
}
|
|
480
|
+
for (const finding of entry.value.findings) {
|
|
481
|
+
bucket.findings.push(finding);
|
|
482
|
+
if (finding.severity === "error") bucket.errors += 1;
|
|
483
|
+
else if (finding.severity === "warning") bucket.warnings += 1;
|
|
484
|
+
findings.push({ ...finding, route });
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
findings.sort((a, b) => severityRank(a.severity) - severityRank(b.severity));
|
|
488
|
+
const siteUrl = ctx.site?.url ?? "";
|
|
489
|
+
const routes = [];
|
|
490
|
+
for (const [route, bucket] of perRoute) {
|
|
491
|
+
const stored2 = documents.get(route);
|
|
492
|
+
routes.push({
|
|
493
|
+
route,
|
|
494
|
+
title: stored2?.meta.title ?? route,
|
|
495
|
+
status: stored2?.meta.status ?? "",
|
|
496
|
+
collection: stored2?.meta.collection ?? "",
|
|
497
|
+
id: stored2?.meta.id ?? "",
|
|
498
|
+
editUrl: stored2 ? buildEditUrl(stored2.meta) : "",
|
|
499
|
+
publishedUrl: stored2 ? buildPublishedUrl(stored2.meta, route, siteUrl) : "",
|
|
500
|
+
findingCount: bucket.findings.length,
|
|
501
|
+
errorCount: bucket.errors,
|
|
502
|
+
warningCount: bucket.warnings
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
routes.sort((a, b) => b.errorCount - a.errorCount || a.route.localeCompare(b.route));
|
|
506
|
+
const cached = await ctx.kv.get(
|
|
507
|
+
MANIFEST_FINDINGS_KEY
|
|
508
|
+
);
|
|
509
|
+
if (cached !== void 0 && cached !== null) {
|
|
510
|
+
sitewide.push(...cached.findings);
|
|
511
|
+
}
|
|
512
|
+
return {
|
|
513
|
+
routes,
|
|
514
|
+
findings,
|
|
515
|
+
totals: {
|
|
516
|
+
routes: routes.length,
|
|
517
|
+
findings: findings.length,
|
|
518
|
+
errors: findings.filter((f) => f.severity === "error").length,
|
|
519
|
+
warnings: findings.filter((f) => f.severity === "warning").length,
|
|
520
|
+
documentsIndexed: documents.size
|
|
521
|
+
},
|
|
522
|
+
sitewideFindings: sitewide
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
var MANIFEST_FINDINGS_KEY = "meta:facts-findings";
|
|
526
|
+
async function persistManifestStateFindings(ctx) {
|
|
527
|
+
const findings = await deriveManifestStateFindings(ctx);
|
|
528
|
+
await ctx.kv.set(MANIFEST_FINDINGS_KEY, { findings });
|
|
529
|
+
}
|
|
530
|
+
async function deriveManifestStateFindings(ctx) {
|
|
531
|
+
const manifest = await readStoredFacts(ctx.kv);
|
|
532
|
+
if (manifest === null) {
|
|
533
|
+
return [
|
|
534
|
+
{
|
|
535
|
+
rule_id: "FACTS001",
|
|
536
|
+
message: "No truth manifest authored yet. Open the Truth manifest page to generate an LLM authoring prompt and save your facts.json.",
|
|
537
|
+
severity: "warning",
|
|
538
|
+
path: "",
|
|
539
|
+
line: 0,
|
|
540
|
+
column: 0,
|
|
541
|
+
scope: "sitewide",
|
|
542
|
+
suggestion: null
|
|
543
|
+
}
|
|
544
|
+
];
|
|
545
|
+
}
|
|
546
|
+
const documents = await readAllDocuments(ctx.kv);
|
|
547
|
+
if (documents.length === 0) {
|
|
548
|
+
return [];
|
|
549
|
+
}
|
|
550
|
+
try {
|
|
551
|
+
const raw = await validateFactsManifest2(
|
|
552
|
+
JSON.stringify(manifest),
|
|
553
|
+
JSON.stringify(documents)
|
|
554
|
+
);
|
|
555
|
+
const result = JSON.parse(raw);
|
|
556
|
+
const out = [];
|
|
557
|
+
if (!result.validation.valid || result.validation.errors.length > 0) {
|
|
558
|
+
out.push({
|
|
559
|
+
rule_id: "FACTS001",
|
|
560
|
+
message: `Truth manifest fails shape validation: ${result.validation.errors.slice(0, 3).join("; ")}`,
|
|
561
|
+
severity: "error",
|
|
562
|
+
path: "",
|
|
563
|
+
line: 0,
|
|
564
|
+
column: 0,
|
|
565
|
+
scope: "sitewide",
|
|
566
|
+
suggestion: null
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
const errCount = result.assessment.mismatches.filter(
|
|
570
|
+
(m) => m.severity === "error"
|
|
571
|
+
).length;
|
|
572
|
+
const warnCount = result.assessment.mismatches.length - errCount;
|
|
573
|
+
if (result.assessment.mismatches.length > 0) {
|
|
574
|
+
out.push({
|
|
575
|
+
rule_id: "FACTS003",
|
|
576
|
+
message: `Truth manifest disagrees with on-page schema.org: ${errCount} errors, ${warnCount} warnings. Open the Truth manifest page to review and refresh.`,
|
|
577
|
+
severity: errCount > 0 ? "error" : "warning",
|
|
578
|
+
path: "",
|
|
579
|
+
line: 0,
|
|
580
|
+
column: 0,
|
|
581
|
+
scope: "sitewide",
|
|
582
|
+
suggestion: null
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
return out;
|
|
586
|
+
} catch {
|
|
587
|
+
return [];
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
function severityRank(severity) {
|
|
591
|
+
if (severity === "error") return 0;
|
|
592
|
+
if (severity === "warning") return 1;
|
|
593
|
+
return 2;
|
|
594
|
+
}
|
|
595
|
+
function buildEditUrl(meta) {
|
|
596
|
+
if (meta.collection === "" || meta.id === "") return "";
|
|
597
|
+
return `/_emdash/admin/content/${encodeURIComponent(meta.collection)}/${encodeURIComponent(meta.id)}`;
|
|
598
|
+
}
|
|
599
|
+
function buildPublishedUrl(meta, route, siteUrl) {
|
|
600
|
+
if (meta.status !== "published") return "";
|
|
601
|
+
if (siteUrl === "") return "";
|
|
602
|
+
const trimmed = siteUrl.endsWith("/") ? siteUrl.slice(0, -1) : siteUrl;
|
|
603
|
+
return `${trimmed}${route}`;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// src/facts-route.ts
|
|
607
|
+
async function handleFactsRoute(ctx) {
|
|
608
|
+
const body = ctx.input ?? {};
|
|
609
|
+
switch (body.kind) {
|
|
610
|
+
case "data":
|
|
611
|
+
return await handleData(ctx);
|
|
612
|
+
case "prompt":
|
|
613
|
+
return await handlePrompt(ctx);
|
|
614
|
+
case "validate":
|
|
615
|
+
return await handleValidate(ctx, body);
|
|
616
|
+
case "save":
|
|
617
|
+
return await handleSave(ctx, body);
|
|
618
|
+
default:
|
|
619
|
+
return {
|
|
620
|
+
error: {
|
|
621
|
+
code: "unknown_kind",
|
|
622
|
+
message: `unknown facts route kind: ${String(body.kind)}`
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
async function handleData(ctx) {
|
|
628
|
+
const manifest = await readStoredFacts(ctx.kv);
|
|
629
|
+
return {
|
|
630
|
+
data: {
|
|
631
|
+
manifest,
|
|
632
|
+
// The presence flag lets the React component branch on
|
|
633
|
+
// "show authoring CTA" vs "show 'manifest stored' state" without
|
|
634
|
+
// having to introspect the manifest shape.
|
|
635
|
+
present: manifest !== null
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
async function handlePrompt(ctx) {
|
|
640
|
+
const documents = await readAllDocuments(ctx.kv);
|
|
641
|
+
if (documents.length === 0) {
|
|
642
|
+
return {
|
|
643
|
+
error: {
|
|
644
|
+
code: "no_documents",
|
|
645
|
+
message: "no documents indexed yet \u2014 click Refresh on the Findings page first, then come back to author the manifest"
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
const prompt = await generateFactsPrompt2(JSON.stringify(documents));
|
|
650
|
+
return { data: { prompt } };
|
|
651
|
+
}
|
|
652
|
+
async function handleValidate(ctx, body) {
|
|
653
|
+
if (typeof body.manifest_json !== "string" || body.manifest_json.length === 0) {
|
|
654
|
+
return {
|
|
655
|
+
error: {
|
|
656
|
+
code: "missing_manifest",
|
|
657
|
+
message: "manifest_json field is required"
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
const documents = await readAllDocuments(ctx.kv);
|
|
662
|
+
try {
|
|
663
|
+
const raw = await validateFactsManifest2(
|
|
664
|
+
body.manifest_json,
|
|
665
|
+
JSON.stringify(documents)
|
|
666
|
+
);
|
|
667
|
+
return { data: JSON.parse(raw) };
|
|
668
|
+
} catch (error) {
|
|
669
|
+
return {
|
|
670
|
+
error: {
|
|
671
|
+
code: "validate_failed",
|
|
672
|
+
message: error instanceof Error ? error.message : String(error)
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
async function handleSave(ctx, body) {
|
|
678
|
+
if (typeof body.manifest_json !== "string" || body.manifest_json.length === 0) {
|
|
679
|
+
return {
|
|
680
|
+
error: {
|
|
681
|
+
code: "missing_manifest",
|
|
682
|
+
message: "manifest_json field is required"
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
const documents = await readAllDocuments(ctx.kv);
|
|
687
|
+
let validation;
|
|
688
|
+
try {
|
|
689
|
+
const raw = await validateFactsManifest2(
|
|
690
|
+
body.manifest_json,
|
|
691
|
+
JSON.stringify(documents)
|
|
692
|
+
);
|
|
693
|
+
const parsed2 = JSON.parse(raw);
|
|
694
|
+
validation = parsed2.validation;
|
|
695
|
+
} catch (error) {
|
|
696
|
+
return {
|
|
697
|
+
error: {
|
|
698
|
+
code: "validate_failed",
|
|
699
|
+
message: error instanceof Error ? error.message : String(error)
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
if (!validation.valid || validation.errors.length > 0) {
|
|
704
|
+
return {
|
|
705
|
+
error: {
|
|
706
|
+
code: "validation_failed",
|
|
707
|
+
message: `manifest does not pass shape validation: ${validation.errors.slice(0, 3).join("; ")}`
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
let parsed;
|
|
712
|
+
try {
|
|
713
|
+
parsed = JSON.parse(body.manifest_json);
|
|
714
|
+
} catch (error) {
|
|
715
|
+
return {
|
|
716
|
+
error: {
|
|
717
|
+
code: "parse_failed",
|
|
718
|
+
message: error instanceof Error ? error.message : String(error)
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
await ctx.kv.set(FACTS_KEY, parsed);
|
|
723
|
+
await persistManifestStateFindings(ctx);
|
|
724
|
+
return { data: { saved: true } };
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// src/version.ts
|
|
728
|
+
var PACKAGE_VERSION = "0.3.0";
|
|
729
|
+
|
|
341
730
|
// src/configured.ts
|
|
342
731
|
import { definePlugin } from "emdash";
|
|
343
732
|
var inProcessEvaluator = async (documents) => {
|
|
@@ -361,7 +750,7 @@ function createPlugin(options = {}) {
|
|
|
361
750
|
const collections = options.collections === void 0 ? DEFAULT_COLLECTIONS : [...options.collections];
|
|
362
751
|
return definePlugin({
|
|
363
752
|
id: "aexeo-seogeo",
|
|
364
|
-
version:
|
|
753
|
+
version: PACKAGE_VERSION,
|
|
365
754
|
capabilities: ["read:content"],
|
|
366
755
|
hooks: {
|
|
367
756
|
// afterSave processes one saved document at a time — collections
|
|
@@ -375,6 +764,34 @@ function createPlugin(options = {}) {
|
|
|
375
764
|
// every request handles the same set without re-reading options.
|
|
376
765
|
admin: {
|
|
377
766
|
handler: (ctx) => handleAdminRoute(ctx, collections)
|
|
767
|
+
},
|
|
768
|
+
// JSON data endpoint for the React adminEntry. Two routes:
|
|
769
|
+
// POST /_emdash/api/plugins/aexeo-seogeo/data — read current findings
|
|
770
|
+
// POST /_emdash/api/plugins/aexeo-seogeo/refresh — sweep + read
|
|
771
|
+
// Returning JSON (not Block Kit blocks) lets the React
|
|
772
|
+
// <Findings/> component render proper <a href> links to the
|
|
773
|
+
// emdash edit page and the public site, which Block Kit can't
|
|
774
|
+
// express in any element type as of emdash 0.8.0.
|
|
775
|
+
data: {
|
|
776
|
+
handler: async (ctx) => (await handleDataRoute(ctx, {
|
|
777
|
+
collections,
|
|
778
|
+
evaluator: inProcessEvaluator,
|
|
779
|
+
refresh: false
|
|
780
|
+
})).payload
|
|
781
|
+
},
|
|
782
|
+
refresh: {
|
|
783
|
+
handler: (ctx) => handleDataRoute(ctx, {
|
|
784
|
+
collections,
|
|
785
|
+
evaluator: inProcessEvaluator,
|
|
786
|
+
refresh: true
|
|
787
|
+
})
|
|
788
|
+
},
|
|
789
|
+
// /facts route serves the truth-manifest authoring UI. It
|
|
790
|
+
// multiplexes four operations (data / prompt / validate / save)
|
|
791
|
+
// onto one POST endpoint via a "kind" body field — see
|
|
792
|
+
// facts-route.ts for the full contract.
|
|
793
|
+
facts: {
|
|
794
|
+
handler: (ctx) => handleFactsRoute(ctx)
|
|
378
795
|
}
|
|
379
796
|
},
|
|
380
797
|
admin: {
|
|
@@ -385,7 +802,8 @@ function createPlugin(options = {}) {
|
|
|
385
802
|
// duplicate "SEO findings" sidebar entries — that was the
|
|
386
803
|
// visible 0.1.0 / 0.1.1 bug fixed in 0.1.2.
|
|
387
804
|
{ path: "/findings", label: "SEO findings" },
|
|
388
|
-
{ path: "/document", label: "Document SEO" }
|
|
805
|
+
{ path: "/document", label: "Document SEO" },
|
|
806
|
+
{ path: "/facts", label: "Truth manifest" }
|
|
389
807
|
],
|
|
390
808
|
widgets: [
|
|
391
809
|
{ id: "seogeo-score", size: "third", title: "SEO score" }
|
|
@@ -580,14 +998,16 @@ async function renderScoreWidget(ctx) {
|
|
|
580
998
|
]
|
|
581
999
|
};
|
|
582
1000
|
}
|
|
583
|
-
const
|
|
1001
|
+
const facts = await readStoredFacts(ctx.kv);
|
|
1002
|
+
const score = await scoreLocally(documents, facts);
|
|
1003
|
+
const truthLabel = formatTruthLabel(score);
|
|
584
1004
|
const blocks = [
|
|
585
1005
|
{
|
|
586
1006
|
type: "stats",
|
|
587
1007
|
items: [
|
|
588
1008
|
{ label: "Overall", value: `${score.overall_score}` },
|
|
589
1009
|
{ label: "Citation", value: `${score.citation_readiness_score}` },
|
|
590
|
-
{ label:
|
|
1010
|
+
{ label: truthLabel, value: `${score.truth_consistency_score}` },
|
|
591
1011
|
{ label: "Answers", value: `${score.answer_pack_score}` }
|
|
592
1012
|
]
|
|
593
1013
|
}
|
|
@@ -604,10 +1024,25 @@ async function renderScoreWidget(ctx) {
|
|
|
604
1024
|
}
|
|
605
1025
|
return { blocks };
|
|
606
1026
|
}
|
|
607
|
-
async function scoreLocally(documents) {
|
|
608
|
-
const
|
|
1027
|
+
async function scoreLocally(documents, manifest = null) {
|
|
1028
|
+
const manifestJson = manifest === null ? null : JSON.stringify(manifest);
|
|
1029
|
+
const raw = await scoreIntelligence2(JSON.stringify(documents), manifestJson);
|
|
609
1030
|
return JSON.parse(raw);
|
|
610
1031
|
}
|
|
1032
|
+
function formatTruthLabel(score) {
|
|
1033
|
+
switch (score.structured_truth_source) {
|
|
1034
|
+
case "schema_and_manifest":
|
|
1035
|
+
return "Truth (manifest+schema)";
|
|
1036
|
+
case "manifest":
|
|
1037
|
+
return "Truth (manifest only)";
|
|
1038
|
+
case "schema":
|
|
1039
|
+
return "Truth (schema only)";
|
|
1040
|
+
case "none":
|
|
1041
|
+
return "Truth (no signal)";
|
|
1042
|
+
default:
|
|
1043
|
+
return "Truth";
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
611
1046
|
function topBlockersLine(score) {
|
|
612
1047
|
const top = score.blockers.slice(0, 3).map((b) => b.message);
|
|
613
1048
|
if (top.length === 0) return "No blockers identified.";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { EvaluatorFn, RefreshSummary, SandboxCtx } from "./plugin.js";
|
|
2
|
+
import type { Finding } from "./types.js";
|
|
3
|
+
export interface FindingsPayload {
|
|
4
|
+
routes: RouteSummary[];
|
|
5
|
+
findings: FindingRow[];
|
|
6
|
+
totals: {
|
|
7
|
+
routes: number;
|
|
8
|
+
findings: number;
|
|
9
|
+
errors: number;
|
|
10
|
+
warnings: number;
|
|
11
|
+
documentsIndexed: number;
|
|
12
|
+
};
|
|
13
|
+
sitewideFindings: Finding[];
|
|
14
|
+
}
|
|
15
|
+
export interface RouteSummary {
|
|
16
|
+
route: string;
|
|
17
|
+
title: string;
|
|
18
|
+
status: string;
|
|
19
|
+
collection: string;
|
|
20
|
+
id: string;
|
|
21
|
+
editUrl: string;
|
|
22
|
+
publishedUrl: string;
|
|
23
|
+
findingCount: number;
|
|
24
|
+
errorCount: number;
|
|
25
|
+
warningCount: number;
|
|
26
|
+
}
|
|
27
|
+
export interface FindingRow {
|
|
28
|
+
route: string;
|
|
29
|
+
rule_id: string;
|
|
30
|
+
severity: string;
|
|
31
|
+
message: string;
|
|
32
|
+
path: string;
|
|
33
|
+
line: number;
|
|
34
|
+
column: number;
|
|
35
|
+
scope: string;
|
|
36
|
+
suggestion: string | null;
|
|
37
|
+
}
|
|
38
|
+
interface DataRouteOptions {
|
|
39
|
+
collections: readonly string[];
|
|
40
|
+
evaluator: EvaluatorFn;
|
|
41
|
+
refresh: boolean;
|
|
42
|
+
}
|
|
43
|
+
export declare function handleDataRoute(ctx: SandboxCtx, options: DataRouteOptions): Promise<{
|
|
44
|
+
payload: FindingsPayload;
|
|
45
|
+
summary: RefreshSummary | null;
|
|
46
|
+
}>;
|
|
47
|
+
export declare function persistManifestStateFindings(ctx: SandboxCtx): Promise<void>;
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=data-route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-route.d.ts","sourceRoot":"","sources":["../src/data-route.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,UAAU,EAEX,MAAM,aAAa,CAAC;AAQrB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAM1C,MAAM,WAAW,eAAe;IAG9B,MAAM,EAAE,YAAY,EAAE,CAAC;IAIvB,QAAQ,EAAE,UAAU,EAAE,CAAC;IAIvB,MAAM,EAAE;QACN,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;IAIF,gBAAgB,EAAE,OAAO,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IAGd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IAIX,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,UAAU,gBAAgB;IACxB,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,SAAS,EAAE,WAAW,CAAC;IAIvB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC;IACT,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;CAChC,CAAC,CAgBD;AAgGD,wBAAsB,4BAA4B,CAChD,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,IAAI,CAAC,CAGf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facts-route.d.ts","sourceRoot":"","sources":["../src/facts-route.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAa9C,UAAU,YAAa,SAAQ,UAAU;IACvC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAmB1E"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,cAAc,CAAC;AAYtB,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IAOnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,UAAU,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvD,YAAY,EAAE,SAAS;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACxE;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAED,wBAAgB,YAAY,CAC1B,OAAO,GAAE,mBAAwB,GAChC,0BAA0B,CA+C5B"}
|