Files
memind/mindspace-index-policy.mjs
T
john 745e9b691d
Memind CI / Test, build, and release guards (pull_request) Successful in 3m35s
feat(seo): 工作区 public/*.html 默认纳入 SEO 收录
未点公开发布但已落盘到 public/ 的页面,在无在线非 public 发布阻挡时
合成 implicit public snapshot,注入 canonical/JSON-LD 并扫描进 sitemap。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 20:49:20 +08:00

119 lines
3.4 KiB
JavaScript

const INDEXABLE_ACCESS_MODE = 'public';
export function isWorkspacePublicHtmlRelativePath(value) {
const normalized = String(value ?? '')
.replace(/\\/g, '/')
.replace(/^\/+/, '');
if (!/^public\/[^/]+\.html$/i.test(normalized)) return false;
if (/\/_archived[^/]*\.html$/i.test(normalized)) return false;
return true;
}
export function buildImplicitWorkspacePublicPublication({
publicUrl = '',
pageId = null,
updatedAt = null,
title = null,
summary = null,
} = {}) {
const url = String(publicUrl ?? '').trim();
if (!url) return null;
return normalizePublicationSnapshot({
accessMode: INDEXABLE_ACCESS_MODE,
status: 'online',
publicUrl: url,
pageId,
userConfirmedAt: null,
expiresAt: null,
updatedAt: updatedAt ?? Date.now(),
title,
summary,
});
}
export function normalizePublicationSnapshot(input = {}) {
if (!input || typeof input !== 'object') return null;
const accessMode = String(
input.accessMode ?? input.access_mode ?? '',
).trim();
if (!accessMode) return null;
const status = String(input.status ?? 'online').trim() || 'online';
const userConfirmedRaw =
input.userConfirmedAt ?? input.user_confirmed_at;
const userConfirmedAt =
userConfirmedRaw == null || userConfirmedRaw === ''
? null
: Number(userConfirmedRaw);
const expiresRaw = input.expiresAt ?? input.expires_at;
const expiresAt =
expiresRaw == null || expiresRaw === ''
? null
: Number(expiresRaw);
return {
id: String(input.id ?? input.publicationId ?? '').trim() || null,
pageId: String(input.pageId ?? input.page_id ?? '').trim() || null,
status,
accessMode,
userConfirmedAt:
Number.isFinite(userConfirmedAt) ? userConfirmedAt : null,
expiresAt: Number.isFinite(expiresAt) ? expiresAt : null,
publicUrl: String(input.publicUrl ?? input.public_url ?? '').trim() || null,
title: String(input.title ?? '').trim() || null,
summary: String(input.summary ?? '').trim() || null,
updatedAt:
Number(input.updatedAt ?? input.updated_at ?? input.publishedAt ?? input.published_at) ||
null,
};
}
export function isPublicationIndexable(publication, { now = Date.now() } = {}) {
const snapshot = normalizePublicationSnapshot(publication);
if (!snapshot) return false;
if (snapshot.status !== 'online') return false;
if (snapshot.accessMode !== INDEXABLE_ACCESS_MODE) return false;
if (snapshot.expiresAt != null && snapshot.expiresAt <= now) return false;
return true;
}
export function resolveIndexPolicy({
seoGeoConfig = null,
publication = null,
embed = false,
} = {}) {
if (embed) {
return {
mode: 'off',
injectNoindex: false,
reason: 'embed',
};
}
if (!seoGeoConfig?.enabled) {
return {
mode: 'off',
injectNoindex: false,
reason: 'disabled',
};
}
if (!isPublicationIndexable(publication)) {
return {
mode: 'noindex',
injectNoindex: true,
reason: publication ? 'not_indexable_publication' : 'missing_publication',
};
}
return {
mode: 'indexable',
injectNoindex: false,
reason: 'public_online',
seoEnabled: Boolean(seoGeoConfig.seo?.enabled),
geoEnabled: Boolean(seoGeoConfig.geo?.enabled),
canonicalEnabled: seoGeoConfig.seo?.canonical !== false,
jsonLdEnabled: seoGeoConfig.geo?.jsonLd !== false,
};
}
export const indexPolicyInternals = {
INDEXABLE_ACCESS_MODE,
isWorkspacePublicHtmlRelativePath,
};