@aeptus/aexeo-emdash 0.3.0 → 0.5.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 +109 -8
- package/INSTALL.md +20 -20
- package/LICENSE +1 -1
- package/README.md +101 -6
- package/dist/admin.js +2 -2
- package/dist/configured.d.ts +20 -4
- package/dist/configured.d.ts.map +1 -1
- package/dist/configured.js +126 -18
- package/dist/data-route.d.ts +1 -0
- package/dist/data-route.d.ts.map +1 -1
- package/dist/index.d.ts +74 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -14
- package/dist/plugin.d.ts +3 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/sandbox-entry.js +24 -14
- package/dist/sandbox.d.ts +2 -2
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/suppressions.d.ts +17 -0
- package/dist/suppressions.d.ts.map +1 -0
- package/dist/version.d.ts +1 -1
- package/package.json +3 -3
- package/wasm/aexeo_emdash_bridge_bg.wasm +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,105 @@ and the project follows [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.5.0] - 2026-05-01
|
|
10
|
+
|
|
11
|
+
Three follow-ups from real-world adoption feedback after 0.4.0:
|
|
12
|
+
|
|
13
|
+
- richer suppression selectors so editors can target by collection
|
|
14
|
+
and document status, not just route + rule
|
|
15
|
+
- ergonomic collections API (`includeCollections` /
|
|
16
|
+
`excludeCollections`) for sites whose schema is close to the
|
|
17
|
+
default but needs minor tweaks
|
|
18
|
+
- README now leads with the suppressions glob semantics so consumers
|
|
19
|
+
migrating from local patches don't have to dig through the
|
|
20
|
+
CHANGELOG to learn that `*` is single-segment and `**` is recursive
|
|
21
|
+
|
|
22
|
+
**Compatibility:** verified against emdash `0.7.0` and `0.8.0`.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **`Suppression.collections`** — silence findings for documents in
|
|
27
|
+
the named emdash collections.
|
|
28
|
+
- **`Suppression.statuses`** — silence findings for documents in the
|
|
29
|
+
named statuses (`"draft"`, `"published"`, etc.). Useful for
|
|
30
|
+
preventing draft-stage findings from cluttering the dashboard.
|
|
31
|
+
- **`includeCollections`** factory option — adds slugs to the
|
|
32
|
+
default `["posts", "pages"]`. For sites that have the defaults
|
|
33
|
+
PLUS extras (e.g. blog adapter + `guides` and `faqs`).
|
|
34
|
+
- **`excludeCollections`** factory option — removes slugs from the
|
|
35
|
+
default. For sites that have most of the defaults but want to
|
|
36
|
+
skip one.
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- **`SuppressionFilter.apply` signature** — now takes a
|
|
41
|
+
`SuppressionContext` object (`{ route, collection?, status? }`)
|
|
42
|
+
instead of a bare route string. Direct callers of `apply` will
|
|
43
|
+
see a TypeScript error and need a one-line update; the public
|
|
44
|
+
factory API (`aexeoPlugin({ suppressions })`) is unchanged.
|
|
45
|
+
|
|
46
|
+
### Notes for hosts upgrading from 0.4.x
|
|
47
|
+
|
|
48
|
+
- No automatic behavior change. New selectors and options default
|
|
49
|
+
to undefined and are ignored unless the host opts in.
|
|
50
|
+
- Selector matching is **AND across selectors, OR across rules**.
|
|
51
|
+
A suppression with both `routePattern: "/fr-fr/**"` and
|
|
52
|
+
`collections: ["pages"]` only silences findings on French pages,
|
|
53
|
+
not on French blog posts.
|
|
54
|
+
- Sitewide findings (route `*`) ignore `collections` /
|
|
55
|
+
`statuses` selectors — those findings are inherently
|
|
56
|
+
cross-document and have no single collection or status to match.
|
|
57
|
+
Use `routePattern` (or omit it) and `ruleIds` for sitewide
|
|
58
|
+
suppressions.
|
|
59
|
+
|
|
60
|
+
## [0.4.0] - 2026-05-01
|
|
61
|
+
|
|
62
|
+
Adds upstreamed support for editor-workflow finding suppressions.
|
|
63
|
+
Removes the last reason for consumer sites to maintain a local
|
|
64
|
+
patch over the published plugin.
|
|
65
|
+
|
|
66
|
+
**Compatibility:** verified against emdash `0.7.0` and `0.8.0`.
|
|
67
|
+
|
|
68
|
+
### Added
|
|
69
|
+
|
|
70
|
+
- **`aexeoPlugin({ suppressions })` option.** Each rule silences
|
|
71
|
+
findings matching the route pattern (glob) AND/OR a rule-id set.
|
|
72
|
+
Applied before findings are persisted to KV — suppressed findings
|
|
73
|
+
never reach the dashboard, /findings, or the per-document panel.
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
aexeoPlugin({
|
|
77
|
+
suppressions: [
|
|
78
|
+
{ routePattern: "/privacy", ruleIds: ["RULE001"] },
|
|
79
|
+
{ routePattern: "/fr-fr/**", ruleIds: ["RULE002"] },
|
|
80
|
+
{ ruleIds: ["RULE999"] }, // applies to every route
|
|
81
|
+
],
|
|
82
|
+
})
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Glob: `*` matches non-`/` chars, `**` matches across `/`, `?`
|
|
86
|
+
matches one non-`/` char. Patterns are anchored. Empty rules
|
|
87
|
+
(`{}` with neither field) are rejected at plugin construction
|
|
88
|
+
with a clear error — that's a kill-switch for all findings
|
|
89
|
+
everywhere and almost certainly an editor mistake.
|
|
90
|
+
|
|
91
|
+
- **`Suppression` type** re-exported from the package root for hosts
|
|
92
|
+
that want to type their config:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import type { Suppression } from "@aeptus/aexeo-emdash";
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Notes for hosts upgrading from 0.3.x
|
|
99
|
+
|
|
100
|
+
- No automatic behavior change. `suppressions` defaults to undefined
|
|
101
|
+
and the filter is a no-op until the host opts in.
|
|
102
|
+
- Suppressions are plugin-only by design. The CLI `check` continues
|
|
103
|
+
to surface every finding; if you want to silence findings at the
|
|
104
|
+
CLI layer, use `aexeo.toml`'s `[ignore]` block. The two surfaces
|
|
105
|
+
serve different audiences: the plugin is editorial workflow, the
|
|
106
|
+
CLI is build-gating.
|
|
107
|
+
|
|
9
108
|
## [0.3.0] - 2026-05-01
|
|
10
109
|
|
|
11
110
|
Adds an LLM-assisted authoring flow for the truth manifest
|
|
@@ -96,10 +195,10 @@ Block Kit (no link needs there).
|
|
|
96
195
|
emdash's `usePluginPage` hook picks this up and renders the
|
|
97
196
|
React component in place of the Block Kit fallback.
|
|
98
197
|
- **Two new HTTP routes** the React component consumes:
|
|
99
|
-
- `POST /_emdash/api/plugins/aexeo-
|
|
198
|
+
- `POST /_emdash/api/plugins/aexeo-emdash/data` — read current
|
|
100
199
|
findings + per-route metadata + computed URLs (no
|
|
101
200
|
re-evaluation).
|
|
102
|
-
- `POST /_emdash/api/plugins/aexeo-
|
|
201
|
+
- `POST /_emdash/api/plugins/aexeo-emdash/refresh` — sweep the
|
|
103
202
|
configured collections, write findings to KV, return the same
|
|
104
203
|
payload as `/data` plus a refresh summary.
|
|
105
204
|
Both routes return JSON in the shape exported as `FindingsPayload`
|
|
@@ -144,7 +243,7 @@ rule-engine change).
|
|
|
144
243
|
|
|
145
244
|
### Added
|
|
146
245
|
|
|
147
|
-
- **`
|
|
246
|
+
- **`aexeoPlugin({ collections })` option** for configured mode.
|
|
148
247
|
Lets sites with non-default collection slugs override which
|
|
149
248
|
collections the Refresh button sweeps. Defaults to
|
|
150
249
|
`["posts", "pages"]` when omitted (the slugs from
|
|
@@ -182,15 +281,15 @@ First public release.
|
|
|
182
281
|
|
|
183
282
|
### Added
|
|
184
283
|
|
|
185
|
-
- `
|
|
284
|
+
- `aexeoPlugin()` factory for **configured mode** — the recommended
|
|
186
285
|
install path for first-party emdash sites. Plugin runs in-process
|
|
187
286
|
inside the host Worker. No sidecar deploy, no auth token, no admin
|
|
188
287
|
Setup page.
|
|
189
|
-
- `
|
|
288
|
+
- `aexeoPluginSandboxed({ evaluatorHost })` factory for **sandboxed
|
|
190
289
|
mode** — preserved for future third-party-deploy scenarios where
|
|
191
290
|
the plugin code shouldn't have full host access. Requires a
|
|
192
291
|
separately-deployed sidecar Worker (template at
|
|
193
|
-
`
|
|
292
|
+
`aexeo-crawl-worker` in the source repo).
|
|
194
293
|
- Block Kit admin pages: findings table, per-document panel,
|
|
195
294
|
intelligence-score dashboard widget. Refresh button on the
|
|
196
295
|
findings page sweeps every document in the configured collections.
|
|
@@ -198,7 +297,7 @@ First public release.
|
|
|
198
297
|
automatic re-evaluation of the changed document and update the
|
|
199
298
|
findings table without manual intervention.
|
|
200
299
|
- WASM-backed evaluator powered by the `aexeo-emdash-bridge` Rust
|
|
201
|
-
crate (same engine as the
|
|
300
|
+
crate (same engine as the Aexeo CLI). Compiles via the consumer's
|
|
202
301
|
Vite/Wrangler chain — `vite-plugin-wasm` is a peer-side runtime
|
|
203
302
|
dependency for Vite-driven Cloudflare deploys.
|
|
204
303
|
|
|
@@ -218,7 +317,9 @@ First public release.
|
|
|
218
317
|
`astro.config.mjs` for the WASM import to resolve to a
|
|
219
318
|
precompiled `WebAssembly.Module`. Not optional.
|
|
220
319
|
|
|
221
|
-
[Unreleased]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.
|
|
320
|
+
[Unreleased]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.5.0...HEAD
|
|
321
|
+
[0.5.0]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.4.0...aexeo-emdash-v0.5.0
|
|
322
|
+
[0.4.0]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.3.0...aexeo-emdash-v0.4.0
|
|
222
323
|
[0.3.0]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.2.0...aexeo-emdash-v0.3.0
|
|
223
324
|
[0.2.0]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.1.2...aexeo-emdash-v0.2.0
|
|
224
325
|
[0.1.2]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.1.1...aexeo-emdash-v0.1.2
|
package/INSTALL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Installing `@aeptus/aexeo-emdash`
|
|
2
2
|
|
|
3
|
-
This package adds Aexeo
|
|
3
|
+
This package adds Aexeo SEO/GEO content evaluation to an emdash
|
|
4
4
|
site. Findings show up as a Block Kit admin page; a sidebar widget
|
|
5
5
|
shows the site's current intelligence score; saves auto-evaluate the
|
|
6
6
|
changed document.
|
|
@@ -9,11 +9,11 @@ changed document.
|
|
|
9
9
|
|
|
10
10
|
The package exports two factories:
|
|
11
11
|
|
|
12
|
-
- **`
|
|
12
|
+
- **`aexeoPlugin()`** — **configured mode** (recommended). Plugin
|
|
13
13
|
runs in-process inside the host emdash Worker. No separate
|
|
14
14
|
deployment, no auth token, no admin Setup page. Use this for
|
|
15
15
|
first-party emdash sites.
|
|
16
|
-
- **`
|
|
16
|
+
- **`aexeoPluginSandboxed({ evaluatorHost })`** — **sandboxed
|
|
17
17
|
mode**. Plugin runs inside emdash's Worker Loader isolate; WASM
|
|
18
18
|
evaluation runs in a separate sidecar Worker the operator
|
|
19
19
|
deploys. Use this only when a third party hosts emdash and
|
|
@@ -42,7 +42,7 @@ npm install @aeptus/aexeo-emdash vite-plugin-wasm
|
|
|
42
42
|
`vite-plugin-wasm` is required because Vite's defaults treat `.wasm`
|
|
43
43
|
imports as static-asset URLs, but Cloudflare Workers can only run
|
|
44
44
|
WASM as precompiled `WebAssembly.Module` instances. The plugin
|
|
45
|
-
bridges the two; without it, the
|
|
45
|
+
bridges the two; without it, the Aexeo plugin's first call throws
|
|
46
46
|
"WASM module did not resolve to a WebAssembly.Module."
|
|
47
47
|
|
|
48
48
|
> **If installing from a private git remote or as a vendored
|
|
@@ -54,7 +54,7 @@ bridges the two; without it, the seogeo plugin's first call throws
|
|
|
54
54
|
```js
|
|
55
55
|
import cloudflare from "@astrojs/cloudflare";
|
|
56
56
|
import { d1, r2 } from "@emdash-cms/cloudflare";
|
|
57
|
-
import {
|
|
57
|
+
import { aexeoPlugin } from "@aeptus/aexeo-emdash";
|
|
58
58
|
import { defineConfig } from "astro/config";
|
|
59
59
|
import emdash from "emdash/astro";
|
|
60
60
|
import wasm from "vite-plugin-wasm";
|
|
@@ -68,7 +68,7 @@ export default defineConfig({
|
|
|
68
68
|
// workerd disallow runtime WebAssembly.instantiate from raw
|
|
69
69
|
// bytes, so the bundler has to do the compilation.
|
|
70
70
|
plugins: [wasm()],
|
|
71
|
-
// The
|
|
71
|
+
// The Aexeo plugin's WASM import confuses Vite's dep
|
|
72
72
|
// optimizer when it tries to pre-bundle the package.
|
|
73
73
|
optimizeDeps: { exclude: ["@aeptus/aexeo-emdash"] },
|
|
74
74
|
},
|
|
@@ -76,7 +76,7 @@ export default defineConfig({
|
|
|
76
76
|
emdash({
|
|
77
77
|
database: d1({ binding: "DB" }),
|
|
78
78
|
storage: r2({ binding: "MEDIA" }),
|
|
79
|
-
plugins: [
|
|
79
|
+
plugins: [aexeoPlugin()],
|
|
80
80
|
}),
|
|
81
81
|
],
|
|
82
82
|
});
|
|
@@ -96,7 +96,7 @@ no sidecar to deploy.
|
|
|
96
96
|
http://localhost:4321/_emdash/admin/plugins
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
The
|
|
99
|
+
The Aexeo plugin will appear in the list. Click it.
|
|
100
100
|
|
|
101
101
|
3. The findings page renders with a Refresh button. Click **Refresh**
|
|
102
102
|
— toast says "Refreshed N routes (M findings across K documents)"
|
|
@@ -151,7 +151,7 @@ token to rotate, no Setup page to revisit.
|
|
|
151
151
|
|
|
152
152
|
**Verify after a plugin update:**
|
|
153
153
|
|
|
154
|
-
1. Visit `/admin/plugins/aexeo-
|
|
154
|
+
1. Visit `/admin/plugins/aexeo-emdash/findings` and click **Refresh**.
|
|
155
155
|
Toast should show non-zero rules sweeping. (A zero count *can*
|
|
156
156
|
be valid for a clean site, but if you previously had findings
|
|
157
157
|
and now have none, suspect the upgrade.)
|
|
@@ -216,7 +216,7 @@ Treat anything outside that range as best-effort.
|
|
|
216
216
|
|
|
217
217
|
## Removing
|
|
218
218
|
|
|
219
|
-
Delete the dependency, the import, and the `
|
|
219
|
+
Delete the dependency, the import, and the `aexeoPlugin()` line in
|
|
220
220
|
`integrations:[emdash({plugins:[...]})]`. The KV keys the plugin
|
|
221
221
|
wrote remain in your KV namespace — purge with
|
|
222
222
|
`wrangler kv:key delete --prefix=findings:` and
|
|
@@ -243,26 +243,26 @@ Trade-offs vs. configured mode:
|
|
|
243
243
|
```js
|
|
244
244
|
// astro.config.mjs (sandboxed mode)
|
|
245
245
|
import { sandbox } from "@emdash-cms/cloudflare";
|
|
246
|
-
import {
|
|
246
|
+
import { aexeoPluginSandboxed } from "@aeptus/aexeo-emdash";
|
|
247
247
|
|
|
248
248
|
emdash({
|
|
249
249
|
database: d1({ binding: "DB" }),
|
|
250
250
|
storage: r2({ binding: "MEDIA" }),
|
|
251
251
|
sandboxed: [
|
|
252
|
-
|
|
252
|
+
aexeoPluginSandboxed({
|
|
253
253
|
// Public host of the deployed sidecar Worker.
|
|
254
|
-
evaluatorHost: "
|
|
254
|
+
evaluatorHost: "aexeo-crawl-worker.<subdomain>.workers.dev",
|
|
255
255
|
}),
|
|
256
256
|
],
|
|
257
257
|
sandboxRunner: sandbox(),
|
|
258
258
|
});
|
|
259
259
|
```
|
|
260
260
|
|
|
261
|
-
The sidecar Worker template lives at `packages/
|
|
261
|
+
The sidecar Worker template lives at `packages/aexeo-crawl-worker/`
|
|
262
262
|
in this repo. Per-site deploy:
|
|
263
263
|
|
|
264
264
|
```bash
|
|
265
|
-
cd
|
|
265
|
+
cd aexeo-crawl-worker
|
|
266
266
|
# Edit wrangler.toml: name, R2 bucket name, SITE_URL
|
|
267
267
|
npx wrangler login
|
|
268
268
|
npx wrangler r2 bucket create <bucket-name>
|
|
@@ -271,7 +271,7 @@ echo "$(openssl rand -hex 32)" | npx wrangler secret put EVAL_TOKEN
|
|
|
271
271
|
```
|
|
272
272
|
|
|
273
273
|
Then in the admin UI, visit
|
|
274
|
-
`/admin/plugins/aexeo-
|
|
274
|
+
`/admin/plugins/aexeo-emdash/setup` and paste the deployed URL +
|
|
275
275
|
the same token.
|
|
276
276
|
|
|
277
277
|
## Alternative install sources
|
|
@@ -316,7 +316,7 @@ present, double-check the package version is recent (≥ the version
|
|
|
316
316
|
that switched to direct .wasm imports — see git log for `Switch
|
|
317
317
|
configured-mode WASM from inlined bytes to direct .wasm import`).
|
|
318
318
|
|
|
319
|
-
**`
|
|
319
|
+
**`aexeo: WASM module did not resolve to a WebAssembly.Module`**
|
|
320
320
|
The bundler resolved the .wasm import but produced something other
|
|
321
321
|
than a Module (URL string, Uint8Array). Same fix as above: ensure
|
|
322
322
|
`vite-plugin-wasm` is loaded.
|
|
@@ -327,7 +327,7 @@ sandboxed two-arg ctx shape. Update; it's fixed in the version with
|
|
|
327
327
|
`Switch configured-mode WASM from inlined bytes to direct .wasm
|
|
328
328
|
import` in the commit log.
|
|
329
329
|
|
|
330
|
-
**`/admin/plugins` doesn't list
|
|
330
|
+
**`/admin/plugins` doesn't list Aexeo, but `/findings` works.** The
|
|
331
331
|
emdash version's plugins meta page may filter out plugins without a
|
|
332
332
|
`/` adminPage entry. The package declares one explicitly; if you see
|
|
333
333
|
this on a recent version, it's an emdash regression — file upstream.
|
|
@@ -344,7 +344,7 @@ Node adapter.
|
|
|
344
344
|
|
|
345
345
|
## What the plugin actually does
|
|
346
346
|
|
|
347
|
-
- **Findings page** (`/_emdash/admin/plugins/aexeo-
|
|
347
|
+
- **Findings page** (`/_emdash/admin/plugins/aexeo-emdash/findings`):
|
|
348
348
|
Block Kit table of every rule violation across the site. Filter by
|
|
349
349
|
severity. Click a route in the picker to drill into per-document
|
|
350
350
|
findings.
|
|
@@ -371,6 +371,6 @@ inline. Findings are stored in the host's plugin KV (the
|
|
|
371
371
|
`PluginContext.kv` accessor). The Refresh button does the same thing
|
|
372
372
|
but for every document in every configured collection. The WASM
|
|
373
373
|
itself is the same `aexeo-emdash-bridge` Rust crate that powers the
|
|
374
|
-
|
|
374
|
+
Aexeo CLI; it's compiled to WebAssembly via wasm-pack and imported
|
|
375
375
|
by the host's bundler (Vite + `vite-plugin-wasm`). No separate
|
|
376
376
|
service, no sidecar, no auth token.
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @aeptus/aexeo-emdash
|
|
2
2
|
|
|
3
|
-
Aexeo
|
|
3
|
+
Aexeo SEO/GEO content evaluator as an emdash plugin.
|
|
4
4
|
|
|
5
5
|
Adds a Findings admin page, per-document panel, and dashboard
|
|
6
6
|
intelligence-score widget to an emdash site. Saves auto-evaluate the
|
|
@@ -14,7 +14,7 @@ npm install @aeptus/aexeo-emdash vite-plugin-wasm
|
|
|
14
14
|
|
|
15
15
|
```js
|
|
16
16
|
// astro.config.mjs
|
|
17
|
-
import {
|
|
17
|
+
import { aexeoPlugin } from "@aeptus/aexeo-emdash";
|
|
18
18
|
import wasm from "vite-plugin-wasm";
|
|
19
19
|
|
|
20
20
|
export default defineConfig({
|
|
@@ -26,7 +26,7 @@ export default defineConfig({
|
|
|
26
26
|
emdash({
|
|
27
27
|
database: d1({ binding: "DB" }),
|
|
28
28
|
storage: r2({ binding: "MEDIA" }),
|
|
29
|
-
plugins: [
|
|
29
|
+
plugins: [aexeoPlugin()],
|
|
30
30
|
}),
|
|
31
31
|
],
|
|
32
32
|
});
|
|
@@ -40,7 +40,7 @@ troubleshooting list, see [INSTALL.md](./INSTALL.md).
|
|
|
40
40
|
|
|
41
41
|
## What it does
|
|
42
42
|
|
|
43
|
-
- **Findings page** at `/_emdash/admin/plugins/aexeo-
|
|
43
|
+
- **Findings page** at `/_emdash/admin/plugins/aexeo-emdash/findings`:
|
|
44
44
|
rule violations across the site, filterable by severity.
|
|
45
45
|
- **Document panel** at `/document`: findings scoped to one document.
|
|
46
46
|
- **Dashboard widget**: top-line intelligence score (citation, truth,
|
|
@@ -59,13 +59,108 @@ troubleshooting list, see [INSTALL.md](./INSTALL.md).
|
|
|
59
59
|
bundler handles compilation at build time. `vite-plugin-wasm` is a
|
|
60
60
|
hard requirement on the consumer side.
|
|
61
61
|
|
|
62
|
+
## Configuring collections
|
|
63
|
+
|
|
64
|
+
The plugin sweeps `["posts", "pages"]` by default — the slugs the
|
|
65
|
+
`@emdash-cms/template-blog-cloudflare` template ships with. Three knobs
|
|
66
|
+
to override, in precedence order:
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
// Full override — replace the default entirely.
|
|
70
|
+
// Use when your schema has none of the default slugs.
|
|
71
|
+
aexeoPlugin({ collections: ["blog_posts", "pages"] })
|
|
72
|
+
|
|
73
|
+
// Extend the default — add slugs alongside posts + pages.
|
|
74
|
+
aexeoPlugin({ includeCollections: ["guides", "faqs"] })
|
|
75
|
+
|
|
76
|
+
// Subtract from the default — remove a slug.
|
|
77
|
+
aexeoPlugin({ excludeCollections: ["posts"] })
|
|
78
|
+
|
|
79
|
+
// Combine include + exclude (subtract first, then add).
|
|
80
|
+
// `collections` ignores both — it's the explicit-list override.
|
|
81
|
+
aexeoPlugin({
|
|
82
|
+
excludeCollections: ["posts"],
|
|
83
|
+
includeCollections: ["blog_posts", "guides"],
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Pointing any of these at a slug that doesn't exist is non-fatal:
|
|
88
|
+
the bridge's `content.list` returns empty and the missing collection
|
|
89
|
+
shows up in the Refresh summary's `errors` field.
|
|
90
|
+
|
|
91
|
+
## Suppressing findings
|
|
92
|
+
|
|
93
|
+
When a finding is intentional (legal pages with non-standard SEO,
|
|
94
|
+
localized routes where a rule doesn't apply, draft documents whose
|
|
95
|
+
findings shouldn't surface yet), silence it with a suppression rule.
|
|
96
|
+
Suppressions are applied **before** findings are persisted to KV —
|
|
97
|
+
suppressed findings never reach the dashboard, `/findings`, or the
|
|
98
|
+
per-document panel.
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
aexeoPlugin({
|
|
102
|
+
suppressions: [
|
|
103
|
+
// route + rule
|
|
104
|
+
{ routePattern: "/privacy", ruleIds: ["RULE001"] },
|
|
105
|
+
|
|
106
|
+
// recursive route subtree
|
|
107
|
+
{ routePattern: "/fr-fr/**", ruleIds: ["RULE002"] },
|
|
108
|
+
|
|
109
|
+
// applies to every route
|
|
110
|
+
{ ruleIds: ["RULE999"] },
|
|
111
|
+
|
|
112
|
+
// by collection
|
|
113
|
+
{ collections: ["drafts"], ruleIds: ["RULE042"] },
|
|
114
|
+
|
|
115
|
+
// by document status
|
|
116
|
+
{ statuses: ["draft"] }, // silence ALL findings on drafts
|
|
117
|
+
],
|
|
118
|
+
})
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Glob syntax for `routePattern`
|
|
122
|
+
|
|
123
|
+
| Pattern | Matches |
|
|
124
|
+
|---|---|
|
|
125
|
+
| `*` | any chars **except** `/` |
|
|
126
|
+
| `**` | any chars **including** `/` (recursive) |
|
|
127
|
+
| `?` | exactly one char except `/` |
|
|
128
|
+
|
|
129
|
+
Patterns are anchored. `/about` matches only `/about`, not
|
|
130
|
+
`/about/team` — use `/about/**` if you want a subtree.
|
|
131
|
+
|
|
132
|
+
> **Migrating from a local patch**: if your previous setup used
|
|
133
|
+
> looser patterns (e.g. one-asterisk-means-everything), update them
|
|
134
|
+
> on bump. `*` is intentionally single-segment so editors can scope
|
|
135
|
+
> rules to a level of the path hierarchy without recursive surprises.
|
|
136
|
+
|
|
137
|
+
### Selector semantics
|
|
138
|
+
|
|
139
|
+
A rule may set any combination of `routePattern`, `ruleIds`,
|
|
140
|
+
`collections`, and `statuses`. Matching is **AND across selectors,
|
|
141
|
+
OR across rules**: a finding is suppressed when at least one rule
|
|
142
|
+
matches it; a rule matches when every selector it sets matches the
|
|
143
|
+
finding's context.
|
|
144
|
+
|
|
145
|
+
Empty rules (`{}` with no selectors) are rejected at plugin
|
|
146
|
+
construction. That's a kill-switch for all findings everywhere
|
|
147
|
+
and almost certainly an editor mistake.
|
|
148
|
+
|
|
149
|
+
`collections` and `statuses` only meaningful for per-document
|
|
150
|
+
findings. Sitewide findings (cross-document audit issues) are
|
|
151
|
+
matched only by `routePattern` and `ruleIds`.
|
|
152
|
+
|
|
153
|
+
Suppressions are plugin-only by design. The CLI's `check` is the
|
|
154
|
+
canonical strict audit; if you want to silence findings at the CLI
|
|
155
|
+
layer, use `aexeo.toml`'s `[ignore]` block instead.
|
|
156
|
+
|
|
62
157
|
## Two factories
|
|
63
158
|
|
|
64
159
|
The package exports two factories for different trust contexts:
|
|
65
160
|
|
|
66
|
-
- `
|
|
161
|
+
- `aexeoPlugin()` — **configured mode** (recommended). In-process
|
|
67
162
|
plugin. Use for first-party emdash sites.
|
|
68
|
-
- `
|
|
163
|
+
- `aexeoPluginSandboxed({ evaluatorHost })` — **sandboxed mode**.
|
|
69
164
|
Requires a separately-deployed sidecar Worker. Use only when
|
|
70
165
|
shipping to third-party emdash sites that shouldn't trust the
|
|
71
166
|
plugin code with full host access.
|
package/dist/admin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/admin/Facts.tsx
|
|
2
2
|
import { useCallback, useEffect, useState } from "react";
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
-
var PLUGIN_ID = "aexeo-
|
|
4
|
+
var PLUGIN_ID = "aexeo-emdash";
|
|
5
5
|
var API_BASE = "/_emdash/api";
|
|
6
6
|
function Facts() {
|
|
7
7
|
const [data, setData] = useState(null);
|
|
@@ -275,7 +275,7 @@ async function callRoute(kind, extra) {
|
|
|
275
275
|
// src/admin/Findings.tsx
|
|
276
276
|
import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
|
|
277
277
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
278
|
-
var PLUGIN_ID2 = "aexeo-
|
|
278
|
+
var PLUGIN_ID2 = "aexeo-emdash";
|
|
279
279
|
var API_BASE2 = "/_emdash/api";
|
|
280
280
|
function Findings() {
|
|
281
281
|
const [state, setState] = useState2({
|
package/dist/configured.d.ts
CHANGED
|
@@ -1,11 +1,27 @@
|
|
|
1
|
+
import type { Suppression } from "./suppressions.js";
|
|
1
2
|
export interface ConfiguredPluginOptions {
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* in src/index.ts. When undefined, falls back to DEFAULT_COLLECTIONS
|
|
6
|
-
* (`["posts", "pages"]`).
|
|
4
|
+
* Full override of the swept collections. See `aexeoPlugin` in
|
|
5
|
+
* src/index.ts for the full precedence story.
|
|
7
6
|
*/
|
|
8
7
|
collections?: readonly string[];
|
|
8
|
+
/**
|
|
9
|
+
* Add to the default `["posts", "pages"]`. Ignored when
|
|
10
|
+
* `collections` is set.
|
|
11
|
+
*/
|
|
12
|
+
includeCollections?: readonly string[];
|
|
13
|
+
/**
|
|
14
|
+
* Remove from the default `["posts", "pages"]`. Applied before
|
|
15
|
+
* `includeCollections`. Ignored when `collections` is set.
|
|
16
|
+
*/
|
|
17
|
+
excludeCollections?: readonly string[];
|
|
18
|
+
/**
|
|
19
|
+
* Editor-workflow suppressions. See `Suppression` in suppressions.ts
|
|
20
|
+
* for the rule shape and matching semantics. Compiled once at plugin
|
|
21
|
+
* construction; the resulting filter is captured in the closures
|
|
22
|
+
* attached to the route handlers and the afterSave hook.
|
|
23
|
+
*/
|
|
24
|
+
suppressions?: readonly Suppression[];
|
|
9
25
|
}
|
|
10
26
|
export declare function createPlugin(options?: ConfiguredPluginOptions): unknown;
|
|
11
27
|
export default createPlugin;
|
package/dist/configured.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configured.d.ts","sourceRoot":"","sources":["../src/configured.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"configured.d.ts","sourceRoot":"","sources":["../src/configured.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAmFrD,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEhC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEvC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;CACvC;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAE,uBAA4B,GAAG,OAAO,CAyG3E;AAID,eAAe,YAAY,CAAC"}
|
package/dist/configured.js
CHANGED
|
@@ -73,7 +73,7 @@ function isPortableTextArray(value) {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
// src/plugin.ts
|
|
76
|
-
async function handleAfterSaveConfigured(event, ctx, evaluator) {
|
|
76
|
+
async function handleAfterSaveConfigured(event, ctx, evaluator, suppressionFilter) {
|
|
77
77
|
const adapted = adaptContentItem(event.content);
|
|
78
78
|
const document = adapted.document;
|
|
79
79
|
const { kv, log } = ctx;
|
|
@@ -89,14 +89,23 @@ async function handleAfterSaveConfigured(event, ctx, evaluator) {
|
|
|
89
89
|
const pageFindings = result.findings.filter(
|
|
90
90
|
(finding) => finding.scope === "page"
|
|
91
91
|
);
|
|
92
|
+
const filtered = suppressionFilter === void 0 ? pageFindings : suppressionFilter.apply(
|
|
93
|
+
{
|
|
94
|
+
route: document.route,
|
|
95
|
+
collection: adapted.meta.collection,
|
|
96
|
+
status: adapted.meta.status
|
|
97
|
+
},
|
|
98
|
+
pageFindings
|
|
99
|
+
);
|
|
92
100
|
await kv.set(findingsKey(document.route), {
|
|
93
101
|
route: document.route,
|
|
94
|
-
findings:
|
|
102
|
+
findings: filtered
|
|
95
103
|
});
|
|
96
104
|
}
|
|
97
105
|
var DEFAULT_COLLECTIONS = ["posts", "pages"];
|
|
98
106
|
async function evaluateAndPersistAll(ctx, options) {
|
|
99
107
|
const collections = options.collections ?? DEFAULT_COLLECTIONS;
|
|
108
|
+
const suppressionFilter = options.suppressionFilter;
|
|
100
109
|
const { kv, log } = ctx;
|
|
101
110
|
const summary = {
|
|
102
111
|
documentsScanned: 0,
|
|
@@ -138,7 +147,7 @@ async function evaluateAndPersistAll(ctx, options) {
|
|
|
138
147
|
}
|
|
139
148
|
const result = await options.evaluator(documents);
|
|
140
149
|
if (!result.ok) {
|
|
141
|
-
log?.error?.(`
|
|
150
|
+
log?.error?.(`aexeo evaluator failure (${result.reason})`, {
|
|
142
151
|
detail: result.detail
|
|
143
152
|
});
|
|
144
153
|
summary.errors.push(`${result.reason}: ${result.detail}`);
|
|
@@ -154,11 +163,20 @@ async function evaluateAndPersistAll(ctx, options) {
|
|
|
154
163
|
list.push(finding);
|
|
155
164
|
findingsByRoute.set(bucket, list);
|
|
156
165
|
}
|
|
166
|
+
let totalAfterSuppression = 0;
|
|
157
167
|
for (const [route, findings] of findingsByRoute) {
|
|
158
|
-
|
|
168
|
+
const stored = adaptedByRoute.get(route);
|
|
169
|
+
const context = {
|
|
170
|
+
route,
|
|
171
|
+
...stored?.meta.collection === void 0 ? {} : { collection: stored.meta.collection },
|
|
172
|
+
...stored?.meta.status === void 0 ? {} : { status: stored.meta.status }
|
|
173
|
+
};
|
|
174
|
+
const filtered = suppressionFilter === void 0 ? findings : suppressionFilter.apply(context, findings);
|
|
175
|
+
await kv.set(findingsKey(route), { route, findings: filtered });
|
|
159
176
|
summary.routesUpdated += 1;
|
|
177
|
+
totalAfterSuppression += filtered.length;
|
|
160
178
|
}
|
|
161
|
-
summary.totalFindings =
|
|
179
|
+
summary.totalFindings = totalAfterSuppression;
|
|
162
180
|
return summary;
|
|
163
181
|
}
|
|
164
182
|
function findingsKey(route) {
|
|
@@ -413,7 +431,7 @@ function ensureInitialized() {
|
|
|
413
431
|
}
|
|
414
432
|
if (!(bridgeModule instanceof WebAssembly.Module)) {
|
|
415
433
|
throw new Error(
|
|
416
|
-
"
|
|
434
|
+
"aexeo: WASM module did not resolve to a WebAssembly.Module \u2014 the consumer's bundler isn't configured for .wasm imports. Add the .wasm loader to your Vite/wrangler config; see @aeptus/aexeo-emdash INSTALL.md for the recipe."
|
|
417
435
|
);
|
|
418
436
|
}
|
|
419
437
|
const instance = new WebAssembly.Instance(bridgeModule, {
|
|
@@ -446,7 +464,8 @@ async function handleDataRoute(ctx, options) {
|
|
|
446
464
|
if (options.refresh) {
|
|
447
465
|
summary = await evaluateAndPersistAll(ctx, {
|
|
448
466
|
collections: options.collections,
|
|
449
|
-
evaluator: options.evaluator
|
|
467
|
+
evaluator: options.evaluator,
|
|
468
|
+
...options.suppressionFilter === void 0 ? {} : { suppressionFilter: options.suppressionFilter }
|
|
450
469
|
});
|
|
451
470
|
await persistManifestStateFindings(ctx);
|
|
452
471
|
}
|
|
@@ -724,11 +743,88 @@ async function handleSave(ctx, body) {
|
|
|
724
743
|
return { data: { saved: true } };
|
|
725
744
|
}
|
|
726
745
|
|
|
746
|
+
// src/suppressions.ts
|
|
747
|
+
var NOOP_FILTER = {
|
|
748
|
+
apply: (_context, findings) => [...findings]
|
|
749
|
+
};
|
|
750
|
+
function compileSuppressions(rules) {
|
|
751
|
+
if (rules === void 0 || rules.length === 0) {
|
|
752
|
+
return NOOP_FILTER;
|
|
753
|
+
}
|
|
754
|
+
rules.forEach((rule, index) => {
|
|
755
|
+
const hasRoute = rule.routePattern !== void 0 && rule.routePattern.length > 0;
|
|
756
|
+
const hasRuleIds = rule.ruleIds !== void 0 && rule.ruleIds.length > 0;
|
|
757
|
+
const hasCollections = rule.collections !== void 0 && rule.collections.length > 0;
|
|
758
|
+
const hasStatuses = rule.statuses !== void 0 && rule.statuses.length > 0;
|
|
759
|
+
if (!hasRoute && !hasRuleIds && !hasCollections && !hasStatuses) {
|
|
760
|
+
throw new Error(
|
|
761
|
+
`aexeoPlugin: suppressions[${index}] is empty \u2014 set at least one of routePattern, ruleIds, collections, statuses`
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
const compiled = rules.map((rule) => ({
|
|
766
|
+
matchRoute: rule.routePattern === void 0 ? matchAlways : globToMatcher(rule.routePattern),
|
|
767
|
+
ruleIds: rule.ruleIds === void 0 || rule.ruleIds.length === 0 ? null : new Set(rule.ruleIds),
|
|
768
|
+
collections: rule.collections === void 0 || rule.collections.length === 0 ? null : new Set(rule.collections),
|
|
769
|
+
statuses: rule.statuses === void 0 || rule.statuses.length === 0 ? null : new Set(rule.statuses)
|
|
770
|
+
}));
|
|
771
|
+
return {
|
|
772
|
+
apply(context, findings) {
|
|
773
|
+
return findings.filter(
|
|
774
|
+
(finding) => !compiled.some((rule) => {
|
|
775
|
+
if (!rule.matchRoute(context.route)) return false;
|
|
776
|
+
if (rule.ruleIds !== null && !rule.ruleIds.has(finding.rule_id)) {
|
|
777
|
+
return false;
|
|
778
|
+
}
|
|
779
|
+
if (rule.collections !== null) {
|
|
780
|
+
if (context.collection === void 0 || !rule.collections.has(context.collection)) {
|
|
781
|
+
return false;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
if (rule.statuses !== null) {
|
|
785
|
+
if (context.status === void 0 || !rule.statuses.has(context.status)) {
|
|
786
|
+
return false;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return true;
|
|
790
|
+
})
|
|
791
|
+
);
|
|
792
|
+
}
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
var matchAlways = () => true;
|
|
796
|
+
function globToMatcher(pattern) {
|
|
797
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
798
|
+
const DOUBLE_STAR_TOKEN = "";
|
|
799
|
+
const body = escaped.replace(/\*\*/g, DOUBLE_STAR_TOKEN).replace(/\*/g, "[^/]*").replace(new RegExp(DOUBLE_STAR_TOKEN, "g"), ".*").replace(/\?/g, "[^/]");
|
|
800
|
+
const re = new RegExp(`^${body}$`);
|
|
801
|
+
return (route) => re.test(route);
|
|
802
|
+
}
|
|
803
|
+
|
|
727
804
|
// src/version.ts
|
|
728
|
-
var PACKAGE_VERSION = "0.
|
|
805
|
+
var PACKAGE_VERSION = "0.5.0";
|
|
729
806
|
|
|
730
807
|
// src/configured.ts
|
|
731
808
|
import { definePlugin } from "emdash";
|
|
809
|
+
function resolveCollections(explicit, include, exclude) {
|
|
810
|
+
if (explicit !== void 0) {
|
|
811
|
+
return [...explicit];
|
|
812
|
+
}
|
|
813
|
+
const excludeSet = new Set(exclude ?? []);
|
|
814
|
+
const base = DEFAULT_COLLECTIONS.filter(
|
|
815
|
+
(slug) => !excludeSet.has(slug)
|
|
816
|
+
);
|
|
817
|
+
if (include === void 0 || include.length === 0) {
|
|
818
|
+
return base;
|
|
819
|
+
}
|
|
820
|
+
const result = [...base];
|
|
821
|
+
for (const slug of include) {
|
|
822
|
+
if (!result.includes(slug)) {
|
|
823
|
+
result.push(slug);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
return result;
|
|
827
|
+
}
|
|
732
828
|
var inProcessEvaluator = async (documents) => {
|
|
733
829
|
try {
|
|
734
830
|
const raw = await evaluateDocuments2(JSON.stringify(documents));
|
|
@@ -747,16 +843,26 @@ var inProcessEvaluator = async (documents) => {
|
|
|
747
843
|
}
|
|
748
844
|
};
|
|
749
845
|
function createPlugin(options = {}) {
|
|
750
|
-
const collections =
|
|
846
|
+
const collections = resolveCollections(
|
|
847
|
+
options.collections,
|
|
848
|
+
options.includeCollections,
|
|
849
|
+
options.excludeCollections
|
|
850
|
+
);
|
|
851
|
+
const suppressionFilter = compileSuppressions(options.suppressions);
|
|
751
852
|
return definePlugin({
|
|
752
|
-
id: "aexeo-
|
|
853
|
+
id: "aexeo-emdash",
|
|
753
854
|
version: PACKAGE_VERSION,
|
|
754
855
|
capabilities: ["read:content"],
|
|
755
856
|
hooks: {
|
|
756
857
|
// afterSave processes one saved document at a time — collections
|
|
757
858
|
// list isn't needed here. The hook always runs regardless of
|
|
758
859
|
// which collection the document came from.
|
|
759
|
-
"content:afterSave": (event, ctx) => handleAfterSaveConfigured(
|
|
860
|
+
"content:afterSave": (event, ctx) => handleAfterSaveConfigured(
|
|
861
|
+
event,
|
|
862
|
+
ctx,
|
|
863
|
+
inProcessEvaluator,
|
|
864
|
+
suppressionFilter
|
|
865
|
+
)
|
|
760
866
|
},
|
|
761
867
|
routes: {
|
|
762
868
|
// The Refresh sweep (handleAdminRoute → handleRefresh) is the
|
|
@@ -766,8 +872,8 @@ function createPlugin(options = {}) {
|
|
|
766
872
|
handler: (ctx) => handleAdminRoute(ctx, collections)
|
|
767
873
|
},
|
|
768
874
|
// JSON data endpoint for the React adminEntry. Two routes:
|
|
769
|
-
// POST /_emdash/api/plugins/aexeo-
|
|
770
|
-
// POST /_emdash/api/plugins/aexeo-
|
|
875
|
+
// POST /_emdash/api/plugins/aexeo-emdash/data — read current findings
|
|
876
|
+
// POST /_emdash/api/plugins/aexeo-emdash/refresh — sweep + read
|
|
771
877
|
// Returning JSON (not Block Kit blocks) lets the React
|
|
772
878
|
// <Findings/> component render proper <a href> links to the
|
|
773
879
|
// emdash edit page and the public site, which Block Kit can't
|
|
@@ -776,14 +882,16 @@ function createPlugin(options = {}) {
|
|
|
776
882
|
handler: async (ctx) => (await handleDataRoute(ctx, {
|
|
777
883
|
collections,
|
|
778
884
|
evaluator: inProcessEvaluator,
|
|
779
|
-
refresh: false
|
|
885
|
+
refresh: false,
|
|
886
|
+
suppressionFilter
|
|
780
887
|
})).payload
|
|
781
888
|
},
|
|
782
889
|
refresh: {
|
|
783
890
|
handler: (ctx) => handleDataRoute(ctx, {
|
|
784
891
|
collections,
|
|
785
892
|
evaluator: inProcessEvaluator,
|
|
786
|
-
refresh: true
|
|
893
|
+
refresh: true,
|
|
894
|
+
suppressionFilter
|
|
787
895
|
})
|
|
788
896
|
},
|
|
789
897
|
// /facts route serves the truth-manifest authoring UI. It
|
|
@@ -806,7 +914,7 @@ function createPlugin(options = {}) {
|
|
|
806
914
|
{ path: "/facts", label: "Truth manifest" }
|
|
807
915
|
],
|
|
808
916
|
widgets: [
|
|
809
|
-
{ id: "
|
|
917
|
+
{ id: "aexeo-score", size: "third", title: "SEO score" }
|
|
810
918
|
]
|
|
811
919
|
}
|
|
812
920
|
});
|
|
@@ -845,7 +953,7 @@ async function handlePageLoad(ctx, page) {
|
|
|
845
953
|
if (normalized === "" || normalized === "findings") {
|
|
846
954
|
return renderFindingsPage(ctx);
|
|
847
955
|
}
|
|
848
|
-
if (normalized === "widget:
|
|
956
|
+
if (normalized === "widget:aexeo-score") {
|
|
849
957
|
return renderScoreWidget(ctx);
|
|
850
958
|
}
|
|
851
959
|
if (normalized === "document") {
|
|
@@ -993,7 +1101,7 @@ async function renderScoreWidget(ctx) {
|
|
|
993
1101
|
{ type: "header", text: "SEO score" },
|
|
994
1102
|
{
|
|
995
1103
|
type: "context",
|
|
996
|
-
text: "No documents indexed \u2014 click Refresh on the
|
|
1104
|
+
text: "No documents indexed \u2014 click Refresh on the Aexeo findings page."
|
|
997
1105
|
}
|
|
998
1106
|
]
|
|
999
1107
|
};
|
package/dist/data-route.d.ts
CHANGED
|
@@ -39,6 +39,7 @@ interface DataRouteOptions {
|
|
|
39
39
|
collections: readonly string[];
|
|
40
40
|
evaluator: EvaluatorFn;
|
|
41
41
|
refresh: boolean;
|
|
42
|
+
suppressionFilter?: import("./suppressions.js").SuppressionFilter;
|
|
42
43
|
}
|
|
43
44
|
export declare function handleDataRoute(ctx: SandboxCtx, options: DataRouteOptions): Promise<{
|
|
44
45
|
payload: FindingsPayload;
|
package/dist/data-route.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
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;IAIjB,iBAAiB,CAAC,EAAE,OAAO,mBAAmB,EAAE,iBAAiB,CAAC;CACnE;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,CAmBD;AAgGD,wBAAsB,4BAA4B,CAChD,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,IAAI,CAAC,CAGf"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type { PluginAdminPage, PluginAdminWidget, SandboxedPluginDescriptor,
|
|
1
|
+
export { aexeoPluginSandboxed } from "./sandbox.js";
|
|
2
|
+
export type { PluginAdminPage, PluginAdminWidget, SandboxedPluginDescriptor, AexeoSandboxedOptions, } from "./sandbox.js";
|
|
3
3
|
export interface ConfiguredPluginDescriptor {
|
|
4
4
|
id: string;
|
|
5
5
|
version: string;
|
|
@@ -18,7 +18,7 @@ export interface ConfiguredPluginDescriptor {
|
|
|
18
18
|
title?: string;
|
|
19
19
|
}[];
|
|
20
20
|
}
|
|
21
|
-
export interface
|
|
21
|
+
export interface AexeoPluginOptions {
|
|
22
22
|
/**
|
|
23
23
|
* emdash collections the plugin sweeps when an admin clicks
|
|
24
24
|
* Refresh on the findings page. Order doesn't matter; the sweep
|
|
@@ -29,17 +29,80 @@ export interface SeogeoPluginOptions {
|
|
|
29
29
|
*
|
|
30
30
|
* Defaults to `["posts", "pages"]` (the slugs the
|
|
31
31
|
* `@emdash-cms/template-blog-cloudflare` template ships with).
|
|
32
|
-
*
|
|
32
|
+
* Three knobs, in precedence order:
|
|
33
33
|
*
|
|
34
|
-
*
|
|
34
|
+
* - `collections` — full override. When set, replaces the
|
|
35
|
+
* default entirely. Use this when your schema has none of the
|
|
36
|
+
* default slugs (e.g. a site with `blog_posts` and `pages`).
|
|
35
37
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
38
|
+
* aexeoPlugin({ collections: ["blog_posts", "pages"] })
|
|
39
|
+
*
|
|
40
|
+
* - `includeCollections` — extend the default. Adds slugs to
|
|
41
|
+
* the existing default. Use this when your schema has the
|
|
42
|
+
* default slugs PLUS extras.
|
|
43
|
+
*
|
|
44
|
+
* aexeoPlugin({ includeCollections: ["guides", "faqs"] })
|
|
45
|
+
*
|
|
46
|
+
* - `excludeCollections` — subtract from the default. Removes
|
|
47
|
+
* slugs from the existing default. Use this when your schema
|
|
48
|
+
* has the defaults but you want to skip one.
|
|
49
|
+
*
|
|
50
|
+
* aexeoPlugin({ excludeCollections: ["posts"] })
|
|
51
|
+
*
|
|
52
|
+
* `includeCollections` and `excludeCollections` may be combined
|
|
53
|
+
* (subtract first, then add). `collections` ignores both — it's
|
|
54
|
+
* the explicit-list override.
|
|
55
|
+
*
|
|
56
|
+
* Pointing any of these at a slug that doesn't exist in your
|
|
57
|
+
* schema is non-fatal: the bridge's `content.list` returns empty
|
|
58
|
+
* and the sweep records the missing collection in the Refresh
|
|
59
|
+
* summary's `errors` field. Safe to ship a superset for a project
|
|
60
|
+
* that may add collections later.
|
|
41
61
|
*/
|
|
42
62
|
collections?: readonly string[];
|
|
63
|
+
/**
|
|
64
|
+
* Slugs to add on top of the default `["posts", "pages"]`. Ignored
|
|
65
|
+
* when `collections` is set (which fully overrides the default).
|
|
66
|
+
* See `collections` for the full precedence story.
|
|
67
|
+
*/
|
|
68
|
+
includeCollections?: readonly string[];
|
|
69
|
+
/**
|
|
70
|
+
* Slugs to remove from the default `["posts", "pages"]`. Applied
|
|
71
|
+
* before `includeCollections`, so adding a slug back via include
|
|
72
|
+
* is a no-op (it was never removed). Ignored when `collections`
|
|
73
|
+
* is set.
|
|
74
|
+
*/
|
|
75
|
+
excludeCollections?: readonly string[];
|
|
76
|
+
/**
|
|
77
|
+
* Editor-workflow suppressions. Each rule silences findings that
|
|
78
|
+
* match the route pattern (glob) AND/OR are in the rule-id set.
|
|
79
|
+
* Applied before findings are persisted to KV — suppressed findings
|
|
80
|
+
* never reach the dashboard, /findings, or the per-document panel.
|
|
81
|
+
*
|
|
82
|
+
* aexeoPlugin({
|
|
83
|
+
* suppressions: [
|
|
84
|
+
* { routePattern: "/privacy", ruleIds: ["RULE001"] },
|
|
85
|
+
* { routePattern: "/fr-fr/**", ruleIds: ["RULE002"] },
|
|
86
|
+
* { ruleIds: ["RULE999"] }, // applies to every route
|
|
87
|
+
* ],
|
|
88
|
+
* })
|
|
89
|
+
*
|
|
90
|
+
* Glob syntax: `*` matches any chars except `/`; `**` matches across
|
|
91
|
+
* `/`; `?` matches one char except `/`. Patterns are anchored.
|
|
92
|
+
*
|
|
93
|
+
* Empty rules (`{}` with neither field set) are rejected at plugin
|
|
94
|
+
* construction — that's a kill-switch for all findings everywhere
|
|
95
|
+
* and almost certainly an editor mistake.
|
|
96
|
+
*
|
|
97
|
+
* Suppressions are plugin-only by design. The CLI's `check` is the
|
|
98
|
+
* canonical strict audit; if you want to silence findings at the
|
|
99
|
+
* CLI layer, use `aexeo.toml`'s `[ignore]` block instead. The two
|
|
100
|
+
* surfaces serve different audiences: the plugin is editorial
|
|
101
|
+
* workflow, the CLI is build-gating.
|
|
102
|
+
*/
|
|
103
|
+
suppressions?: readonly Suppression[];
|
|
43
104
|
}
|
|
44
|
-
export
|
|
105
|
+
export type { Suppression } from "./suppressions.js";
|
|
106
|
+
import type { Suppression } from "./suppressions.js";
|
|
107
|
+
export declare function aexeoPlugin(options?: AexeoPluginOptions): ConfiguredPluginDescriptor;
|
|
45
108
|
//# sourceMappingURL=index.d.ts.map
|
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,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,yBAAyB,EACzB,qBAAqB,GACtB,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,kBAAkB;IACjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuCG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEhC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEvC;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,YAAY,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;CACvC;AAED,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,wBAAgB,WAAW,CACzB,OAAO,GAAE,kBAAuB,GAC/B,0BAA0B,CAqE5B"}
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ var baseCapabilities = [
|
|
|
6
6
|
"write:artifacts:public/llms-full.txt",
|
|
7
7
|
"write:artifacts:public/facts.json",
|
|
8
8
|
"write:artifacts:public/*.md.txt",
|
|
9
|
-
"kv:
|
|
9
|
+
"kv:aexeo-baselines"
|
|
10
10
|
];
|
|
11
11
|
function buildCapabilities(evaluatorHost) {
|
|
12
12
|
if (evaluatorHost === null) {
|
|
@@ -23,13 +23,13 @@ function buildAllowedHosts(evaluatorHost) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
// src/version.ts
|
|
26
|
-
var PACKAGE_VERSION = "0.
|
|
26
|
+
var PACKAGE_VERSION = "0.5.0";
|
|
27
27
|
|
|
28
28
|
// src/sandbox.ts
|
|
29
|
-
function
|
|
30
|
-
const evaluatorHost = options.evaluatorHost ?? process.env.
|
|
29
|
+
function aexeoPluginSandboxed(options = {}) {
|
|
30
|
+
const evaluatorHost = options.evaluatorHost ?? process.env.AEXEO_EVALUATOR_HOST ?? null;
|
|
31
31
|
return {
|
|
32
|
-
id: "aexeo-
|
|
32
|
+
id: "aexeo-emdash",
|
|
33
33
|
version: PACKAGE_VERSION,
|
|
34
34
|
// Subpath export of this same package; must match package.json
|
|
35
35
|
// `exports["./sandbox"]`.
|
|
@@ -37,7 +37,7 @@ function seogeoPluginSandboxed(options = {}) {
|
|
|
37
37
|
format: "standard",
|
|
38
38
|
capabilities: buildCapabilities(evaluatorHost),
|
|
39
39
|
allowedHosts: buildAllowedHosts(evaluatorHost),
|
|
40
|
-
// Pages mount at /admin/plugins/aexeo-
|
|
40
|
+
// Pages mount at /admin/plugins/aexeo-emdash/<path>. The page name
|
|
41
41
|
// (without leading slash) is what the sandbox entry receives in
|
|
42
42
|
// `body.page` when emdash POSTs the page_load interaction.
|
|
43
43
|
adminPages: [
|
|
@@ -46,15 +46,15 @@ function seogeoPluginSandboxed(options = {}) {
|
|
|
46
46
|
{ path: "/setup", label: "Setup" }
|
|
47
47
|
],
|
|
48
48
|
adminWidgets: [
|
|
49
|
-
{ id: "
|
|
49
|
+
{ id: "aexeo-score", size: "third", title: "SEO score" }
|
|
50
50
|
]
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
// src/index.ts
|
|
55
|
-
function
|
|
55
|
+
function aexeoPlugin(options = {}) {
|
|
56
56
|
return {
|
|
57
|
-
id: "aexeo-
|
|
57
|
+
id: "aexeo-emdash",
|
|
58
58
|
version: PACKAGE_VERSION,
|
|
59
59
|
// Subpath import resolved by the consumer's bundler at build
|
|
60
60
|
// time — must match the package.json `exports["./configured"]`
|
|
@@ -75,12 +75,22 @@ function seogeoPlugin(options = {}) {
|
|
|
75
75
|
// receives. Spread to a plain object so readonly arrays survive
|
|
76
76
|
// the structured-clone semantics of that codegen.
|
|
77
77
|
options: {
|
|
78
|
-
...options.collections === void 0 ? {} : { collections: [...options.collections] }
|
|
78
|
+
...options.collections === void 0 ? {} : { collections: [...options.collections] },
|
|
79
|
+
...options.includeCollections === void 0 ? {} : { includeCollections: [...options.includeCollections] },
|
|
80
|
+
...options.excludeCollections === void 0 ? {} : { excludeCollections: [...options.excludeCollections] },
|
|
81
|
+
...options.suppressions === void 0 ? {} : {
|
|
82
|
+
suppressions: options.suppressions.map((rule) => ({
|
|
83
|
+
...rule,
|
|
84
|
+
...rule.ruleIds === void 0 ? {} : { ruleIds: [...rule.ruleIds] },
|
|
85
|
+
...rule.collections === void 0 ? {} : { collections: [...rule.collections] },
|
|
86
|
+
...rule.statuses === void 0 ? {} : { statuses: [...rule.statuses] }
|
|
87
|
+
}))
|
|
88
|
+
}
|
|
79
89
|
},
|
|
80
90
|
capabilities: [
|
|
81
91
|
"read:content",
|
|
82
92
|
"read:schema",
|
|
83
|
-
"kv:
|
|
93
|
+
"kv:aexeo-baselines"
|
|
84
94
|
],
|
|
85
95
|
// adminPages drives the admin sidebar — one nav entry per item.
|
|
86
96
|
// Don't list "/" alongside "/findings": both would render as
|
|
@@ -94,11 +104,11 @@ function seogeoPlugin(options = {}) {
|
|
|
94
104
|
{ path: "/document", label: "Document SEO" }
|
|
95
105
|
],
|
|
96
106
|
adminWidgets: [
|
|
97
|
-
{ id: "
|
|
107
|
+
{ id: "aexeo-score", size: "third", title: "SEO score" }
|
|
98
108
|
]
|
|
99
109
|
};
|
|
100
110
|
}
|
|
101
111
|
export {
|
|
102
|
-
|
|
103
|
-
|
|
112
|
+
aexeoPlugin,
|
|
113
|
+
aexeoPluginSandboxed
|
|
104
114
|
};
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SuppressionFilter } from "./suppressions.js";
|
|
1
2
|
import type { EmdashDocument, Finding } from "./types.js";
|
|
2
3
|
import { type EmdashContentItem, type EmdashContentMeta } from "./adapter.js";
|
|
3
4
|
import type { SidecarHttp } from "./sidecar.js";
|
|
@@ -58,7 +59,7 @@ export interface ContentAfterSaveEvent {
|
|
|
58
59
|
isNew: boolean;
|
|
59
60
|
}
|
|
60
61
|
export declare function handleAfterSave(_event: ContentAfterSaveEvent, _ctx: SandboxCtx): Promise<void>;
|
|
61
|
-
export declare function handleAfterSaveConfigured(event: ContentAfterSaveEvent, ctx: SandboxCtx, evaluator: EvaluatorFn): Promise<void>;
|
|
62
|
+
export declare function handleAfterSaveConfigured(event: ContentAfterSaveEvent, ctx: SandboxCtx, evaluator: EvaluatorFn, suppressionFilter?: SuppressionFilter): Promise<void>;
|
|
62
63
|
export declare const DEFAULT_COLLECTIONS: readonly ["posts", "pages"];
|
|
63
64
|
export interface RefreshSummary {
|
|
64
65
|
documentsScanned: number;
|
|
@@ -78,6 +79,7 @@ export type EvaluatorFn = (documents: readonly EmdashDocument[]) => Promise<Eval
|
|
|
78
79
|
export declare function evaluateAndPersistAll(ctx: SandboxCtx, options: {
|
|
79
80
|
collections?: readonly string[];
|
|
80
81
|
evaluator: EvaluatorFn;
|
|
82
|
+
suppressionFilter?: SuppressionFilter;
|
|
81
83
|
}): Promise<RefreshSummary>;
|
|
82
84
|
export declare function findingsKey(route: string): string;
|
|
83
85
|
export declare function documentKey(route: string): string;
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/sandbox-entry.js
CHANGED
|
@@ -89,6 +89,7 @@ async function handleAfterSave(_event, _ctx) {
|
|
|
89
89
|
var DEFAULT_COLLECTIONS = ["posts", "pages"];
|
|
90
90
|
async function evaluateAndPersistAll(ctx, options) {
|
|
91
91
|
const collections = options.collections ?? DEFAULT_COLLECTIONS;
|
|
92
|
+
const suppressionFilter = options.suppressionFilter;
|
|
92
93
|
const { kv, log } = ctx;
|
|
93
94
|
const summary = {
|
|
94
95
|
documentsScanned: 0,
|
|
@@ -130,7 +131,7 @@ async function evaluateAndPersistAll(ctx, options) {
|
|
|
130
131
|
}
|
|
131
132
|
const result = await options.evaluator(documents);
|
|
132
133
|
if (!result.ok) {
|
|
133
|
-
log?.error?.(`
|
|
134
|
+
log?.error?.(`aexeo evaluator failure (${result.reason})`, {
|
|
134
135
|
detail: result.detail
|
|
135
136
|
});
|
|
136
137
|
summary.errors.push(`${result.reason}: ${result.detail}`);
|
|
@@ -146,11 +147,20 @@ async function evaluateAndPersistAll(ctx, options) {
|
|
|
146
147
|
list.push(finding);
|
|
147
148
|
findingsByRoute2.set(bucket, list);
|
|
148
149
|
}
|
|
150
|
+
let totalAfterSuppression = 0;
|
|
149
151
|
for (const [route, findings] of findingsByRoute2) {
|
|
150
|
-
|
|
152
|
+
const stored = adaptedByRoute.get(route);
|
|
153
|
+
const context = {
|
|
154
|
+
route,
|
|
155
|
+
...stored?.meta.collection === void 0 ? {} : { collection: stored.meta.collection },
|
|
156
|
+
...stored?.meta.status === void 0 ? {} : { status: stored.meta.status }
|
|
157
|
+
};
|
|
158
|
+
const filtered = suppressionFilter === void 0 ? findings : suppressionFilter.apply(context, findings);
|
|
159
|
+
await kv.set(findingsKey(route), { route, findings: filtered });
|
|
151
160
|
summary.routesUpdated += 1;
|
|
161
|
+
totalAfterSuppression += filtered.length;
|
|
152
162
|
}
|
|
153
|
-
summary.totalFindings =
|
|
163
|
+
summary.totalFindings = totalAfterSuppression;
|
|
154
164
|
return summary;
|
|
155
165
|
}
|
|
156
166
|
function findingsKey(route) {
|
|
@@ -360,8 +370,8 @@ function failure(reason, rejected) {
|
|
|
360
370
|
|
|
361
371
|
// src/mcp.ts
|
|
362
372
|
var checkTool = {
|
|
363
|
-
name: "
|
|
364
|
-
description: "Evaluate a list of EmdashDocument values against the
|
|
373
|
+
name: "aexeo.check",
|
|
374
|
+
description: "Evaluate a list of EmdashDocument values against the Aexeo rule engine and return the stable Finding contract. Mirrors the CLI's `aexeo-cli check` surface so agents, the admin UI, and the CI gate all see the same rule ids.",
|
|
365
375
|
inputSchema: {
|
|
366
376
|
type: "object",
|
|
367
377
|
properties: {
|
|
@@ -371,7 +381,7 @@ var checkTool = {
|
|
|
371
381
|
},
|
|
372
382
|
configJson: {
|
|
373
383
|
type: "string",
|
|
374
|
-
description: "Optional JSON-serialized
|
|
384
|
+
description: "Optional JSON-serialized Aexeo config. When absent the evaluator uses Config::default(), matching a cold CLI run."
|
|
375
385
|
}
|
|
376
386
|
},
|
|
377
387
|
required: ["documents"]
|
|
@@ -398,8 +408,8 @@ var checkTool = {
|
|
|
398
408
|
}
|
|
399
409
|
};
|
|
400
410
|
var indexNowSubmitTool = {
|
|
401
|
-
name: "
|
|
402
|
-
description: "Submit a list of URLs to the IndexNow freshness endpoint. Mirrors the
|
|
411
|
+
name: "aexeo.indexnow.submit",
|
|
412
|
+
description: "Submit a list of URLs to the IndexNow freshness endpoint. Mirrors the aexeo-cli `indexnow submit` contract: the IndexNow protocol requires every submitted URL to belong to the configured site host. URLs that do not match the host are returned in `rejected` and never sent over the wire.",
|
|
403
413
|
inputSchema: {
|
|
404
414
|
type: "object",
|
|
405
415
|
properties: {
|
|
@@ -431,7 +441,7 @@ function definePlugin(plugin) {
|
|
|
431
441
|
}
|
|
432
442
|
async function handleAdminRoute(input, ctx) {
|
|
433
443
|
ctx.log?.info?.(
|
|
434
|
-
`
|
|
444
|
+
`aexeo route: type=${input.input?.type} page=${input.input?.page ?? ""}`
|
|
435
445
|
);
|
|
436
446
|
const dispatch = { body: input.input, kv: ctx.kv, ctx };
|
|
437
447
|
if (dispatch.body.type === "page_load") {
|
|
@@ -470,7 +480,7 @@ async function handlePageLoad(ctx, page) {
|
|
|
470
480
|
if (normalized === "findings") {
|
|
471
481
|
return renderFindingsPage(ctx);
|
|
472
482
|
}
|
|
473
|
-
if (normalized === "widget:
|
|
483
|
+
if (normalized === "widget:aexeo-score") {
|
|
474
484
|
return renderScoreWidget(ctx);
|
|
475
485
|
}
|
|
476
486
|
if (normalized === "document") {
|
|
@@ -500,7 +510,7 @@ async function handleRefresh(ctx) {
|
|
|
500
510
|
return {
|
|
501
511
|
ok: false,
|
|
502
512
|
reason: "config_missing",
|
|
503
|
-
detail: "sidecar not configured \u2014 open the
|
|
513
|
+
detail: "sidecar not configured \u2014 open the Aexeo Setup page and enter your evaluator URL and token"
|
|
504
514
|
};
|
|
505
515
|
}
|
|
506
516
|
return evaluateViaSidecar(
|
|
@@ -759,10 +769,10 @@ function documentFindingsTable(findings) {
|
|
|
759
769
|
async function renderSetupPage(ctx, options = {}) {
|
|
760
770
|
const existing = await readSidecarConfig(ctx.kv);
|
|
761
771
|
const blocks = [
|
|
762
|
-
{ type: "header", text: "
|
|
772
|
+
{ type: "header", text: "Aexeo setup" },
|
|
763
773
|
{
|
|
764
774
|
type: "context",
|
|
765
|
-
text: "Paste the URL and auth token of your deployed
|
|
775
|
+
text: "Paste the URL and auth token of your deployed aexeo-crawl-worker. These are stored in plugin KV and read at runtime \u2014 no rebuild required after a change. Rotate the token here whenever you redeploy the sidecar with a new secret."
|
|
766
776
|
}
|
|
767
777
|
];
|
|
768
778
|
if (options.bannerError !== void 0) {
|
|
@@ -786,7 +796,7 @@ async function renderSetupPage(ctx, options = {}) {
|
|
|
786
796
|
type: "text_input",
|
|
787
797
|
action_id: "evaluator_url",
|
|
788
798
|
label: "Sidecar URL",
|
|
789
|
-
placeholder: "https://
|
|
799
|
+
placeholder: "https://aexeo-crawl-worker.<subdomain>.workers.dev",
|
|
790
800
|
initial_value: options.initialUrl ?? existing?.url ?? ""
|
|
791
801
|
},
|
|
792
802
|
{
|
package/dist/sandbox.d.ts
CHANGED
|
@@ -18,8 +18,8 @@ export interface SandboxedPluginDescriptor {
|
|
|
18
18
|
adminWidgets?: readonly PluginAdminWidget[];
|
|
19
19
|
allowedHosts?: readonly string[];
|
|
20
20
|
}
|
|
21
|
-
export interface
|
|
21
|
+
export interface AexeoSandboxedOptions {
|
|
22
22
|
evaluatorHost?: string;
|
|
23
23
|
}
|
|
24
|
-
export declare function
|
|
24
|
+
export declare function aexeoPluginSandboxed(options?: AexeoSandboxedOptions): SandboxedPluginDescriptor;
|
|
25
25
|
//# sourceMappingURL=sandbox.d.ts.map
|
package/dist/sandbox.d.ts.map
CHANGED
|
@@ -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,
|
|
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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Finding } from "./types.js";
|
|
2
|
+
export interface Suppression {
|
|
3
|
+
routePattern?: string;
|
|
4
|
+
ruleIds?: readonly string[];
|
|
5
|
+
collections?: readonly string[];
|
|
6
|
+
statuses?: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
export interface SuppressionContext {
|
|
9
|
+
route: string;
|
|
10
|
+
collection?: string;
|
|
11
|
+
status?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface SuppressionFilter {
|
|
14
|
+
apply(context: SuppressionContext, findings: readonly Finding[]): Finding[];
|
|
15
|
+
}
|
|
16
|
+
export declare function compileSuppressions(rules: readonly Suppression[] | undefined): SuppressionFilter;
|
|
17
|
+
//# sourceMappingURL=suppressions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suppressions.d.ts","sourceRoot":"","sources":["../src/suppressions.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAsB1C,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B;AAOD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,MAAM,WAAW,iBAAiB;IAChC,KAAK,CACH,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,SAAS,OAAO,EAAE,GAC3B,OAAO,EAAE,CAAC;CACd;AASD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,SAAS,GACxC,iBAAiB,CAyEnB"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "0.
|
|
1
|
+
export declare const PACKAGE_VERSION = "0.5.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aeptus/aexeo-emdash",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Aexeo
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Aexeo SEO/GEO content evaluator as an emdash plugin",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"author": "
|
|
6
|
+
"author": "Aeptus",
|
|
7
7
|
"homepage": "https://github.com/schiste/Aexeo/tree/main/packages/aexeo-emdash",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
Binary file
|