@growth-labs/seo 0.1.5 → 0.2.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/README.md +142 -54
- package/dist/bindings.d.ts +127 -0
- package/dist/bindings.d.ts.map +1 -0
- package/dist/bindings.js +11 -0
- package/dist/bindings.js.map +1 -0
- package/dist/cron/prune-aeo-r2.d.ts +36 -0
- package/dist/cron/prune-aeo-r2.d.ts.map +1 -0
- package/dist/cron/prune-aeo-r2.js +94 -0
- package/dist/cron/prune-aeo-r2.js.map +1 -0
- package/dist/durable-objects/aeo-revalidation-coord.d.ts +69 -0
- package/dist/durable-objects/aeo-revalidation-coord.d.ts.map +1 -0
- package/dist/durable-objects/aeo-revalidation-coord.js +177 -0
- package/dist/durable-objects/aeo-revalidation-coord.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +101 -14
- package/dist/index.js.map +1 -1
- package/dist/middleware/seo.d.ts +44 -4
- package/dist/middleware/seo.d.ts.map +1 -1
- package/dist/middleware/seo.js +237 -41
- package/dist/middleware/seo.js.map +1 -1
- package/dist/options.d.ts +1293 -6
- package/dist/options.d.ts.map +1 -1
- package/dist/options.js +238 -1
- package/dist/options.js.map +1 -1
- package/dist/routes/apple-news.d.ts +4 -0
- package/dist/routes/apple-news.d.ts.map +1 -0
- package/dist/routes/apple-news.js +28 -0
- package/dist/routes/apple-news.js.map +1 -0
- package/dist/routes/llms-full.d.ts +4 -0
- package/dist/routes/llms-full.d.ts.map +1 -0
- package/dist/routes/llms-full.js +29 -0
- package/dist/routes/llms-full.js.map +1 -0
- package/dist/routes/revalidate.d.ts +16 -0
- package/dist/routes/revalidate.d.ts.map +1 -0
- package/dist/routes/revalidate.js +243 -0
- package/dist/routes/revalidate.js.map +1 -0
- package/dist/routes/rss.d.ts.map +1 -1
- package/dist/routes/rss.js +4 -1
- package/dist/routes/rss.js.map +1 -1
- package/dist/routes/sitemap-markdown.d.ts +4 -0
- package/dist/routes/sitemap-markdown.d.ts.map +1 -0
- package/dist/routes/sitemap-markdown.js +32 -0
- package/dist/routes/sitemap-markdown.js.map +1 -0
- package/dist/types.d.ts +16 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/aeo-summary.d.ts +35 -0
- package/dist/utils/aeo-summary.d.ts.map +1 -0
- package/dist/utils/aeo-summary.js +141 -0
- package/dist/utils/aeo-summary.js.map +1 -0
- package/dist/utils/aeo-twin-emitter.d.ts +79 -0
- package/dist/utils/aeo-twin-emitter.d.ts.map +1 -0
- package/dist/utils/aeo-twin-emitter.js +99 -0
- package/dist/utils/aeo-twin-emitter.js.map +1 -0
- package/dist/utils/aeo.d.ts +62 -12
- package/dist/utils/aeo.d.ts.map +1 -1
- package/dist/utils/aeo.js +187 -26
- package/dist/utils/aeo.js.map +1 -1
- package/dist/utils/apple-news-anf.d.ts +38 -0
- package/dist/utils/apple-news-anf.d.ts.map +1 -0
- package/dist/utils/apple-news-anf.js +120 -0
- package/dist/utils/apple-news-anf.js.map +1 -0
- package/dist/utils/apple-news-rss.d.ts +31 -0
- package/dist/utils/apple-news-rss.d.ts.map +1 -0
- package/dist/utils/apple-news-rss.js +103 -0
- package/dist/utils/apple-news-rss.js.map +1 -0
- package/dist/utils/content-filter.d.ts +52 -0
- package/dist/utils/content-filter.d.ts.map +1 -0
- package/dist/utils/content-filter.js +75 -0
- package/dist/utils/content-filter.js.map +1 -0
- package/dist/utils/crawler-class.d.ts +39 -0
- package/dist/utils/crawler-class.d.ts.map +1 -0
- package/dist/utils/crawler-class.js +127 -0
- package/dist/utils/crawler-class.js.map +1 -0
- package/dist/utils/effective-auth.d.ts +28 -0
- package/dist/utils/effective-auth.d.ts.map +1 -0
- package/dist/utils/effective-auth.js +33 -0
- package/dist/utils/effective-auth.js.map +1 -0
- package/dist/utils/fcrdns.d.ts +73 -0
- package/dist/utils/fcrdns.d.ts.map +1 -0
- package/dist/utils/fcrdns.js +219 -0
- package/dist/utils/fcrdns.js.map +1 -0
- package/dist/utils/fresh-layer.d.ts +53 -0
- package/dist/utils/fresh-layer.d.ts.map +1 -0
- package/dist/utils/fresh-layer.js +147 -0
- package/dist/utils/fresh-layer.js.map +1 -0
- package/dist/utils/index.d.ts +14 -3
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +14 -3
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/json-ld/article.d.ts +13 -1
- package/dist/utils/json-ld/article.d.ts.map +1 -1
- package/dist/utils/json-ld/article.js +37 -8
- package/dist/utils/json-ld/article.js.map +1 -1
- package/dist/utils/llms-full.d.ts +29 -0
- package/dist/utils/llms-full.d.ts.map +1 -0
- package/dist/utils/llms-full.js +67 -0
- package/dist/utils/llms-full.js.map +1 -0
- package/dist/utils/meta.d.ts +4 -1
- package/dist/utils/meta.d.ts.map +1 -1
- package/dist/utils/meta.js +25 -2
- package/dist/utils/meta.js.map +1 -1
- package/dist/utils/sitemap-markdown.d.ts +24 -0
- package/dist/utils/sitemap-markdown.d.ts.map +1 -0
- package/dist/utils/sitemap-markdown.js +57 -0
- package/dist/utils/sitemap-markdown.js.map +1 -0
- package/dist/utils/staleness.d.ts +27 -0
- package/dist/utils/staleness.d.ts.map +1 -0
- package/dist/utils/staleness.js +46 -0
- package/dist/utils/staleness.js.map +1 -0
- package/dist/utils/validation.d.ts +41 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +78 -0
- package/dist/utils/validation.js.map +1 -1
- package/package.json +13 -1
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// Revalidation Coordinator — a single Durable Object class that manages three
|
|
2
|
+
// concerns for the revalidation endpoint and middleware fallthrough path:
|
|
3
|
+
//
|
|
4
|
+
// rl:<token> — token-bucket rate-limit state (10 RPM per token)
|
|
5
|
+
// lock:<slug> — per-slug advisory lock (30s max hold)
|
|
6
|
+
// idempotency:<key> — response dedup cache (10-minute TTL)
|
|
7
|
+
//
|
|
8
|
+
// One DO instance per request-hostname (derived from url.host at request time,
|
|
9
|
+
// NOT build-time options.site). Multi-tenant Workers serving multiple domains
|
|
10
|
+
// from one deployment get per-tenant isolation.
|
|
11
|
+
//
|
|
12
|
+
// Uses the async KV API (ctx.storage.get/put/delete/list) on the SQLite-backed
|
|
13
|
+
// DO runtime — no raw SQL. TTL eviction runs via a self-scheduled 5-minute
|
|
14
|
+
// alarm; if an alarm misses (Worker restart), the next write re-arms it.
|
|
15
|
+
//
|
|
16
|
+
// Export the class from `@growth-labs/seo/durable-objects`; consumers re-export
|
|
17
|
+
// from their Worker entrypoint per Cloudflare DO conventions.
|
|
18
|
+
const LOCK_DEFAULT_LEASE_MS = 30_000;
|
|
19
|
+
const IDEMPOTENCY_DEFAULT_TTL_MS = 10 * 60 * 1000;
|
|
20
|
+
const ALARM_INTERVAL_MS = 5 * 60 * 1000;
|
|
21
|
+
const RATE_LIMIT_MAX_IDLE_MS = 10 * 60 * 1000;
|
|
22
|
+
// ─── DO class ───
|
|
23
|
+
export class AeoRevalidationCoordinator {
|
|
24
|
+
ctx;
|
|
25
|
+
constructor(ctx) {
|
|
26
|
+
this.ctx = ctx;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Dispatch a JSON-encoded CoordRequest. Returns a JSON response. Not a
|
|
30
|
+
* public HTTP API — called from the consumer's Worker via the namespace
|
|
31
|
+
* binding: `await stub.fetch(new Request('https://internal/', { method: 'POST', body: JSON.stringify(req) }))`.
|
|
32
|
+
*/
|
|
33
|
+
async fetch(request) {
|
|
34
|
+
if (request.method !== 'POST') {
|
|
35
|
+
return json({ ok: false, error: 'method_not_allowed' }, 405);
|
|
36
|
+
}
|
|
37
|
+
let body;
|
|
38
|
+
try {
|
|
39
|
+
body = (await request.json());
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return json({ ok: false, error: 'bad_json' }, 400);
|
|
43
|
+
}
|
|
44
|
+
await this.ensureAlarm();
|
|
45
|
+
switch (body.action) {
|
|
46
|
+
case 'rate-check':
|
|
47
|
+
return json(await this.rateCheck(body.token, body.limitRpm));
|
|
48
|
+
case 'acquire-lock':
|
|
49
|
+
return json(await this.acquireLock(body.slug, body.leaseMs ?? LOCK_DEFAULT_LEASE_MS));
|
|
50
|
+
case 'release-lock':
|
|
51
|
+
return json(await this.releaseLock(body.slug, body.leaseId));
|
|
52
|
+
case 'idempotency-check':
|
|
53
|
+
return json(await this.idempotencyCheck(body.key));
|
|
54
|
+
case 'idempotency-set':
|
|
55
|
+
return json(await this.idempotencySet(body.key, body.result, body.ttlMs ?? IDEMPOTENCY_DEFAULT_TTL_MS));
|
|
56
|
+
default:
|
|
57
|
+
return json({ ok: false, error: 'unknown_action' }, 400);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Alarm handler: runs every 5 minutes, sweeps expired entries across all
|
|
62
|
+
* three namespaces. Self-re-arming.
|
|
63
|
+
*/
|
|
64
|
+
async alarm() {
|
|
65
|
+
const now = Date.now();
|
|
66
|
+
// rate-limit: delete token buckets that haven't been refilled in >10 min.
|
|
67
|
+
const rlEntries = await this.ctx.storage.list({ prefix: 'rl:' });
|
|
68
|
+
for (const [key, entry] of rlEntries) {
|
|
69
|
+
if (now - entry.lastRefill > RATE_LIMIT_MAX_IDLE_MS) {
|
|
70
|
+
await this.ctx.storage.delete(key);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// lock: delete expired leases.
|
|
74
|
+
const lockEntries = await this.ctx.storage.list({ prefix: 'lock:' });
|
|
75
|
+
for (const [key, entry] of lockEntries) {
|
|
76
|
+
if (now >= entry.expiresAt)
|
|
77
|
+
await this.ctx.storage.delete(key);
|
|
78
|
+
}
|
|
79
|
+
// idempotency: delete expired entries.
|
|
80
|
+
const idemEntries = await this.ctx.storage.list({ prefix: 'idempotency:' });
|
|
81
|
+
for (const [key, entry] of idemEntries) {
|
|
82
|
+
if (now >= entry.expiresAt)
|
|
83
|
+
await this.ctx.storage.delete(key);
|
|
84
|
+
}
|
|
85
|
+
// Re-arm the alarm.
|
|
86
|
+
await this.ctx.storage.setAlarm(now + ALARM_INTERVAL_MS);
|
|
87
|
+
}
|
|
88
|
+
// ─── Rate limit ───
|
|
89
|
+
async rateCheck(token, limitRpm) {
|
|
90
|
+
const key = `rl:${token}`;
|
|
91
|
+
const now = Date.now();
|
|
92
|
+
const existing = await this.ctx.storage.get(key);
|
|
93
|
+
const refillRate = limitRpm / 60_000; // tokens per ms
|
|
94
|
+
let tokens;
|
|
95
|
+
if (existing) {
|
|
96
|
+
const elapsed = now - existing.lastRefill;
|
|
97
|
+
tokens = Math.min(limitRpm, existing.tokens + elapsed * refillRate);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
tokens = limitRpm;
|
|
101
|
+
}
|
|
102
|
+
if (tokens < 1) {
|
|
103
|
+
const retryAfterMs = Math.ceil((1 - tokens) / refillRate);
|
|
104
|
+
return { ok: false, error: 'rate_limited', retryAfterMs };
|
|
105
|
+
}
|
|
106
|
+
const next = { tokens: tokens - 1, lastRefill: now, capacity: limitRpm };
|
|
107
|
+
await this.ctx.storage.put(key, next);
|
|
108
|
+
return { ok: true, remaining: Math.floor(next.tokens) };
|
|
109
|
+
}
|
|
110
|
+
// ─── Per-slug lock ───
|
|
111
|
+
async acquireLock(slug, leaseMs) {
|
|
112
|
+
const key = `lock:${slug}`;
|
|
113
|
+
const now = Date.now();
|
|
114
|
+
const existing = await this.ctx.storage.get(key);
|
|
115
|
+
if (existing && now < existing.expiresAt) {
|
|
116
|
+
return { ok: false, error: 'locked', expiresAt: existing.expiresAt };
|
|
117
|
+
}
|
|
118
|
+
const leaseId = newLeaseId();
|
|
119
|
+
const entry = { leaseId, expiresAt: now + leaseMs };
|
|
120
|
+
await this.ctx.storage.put(key, entry);
|
|
121
|
+
return { ok: true, leaseId, expiresAt: entry.expiresAt };
|
|
122
|
+
}
|
|
123
|
+
async releaseLock(slug, leaseId) {
|
|
124
|
+
const key = `lock:${slug}`;
|
|
125
|
+
const existing = await this.ctx.storage.get(key);
|
|
126
|
+
if (!existing)
|
|
127
|
+
return { ok: true, note: 'not_held' };
|
|
128
|
+
if (existing.leaseId !== leaseId) {
|
|
129
|
+
return { ok: false, error: 'lease_mismatch' };
|
|
130
|
+
}
|
|
131
|
+
await this.ctx.storage.delete(key);
|
|
132
|
+
return { ok: true };
|
|
133
|
+
}
|
|
134
|
+
// ─── Idempotency ───
|
|
135
|
+
async idempotencyCheck(key) {
|
|
136
|
+
const storageKey = `idempotency:${key}`;
|
|
137
|
+
const entry = await this.ctx.storage.get(storageKey);
|
|
138
|
+
if (!entry || Date.now() >= entry.expiresAt) {
|
|
139
|
+
return { ok: true, hit: false };
|
|
140
|
+
}
|
|
141
|
+
return { ok: true, hit: true, result: entry.result };
|
|
142
|
+
}
|
|
143
|
+
async idempotencySet(key, result, ttlMs) {
|
|
144
|
+
const storageKey = `idempotency:${key}`;
|
|
145
|
+
const entry = { result, expiresAt: Date.now() + ttlMs };
|
|
146
|
+
await this.ctx.storage.put(storageKey, entry);
|
|
147
|
+
return { ok: true };
|
|
148
|
+
}
|
|
149
|
+
// ─── Alarm management ───
|
|
150
|
+
async ensureAlarm() {
|
|
151
|
+
const current = await this.ctx.storage.getAlarm();
|
|
152
|
+
if (current === null) {
|
|
153
|
+
await this.ctx.storage.setAlarm(Date.now() + ALARM_INTERVAL_MS);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// ─── Helpers ───
|
|
158
|
+
function json(body, status = 200) {
|
|
159
|
+
return new Response(JSON.stringify(body), {
|
|
160
|
+
status,
|
|
161
|
+
headers: { 'content-type': 'application/json' },
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
function newLeaseId() {
|
|
165
|
+
const bytes = new Uint8Array(16);
|
|
166
|
+
crypto.getRandomValues(bytes);
|
|
167
|
+
let hex = '';
|
|
168
|
+
for (const b of bytes)
|
|
169
|
+
hex += b.toString(16).padStart(2, '0');
|
|
170
|
+
return hex;
|
|
171
|
+
}
|
|
172
|
+
export const _internals = {
|
|
173
|
+
LOCK_DEFAULT_LEASE_MS,
|
|
174
|
+
IDEMPOTENCY_DEFAULT_TTL_MS,
|
|
175
|
+
ALARM_INTERVAL_MS,
|
|
176
|
+
};
|
|
177
|
+
//# sourceMappingURL=aeo-revalidation-coord.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aeo-revalidation-coord.js","sourceRoot":"","sources":["../../src/durable-objects/aeo-revalidation-coord.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { AstroIntegration } from 'astro';
|
|
|
2
2
|
import { type SeoOptions } from './options.js';
|
|
3
3
|
export default function seo(userOptions: SeoOptions): AstroIntegration;
|
|
4
4
|
export type { ResolvedSeoOptions, SeoOptions } from './options.js';
|
|
5
|
-
export { seoOptionsSchema } from './options.js';
|
|
5
|
+
export { resolveAeoTwins, seoOptionsSchema, validatedSeoOptionsSchema } from './options.js';
|
|
6
6
|
export { getConfig, getContentProvider } from './state.js';
|
|
7
7
|
export type * from './types.js';
|
|
8
8
|
//# 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":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAA;AAC7C,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAA;AAC7C,OAAO,EAAmB,KAAK,UAAU,EAA6B,MAAM,cAAc,CAAA;AAiB1F,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,WAAW,EAAE,UAAU,GAAG,gBAAgB,CAyPrE;AAeD,YAAY,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAClE,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAA;AAC3F,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC1D,mBAAmB,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import { readdirSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
1
|
+
import { mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import {
|
|
4
|
+
import { resolveAeoTwins, validatedSeoOptionsSchema } from './options.js';
|
|
5
5
|
import { _setConfig, _setContentProvider } from './state.js';
|
|
6
|
+
import { emitAeoTwins } from './utils/aeo-twin-emitter.js';
|
|
6
7
|
import { SITEMAP_INDEX_PATH } from './utils/sitemap.js';
|
|
7
|
-
import { validateJsonLd, validatePage } from './utils/validation.js';
|
|
8
|
+
import { validateHreflangReciprocity, validateJsonLd, validatePage, validatePrerenderedGatedRoutes, } from './utils/validation.js';
|
|
8
9
|
import { growthLabsSeoPlugin } from './vite-plugin.js';
|
|
9
10
|
function resolveEntrypoint(path) {
|
|
10
11
|
const ext = typeof import.meta.url === 'string' && import.meta.url.endsWith('.ts') ? '.ts' : '.js';
|
|
11
12
|
return fileURLToPath(new URL(`${path}${ext}`, import.meta.url));
|
|
12
13
|
}
|
|
13
14
|
export default function seo(userOptions) {
|
|
14
|
-
const options =
|
|
15
|
+
const options = validatedSeoOptionsSchema.parse(userOptions);
|
|
16
|
+
const aeo = resolveAeoTwins(options.aeoTwins);
|
|
15
17
|
_setConfig(options);
|
|
16
18
|
if (userOptions.contentProvider) {
|
|
17
19
|
_setContentProvider(userOptions.contentProvider);
|
|
@@ -22,7 +24,7 @@ export default function seo(userOptions) {
|
|
|
22
24
|
'astro:config:setup': ({ addMiddleware, injectRoute, updateConfig }) => {
|
|
23
25
|
updateConfig({ vite: { plugins: [growthLabsSeoPlugin(options)] } });
|
|
24
26
|
addMiddleware({ entrypoint: resolveEntrypoint('./middleware/seo'), order: 'post' });
|
|
25
|
-
// Sitemaps
|
|
27
|
+
// ─── Sitemaps ───
|
|
26
28
|
injectRoute({
|
|
27
29
|
pattern: SITEMAP_INDEX_PATH,
|
|
28
30
|
entrypoint: resolveEntrypoint('./routes/sitemap-index'),
|
|
@@ -50,7 +52,15 @@ export default function seo(userOptions) {
|
|
|
50
52
|
prerender: false,
|
|
51
53
|
});
|
|
52
54
|
}
|
|
53
|
-
//
|
|
55
|
+
// Markdown sitemap — only emitted when twin URLs exist (static or both mode).
|
|
56
|
+
if (options.markdownSitemap && aeo && aeo.mode !== 'middleware') {
|
|
57
|
+
injectRoute({
|
|
58
|
+
pattern: '/sitemap-markdown.xml',
|
|
59
|
+
entrypoint: resolveEntrypoint('./routes/sitemap-markdown'),
|
|
60
|
+
prerender: false,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
// ─── Robots + llms.txt + llms-full.txt ───
|
|
54
64
|
injectRoute({
|
|
55
65
|
pattern: '/robots.txt',
|
|
56
66
|
entrypoint: resolveEntrypoint('./routes/robots'),
|
|
@@ -63,7 +73,14 @@ export default function seo(userOptions) {
|
|
|
63
73
|
prerender: false,
|
|
64
74
|
});
|
|
65
75
|
}
|
|
66
|
-
|
|
76
|
+
if (options.llmsFullTxt) {
|
|
77
|
+
injectRoute({
|
|
78
|
+
pattern: '/llms-full.txt',
|
|
79
|
+
entrypoint: resolveEntrypoint('./routes/llms-full'),
|
|
80
|
+
prerender: false,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
// ─── RSS ───
|
|
67
84
|
if (options.rss) {
|
|
68
85
|
injectRoute({
|
|
69
86
|
pattern: '/feed.xml',
|
|
@@ -71,7 +88,15 @@ export default function seo(userOptions) {
|
|
|
71
88
|
prerender: false,
|
|
72
89
|
});
|
|
73
90
|
}
|
|
74
|
-
//
|
|
91
|
+
// ─── Apple News Publisher RSS ───
|
|
92
|
+
if (options.appleNews?.enabled) {
|
|
93
|
+
injectRoute({
|
|
94
|
+
pattern: options.appleNews.feedPath,
|
|
95
|
+
entrypoint: resolveEntrypoint('./routes/apple-news'),
|
|
96
|
+
prerender: false,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
// ─── Podcast ───
|
|
75
100
|
if (options.podcast?.enabled) {
|
|
76
101
|
injectRoute({
|
|
77
102
|
pattern: options.podcast.feedPath,
|
|
@@ -79,7 +104,7 @@ export default function seo(userOptions) {
|
|
|
79
104
|
prerender: false,
|
|
80
105
|
});
|
|
81
106
|
}
|
|
82
|
-
// Narrated articles podcast feed
|
|
107
|
+
// ─── Narrated articles podcast feed ───
|
|
83
108
|
if (options.audioNarration?.asPodcastFeed) {
|
|
84
109
|
injectRoute({
|
|
85
110
|
pattern: options.audioNarration.podcastFeedPath,
|
|
@@ -87,11 +112,74 @@ export default function seo(userOptions) {
|
|
|
87
112
|
prerender: false,
|
|
88
113
|
});
|
|
89
114
|
}
|
|
115
|
+
// ─── Revalidation endpoint ───
|
|
116
|
+
if (aeo?.onDemandRevalidation) {
|
|
117
|
+
injectRoute({
|
|
118
|
+
pattern: '/_seo/revalidate',
|
|
119
|
+
entrypoint: resolveEntrypoint('./routes/revalidate'),
|
|
120
|
+
prerender: false,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
90
123
|
},
|
|
91
|
-
'astro:build:done': async ({ dir, logger }) => {
|
|
124
|
+
'astro:build:done': async ({ dir, pages, logger }) => {
|
|
125
|
+
const outDir = fileURLToPath(dir);
|
|
126
|
+
const contentProvider = userOptions.contentProvider;
|
|
127
|
+
// ─── Build-time prerender-gated guard (test 32) ───
|
|
128
|
+
if (contentProvider && options.flexibleSampling?.enabled) {
|
|
129
|
+
let items = [];
|
|
130
|
+
try {
|
|
131
|
+
items = await contentProvider({ type: 'articles' }, {});
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
logger.warn(`Could not run contentProvider for prerender-guard validation: ${err instanceof Error ? err.message : String(err)}`);
|
|
135
|
+
}
|
|
136
|
+
// Astro's `pages` array contains { pathname } entries for prerendered pages.
|
|
137
|
+
const prerenderedUrls = new Set(pages.map((p) => `/${p.pathname}`.replace(/\/+/g, '/')));
|
|
138
|
+
const issues = validatePrerenderedGatedRoutes({ prerenderedUrls, items });
|
|
139
|
+
if (issues.length > 0) {
|
|
140
|
+
for (const issue of issues)
|
|
141
|
+
logger.error(issue.message);
|
|
142
|
+
throw new Error(`[@growth-labs/seo] ${issues.length} prerendered route(s) serve members-gated items. See errors above.`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// ─── Emit static twins (static or both mode) ───
|
|
146
|
+
if (aeo && aeo.mode !== 'middleware' && contentProvider) {
|
|
147
|
+
let items = [];
|
|
148
|
+
try {
|
|
149
|
+
items = await contentProvider({ type: 'articles' }, {});
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
logger.warn(`Could not run contentProvider for twin emission: ${err instanceof Error ? err.message : String(err)}`);
|
|
153
|
+
}
|
|
154
|
+
if (items.length > 0) {
|
|
155
|
+
const result = await emitAeoTwins({
|
|
156
|
+
items,
|
|
157
|
+
publisherName: options.organization.name,
|
|
158
|
+
schemaType: options.schemaType,
|
|
159
|
+
renderBody: (item) => item.description ?? '',
|
|
160
|
+
twinUrl: aeo.twinUrl,
|
|
161
|
+
include: aeo.include,
|
|
162
|
+
summaryTwin: aeo.summaryTwin,
|
|
163
|
+
ragChunkMarkers: aeo.ragChunkMarkers,
|
|
164
|
+
stalenessCheck: aeo.stalenessCheck,
|
|
165
|
+
onSummaryMinimalFallback: (item) => logger.warn(`AEO summary fell back to tier 4 (description-only) for ${item.url}. Set item.summary to improve.`),
|
|
166
|
+
});
|
|
167
|
+
for (const twin of result.twins) {
|
|
168
|
+
const path = join(outDir, twin.urlPath.replace(/^\//, ''));
|
|
169
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
170
|
+
writeFileSync(path, twin.content);
|
|
171
|
+
}
|
|
172
|
+
logger.info(`AEO twin emission: wrote ${result.twins.length} files (${result.skipped} items skipped by access/include filters)`);
|
|
173
|
+
}
|
|
174
|
+
// Hreflang reciprocity check is relevant whenever items are loaded.
|
|
175
|
+
const hreflangIssues = validateHreflangReciprocity(items);
|
|
176
|
+
for (const issue of hreflangIssues) {
|
|
177
|
+
logger.warn(`Hreflang reciprocity: ${issue.url} declares ${issue.missingReciprocal.lang} -> ${issue.missingReciprocal.from} but no back-reference found.`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// ─── Legacy per-page validation ───
|
|
92
181
|
if (!options.validation.enabled)
|
|
93
182
|
return;
|
|
94
|
-
const outDir = fileURLToPath(dir);
|
|
95
183
|
const htmlFiles = findHtmlFiles(outDir);
|
|
96
184
|
let errorCount = 0;
|
|
97
185
|
let warningCount = 0;
|
|
@@ -111,7 +199,6 @@ export default function seo(userOptions) {
|
|
|
111
199
|
logger.warn(`${relPath}: ${warning}`);
|
|
112
200
|
warningCount++;
|
|
113
201
|
}
|
|
114
|
-
// Validate JSON-LD blocks
|
|
115
202
|
const jsonLdMatches = html.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/gi);
|
|
116
203
|
for (const match of jsonLdMatches) {
|
|
117
204
|
try {
|
|
@@ -157,6 +244,6 @@ function findHtmlFiles(dir) {
|
|
|
157
244
|
catch { }
|
|
158
245
|
return results;
|
|
159
246
|
}
|
|
160
|
-
export { seoOptionsSchema } from './options.js';
|
|
247
|
+
export { resolveAeoTwins, seoOptionsSchema, validatedSeoOptionsSchema } from './options.js';
|
|
161
248
|
export { getConfig, getContentProvider } from './state.js';
|
|
162
249
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/middleware/seo.d.ts
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type { SeoEnv } from '../bindings.js';
|
|
2
|
+
import { type ResolvedSeoOptions } from '../options.js';
|
|
3
|
+
import type { ContentItem, ContentProvider, CrawlerClass } from '../types.js';
|
|
4
|
+
import { type RawAuthSegment } from '../utils/effective-auth.js';
|
|
5
|
+
import { type FreshLayerBinding } from '../utils/fresh-layer.js';
|
|
6
|
+
export interface SeoMiddlewareDeps {
|
|
7
|
+
/** Request classifier. Defaults to one backed by a DoH FCrDNS verifier. */
|
|
8
|
+
classify?: (request: Request) => Promise<CrawlerClass>;
|
|
9
|
+
/** R2/KV binding for the fresh-twin layer. Required for mode 'middleware' or 'both'. */
|
|
10
|
+
freshLayer?: FreshLayerBinding;
|
|
11
|
+
/** Assets binding for reading the stale build-time twin on R2 miss. */
|
|
12
|
+
assets?: {
|
|
13
|
+
fetch(request: Request): Promise<Response>;
|
|
14
|
+
};
|
|
15
|
+
/** Consumer's raw auth segment for this request. Defaults to 'anon'. */
|
|
16
|
+
rawAuthSegment?: (request: Request) => RawAuthSegment;
|
|
17
|
+
/** Fire-and-forget ctx.waitUntil equivalent. Used to schedule background revalidation. */
|
|
18
|
+
waitUntil?: (promise: Promise<unknown>) => void;
|
|
19
|
+
}
|
|
20
|
+
export interface SeoMiddlewareContext {
|
|
21
|
+
request: Request;
|
|
22
|
+
locals?: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
export declare function createSeoMiddleware(options: ResolvedSeoOptions, contentProvider?: ContentProvider, deps?: SeoMiddlewareDeps): (context: SeoMiddlewareContext, next: () => Promise<Response>) => Promise<Response>;
|
|
25
|
+
export declare const onRequest: (context: SeoMiddlewareContext & {
|
|
26
|
+
locals?: {
|
|
27
|
+
runtime?: {
|
|
28
|
+
env?: SeoEnv;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
}, next: () => Promise<Response>) => Promise<Response>;
|
|
32
|
+
declare function appendVaryHeaders(headers: Headers): void;
|
|
33
|
+
declare function dedupVary(combined: string): string;
|
|
34
|
+
declare function twinUrlFor(url: URL, aeo: {
|
|
35
|
+
twinUrl?: (u: string) => string;
|
|
36
|
+
}): string;
|
|
37
|
+
declare function findItemForPath(contentProvider: ContentProvider, context: SeoMiddlewareContext, pathname: string): Promise<ContentItem | undefined>;
|
|
38
|
+
export declare const _internals: {
|
|
39
|
+
appendVaryHeaders: typeof appendVaryHeaders;
|
|
40
|
+
dedupVary: typeof dedupVary;
|
|
41
|
+
twinUrlFor: typeof twinUrlFor;
|
|
42
|
+
findItemForPath: typeof findItemForPath;
|
|
43
|
+
};
|
|
44
|
+
export {};
|
|
5
45
|
//# sourceMappingURL=seo.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seo.d.ts","sourceRoot":"","sources":["../../src/middleware/seo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"seo.d.ts","sourceRoot":"","sources":["../../src/middleware/seo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,KAAK,kBAAkB,EAAmB,MAAM,eAAe,CAAA;AAExE,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAwB,MAAM,aAAa,CAAA;AAGnG,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAE7F,OAAO,EAAE,KAAK,iBAAiB,EAAiC,MAAM,yBAAyB,CAAA;AAI/F,MAAM,WAAW,iBAAiB;IACjC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;IACtD,wFAAwF;IACxF,UAAU,CAAC,EAAE,iBAAiB,CAAA;IAC9B,uEAAuE;IACvE,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;KAAE,CAAA;IACvD,wEAAwE;IACxE,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,cAAc,CAAA;IACrD,0FAA0F;IAC1F,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;CAC/C;AAED,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChC;AAED,wBAAgB,mBAAmB,CAClC,OAAO,EAAE,kBAAkB,EAC3B,eAAe,CAAC,EAAE,eAAe,EACjC,IAAI,GAAE,iBAAsB,IAM3B,SAAS,oBAAoB,EAC7B,MAAM,MAAM,OAAO,CAAC,QAAQ,CAAC,KAC3B,OAAO,CAAC,QAAQ,CAAC,CAyFpB;AAMD,eAAO,MAAM,SAAS,GACrB,SAAS,oBAAoB,GAAG;IAAE,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE;YAAE,GAAG,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE,EAC3E,MAAM,MAAM,OAAO,CAAC,QAAQ,CAAC,KAC3B,OAAO,CAAC,QAAQ,CA+BlB,CAAA;AAqBD,iBAAS,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAIjD;AAED,iBAAS,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM3C;AAOD,iBAAS,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;IAAE,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,GAAG,MAAM,CAG9E;AAED,iBAAe,eAAe,CAC7B,eAAe,EAAE,eAAe,EAChC,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAmBlC;AA4GD,eAAO,MAAM,UAAU;;;;;CAKtB,CAAA"}
|