@aeptus/aexeo-emdash 0.8.1 → 0.8.6
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 +247 -1
- package/dist/configured.js +50 -81
- package/dist/facts-route.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/presence-route.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/wasm/aexeo_emdash_bridge_bg.wasm +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,247 @@ and the project follows [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.8.6] - 2026-05-04
|
|
10
|
+
|
|
11
|
+
Code-review follow-ups on the 0.8.5 agent-readiness rule bundles.
|
|
12
|
+
All five issues are real correctness fixes; no behavior change
|
|
13
|
+
for sites that already had clean output.
|
|
14
|
+
|
|
15
|
+
### Fixed (engine via bridge)
|
|
16
|
+
|
|
17
|
+
- **Public API exposure.** `SiteCapabilities`, `infer_site_capabilities`,
|
|
18
|
+
`well_known_path_exists`, `run_well_known_rules`, and
|
|
19
|
+
`run_header_rules` are now re-exported at the `aexeo-core` root
|
|
20
|
+
to match the existing pattern (`run_robots_rules`,
|
|
21
|
+
`run_surface_rules`, etc.). Previously consumers had to use the
|
|
22
|
+
long `aexeo_core::well_known_rules::run_well_known_rules` form.
|
|
23
|
+
- **LNK020 group/check-key mismatch.** The rule was registered under
|
|
24
|
+
the `links` group but gated on the `headers` config key in
|
|
25
|
+
`static_check.rs`; toggling `links: false` would not silence it
|
|
26
|
+
and toggling `headers: false` would silence an unrelated group.
|
|
27
|
+
Fixed by moving LNK020 to a new `headers` rule group so the
|
|
28
|
+
registry name matches the toggle key.
|
|
29
|
+
- **`route_looks_api` over-match.** Bare `v1/`, `v2/`, and
|
|
30
|
+
`graphql` prefixes incorrectly classified docs routes
|
|
31
|
+
(`/v1/getting-started`, `/v2/migration-guide`, `/graphql-101`)
|
|
32
|
+
as API surfaces, triggering SRF020 false-positives on
|
|
33
|
+
content-only docs sites. Tightened to require `api/` or
|
|
34
|
+
`graphql/` (with the slash) — the conditional-firing design's
|
|
35
|
+
whole point is to keep these silent on content sites.
|
|
36
|
+
- **`render_robots_txt` round-trip.** Aexeo's own generator emitted
|
|
37
|
+
a robots.txt that tripped ROB010 + ROB011 (no AI-bot block, no
|
|
38
|
+
Content-Signal). Generator now emits explicit AI-bot blocks
|
|
39
|
+
(GPTBot, ClaudeBot, PerplexityBot, Google-Extended, CCBot) and
|
|
40
|
+
a permissive Content-Signal default so Aexeo's own output
|
|
41
|
+
passes Aexeo's own rules.
|
|
42
|
+
- **SRF010/SRF015 unreachable from path-only signals.** The
|
|
43
|
+
capability gate required the canonical card/index file to
|
|
44
|
+
exist, but the rule fires when that exact file is missing —
|
|
45
|
+
structurally unreachable. Inference now also fires when the
|
|
46
|
+
`.well-known/mcp/` or `.well-known/agent-skills/` directory
|
|
47
|
+
exists without a canonical file inside (the partial-stub
|
|
48
|
+
pattern editors hit when starting an implementation).
|
|
49
|
+
|
|
50
|
+
### Notes for hosts upgrading from 0.8.5
|
|
51
|
+
|
|
52
|
+
- No code changes required.
|
|
53
|
+
- `aexeo-cli generate robots-txt` (and the deploy generator) now
|
|
54
|
+
produces a robots.txt with explicit AI-bot blocks and a
|
|
55
|
+
Content-Signal directive. Editors who want a non-permissive
|
|
56
|
+
stance edit the line; the defaults match the wildcard `Allow: /`
|
|
57
|
+
posture so existing crawl behavior is unchanged.
|
|
58
|
+
- Sites that have a `.well-known/mcp/` or
|
|
59
|
+
`.well-known/agent-skills/` directory stub without canonical
|
|
60
|
+
files inside will now see SRF010 / SRF015 fire (correctly —
|
|
61
|
+
the directory-stub state is exactly what the rule was meant
|
|
62
|
+
to catch).
|
|
63
|
+
|
|
64
|
+
## [0.8.5] - 2026-05-04
|
|
65
|
+
|
|
66
|
+
Brings in the agent-readiness audit rules from upstream
|
|
67
|
+
aexeo-core 0.0.11 — three bundles extracted from the Cloudflare
|
|
68
|
+
"Is Your Site Agent-Ready?" scan model.
|
|
69
|
+
|
|
70
|
+
### Added (engine via bridge)
|
|
71
|
+
|
|
72
|
+
- **Bundle A — robots.txt extensions** (always-on, retrievability):
|
|
73
|
+
- `ROB010` — robots.txt has no AI-bot User-agent directives
|
|
74
|
+
(GPTBot, ClaudeBot, ChatGPT-User, PerplexityBot, …)
|
|
75
|
+
- `ROB011` — robots.txt has no Content-Signal directives
|
|
76
|
+
(`ai-train`, `search`, `ai-input`)
|
|
77
|
+
|
|
78
|
+
- **Bundle B — `.well-known/*` discovery surfaces** (conditional,
|
|
79
|
+
absorbability). All gated on a new `SiteCapabilities` inference
|
|
80
|
+
that reads route patterns, JSON-LD schema, llms.txt content,
|
|
81
|
+
and partial-file presence to decide whether the site claims
|
|
82
|
+
the underlying capability — so these rules don't fire on
|
|
83
|
+
content-only sites that have no business exposing the surface:
|
|
84
|
+
- `SRF010 / SRF011` — agent-skills index (Cloudflare RFC v0.2.0)
|
|
85
|
+
- `SRF015 / SRF016` — MCP server card (SEP-1649)
|
|
86
|
+
- `SRF020 / SRF021` — API catalog (RFC 9727 linkset+json)
|
|
87
|
+
- `SRF025` — OAuth/OIDC discovery (RFC 8414, OIDC Discovery 1.0)
|
|
88
|
+
- `SRF026` — OAuth protected-resource metadata (RFC 9728)
|
|
89
|
+
|
|
90
|
+
- **Bundle C — runtime header audits** (runtime-only, mixed):
|
|
91
|
+
- `LNK020` — homepage response sends no Link headers (RFC 8288).
|
|
92
|
+
Silent on pure static audits — fires only when `Page.response_headers`
|
|
93
|
+
is populated.
|
|
94
|
+
- `SRF030` — homepage doesn't honor `Accept: text/markdown`
|
|
95
|
+
content negotiation (Cloudflare Markdown for Agents). Adds
|
|
96
|
+
one extra HTTP probe at the end of the runtime audit.
|
|
97
|
+
|
|
98
|
+
### Notes for hosts upgrading from 0.8.4
|
|
99
|
+
|
|
100
|
+
- No code changes required.
|
|
101
|
+
- Static audits will gain ROB010/011 immediately on every site;
|
|
102
|
+
the SRF010+ rules are silent unless the site has the
|
|
103
|
+
capability signal (so most content sites see no new findings).
|
|
104
|
+
- LNK020 + SRF030 only fire during runtime audits — static
|
|
105
|
+
audits don't reach that code path.
|
|
106
|
+
- The new `SiteCapabilities` API is exported from aexeo-core
|
|
107
|
+
for hosts that want to reuse the inference in their own
|
|
108
|
+
tooling.
|
|
109
|
+
|
|
110
|
+
## [0.8.4] - 2026-05-04
|
|
111
|
+
|
|
112
|
+
Three follow-up quality fixes from Aeptus's post-0.8.3 rollout
|
|
113
|
+
report. The 0.8.3 manifest-quality and GEO009 fixes landed
|
|
114
|
+
correctly; this release closes the remaining edges that surfaced
|
|
115
|
+
once those were out the door.
|
|
116
|
+
|
|
117
|
+
### Fixed (engine via bridge)
|
|
118
|
+
|
|
119
|
+
- **Multilingual 404 detection.** v0.0.9's blocklist was
|
|
120
|
+
English-only, so French, Spanish, Italian, German, Dutch, and
|
|
121
|
+
Portuguese 404 titles still leaked through as candidate
|
|
122
|
+
organization/product names. Aeptus reported a French
|
|
123
|
+
"Page introuvable" landing as `products[0].name`. The detector
|
|
124
|
+
now matches on cross-language morphological cues
|
|
125
|
+
(`introuvable`, `non trouv`, `no encontrad`, `não encontrad`,
|
|
126
|
+
`non trovat`, `nicht gefunden`, `niet gevonden`) plus the
|
|
127
|
+
literal numeric `404` anchor.
|
|
128
|
+
|
|
129
|
+
### Fixed (presence diagnostic via bridge)
|
|
130
|
+
|
|
131
|
+
- **RDAP normalizes to the apex domain.** The diagnostic was
|
|
132
|
+
asking rdap.org about `www.aeptus.com` (whatever subdomain the
|
|
133
|
+
manifest's website happened to record), which returns
|
|
134
|
+
not_found because the registrable domain is the apex
|
|
135
|
+
(`aeptus.com`). The RDAP fetcher now strips a leading `www.`
|
|
136
|
+
before the lookup; the result text shows the original host
|
|
137
|
+
alongside the apex so editors can see what was actually
|
|
138
|
+
checked. Deeper subdomains (`blog.foo.bar`) still need
|
|
139
|
+
manual manifest correction — full public-suffix-list-aware
|
|
140
|
+
resolution is a future hardening.
|
|
141
|
+
- **Wikidata disambiguation.** wbsearchentities returns
|
|
142
|
+
label-matched candidates without distinguishing
|
|
143
|
+
Aeptus-the-company from Aeptus-the-genus-of-insects. The
|
|
144
|
+
fetcher now requests up to 10 candidates and prefers ones
|
|
145
|
+
whose description doesn't begin with natural-world or
|
|
146
|
+
geographic disambiguators (`genus of`, `species of`, `village
|
|
147
|
+
in`, `asteroid`, …). When every match is a generic-concept
|
|
148
|
+
description, the result still lands but `extra` flags
|
|
149
|
+
"likely disambiguation needed" so the editor sees the
|
|
150
|
+
problem instead of trusting the wrong record.
|
|
151
|
+
|
|
152
|
+
### Notes for hosts upgrading from 0.8.3
|
|
153
|
+
|
|
154
|
+
- No code changes required; pure engine-side improvements.
|
|
155
|
+
- Worth re-running `intelligence facts generate` if your site
|
|
156
|
+
has any non-English 404 page that was leaking through.
|
|
157
|
+
- Worth re-running `intelligence presence` if you saw
|
|
158
|
+
Wikidata false-positives or RDAP not-found on a www-prefixed
|
|
159
|
+
domain.
|
|
160
|
+
|
|
161
|
+
## [0.8.3] - 2026-05-04
|
|
162
|
+
|
|
163
|
+
Picks up the upstream aexeo-core 0.0.9 improvements that address
|
|
164
|
+
the two open quality items Aeptus flagged after the 0.8.1 + CLI
|
|
165
|
+
0.0.8 rollout.
|
|
166
|
+
|
|
167
|
+
### Changed (engine via bridge)
|
|
168
|
+
|
|
169
|
+
- **Truth-manifest generator no longer picks listing-page or
|
|
170
|
+
404 titles as the organization/product name.** Aeptus's
|
|
171
|
+
facts.json was being generated with `organization.name = "Blog"`
|
|
172
|
+
and `product.name = "Page not found"` because the listing page's
|
|
173
|
+
title outvoted the homepage and the 404 page's title leaked into
|
|
174
|
+
the candidate corpus. Three engine fixes ship in this release:
|
|
175
|
+
(a) the generic-label blocklist now covers blog, posts,
|
|
176
|
+
articles, authors, tags, categories, search, archive, page not
|
|
177
|
+
found, 404, error, oops, and pure-numeric labels;
|
|
178
|
+
(b) 404 / error pages are detected by title/h1 patterns and
|
|
179
|
+
excluded from the candidate corpus entirely;
|
|
180
|
+
(c) the homepage signal wins over any subpage signal regardless
|
|
181
|
+
of count when present.
|
|
182
|
+
|
|
183
|
+
This is a generation-quality improvement, not a wire-format
|
|
184
|
+
change — existing stored manifests are unaffected. Hosts who
|
|
185
|
+
re-run `intelligence facts generate` will get a cleaner draft.
|
|
186
|
+
|
|
187
|
+
- **GEO009 ("page facts misalign across title/H1/OG/schema")
|
|
188
|
+
now uses the same identity-extraction logic as the
|
|
189
|
+
`intelligence identity` diagnostic.** Previously the rule read
|
|
190
|
+
every JSON-LD `name` field (including BreadcrumbList items and
|
|
191
|
+
ItemList children), so it fired on listing/author/localized
|
|
192
|
+
routes where breadcrumb crumbs leaked in. The diagnostic
|
|
193
|
+
already restricted to top-level identity-bearing schema; the
|
|
194
|
+
rule and the diagnostic now share that filter. Aeptus's
|
|
195
|
+
~44 GEO009 warnings on listing/author/localized routes should
|
|
196
|
+
drop after re-running the audit.
|
|
197
|
+
|
|
198
|
+
### Notes for hosts upgrading from 0.8.x
|
|
199
|
+
|
|
200
|
+
- No code changes required — pure engine-side improvements.
|
|
201
|
+
- Re-run `intelligence facts generate` if you generated your
|
|
202
|
+
manifest with v0.0.7 or earlier of the CLI; the new generator
|
|
203
|
+
output is materially better.
|
|
204
|
+
- Re-run the audit; expect GEO009 counts to drop on listing
|
|
205
|
+
pages without any host-side change.
|
|
206
|
+
|
|
207
|
+
## [0.8.2] - 2026-05-04
|
|
208
|
+
|
|
209
|
+
Fix for the residual entity-presence trim() crash that 0.8.1
|
|
210
|
+
didn't solve.
|
|
211
|
+
|
|
212
|
+
### Fixed
|
|
213
|
+
|
|
214
|
+
- **`/facts` and `/presence` routes were double-wrapping their
|
|
215
|
+
return values.** Both handlers returned `{ data: ... }` payloads,
|
|
216
|
+
but emdash's route registry already wraps a handler's return as
|
|
217
|
+
`{ data: <result> }` at the wire boundary. The result was
|
|
218
|
+
`{ data: { data: ... } }` on the wire. The React caller's
|
|
219
|
+
single-unwrap (`body.data`) surfaced `{ data: ... }` to the
|
|
220
|
+
consumer where the actual payload was expected — so
|
|
221
|
+
`(res as ManifestData).manifest` came back as `undefined`,
|
|
222
|
+
`JSON.stringify(undefined)` returned the literal `undefined`,
|
|
223
|
+
`setDraft(undefined)` set the textarea draft to undefined, and
|
|
224
|
+
the next render crashed on `draft.trim()`.
|
|
225
|
+
|
|
226
|
+
Fixed by changing both route handlers to return raw payloads
|
|
227
|
+
(matching the `/data` and `/refresh` route convention that has
|
|
228
|
+
always worked correctly). Errors are now signaled by throwing
|
|
229
|
+
`PluginRouteError` from the `emdash` package — the registry
|
|
230
|
+
treats thrown PluginRouteErrors as structured failures and
|
|
231
|
+
routes them through the host's standard error path. Returned
|
|
232
|
+
`{ error: ... }` objects (the previous pattern) flowed through
|
|
233
|
+
the success path and silently masqueraded as data.
|
|
234
|
+
|
|
235
|
+
### Notes for hosts upgrading from 0.8.x
|
|
236
|
+
|
|
237
|
+
- No code changes required.
|
|
238
|
+
- The wire format of the `/facts` and `/presence` route responses
|
|
239
|
+
changes: where they previously returned
|
|
240
|
+
`{ data: { data: <payload> } }`, they now return
|
|
241
|
+
`{ data: <payload> }`. Anyone calling these routes directly
|
|
242
|
+
(outside the bundled React admin) needs to drop one unwrap.
|
|
243
|
+
The bundled admin is updated in lockstep so editors see no
|
|
244
|
+
behavioral difference beyond the bug being fixed.
|
|
245
|
+
- Error responses for these routes now come back through the
|
|
246
|
+
standard `PluginRouteError` envelope (HTTP 4xx with
|
|
247
|
+
`{ error: { code, message } }`) instead of being silently
|
|
248
|
+
embedded in success responses.
|
|
249
|
+
|
|
9
250
|
## [0.8.1] - 2026-05-03
|
|
10
251
|
|
|
11
252
|
Fix for the entity-presence diagnostic shipped in 0.8.0.
|
|
@@ -519,7 +760,12 @@ First public release.
|
|
|
519
760
|
`astro.config.mjs` for the WASM import to resolve to a
|
|
520
761
|
precompiled `WebAssembly.Module`. Not optional.
|
|
521
762
|
|
|
522
|
-
[Unreleased]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.
|
|
763
|
+
[Unreleased]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.6...HEAD
|
|
764
|
+
[0.8.6]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.5...aexeo-emdash-v0.8.6
|
|
765
|
+
[0.8.5]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.4...aexeo-emdash-v0.8.5
|
|
766
|
+
[0.8.4]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.3...aexeo-emdash-v0.8.4
|
|
767
|
+
[0.8.3]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.2...aexeo-emdash-v0.8.3
|
|
768
|
+
[0.8.2]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.1...aexeo-emdash-v0.8.2
|
|
523
769
|
[0.8.1]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.0...aexeo-emdash-v0.8.1
|
|
524
770
|
[0.8.0]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.7.0...aexeo-emdash-v0.8.0
|
|
525
771
|
[0.7.0]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.6.0...aexeo-emdash-v0.7.0
|
package/dist/configured.js
CHANGED
|
@@ -469,8 +469,8 @@ async function handleDataRoute(ctx, options) {
|
|
|
469
469
|
});
|
|
470
470
|
await persistManifestStateFindings(ctx);
|
|
471
471
|
}
|
|
472
|
-
const
|
|
473
|
-
return { payload, summary };
|
|
472
|
+
const payload2 = await buildFindingsPayload(ctx);
|
|
473
|
+
return { payload: payload2, summary };
|
|
474
474
|
}
|
|
475
475
|
async function buildFindingsPayload(ctx) {
|
|
476
476
|
const stored = await readAllStoredDocuments(ctx.kv);
|
|
@@ -649,6 +649,7 @@ function buildPublishedUrl(meta, route, siteUrl) {
|
|
|
649
649
|
}
|
|
650
650
|
|
|
651
651
|
// src/facts-route.ts
|
|
652
|
+
import { PluginRouteError } from "emdash";
|
|
652
653
|
async function handleFactsRoute(ctx) {
|
|
653
654
|
const body = ctx.input ?? {};
|
|
654
655
|
switch (body.kind) {
|
|
@@ -661,47 +662,34 @@ async function handleFactsRoute(ctx) {
|
|
|
661
662
|
case "save":
|
|
662
663
|
return await handleSave(ctx, body);
|
|
663
664
|
default:
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
message: `unknown facts route kind: ${String(body.kind)}`
|
|
668
|
-
}
|
|
669
|
-
};
|
|
665
|
+
throw PluginRouteError.badRequest(
|
|
666
|
+
`unknown facts route kind: ${String(body.kind)}`
|
|
667
|
+
);
|
|
670
668
|
}
|
|
671
669
|
}
|
|
672
670
|
async function handleData(ctx) {
|
|
673
671
|
const manifest = await readStoredFacts(ctx.kv);
|
|
674
672
|
return {
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
present: manifest !== null
|
|
681
|
-
}
|
|
673
|
+
manifest,
|
|
674
|
+
// The presence flag lets the React component branch on
|
|
675
|
+
// "show authoring CTA" vs "show 'manifest stored' state" without
|
|
676
|
+
// having to introspect the manifest shape.
|
|
677
|
+
present: manifest !== null
|
|
682
678
|
};
|
|
683
679
|
}
|
|
684
680
|
async function handlePrompt(ctx) {
|
|
685
681
|
const documents = await readAllDocuments(ctx.kv);
|
|
686
682
|
if (documents.length === 0) {
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
message: "no documents indexed yet \u2014 click Refresh on the Findings page first, then come back to author the manifest"
|
|
691
|
-
}
|
|
692
|
-
};
|
|
683
|
+
throw PluginRouteError.badRequest(
|
|
684
|
+
"no documents indexed yet \u2014 click Refresh on the Findings page first, then come back to author the manifest"
|
|
685
|
+
);
|
|
693
686
|
}
|
|
694
687
|
const prompt = await generateFactsPrompt2(JSON.stringify(documents));
|
|
695
|
-
return {
|
|
688
|
+
return { prompt };
|
|
696
689
|
}
|
|
697
690
|
async function handleValidate(ctx, body) {
|
|
698
691
|
if (typeof body.manifest_json !== "string" || body.manifest_json.length === 0) {
|
|
699
|
-
|
|
700
|
-
error: {
|
|
701
|
-
code: "missing_manifest",
|
|
702
|
-
message: "manifest_json field is required"
|
|
703
|
-
}
|
|
704
|
-
};
|
|
692
|
+
throw PluginRouteError.badRequest("manifest_json field is required");
|
|
705
693
|
}
|
|
706
694
|
const documents = await readAllDocuments(ctx.kv);
|
|
707
695
|
try {
|
|
@@ -709,24 +697,16 @@ async function handleValidate(ctx, body) {
|
|
|
709
697
|
body.manifest_json,
|
|
710
698
|
JSON.stringify(documents)
|
|
711
699
|
);
|
|
712
|
-
return
|
|
700
|
+
return JSON.parse(raw);
|
|
713
701
|
} catch (error) {
|
|
714
|
-
|
|
715
|
-
error:
|
|
716
|
-
|
|
717
|
-
message: error instanceof Error ? error.message : String(error)
|
|
718
|
-
}
|
|
719
|
-
};
|
|
702
|
+
throw PluginRouteError.badRequest(
|
|
703
|
+
error instanceof Error ? error.message : String(error)
|
|
704
|
+
);
|
|
720
705
|
}
|
|
721
706
|
}
|
|
722
707
|
async function handleSave(ctx, body) {
|
|
723
708
|
if (typeof body.manifest_json !== "string" || body.manifest_json.length === 0) {
|
|
724
|
-
|
|
725
|
-
error: {
|
|
726
|
-
code: "missing_manifest",
|
|
727
|
-
message: "manifest_json field is required"
|
|
728
|
-
}
|
|
729
|
-
};
|
|
709
|
+
throw PluginRouteError.badRequest("manifest_json field is required");
|
|
730
710
|
}
|
|
731
711
|
const documents = await readAllDocuments(ctx.kv);
|
|
732
712
|
let validation;
|
|
@@ -738,37 +718,31 @@ async function handleSave(ctx, body) {
|
|
|
738
718
|
const parsed2 = JSON.parse(raw);
|
|
739
719
|
validation = parsed2.validation;
|
|
740
720
|
} catch (error) {
|
|
741
|
-
|
|
742
|
-
error:
|
|
743
|
-
|
|
744
|
-
message: error instanceof Error ? error.message : String(error)
|
|
745
|
-
}
|
|
746
|
-
};
|
|
721
|
+
throw PluginRouteError.badRequest(
|
|
722
|
+
error instanceof Error ? error.message : String(error)
|
|
723
|
+
);
|
|
747
724
|
}
|
|
748
725
|
if (!validation.valid || validation.errors.length > 0) {
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
message: `manifest does not pass shape validation: ${validation.errors.slice(0, 3).join("; ")}`
|
|
753
|
-
}
|
|
754
|
-
};
|
|
726
|
+
throw PluginRouteError.badRequest(
|
|
727
|
+
`manifest does not pass shape validation: ${validation.errors.slice(0, 3).join("; ")}`
|
|
728
|
+
);
|
|
755
729
|
}
|
|
756
730
|
let parsed;
|
|
757
731
|
try {
|
|
758
732
|
parsed = JSON.parse(body.manifest_json);
|
|
759
733
|
} catch (error) {
|
|
760
|
-
|
|
761
|
-
error:
|
|
762
|
-
|
|
763
|
-
message: error instanceof Error ? error.message : String(error)
|
|
764
|
-
}
|
|
765
|
-
};
|
|
734
|
+
throw PluginRouteError.badRequest(
|
|
735
|
+
error instanceof Error ? error.message : String(error)
|
|
736
|
+
);
|
|
766
737
|
}
|
|
767
738
|
await ctx.kv.set(FACTS_KEY, parsed);
|
|
768
739
|
await persistManifestStateFindings(ctx);
|
|
769
|
-
return {
|
|
740
|
+
return { saved: true };
|
|
770
741
|
}
|
|
771
742
|
|
|
743
|
+
// src/presence-route.ts
|
|
744
|
+
import { PluginRouteError as PluginRouteError2 } from "emdash";
|
|
745
|
+
|
|
772
746
|
// src/presence-check.ts
|
|
773
747
|
var FETCH_TIMEOUT_MS = 5e3;
|
|
774
748
|
var USER_AGENT = "aexeo-emdash-plugin/0.8 (+https://github.com/schiste/Aexeo; entity-presence diagnostic)";
|
|
@@ -1073,58 +1047,53 @@ async function handlePresenceRoute(ctx) {
|
|
|
1073
1047
|
case "refresh":
|
|
1074
1048
|
return await handleRefresh(ctx);
|
|
1075
1049
|
default:
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
message: `unknown presence route kind: ${String(body.kind)}`
|
|
1080
|
-
}
|
|
1081
|
-
};
|
|
1050
|
+
throw PluginRouteError2.badRequest(
|
|
1051
|
+
`unknown presence route kind: ${String(body.kind)}`
|
|
1052
|
+
);
|
|
1082
1053
|
}
|
|
1083
1054
|
}
|
|
1084
1055
|
async function handleData2(ctx) {
|
|
1085
1056
|
const manifest = await readStoredFacts(ctx.kv);
|
|
1086
1057
|
if (manifest === null) {
|
|
1087
|
-
return
|
|
1058
|
+
return payload("no_manifest", [], null, null);
|
|
1088
1059
|
}
|
|
1089
1060
|
const entity = entityFromManifest(manifest);
|
|
1090
1061
|
if (entity === null) {
|
|
1091
|
-
return
|
|
1062
|
+
return payload("no_organization", [], null, null);
|
|
1092
1063
|
}
|
|
1093
1064
|
const cached = await ctx.kv.get(PRESENCE_KEY);
|
|
1094
1065
|
if (!cached) {
|
|
1095
|
-
return
|
|
1066
|
+
return payload("empty", [], null, entity.name);
|
|
1096
1067
|
}
|
|
1097
1068
|
if (cached.entityName !== entity.name) {
|
|
1098
|
-
return
|
|
1069
|
+
return payload("empty", [], null, entity.name);
|
|
1099
1070
|
}
|
|
1100
1071
|
const ageMs = ageMillis(cached.generatedAt);
|
|
1101
1072
|
const state = ageMs !== null && ageMs > CACHE_TTL_MS ? "stale" : "fresh";
|
|
1102
|
-
return
|
|
1073
|
+
return payload(state, cached.results, cached.generatedAt, entity.name);
|
|
1103
1074
|
}
|
|
1104
1075
|
async function handleRefresh(ctx) {
|
|
1105
1076
|
const manifest = await readStoredFacts(ctx.kv);
|
|
1106
1077
|
if (manifest === null) {
|
|
1107
|
-
return
|
|
1078
|
+
return payload("no_manifest", [], null, null);
|
|
1108
1079
|
}
|
|
1109
1080
|
const entity = entityFromManifest(manifest);
|
|
1110
1081
|
if (entity === null) {
|
|
1111
|
-
return
|
|
1082
|
+
return payload("no_organization", [], null, null);
|
|
1112
1083
|
}
|
|
1113
1084
|
const results = await checkAllSources(entity);
|
|
1114
1085
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1115
|
-
const
|
|
1086
|
+
const cachePayload = {
|
|
1116
1087
|
results,
|
|
1117
1088
|
generatedAt,
|
|
1118
1089
|
entityName: entity.name
|
|
1119
1090
|
};
|
|
1120
|
-
await ctx.kv.set(PRESENCE_KEY,
|
|
1121
|
-
return
|
|
1091
|
+
await ctx.kv.set(PRESENCE_KEY, cachePayload);
|
|
1092
|
+
return payload("fresh", results, generatedAt, entity.name);
|
|
1122
1093
|
}
|
|
1123
|
-
function
|
|
1094
|
+
function payload(state, results, generatedAt, entityName) {
|
|
1124
1095
|
const ageMinutes = generatedAt === null ? null : Math.max(0, Math.floor((ageMillis(generatedAt) ?? 0) / 6e4));
|
|
1125
|
-
return {
|
|
1126
|
-
data: { state, results, generatedAt, entityName, ageMinutes }
|
|
1127
|
-
};
|
|
1096
|
+
return { state, results, generatedAt, entityName, ageMinutes };
|
|
1128
1097
|
}
|
|
1129
1098
|
function ageMillis(iso) {
|
|
1130
1099
|
const t = Date.parse(iso);
|
|
@@ -1191,7 +1160,7 @@ function globToMatcher(pattern) {
|
|
|
1191
1160
|
}
|
|
1192
1161
|
|
|
1193
1162
|
// src/version.ts
|
|
1194
|
-
var PACKAGE_VERSION = "0.8.
|
|
1163
|
+
var PACKAGE_VERSION = "0.8.6";
|
|
1195
1164
|
|
|
1196
1165
|
// src/configured.ts
|
|
1197
1166
|
import { definePlugin } from "emdash";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"facts-route.d.ts","sourceRoot":"","sources":["../src/facts-route.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"facts-route.d.ts","sourceRoot":"","sources":["../src/facts-route.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAa9C,UAAU,YAAa,SAAQ,UAAU;IACvC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAcD,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAgB1E"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presence-route.d.ts","sourceRoot":"","sources":["../src/presence-route.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"presence-route.d.ts","sourceRoot":"","sources":["../src/presence-route.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA0C9C,UAAU,YAAa,SAAQ,UAAU;IACvC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAMD,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,YAAY,GAChB,OAAO,CAAC,OAAO,CAAC,CAYlB"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "0.8.
|
|
1
|
+
export declare const PACKAGE_VERSION = "0.8.6";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
Binary file
|