@aeptus/aexeo-emdash 0.8.16 → 0.8.18

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.
Files changed (73) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/INSTALL.md +9 -10
  3. package/LICENSE +0 -0
  4. package/README.md +6 -3
  5. package/dist/adapter.d.ts +32 -1
  6. package/dist/adapter.d.ts.map +1 -1
  7. package/dist/admin/Absorbability.d.ts +0 -0
  8. package/dist/admin/Absorbability.d.ts.map +0 -0
  9. package/dist/admin/Accessibility.d.ts +0 -0
  10. package/dist/admin/Accessibility.d.ts.map +0 -0
  11. package/dist/admin/Citability.d.ts +0 -0
  12. package/dist/admin/Citability.d.ts.map +0 -0
  13. package/dist/admin/EntityLegitimacy.d.ts +0 -0
  14. package/dist/admin/EntityLegitimacy.d.ts.map +0 -0
  15. package/dist/admin/EntityPresence.d.ts +0 -0
  16. package/dist/admin/EntityPresence.d.ts.map +0 -0
  17. package/dist/admin/Facts.d.ts +0 -0
  18. package/dist/admin/Facts.d.ts.map +0 -0
  19. package/dist/admin/Findings.d.ts +0 -0
  20. package/dist/admin/Findings.d.ts.map +0 -0
  21. package/dist/admin/PillarView.d.ts +0 -0
  22. package/dist/admin/PillarView.d.ts.map +0 -0
  23. package/dist/admin/Retrievability.d.ts +0 -0
  24. package/dist/admin/Retrievability.d.ts.map +0 -0
  25. package/dist/admin.d.ts +0 -0
  26. package/dist/admin.d.ts.map +0 -0
  27. package/dist/admin.js +0 -0
  28. package/dist/configured.d.ts +0 -0
  29. package/dist/configured.d.ts.map +1 -1
  30. package/dist/configured.js +247 -60
  31. package/dist/data-route.d.ts +0 -0
  32. package/dist/data-route.d.ts.map +1 -1
  33. package/dist/evaluator-sandbox.d.ts +0 -0
  34. package/dist/evaluator-sandbox.d.ts.map +0 -0
  35. package/dist/evaluator.d.ts +0 -0
  36. package/dist/evaluator.d.ts.map +0 -0
  37. package/dist/facts-route.d.ts +0 -0
  38. package/dist/facts-route.d.ts.map +0 -0
  39. package/dist/index.d.ts +0 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +12 -22
  42. package/dist/indexnow.d.ts +0 -0
  43. package/dist/indexnow.d.ts.map +0 -0
  44. package/dist/mcp.d.ts +0 -0
  45. package/dist/mcp.d.ts.map +0 -0
  46. package/dist/plugin.d.ts +3 -1
  47. package/dist/plugin.d.ts.map +1 -1
  48. package/dist/presence-check.d.ts +0 -0
  49. package/dist/presence-check.d.ts.map +0 -0
  50. package/dist/presence-route.d.ts +0 -0
  51. package/dist/presence-route.d.ts.map +0 -0
  52. package/dist/sandbox-entry.d.ts +1 -1
  53. package/dist/sandbox-entry.d.ts.map +1 -1
  54. package/dist/sandbox-entry.js +363 -125
  55. package/dist/sandbox.d.ts +0 -0
  56. package/dist/sandbox.d.ts.map +1 -1
  57. package/dist/sidecar.d.ts +0 -0
  58. package/dist/sidecar.d.ts.map +1 -1
  59. package/dist/suppressions.d.ts +0 -0
  60. package/dist/suppressions.d.ts.map +0 -0
  61. package/dist/types.d.ts +0 -0
  62. package/dist/types.d.ts.map +0 -0
  63. package/dist/version.d.ts +1 -1
  64. package/dist/version.d.ts.map +0 -0
  65. package/dist/wasm-init.d.ts +0 -0
  66. package/dist/wasm-init.d.ts.map +0 -0
  67. package/package.json +8 -4
  68. package/wasm/aexeo_emdash_bridge.d.ts +0 -0
  69. package/wasm/aexeo_emdash_bridge.js +0 -0
  70. package/wasm/aexeo_emdash_bridge_bg.d.ts +0 -0
  71. package/wasm/aexeo_emdash_bridge_bg.js +0 -0
  72. package/wasm/aexeo_emdash_bridge_bg.wasm +0 -0
  73. package/wasm/aexeo_emdash_bridge_bg.wasm.d.ts +0 -0
@@ -1,13 +1,40 @@
1
1
  // src/adapter.ts
2
- function adaptContentItem(content) {
3
- const route = deriveRoute(content);
2
+ async function adaptContentItemWithContext(content, contentApi, defaultLocale) {
3
+ const publicUrl = content.status === "published" ? await contentApi.getPublicUrl(content.type, content.id) : null;
4
+ const route = publicUrl === null ? deriveRoute(content) : routeFromPublicUrl(publicUrl);
5
+ const adapted = adaptContentItem(content, {
6
+ route,
7
+ publicUrl,
8
+ ...defaultLocale === void 0 ? {} : { defaultLocale }
9
+ });
10
+ const translationSet = await contentApi.getTranslations(
11
+ content.type,
12
+ content.id
13
+ );
14
+ const alternates = await Promise.all(
15
+ translationSet.translations.filter(
16
+ (translation) => translation.status === "published" && typeof translation.locale === "string" && translation.locale.length > 0
17
+ ).map(async (translation) => {
18
+ const href = translation.id === content.id ? publicUrl : await contentApi.getPublicUrl(content.type, translation.id);
19
+ if (href === null) return null;
20
+ return { lang: translation.locale, href };
21
+ })
22
+ );
23
+ const uniqueAlternates = /* @__PURE__ */ new Map();
24
+ for (const alternate of alternates) {
25
+ if (alternate !== null) uniqueAlternates.set(alternate.lang, alternate);
26
+ }
27
+ if (uniqueAlternates.size > 0) {
28
+ adapted.document.alternates = [...uniqueAlternates.values()];
29
+ }
30
+ return adapted;
31
+ }
32
+ function adaptContentItem(content, options = {}) {
33
+ const route = options.route ?? deriveRoute(content);
4
34
  const title = stringOrEmpty(
5
35
  content.seo?.title ?? content.data["title"] ?? content.slug ?? content.id
6
36
  );
7
- const document = {
8
- route,
9
- title
10
- };
37
+ const document = { route, title };
11
38
  const description = content.seo?.description ?? content.data["description"];
12
39
  if (typeof description === "string" && description.length > 0) {
13
40
  document.description = description;
@@ -16,13 +43,12 @@ function adaptContentItem(content) {
16
43
  if (typeof canonical === "string" && canonical.length > 0) {
17
44
  document.canonical = canonical;
18
45
  }
19
- if (content.locale !== null) {
20
- document.lang = content.locale;
46
+ const locale = content.locale || options.defaultLocale;
47
+ if (typeof locale === "string" && locale.length > 0) {
48
+ document.lang = locale;
21
49
  }
22
50
  const body = extractPortableText(content.data);
23
- if (body !== null) {
24
- document.body = body;
25
- }
51
+ if (body !== null) document.body = body;
26
52
  return {
27
53
  document,
28
54
  meta: {
@@ -30,40 +56,202 @@ function adaptContentItem(content) {
30
56
  collection: content.type,
31
57
  slug: content.slug,
32
58
  status: content.status,
33
- title
59
+ title,
60
+ publicUrl: options.publicUrl ?? null
34
61
  }
35
62
  };
36
63
  }
37
64
  function deriveRoute(content) {
38
- if (typeof content.slug === "string" && content.slug.length > 0) {
39
- return content.slug.startsWith("/") ? content.slug : `/${content.slug}`;
65
+ return `/${encodeURIComponent(content.type)}/${encodeURIComponent(content.id)}`;
66
+ }
67
+ function routeFromPublicUrl(publicUrl) {
68
+ try {
69
+ return new URL(publicUrl).pathname || "/";
70
+ } catch (cause) {
71
+ throw new Error(`EmDash returned an invalid public URL: ${publicUrl}`, {
72
+ cause
73
+ });
40
74
  }
41
- return `/${content.type}/${content.id}`;
42
75
  }
43
76
  function stringOrEmpty(value) {
44
77
  return typeof value === "string" ? value : "";
45
78
  }
46
79
  function extractPortableText(data) {
47
- const candidates = ["body", "content"];
48
- for (const slug of candidates) {
80
+ for (const slug of ["body", "content"]) {
49
81
  const value = data[slug];
50
- if (isPortableTextArray(value)) {
51
- return value;
82
+ if (isPortableTextArray(value)) return value;
83
+ if (isEmdashBlocksArray(value, slug)) return blocksToPortableText(value);
84
+ if (typeof value === "string" && value.trim().length > 0) {
85
+ return [portableTextBlock(value.trim(), `${slug}-text`)];
52
86
  }
53
87
  }
54
- for (const value of Object.values(data)) {
55
- if (isPortableTextArray(value)) {
56
- return value;
57
- }
88
+ const blocks = data["blocks"];
89
+ if (isPortableTextArray(blocks)) return blocks;
90
+ if (isEmdashBlocksArray(blocks, "blocks")) return blocksToPortableText(blocks);
91
+ for (const [field, value] of Object.entries(data)) {
92
+ if (field === "body" || field === "content" || field === "blocks") continue;
93
+ if (isPortableTextArray(value)) return value;
94
+ if (isEmdashBlocksArray(value, field)) return blocksToPortableText(value);
58
95
  }
59
96
  return null;
60
97
  }
61
98
  function isPortableTextArray(value) {
62
- if (!Array.isArray(value) || value.length === 0) {
63
- return false;
99
+ return Array.isArray(value) && value.length > 0 && value.every(
100
+ (item) => isRecord(item) && item["_type"] === "block" && Array.isArray(item["children"]) && item["children"].every(
101
+ (child) => isRecord(child) && typeof child["text"] === "string"
102
+ )
103
+ );
104
+ }
105
+ function isEmdashBlocksArray(value, field) {
106
+ if (!Array.isArray(value) || value.length === 0) return false;
107
+ return value.every(
108
+ (item) => isRecord(item) && typeof item["_type"] === "string" && typeof item["_key"] === "string" && (typeof item["_version"] === "number" || field === "blocks")
109
+ );
110
+ }
111
+ function blocksToPortableText(blocks) {
112
+ const paragraphs = [];
113
+ for (const block of blocks) {
114
+ const segments = [];
115
+ collectText(block, "", segments);
116
+ const text = segments.map((segment) => segment.trim()).filter(Boolean).join(" ");
117
+ if (text.length > 0) {
118
+ paragraphs.push(portableTextBlock(text, stringOrEmpty(block["_key"])));
119
+ }
120
+ }
121
+ return paragraphs;
122
+ }
123
+ function collectText(value, key, out) {
124
+ if (typeof value === "string") {
125
+ if (!isStructuralField(key) && value.trim().length > 0) out.push(value);
126
+ return;
127
+ }
128
+ if (Array.isArray(value)) {
129
+ for (const item of value) collectText(item, key, out);
130
+ return;
131
+ }
132
+ if (!isRecord(value)) return;
133
+ for (const [childKey, childValue] of Object.entries(value)) {
134
+ if (isStructuralField(childKey)) continue;
135
+ collectText(childValue, childKey, out);
136
+ }
137
+ }
138
+ var STRUCTURAL_FIELDS = /* @__PURE__ */ new Set([
139
+ "_key",
140
+ "_ref",
141
+ "_type",
142
+ "_version",
143
+ "asset",
144
+ "align",
145
+ "alignment",
146
+ "autoplay",
147
+ "color",
148
+ "controls",
149
+ "focalpoint",
150
+ "height",
151
+ "href",
152
+ "id",
153
+ "layout",
154
+ "level",
155
+ "loop",
156
+ "markdefs",
157
+ "marks",
158
+ "mime_type",
159
+ "mimetype",
160
+ "position",
161
+ "rel",
162
+ "size",
163
+ "src",
164
+ "style",
165
+ "target",
166
+ "theme",
167
+ "tone",
168
+ "url",
169
+ "variant",
170
+ "width"
171
+ ]);
172
+ function isStructuralField(key) {
173
+ const normalized = key.toLowerCase();
174
+ return normalized.startsWith("_") || STRUCTURAL_FIELDS.has(normalized);
175
+ }
176
+ function portableTextBlock(text, key) {
177
+ return {
178
+ _type: "block",
179
+ ...key.length === 0 ? {} : { _key: key },
180
+ children: [
181
+ {
182
+ _type: "span",
183
+ ...key.length === 0 ? {} : { _key: `${key}-text` },
184
+ text,
185
+ marks: []
186
+ }
187
+ ]
188
+ };
189
+ }
190
+ function isRecord(value) {
191
+ return typeof value === "object" && value !== null && !Array.isArray(value);
192
+ }
193
+
194
+ // src/sidecar.ts
195
+ async function evaluateViaSidecar(http, config, documents) {
196
+ const body = {
197
+ documents
198
+ };
199
+ if (config.configJson !== void 0) {
200
+ body.configJson = config.configJson;
201
+ }
202
+ let response;
203
+ try {
204
+ response = await http.fetch(`${trimTrailingSlash(config.url)}/evaluate`, {
205
+ method: "POST",
206
+ headers: {
207
+ authorization: `Bearer ${config.authToken}`,
208
+ "content-type": "application/json"
209
+ },
210
+ body: JSON.stringify(body)
211
+ });
212
+ } catch (err) {
213
+ const detail = err instanceof Error ? err.message : String(err);
214
+ return { ok: false, reason: "network_error", detail };
215
+ }
216
+ if (response.status === 401 || response.status === 403) {
217
+ return {
218
+ ok: false,
219
+ reason: "auth_error",
220
+ detail: `sidecar rejected token (HTTP ${response.status})`
221
+ };
222
+ }
223
+ if (!response.ok) {
224
+ let detail = `sidecar HTTP ${response.status}`;
225
+ try {
226
+ detail = `${detail}: ${await response.text()}`;
227
+ } catch {
228
+ }
229
+ return { ok: false, reason: "server_error", detail };
230
+ }
231
+ let raw;
232
+ try {
233
+ raw = await response.text();
234
+ } catch (err) {
235
+ const detail = err instanceof Error ? err.message : String(err);
236
+ return { ok: false, reason: "invalid_response", detail };
237
+ }
238
+ try {
239
+ const findings = JSON.parse(raw);
240
+ if (!Array.isArray(findings)) {
241
+ return {
242
+ ok: false,
243
+ reason: "invalid_response",
244
+ detail: "sidecar returned non-array body"
245
+ };
246
+ }
247
+ return { ok: true, findings };
248
+ } catch (err) {
249
+ const detail = err instanceof Error ? err.message : String(err);
250
+ return { ok: false, reason: "invalid_response", detail };
64
251
  }
65
- const first = value[0];
66
- return typeof first === "object" && first !== null && "_type" in first && typeof first._type === "string";
252
+ }
253
+ function trimTrailingSlash(url) {
254
+ return url.endsWith("/") ? url.slice(0, -1) : url;
67
255
  }
68
256
 
69
257
  // src/plugin.ts
@@ -84,7 +272,56 @@ async function writeSidecarConfig(kv, config) {
84
272
  await kv.set(CONFIG_URL_KEY, config.url);
85
273
  await kv.set(CONFIG_TOKEN_KEY, config.token);
86
274
  }
87
- async function handleAfterSave(_event, _ctx) {
275
+ async function handleAfterSave(event, ctx) {
276
+ const runtime = await readSidecarConfig(ctx.kv);
277
+ if (runtime === null) {
278
+ ctx.log?.warn?.(
279
+ "Aexeo afterSave skipped: configure the evaluator URL and token on the Setup page"
280
+ );
281
+ return;
282
+ }
283
+ await handleAfterSaveConfigured(
284
+ event,
285
+ ctx,
286
+ (documents) => evaluateViaSidecar(
287
+ ctx.http,
288
+ { url: runtime.url, authToken: runtime.token },
289
+ documents
290
+ )
291
+ );
292
+ }
293
+ async function handleAfterSaveConfigured(event, ctx, evaluator, suppressionFilter) {
294
+ const adapted = await adaptContentItemWithContext(
295
+ event.content,
296
+ ctx.content,
297
+ ctx.site?.locale
298
+ );
299
+ const document = adapted.document;
300
+ const { kv, log } = ctx;
301
+ const stored = { document, meta: adapted.meta };
302
+ await persistDocument(ctx, stored);
303
+ const result = await evaluator([document]);
304
+ if (!result.ok) {
305
+ log?.error?.(`afterSave evaluator failure (${result.reason})`, {
306
+ detail: result.detail
307
+ });
308
+ return;
309
+ }
310
+ const pageFindings = result.findings.filter(
311
+ (finding) => finding.scope === "page"
312
+ );
313
+ const filtered = suppressionFilter === void 0 ? pageFindings : suppressionFilter.apply(
314
+ {
315
+ route: document.route,
316
+ collection: adapted.meta.collection,
317
+ status: adapted.meta.status
318
+ },
319
+ pageFindings
320
+ );
321
+ await kv.set(findingsKey(document.route), {
322
+ route: document.route,
323
+ findings: filtered
324
+ });
88
325
  }
89
326
  var DEFAULT_COLLECTIONS = ["posts", "pages"];
90
327
  async function evaluateAndPersistAll(ctx, options) {
@@ -109,7 +346,11 @@ async function evaluateAndPersistAll(ctx, options) {
109
346
  ...cursor === void 0 ? {} : { cursor }
110
347
  });
111
348
  for (const item of page.items) {
112
- const adapted = adaptContentItem(item);
349
+ const adapted = await adaptContentItemWithContext(
350
+ item,
351
+ ctx.content,
352
+ ctx.site?.locale
353
+ );
113
354
  documents.push(adapted.document);
114
355
  documentRoutes.add(adapted.document.route);
115
356
  adaptedByRoute.set(adapted.document.route, {
@@ -161,8 +402,57 @@ async function evaluateAndPersistAll(ctx, options) {
161
402
  totalAfterSuppression += filtered.length;
162
403
  }
163
404
  summary.totalFindings = totalAfterSuppression;
405
+ if (summary.errors.length === 0) {
406
+ await removeStaleDocuments(ctx, collections, documentRoutes);
407
+ }
164
408
  return summary;
165
409
  }
410
+ async function persistDocument(ctx, stored) {
411
+ const route = stored.document.route;
412
+ const entries = await ctx.kv.list("document:");
413
+ for (const entry of entries) {
414
+ const previous = toStoredDocument(entry.value);
415
+ if (previous === null || previous.document.route === route || previous.meta.id !== stored.meta.id || previous.meta.collection !== stored.meta.collection) {
416
+ continue;
417
+ }
418
+ await ctx.kv.delete(entry.key);
419
+ await ctx.kv.delete(findingsKey(previous.document.route));
420
+ }
421
+ await ctx.kv.set(documentKey(route), stored);
422
+ }
423
+ async function removeStaleDocuments(ctx, collections, currentRoutes) {
424
+ const scannedCollections = new Set(collections);
425
+ const entries = await ctx.kv.list("document:");
426
+ for (const entry of entries) {
427
+ const stored = toStoredDocument(entry.value);
428
+ if (stored === null || !scannedCollections.has(stored.meta.collection) || currentRoutes.has(stored.document.route)) {
429
+ continue;
430
+ }
431
+ await ctx.kv.delete(entry.key);
432
+ await ctx.kv.delete(findingsKey(stored.document.route));
433
+ }
434
+ }
435
+ function toStoredDocument(value) {
436
+ if (value === null || typeof value !== "object") return null;
437
+ if ("document" in value && "meta" in value && value.document !== null && typeof value.document === "object" && "route" in value.document && typeof value.document.route === "string" && value.meta !== null && typeof value.meta === "object") {
438
+ return value;
439
+ }
440
+ if ("route" in value && typeof value.route === "string") {
441
+ const document = value;
442
+ return {
443
+ document,
444
+ meta: {
445
+ id: document.route,
446
+ collection: "",
447
+ slug: null,
448
+ status: "",
449
+ title: document.title ?? "",
450
+ publicUrl: null
451
+ }
452
+ };
453
+ }
454
+ return null;
455
+ }
166
456
  function findingsKey(route) {
167
457
  const normalized = route === "" || route === "/" ? "/" : route;
168
458
  return `findings:${normalized}`;
@@ -178,25 +468,8 @@ async function readAllStoredDocuments(kv) {
178
468
  const entries = await kv.list("document:");
179
469
  const out = [];
180
470
  for (const entry of entries) {
181
- const value = entry.value;
182
- if (value === null || typeof value !== "object") continue;
183
- if ("document" in value && "meta" in value) {
184
- out.push(value);
185
- continue;
186
- }
187
- if ("route" in value) {
188
- const document = value;
189
- out.push({
190
- document,
191
- meta: {
192
- id: document.route,
193
- collection: "",
194
- slug: null,
195
- status: "",
196
- title: document.title ?? ""
197
- }
198
- });
199
- }
471
+ const stored = toStoredDocument(entry.value);
472
+ if (stored !== null) out.push(stored);
200
473
  }
201
474
  return out;
202
475
  }
@@ -208,69 +481,6 @@ async function readFindings(kv, route) {
208
481
  return stored.findings;
209
482
  }
210
483
 
211
- // src/sidecar.ts
212
- async function evaluateViaSidecar(http, config, documents) {
213
- const body = {
214
- documents
215
- };
216
- if (config.configJson !== void 0) {
217
- body.configJson = config.configJson;
218
- }
219
- let response;
220
- try {
221
- response = await http.fetch(`${trimTrailingSlash(config.url)}/evaluate`, {
222
- method: "POST",
223
- headers: {
224
- authorization: `Bearer ${config.authToken}`,
225
- "content-type": "application/json"
226
- },
227
- body: JSON.stringify(body)
228
- });
229
- } catch (err) {
230
- const detail = err instanceof Error ? err.message : String(err);
231
- return { ok: false, reason: "network_error", detail };
232
- }
233
- if (response.status === 401 || response.status === 403) {
234
- return {
235
- ok: false,
236
- reason: "auth_error",
237
- detail: `sidecar rejected token (HTTP ${response.status})`
238
- };
239
- }
240
- if (!response.ok) {
241
- let detail = `sidecar HTTP ${response.status}`;
242
- try {
243
- detail = `${detail}: ${await response.text()}`;
244
- } catch {
245
- }
246
- return { ok: false, reason: "server_error", detail };
247
- }
248
- let raw;
249
- try {
250
- raw = await response.text();
251
- } catch (err) {
252
- const detail = err instanceof Error ? err.message : String(err);
253
- return { ok: false, reason: "invalid_response", detail };
254
- }
255
- try {
256
- const findings = JSON.parse(raw);
257
- if (!Array.isArray(findings)) {
258
- return {
259
- ok: false,
260
- reason: "invalid_response",
261
- detail: "sidecar returned non-array body"
262
- };
263
- }
264
- return { ok: true, findings };
265
- } catch (err) {
266
- const detail = err instanceof Error ? err.message : String(err);
267
- return { ok: false, reason: "invalid_response", detail };
268
- }
269
- }
270
- function trimTrailingSlash(url) {
271
- return url.endsWith("/") ? url.slice(0, -1) : url;
272
- }
273
-
274
484
  // src/evaluator-sandbox.ts
275
485
  async function evaluate(_documents) {
276
486
  return [];
@@ -439,26 +649,56 @@ var tools = [checkTool, indexNowSubmitTool];
439
649
  function definePlugin(plugin) {
440
650
  return plugin;
441
651
  }
652
+ function normalizeInteraction(input) {
653
+ if (!input || typeof input !== "object") {
654
+ return { type: "page_load", page: "/findings" };
655
+ }
656
+ const raw = input;
657
+ if (raw.type === "page_load") {
658
+ return {
659
+ type: "page_load",
660
+ page: typeof raw.page === "string" && raw.page.length > 0 ? raw.page : "/findings"
661
+ };
662
+ }
663
+ if (raw.type === "block_action") {
664
+ return {
665
+ type: "block_action",
666
+ action_id: typeof raw.action_id === "string" ? raw.action_id : "",
667
+ ...typeof raw.block_id === "string" ? { block_id: raw.block_id } : {},
668
+ value: raw.value
669
+ };
670
+ }
671
+ if (raw.type === "form_submit") {
672
+ return {
673
+ type: "form_submit",
674
+ action_id: typeof raw.action_id === "string" ? raw.action_id : "",
675
+ ...typeof raw.block_id === "string" ? { block_id: raw.block_id } : {},
676
+ values: raw.values && typeof raw.values === "object" ? raw.values : {}
677
+ };
678
+ }
679
+ return { type: "page_load", page: "/findings" };
680
+ }
442
681
  async function handleAdminRoute(input, ctx) {
682
+ const body = normalizeInteraction(input?.input);
443
683
  ctx.log?.info?.(
444
- `aexeo route: type=${input.input?.type} page=${input.input?.page ?? ""}`
684
+ `aexeo route: type=${body.type} page=${body.type === "page_load" ? body.page : ""}`
445
685
  );
446
- const dispatch = { body: input.input, kv: ctx.kv, ctx };
447
- if (dispatch.body.type === "page_load") {
448
- return handlePageLoad(dispatch, dispatch.body.page);
686
+ const dispatch = { body, kv: ctx.kv, ctx };
687
+ if (body.type === "page_load") {
688
+ return handlePageLoad(dispatch, body.page);
449
689
  }
450
- if (dispatch.body.type === "block_action") {
690
+ if (body.type === "block_action") {
451
691
  return handleBlockAction(
452
692
  dispatch,
453
- dispatch.body.action_id,
454
- dispatch.body.value
693
+ body.action_id,
694
+ body.value
455
695
  );
456
696
  }
457
- if (dispatch.body.type === "form_submit") {
697
+ if (body.type === "form_submit") {
458
698
  return handleFormSubmit(
459
699
  dispatch,
460
- dispatch.body.action_id,
461
- dispatch.body.values
700
+ body.action_id,
701
+ body.values
462
702
  );
463
703
  }
464
704
  return handlePageLoad(dispatch, "findings");
@@ -571,10 +811,8 @@ async function renderFindingsPage(ctx) {
571
811
  {
572
812
  type: "actions",
573
813
  elements: [
574
- // Refresh is the primary action: emdash 0.7.0's afterSave hook
575
- // can't reliably do I/O (post-response bridge invalidation), so
576
- // re-evaluation is admin-triggered rather than save-triggered.
577
- // Pressing this lists all content via the live in-request bridge,
814
+ // Refresh evaluates every configured entry. Pressing it lists
815
+ // content via the live in-request bridge,
578
816
  // calls the sidecar /evaluate, and writes findings back to KV.
579
817
  {
580
818
  type: "button",
package/dist/sandbox.d.ts CHANGED
File without changes
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IAGnB,MAAM,EAAE,UAAU,CAAC;IACnB,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAGxC,YAAY,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC5C,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAeD,MAAM,WAAW,qBAAqB;IAgBpC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,oBAAoB,CAClC,OAAO,GAAE,qBAA0B,GAClC,yBAAyB,CAwB3B"}
1
+ {"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IAGnB,MAAM,EAAE,UAAU,CAAC;IACnB,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAGxC,YAAY,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC5C,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAeD,MAAM,WAAW,qBAAqB;IAgBpC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,oBAAoB,CAClC,OAAO,GAAE,qBAA0B,GAClC,yBAAyB,CAwB3B"}
package/dist/sidecar.d.ts CHANGED
File without changes
@@ -1 +1 @@
1
- {"version":3,"file":"sidecar.d.ts","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAkB1D,MAAM,WAAW,WAAW;IAC1B,KAAK,CACH,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GACA,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;KAAE,CAAC,CAAC;CACtE;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAIlB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;CAAE,GACjC;IACE,EAAE,EAAE,KAAK,CAAC;IAIV,MAAM,EACF,eAAe,GACf,YAAY,GACZ,cAAc,GACd,kBAAkB,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEN,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,SAAS,cAAc,EAAE,GACnC,OAAO,CAAC,aAAa,CAAC,CA+DxB"}
1
+ {"version":3,"file":"sidecar.d.ts","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAiB1D,MAAM,WAAW,WAAW;IAC1B,KAAK,CACH,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GACA,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;KAAE,CAAC,CAAC;CACtE;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAIlB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;CAAE,GACjC;IACE,EAAE,EAAE,KAAK,CAAC;IAGV,MAAM,EACF,eAAe,GACf,YAAY,GACZ,cAAc,GACd,kBAAkB,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEN,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,SAAS,cAAc,EAAE,GACnC,OAAO,CAAC,aAAa,CAAC,CA+DxB"}
File without changes
File without changes
package/dist/types.d.ts CHANGED
File without changes
File without changes
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const PACKAGE_VERSION = "0.8.16";
1
+ export declare const PACKAGE_VERSION = "0.8.18";
2
2
  //# sourceMappingURL=version.d.ts.map
File without changes
File without changes
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeptus/aexeo-emdash",
3
- "version": "0.8.16",
3
+ "version": "0.8.18",
4
4
  "description": "Aexeo SEO/GEO content evaluator as an emdash plugin",
5
5
  "license": "MIT",
6
6
  "author": "Aeptus",
@@ -61,12 +61,13 @@
61
61
  "build:bundle": "node scripts/build-bundle.mjs",
62
62
  "build": "npm run sync-version && npm run build:wasm && npm run build:ts && npm run build:bundle",
63
63
  "typecheck": "npm run sync-version && tsc --noEmit",
64
+ "test": "vitest run",
64
65
  "prepublishOnly": "npm run build"
65
66
  },
66
67
  "peerDependencies": {
67
68
  "@emdash-cms/core": "*",
68
69
  "@emdash-cms/plugin-types": "*",
69
- "emdash": ">=0.7.0",
70
+ "emdash": ">=0.41.0 <0.42.0",
70
71
  "react": "^18.0.0 || ^19.0.0"
71
72
  },
72
73
  "peerDependenciesMeta": {
@@ -86,9 +87,12 @@
86
87
  "devDependencies": {
87
88
  "@types/node": "^22.0.0",
88
89
  "@types/react": "^19.2.14",
89
- "emdash": "^0.15.0",
90
+ "@emdash-cms/plugin-test": "^0.2.4",
91
+ "emdash": "^0.41.0",
90
92
  "esbuild": "^0.28.0",
91
93
  "react": "^19.2.5",
92
- "typescript": "^5.6.0"
94
+ "typescript": "^5.6.0",
95
+ "vite": "^8.0.0",
96
+ "vitest": "^4.1.0"
93
97
  }
94
98
  }
File without changes
File without changes
File without changes
File without changes
Binary file
File without changes