Keep listed published rules public and guest-claim rules unlisted, with semantic document markup and share chrome that stays clickable.
Guest publishes remain share-by-link but stay out of the catalog and sitemap, and their pages send noindex until claimed. The published-rule view now uses heading and list markup matching Markdown export, and top banners sit below the header so Share is not covered. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
77b0ec8ad8
commit
1445cb7e1e
27 files changed
+524
-86
No files matched your search
@@ -1,9 +1,14 @@
|
||||
import {
|
||||
LISTED_PUBLISHED_RULE_WHERE,
|
||||
isListedPublishedRule,
|
||||
} from "../publishedRuleAccess";
|
||||
import { prisma } from "./db";
|
||||
import { isDatabaseConfigured } from "./env";
|
||||
|
||||
/**
|
||||
* Public fields safe to expose via the unauthenticated rule detail surfaces
|
||||
* (`GET /api/rules/[id]` and `/rules/[id]`). `userId` is intentionally omitted.
|
||||
* (`GET /api/rules/[id]` and `/rules/[id]`). `userId` and `claimTokenHash`
|
||||
* stay server-side; callers get {@link PublicPublishedRule.isListed} instead.
|
||||
*/
|
||||
const PUBLISHED_RULE_PUBLIC_SELECT = {
|
||||
id: true,
|
||||
@@ -21,6 +26,8 @@ export type PublicPublishedRule = {
|
||||
document: unknown;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
/** False for guest-claim rows; true for owned and orphaned-after-delete rows. */
|
||||
isListed: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -39,9 +46,18 @@ export async function getPublicPublishedRuleById(
|
||||
try {
|
||||
const rule = await prisma.publishedRule.findUnique({
|
||||
where: { id },
|
||||
select: PUBLISHED_RULE_PUBLIC_SELECT,
|
||||
select: {
|
||||
...PUBLISHED_RULE_PUBLIC_SELECT,
|
||||
userId: true,
|
||||
claimTokenHash: true,
|
||||
},
|
||||
});
|
||||
return rule;
|
||||
if (!rule) return null;
|
||||
const { userId, claimTokenHash, ...publicFields } = rule;
|
||||
return {
|
||||
...publicFields,
|
||||
isListed: isListedPublishedRule({ userId, claimTokenHash }),
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
@@ -64,6 +80,61 @@ export type OwnerPublishedRuleListItem = {
|
||||
updatedAt: Date;
|
||||
};
|
||||
|
||||
const LISTED_RULE_SITEMAP_SELECT = {
|
||||
id: true,
|
||||
updatedAt: true,
|
||||
} as const;
|
||||
|
||||
const LISTED_PUBLISHED_RULE_SITEMAP_CAP = 10_000;
|
||||
|
||||
/**
|
||||
* Public catalog of listed published rules (**most recently updated first**,
|
||||
* then stable `id` tie-break). Guest-claim rows are omitted.
|
||||
* Returns `null` when the database is not configured or the query throws.
|
||||
*/
|
||||
export async function listListedPublishedRules(
|
||||
take: number,
|
||||
): Promise<OwnerPublishedRuleListItem[] | null> {
|
||||
if (!isDatabaseConfigured()) return null;
|
||||
const clamped = Math.min(Math.max(0, take), 100);
|
||||
if (clamped === 0) return [];
|
||||
try {
|
||||
return await prisma.publishedRule.findMany({
|
||||
where: LISTED_PUBLISHED_RULE_WHERE,
|
||||
orderBy: [{ updatedAt: "desc" }, { id: "asc" }],
|
||||
take: clamped,
|
||||
select: PUBLISHED_RULE_OWNER_LIST_SELECT,
|
||||
});
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listed published-rule ids for `/sitemap.xml`. Empty when the database is
|
||||
* not configured or the query throws (marketing URLs still render).
|
||||
*/
|
||||
export async function listListedPublishedRulesForSitemap(
|
||||
take: number = LISTED_PUBLISHED_RULE_SITEMAP_CAP,
|
||||
): Promise<Array<{ id: string; updatedAt: Date }>> {
|
||||
if (!isDatabaseConfigured()) return [];
|
||||
const clamped = Math.min(
|
||||
Math.max(0, take),
|
||||
LISTED_PUBLISHED_RULE_SITEMAP_CAP,
|
||||
);
|
||||
if (clamped === 0) return [];
|
||||
try {
|
||||
return await prisma.publishedRule.findMany({
|
||||
where: LISTED_PUBLISHED_RULE_WHERE,
|
||||
orderBy: [{ updatedAt: "desc" }, { id: "asc" }],
|
||||
take: clamped,
|
||||
select: LISTED_RULE_SITEMAP_SELECT,
|
||||
});
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists published rules owned by the given user (**most recently updated first**,
|
||||
* then stable `id` tie-break).
|
||||
|
||||
Reference in new issue
Block a user