@softure-ai/blog 0.1.6 → 0.1.8
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 +30 -0
- package/README.md +211 -26
- package/dist/cli/report.d.ts +17 -0
- package/dist/cli/report.d.ts.map +1 -0
- package/dist/cli/report.js +149 -0
- package/dist/cli/report.js.map +1 -0
- package/dist/cli/run.d.ts +12 -5
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +122 -88
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/skill.d.ts.map +1 -1
- package/dist/cli/skill.js +2 -1
- package/dist/cli/skill.js.map +1 -1
- package/dist/contract.d.ts +4 -0
- package/dist/contract.d.ts.map +1 -1
- package/dist/db/articles.d.ts +10 -1
- package/dist/db/articles.d.ts.map +1 -1
- package/dist/db/articles.js +41 -5
- package/dist/db/articles.js.map +1 -1
- package/dist/db/history.d.ts +36 -0
- package/dist/db/history.d.ts.map +1 -0
- package/dist/db/history.js +70 -0
- package/dist/db/history.js.map +1 -0
- package/dist/db/publish-run.d.ts +11 -0
- package/dist/db/publish-run.d.ts.map +1 -1
- package/dist/db/publish-run.js +14 -4
- package/dist/db/publish-run.js.map +1 -1
- package/dist/index.d.ts +20 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.d.ts.map +1 -1
- package/dist/next/index.js +2 -0
- package/dist/next/index.js.map +1 -1
- package/dist/next/json-ld.d.ts +13 -0
- package/dist/next/json-ld.d.ts.map +1 -0
- package/dist/next/json-ld.js +42 -0
- package/dist/next/json-ld.js.map +1 -0
- package/dist/next/metadata.d.ts +18 -0
- package/dist/next/metadata.d.ts.map +1 -0
- package/dist/next/metadata.js +84 -0
- package/dist/next/metadata.js.map +1 -0
- package/dist/next/pages.d.ts.map +1 -1
- package/dist/next/pages.js +16 -77
- package/dist/next/pages.js.map +1 -1
- package/dist/options.d.ts +23 -7
- package/dist/options.d.ts.map +1 -1
- package/dist/options.js +26 -1
- package/dist/options.js.map +1 -1
- package/dist/pages/accept.d.ts +7 -0
- package/dist/pages/accept.d.ts.map +1 -0
- package/dist/pages/accept.js +34 -0
- package/dist/pages/accept.js.map +1 -0
- package/dist/pages/body.d.ts +1 -1
- package/dist/pages/body.d.ts.map +1 -1
- package/dist/pages/body.js +1 -0
- package/dist/pages/body.js.map +1 -1
- package/dist/pages/index.d.ts +1 -1
- package/dist/pages/index.d.ts.map +1 -1
- package/dist/pages/index.js.map +1 -1
- package/dist/pages/redirects.d.ts +22 -6
- package/dist/pages/redirects.d.ts.map +1 -1
- package/dist/pages/redirects.js +5 -2
- package/dist/pages/redirects.js.map +1 -1
- package/dist/proxy/index.d.ts +15 -0
- package/dist/proxy/index.d.ts.map +1 -1
- package/dist/proxy/index.js +60 -3
- package/dist/proxy/index.js.map +1 -1
- package/dist/quality/catalog.d.ts.map +1 -1
- package/dist/quality/catalog.js +4 -1
- package/dist/quality/catalog.js.map +1 -1
- package/dist/quality/check-article.d.ts.map +1 -1
- package/dist/quality/check-article.js +2 -1
- package/dist/quality/check-article.js.map +1 -1
- package/dist/quality/index.d.ts +1 -1
- package/dist/quality/index.d.ts.map +1 -1
- package/dist/quality/index.js.map +1 -1
- package/dist/quality/link-targets.d.ts.map +1 -1
- package/dist/quality/link-targets.js +6 -5
- package/dist/quality/link-targets.js.map +1 -1
- package/dist/quality/options.d.ts +3 -3
- package/dist/quality/options.d.ts.map +1 -1
- package/dist/quality/options.js +9 -4
- package/dist/quality/options.js.map +1 -1
- package/dist/quality/rules/blocks.d.ts +8 -1
- package/dist/quality/rules/blocks.d.ts.map +1 -1
- package/dist/quality/rules/blocks.js +26 -0
- package/dist/quality/rules/blocks.js.map +1 -1
- package/dist/quality/settings.d.ts +11 -0
- package/dist/quality/settings.d.ts.map +1 -1
- package/dist/quality/settings.js +7 -1
- package/dist/quality/settings.js.map +1 -1
- package/dist/render/article-markdown.d.ts +12 -0
- package/dist/render/article-markdown.d.ts.map +1 -0
- package/dist/render/article-markdown.js +21 -0
- package/dist/render/article-markdown.js.map +1 -0
- package/dist/render/index.d.ts +2 -1
- package/dist/render/index.d.ts.map +1 -1
- package/dist/render/index.js +2 -1
- package/dist/render/index.js.map +1 -1
- package/dist/render/render-article.d.ts +48 -4
- package/dist/render/render-article.d.ts.map +1 -1
- package/dist/render/render-article.js +146 -17
- package/dist/render/render-article.js.map +1 -1
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/options.js +1 -1
- package/dist/server/options.js.map +1 -1
- package/module.json +1 -1
- package/package.json +1 -1
- package/skill/references/rules.md +2 -1
- package/src/cli/report.ts +182 -0
- package/src/cli/run.ts +122 -92
- package/src/cli/skill.ts +2 -1
- package/src/contract.ts +9 -1
- package/src/db/articles.ts +48 -8
- package/src/db/history.ts +90 -0
- package/src/db/publish-run.ts +24 -4
- package/src/index.ts +1 -1
- package/src/next/index.ts +9 -0
- package/src/next/json-ld.ts +47 -0
- package/src/next/metadata.ts +103 -0
- package/src/next/pages.tsx +16 -82
- package/src/options.ts +32 -3
- package/src/pages/accept.ts +39 -0
- package/src/pages/body.ts +2 -1
- package/src/pages/index.ts +3 -0
- package/src/pages/redirects.ts +27 -3
- package/src/proxy/index.ts +69 -3
- package/src/quality/catalog.ts +4 -1
- package/src/quality/check-article.ts +2 -1
- package/src/quality/index.ts +1 -1
- package/src/quality/link-targets.ts +6 -5
- package/src/quality/options.ts +12 -5
- package/src/quality/rules/blocks.ts +26 -1
- package/src/quality/settings.ts +17 -1
- package/src/render/article-markdown.ts +34 -0
- package/src/render/index.ts +8 -0
- package/src/render/render-article.ts +192 -23
- package/src/server/index.ts +2 -0
- package/src/server/options.ts +1 -1
package/dist/db/articles.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { and, asc, desc, eq, ne } from "drizzle-orm";
|
|
1
|
+
import { and, asc, desc, eq, ne, sql } from "drizzle-orm";
|
|
2
2
|
import { articles, slugHistory } from "./schema.js";
|
|
3
3
|
/**
|
|
4
4
|
* Inserts or updates the article by its `id`. Idempotent: the same file again is `unchanged` and
|
|
@@ -9,10 +9,14 @@ import { articles, slugHistory } from "./schema.js";
|
|
|
9
9
|
* text first becomes `published`. A draft gets none.
|
|
10
10
|
* - `updated_at` moves only when the content hash of a text that already has `published_at` changes.
|
|
11
11
|
*
|
|
12
|
+
* With `history` (an app moving its blog in, see history.ts), an article that has no row yet takes its
|
|
13
|
+
* `published_at` (unless the file sets one) and `updated_at` from it, and its old slugs enter the slug
|
|
14
|
+
* history; the result says `imported: true`. For an existing row the history is ignored.
|
|
15
|
+
*
|
|
12
16
|
* Runs in a transaction that locks the row (`FOR UPDATE`), so two publishes of one article never
|
|
13
17
|
* overwrite each other silently; inside an open transaction it becomes a savepoint.
|
|
14
18
|
*/
|
|
15
|
-
export async function publishArticle(ctx, input) {
|
|
19
|
+
export async function publishArticle(ctx, input, options = {}) {
|
|
16
20
|
return ctx.db.transaction(async (tx) => {
|
|
17
21
|
const [existing] = await tx.select().from(articles).where(eq(articles.id, input.id)).for("update");
|
|
18
22
|
// Current slugs first, then old ones (BF-12). A rename writes both tables in one commit, so a run
|
|
@@ -50,12 +54,26 @@ export async function publishArticle(ctx, input) {
|
|
|
50
54
|
contentSha256: input.contentSha256,
|
|
51
55
|
};
|
|
52
56
|
if (existing === undefined) {
|
|
53
|
-
const
|
|
57
|
+
const history = options.history;
|
|
58
|
+
const publishedAt = input.publishedAt ?? history?.publishedAt ?? (input.status === "published" ? now : null);
|
|
59
|
+
const updatedAt = publishedAt === null ? null : (history?.updatedAt ?? null);
|
|
60
|
+
if (history !== undefined) {
|
|
61
|
+
const taken = await findTakenOldSlug(tx, input, history);
|
|
62
|
+
if (taken !== null)
|
|
63
|
+
return taken;
|
|
64
|
+
}
|
|
54
65
|
const [inserted] = await tx
|
|
55
66
|
.insert(articles)
|
|
56
|
-
.values({ id: input.id, ...content, publishedAt, updatedAt:
|
|
67
|
+
.values({ id: input.id, ...content, publishedAt: toTimestamp(publishedAt), updatedAt: toTimestamp(updatedAt), createdAt: now })
|
|
57
68
|
.returning();
|
|
58
|
-
|
|
69
|
+
const oldSlugs = history?.oldSlugs.filter((old) => old.slug !== input.slug) ?? [];
|
|
70
|
+
if (oldSlugs.length > 0) {
|
|
71
|
+
await tx.insert(slugHistory).values(oldSlugs.map((old) => ({ oldSlug: old.slug, articleId: input.id, changedAt: toTimestamp(old.changedAt) ?? now })));
|
|
72
|
+
}
|
|
73
|
+
const after = readState(requireRow(inserted, input.id));
|
|
74
|
+
return history === undefined
|
|
75
|
+
? { ok: true, action: "added", before: null, after, previousSlug: null }
|
|
76
|
+
: { ok: true, action: "added", before: null, after, previousSlug: null, imported: true };
|
|
59
77
|
}
|
|
60
78
|
const before = readState(existing);
|
|
61
79
|
const publishedAt = input.publishedAt ?? existing.publishedAt ?? (input.status === "published" ? now : null);
|
|
@@ -88,6 +106,24 @@ export async function publishArticle(ctx, input) {
|
|
|
88
106
|
};
|
|
89
107
|
});
|
|
90
108
|
}
|
|
109
|
+
/** A history timestamp goes in as text, so Postgres keeps its microseconds; a `Date` goes in as is. */
|
|
110
|
+
function toTimestamp(value) {
|
|
111
|
+
return typeof value === "string" ? sql `${value}::timestamptz` : value;
|
|
112
|
+
}
|
|
113
|
+
/** The refusal for the first old slug of `history` another article holds, current or old; `null` when all are free. */
|
|
114
|
+
async function findTakenOldSlug(db, input, history) {
|
|
115
|
+
for (const { slug } of history.oldSlugs) {
|
|
116
|
+
if (slug === input.slug)
|
|
117
|
+
continue;
|
|
118
|
+
const [owner] = await db.select({ id: articles.id }).from(articles).where(and(eq(articles.slug, slug), ne(articles.id, input.id)));
|
|
119
|
+
if (owner !== undefined)
|
|
120
|
+
return { ok: false, error: "blog.slug_taken", otherArticleId: owner.id, slug };
|
|
121
|
+
const [historyOwner] = await db.select({ articleId: slugHistory.articleId }).from(slugHistory).where(eq(slugHistory.oldSlug, slug));
|
|
122
|
+
if (historyOwner !== undefined)
|
|
123
|
+
return { ok: false, error: "blog.slug_in_history", otherArticleId: historyOwner.articleId, slug };
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
91
127
|
/** The article under its current slug, in any status: a page tells 200 from 410 by it. */
|
|
92
128
|
export async function findArticleBySlug(ctx, slug) {
|
|
93
129
|
const [row] = await ctx.db.select().from(articles).where(eq(articles.slug, slug));
|
package/dist/db/articles.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"articles.js","sourceRoot":"","sources":["../../src/db/articles.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAY,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"articles.js","sourceRoot":"","sources":["../../src/db/articles.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const articleHistorySchema: z.ZodObject<{
|
|
3
|
+
articles: z.ZodArray<z.ZodObject<{
|
|
4
|
+
id: z.ZodString;
|
|
5
|
+
published_at: z.ZodNullable<z.ZodISODateTime>;
|
|
6
|
+
updated_at: z.ZodOptional<z.ZodNullable<z.ZodISODateTime>>;
|
|
7
|
+
old_slugs: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
8
|
+
slug: z.ZodString;
|
|
9
|
+
changed_at: z.ZodOptional<z.ZodISODateTime>;
|
|
10
|
+
}, z.core.$strict>>>;
|
|
11
|
+
}, z.core.$strict>>;
|
|
12
|
+
}, z.core.$strict>;
|
|
13
|
+
/**
|
|
14
|
+
* What the module keeps from an article's earlier life. Timestamps are ISO 8601 text with a time zone,
|
|
15
|
+
* as the history gives them, so their full precision reaches the database.
|
|
16
|
+
*/
|
|
17
|
+
export interface ArticleHistory {
|
|
18
|
+
readonly publishedAt: string | null;
|
|
19
|
+
/** Kept only with `publishedAt`. */
|
|
20
|
+
readonly updatedAt: string | null;
|
|
21
|
+
readonly oldSlugs: readonly {
|
|
22
|
+
readonly slug: string;
|
|
23
|
+
readonly changedAt: string | null;
|
|
24
|
+
}[];
|
|
25
|
+
}
|
|
26
|
+
/** History by article id. */
|
|
27
|
+
export type ArticleHistoryMap = ReadonlyMap<string, ArticleHistory>;
|
|
28
|
+
/** The parsed history, or the problems that name the field (`articles.3.published_at: …`). */
|
|
29
|
+
export declare function parseArticleHistory(input: unknown): {
|
|
30
|
+
readonly ok: true;
|
|
31
|
+
readonly history: ArticleHistoryMap;
|
|
32
|
+
} | {
|
|
33
|
+
readonly ok: false;
|
|
34
|
+
readonly errors: readonly string[];
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/db/history.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA6BxB,eAAO,MAAM,oBAAoB;;;;;;;;;;kBAa7B,CAAC;AAEL;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,oCAAoC;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;CAC5F;AAED,6BAA6B;AAC7B,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAEpE,8FAA8F;AAC9F,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAmB3K"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// The history of articles an app published before it moved to this module: when each text first went
|
|
2
|
+
// public, when it last changed, and the slugs it had before. A first publish into `blog.*` would
|
|
3
|
+
// otherwise date every text today and lose the old addresses' 301s.
|
|
4
|
+
//
|
|
5
|
+
// The app exports it once from its own tables as JSON (README, "Moving an existing blog") and passes it
|
|
6
|
+
// to `softure-blog publish --history <file>`. It applies only to an article that has no row yet, so a
|
|
7
|
+
// re-run with the same file changes nothing, and the article file's own `published_at` still wins.
|
|
8
|
+
//
|
|
9
|
+
// Timestamps stay the text they were given and go into Postgres as text, so `…:12.421579Z` (what a
|
|
10
|
+
// `timestamptz` holds) is stored to the microsecond; a `Date` would keep only milliseconds. Digits past
|
|
11
|
+
// the sixth are rounded by Postgres.
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
const SLUG = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
14
|
+
const timestamp = z.iso.datetime({
|
|
15
|
+
offset: true,
|
|
16
|
+
error: (issue) => issue.input === undefined
|
|
17
|
+
? "is required: an ISO 8601 timestamp, or null for a text that was never published"
|
|
18
|
+
: "must be an ISO 8601 timestamp with a time zone, e.g. 2026-09-01T08:00:00Z",
|
|
19
|
+
});
|
|
20
|
+
const oldSlugSchema = z.strictObject({
|
|
21
|
+
slug: z.string().max(100).regex(SLUG, "must be a kebab-case slug"),
|
|
22
|
+
changed_at: timestamp.optional(),
|
|
23
|
+
});
|
|
24
|
+
const entrySchema = z
|
|
25
|
+
.strictObject({
|
|
26
|
+
id: z.string().max(100).regex(SLUG, "must be a kebab-case article id"),
|
|
27
|
+
published_at: timestamp.nullable(),
|
|
28
|
+
updated_at: timestamp.nullable().optional(),
|
|
29
|
+
old_slugs: z.array(oldSlugSchema).default([]),
|
|
30
|
+
})
|
|
31
|
+
.refine((entry) => entry.updated_at === undefined || entry.updated_at === null || entry.published_at !== null, {
|
|
32
|
+
message: "updated_at needs published_at: a text is updated only after it was published",
|
|
33
|
+
path: ["updated_at"],
|
|
34
|
+
});
|
|
35
|
+
export const articleHistorySchema = z
|
|
36
|
+
.strictObject({ articles: z.array(entrySchema) })
|
|
37
|
+
.superRefine((history, context) => {
|
|
38
|
+
const ids = new Set();
|
|
39
|
+
const slugs = new Set();
|
|
40
|
+
history.articles.forEach((entry, index) => {
|
|
41
|
+
if (ids.has(entry.id))
|
|
42
|
+
context.addIssue({ code: "custom", path: ["articles", index, "id"], message: `"${entry.id}" is listed twice` });
|
|
43
|
+
ids.add(entry.id);
|
|
44
|
+
entry.old_slugs.forEach((old, slugIndex) => {
|
|
45
|
+
if (slugs.has(old.slug))
|
|
46
|
+
context.addIssue({ code: "custom", path: ["articles", index, "old_slugs", slugIndex, "slug"], message: `"${old.slug}" is an old slug twice` });
|
|
47
|
+
slugs.add(old.slug);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
/** The parsed history, or the problems that name the field (`articles.3.published_at: …`). */
|
|
52
|
+
export function parseArticleHistory(input) {
|
|
53
|
+
const parsed = articleHistorySchema.safeParse(input);
|
|
54
|
+
if (!parsed.success) {
|
|
55
|
+
return { ok: false, errors: parsed.error.issues.map((issue) => `${issue.path.join(".") || "history"}: ${issue.message}`) };
|
|
56
|
+
}
|
|
57
|
+
const orNull = (value) => value ?? null;
|
|
58
|
+
return {
|
|
59
|
+
ok: true,
|
|
60
|
+
history: new Map(parsed.data.articles.map((entry) => [
|
|
61
|
+
entry.id,
|
|
62
|
+
{
|
|
63
|
+
publishedAt: orNull(entry.published_at),
|
|
64
|
+
updatedAt: orNull(entry.updated_at),
|
|
65
|
+
oldSlugs: entry.old_slugs.map((old) => ({ slug: old.slug, changedAt: orNull(old.changed_at) })),
|
|
66
|
+
},
|
|
67
|
+
])),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/db/history.ts"],"names":[],"mappings":"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"}
|
package/dist/db/publish-run.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BlogArticleInput, BlogArticleKind, BlogArticleStatus, BlogPublishAction } from "../contract.js";
|
|
2
2
|
import { type ParseArticleFileOptions } from "../content/article-file.js";
|
|
3
3
|
import { type BlogContext } from "./articles.js";
|
|
4
|
+
import type { ArticleHistoryMap } from "./history.js";
|
|
4
5
|
export interface ArticleFile {
|
|
5
6
|
/** The file name (or path); it must read `<slug>.md`. */
|
|
6
7
|
readonly name: string;
|
|
@@ -18,6 +19,11 @@ export interface RunBlogPublishOptions extends ParseArticleFileOptions {
|
|
|
18
19
|
/** Publish the files as `withdrawn`, whatever their status (taking a text down at once). */
|
|
19
20
|
readonly withdraw?: boolean;
|
|
20
21
|
readonly gate?: PublishGate;
|
|
22
|
+
/**
|
|
23
|
+
* The earlier life of articles an app moves in (history.ts), by id: applied to an article of the run
|
|
24
|
+
* that has no row yet. An entry for an id outside the run is a warning.
|
|
25
|
+
*/
|
|
26
|
+
readonly history?: ArticleHistoryMap;
|
|
21
27
|
}
|
|
22
28
|
/** A problem that stops the run; `subject` is a file name, an article id or a cluster. */
|
|
23
29
|
export interface PublishProblem {
|
|
@@ -35,6 +41,11 @@ export interface PublishedChange {
|
|
|
35
41
|
readonly slug: string;
|
|
36
42
|
/** The slug that entered the slug history in this run. */
|
|
37
43
|
readonly previousSlug: string | null;
|
|
44
|
+
/** Set when the run applied the article's history (`history`): its dates and old slugs. */
|
|
45
|
+
readonly imported?: {
|
|
46
|
+
readonly publishedAt: Date | null;
|
|
47
|
+
readonly oldSlugs: number;
|
|
48
|
+
};
|
|
38
49
|
}
|
|
39
50
|
export type BlogPublishRun = {
|
|
40
51
|
readonly status: "refused";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish-run.d.ts","sourceRoot":"","sources":["../../src/db/publish-run.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC9G,OAAO,EAAoB,KAAK,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAI5F,OAAO,EAAgC,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"publish-run.d.ts","sourceRoot":"","sources":["../../src/db/publish-run.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC9G,OAAO,EAAoB,KAAK,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAI5F,OAAO,EAAgC,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,KAAK,EAAkB,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGtE,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,KAAK,SAAS,MAAM,EAAE,CAAC;AAE9F,MAAM,WAAW,qBAAsB,SAAQ,uBAAuB;IACpE,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,4FAA4F;IAC5F,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;CACtC;AAED,0FAA0F;AAC1F,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,iGAAiG;AACjG,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAChD,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,2FAA2F;IAC3F,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAClB,QAAQ,CAAC,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;QAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAA;CAAE,GAC1H;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAA;CAAE,CAAC;AAgBzJ,wBAAsB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,WAAW,EAAE,EAAE,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,cAAc,CAAC,CA4ElJ"}
|
package/dist/db/publish-run.js
CHANGED
|
@@ -44,14 +44,21 @@ export async function runBlogPublish(ctx, files, options = {}) {
|
|
|
44
44
|
problems.push(...findDuplicateIds(inputs), ...findPillarProblems(inputs));
|
|
45
45
|
if (problems.length > 0)
|
|
46
46
|
return { status: "refused", problems, warnings };
|
|
47
|
+
const runIds = new Set(inputs.map((input) => input.id));
|
|
48
|
+
for (const id of options.history?.keys() ?? []) {
|
|
49
|
+
if (!runIds.has(id))
|
|
50
|
+
warnings.push({ subject: id, message: "the history names an article that is not in this run; it is applied when its file is published" });
|
|
51
|
+
}
|
|
47
52
|
const changes = [];
|
|
48
53
|
try {
|
|
49
54
|
await ctx.db.transaction(async (tx) => {
|
|
50
55
|
for (const input of inputs) {
|
|
51
|
-
const
|
|
56
|
+
const history = options.history?.get(input.id);
|
|
57
|
+
const result = await publishArticleOrRefuse({ ...ctx, db: tx }, input, history);
|
|
52
58
|
if (!result.ok) {
|
|
53
59
|
const reason = result.error === "blog.slug_taken" ? "is the slug of" : "redirects to";
|
|
54
|
-
|
|
60
|
+
const slug = result.slug === undefined ? `slug ${input.slug}` : `old slug ${result.slug} (history)`;
|
|
61
|
+
throw new PublishRefused([{ subject: input.id, message: `${slug} ${reason} article ${result.otherArticleId} (${result.error})` }]);
|
|
55
62
|
}
|
|
56
63
|
changes.push({
|
|
57
64
|
id: input.id,
|
|
@@ -62,6 +69,9 @@ export async function runBlogPublish(ctx, files, options = {}) {
|
|
|
62
69
|
slugBefore: result.before?.slug ?? null,
|
|
63
70
|
slug: result.after.slug,
|
|
64
71
|
previousSlug: result.previousSlug,
|
|
72
|
+
...(result.imported === true && history !== undefined
|
|
73
|
+
? { imported: { publishedAt: result.after.publishedAt, oldSlugs: history.oldSlugs.filter((old) => old.slug !== input.slug).length } }
|
|
74
|
+
: {}),
|
|
65
75
|
});
|
|
66
76
|
}
|
|
67
77
|
const glossary = await checkGlossaryForms({ ...ctx, db: tx }, inputs);
|
|
@@ -139,9 +149,9 @@ async function checkGlossaryForms(ctx, inputs) {
|
|
|
139
149
|
* for that run and fail with 23505. The savepoint is rolled back, so the transaction still reads
|
|
140
150
|
* (at read committed, the winner's row is visible now) and names the article that took the slug.
|
|
141
151
|
*/
|
|
142
|
-
async function publishArticleOrRefuse(ctx, input) {
|
|
152
|
+
async function publishArticleOrRefuse(ctx, input, history) {
|
|
143
153
|
try {
|
|
144
|
-
return await publishArticle(ctx, input);
|
|
154
|
+
return await publishArticle(ctx, input, history === undefined ? {} : { history });
|
|
145
155
|
}
|
|
146
156
|
catch (error) {
|
|
147
157
|
const driverError = findDriverError(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish-run.js","sourceRoot":"","sources":["../../src/db/publish-run.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,gBAAgB,EAAgC,MAAM,4BAA4B,CAAC;AAE5F,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,cAAc,EAAoB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"publish-run.js","sourceRoot":"","sources":["../../src/db/publish-run.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -112,7 +112,7 @@ export declare const blog: import("@softure-ai/core").ModuleFactory<{
|
|
|
112
112
|
}, import("zod/v4/core").$strict>>;
|
|
113
113
|
fonts: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
|
|
114
114
|
name: import("zod").ZodString;
|
|
115
|
-
weight: import("zod").ZodDefault<import("zod").ZodCustom<200 | 600 | 700 |
|
|
115
|
+
weight: import("zod").ZodDefault<import("zod").ZodCustom<200 | 600 | 700 | 100 | 500 | 300 | 400 | 800 | 900, 200 | 600 | 700 | 100 | 500 | 300 | 400 | 800 | 900>>;
|
|
116
116
|
style: import("zod").ZodDefault<import("zod").ZodEnum<{
|
|
117
117
|
normal: "normal";
|
|
118
118
|
italic: "italic";
|
|
@@ -131,10 +131,25 @@ export declare const blog: import("@softure-ai/core").ModuleFactory<{
|
|
|
131
131
|
}, import("zod/v4/core").$strict>>>;
|
|
132
132
|
blocks: import("zod").ZodDefault<import("zod").ZodArray<import("zod").ZodCustom<import("./render/render-article.js").BlockPlugin<unknown>, import("./render/render-article.js").BlockPlugin<unknown>>>>;
|
|
133
133
|
siteHosts: import("zod").ZodDefault<import("zod").ZodArray<import("zod").ZodString>>;
|
|
134
|
+
externalLinkMarker: import("zod").ZodDefault<import("zod").ZodEnum<{
|
|
135
|
+
"icon-and-text": "icon-and-text";
|
|
136
|
+
text: "text";
|
|
137
|
+
none: "none";
|
|
138
|
+
}>>;
|
|
134
139
|
images: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
135
140
|
hosts: import("zod").ZodDefault<import("zod").ZodReadonly<import("zod").ZodArray<import("zod").ZodString>>>;
|
|
136
141
|
dimensions: import("zod").ZodCustom<(src: string) => import("./render/images.js").ImageDimensions | null, (src: string) => import("./render/images.js").ImageDimensions | null>;
|
|
137
142
|
}, import("zod/v4/core").$strict>>;
|
|
143
|
+
gonePage: import("zod").ZodDefault<import("zod").ZodObject<{
|
|
144
|
+
links: import("zod").ZodDefault<import("zod").ZodArray<import("zod").ZodObject<{
|
|
145
|
+
href: import("zod").ZodString;
|
|
146
|
+
label: import("zod").ZodObject<{
|
|
147
|
+
en: import("zod").ZodString;
|
|
148
|
+
pl: import("zod").ZodOptional<import("zod").ZodString>;
|
|
149
|
+
}, import("zod/v4/core").$strict>;
|
|
150
|
+
}, import("zod/v4/core").$strict>>>;
|
|
151
|
+
render: import("zod").ZodOptional<import("zod").ZodCustom<(input: import("./pages/redirects.js").GonePageRenderInput) => string, (input: import("./pages/redirects.js").GonePageRenderInput) => string>>;
|
|
152
|
+
}, import("zod/v4/core").$strict>>;
|
|
138
153
|
revalidateSeconds: import("zod").ZodDefault<import("zod").ZodNumber>;
|
|
139
154
|
quality: import("zod").ZodDefault<import("zod").ZodType<false | {
|
|
140
155
|
language: "en" | "pl";
|
|
@@ -182,8 +197,8 @@ export declare const blog: import("@softure-ai/core").ModuleFactory<{
|
|
|
182
197
|
};
|
|
183
198
|
severity: Record<string, "error" | "warning" | "off">;
|
|
184
199
|
paths: {
|
|
185
|
-
articles
|
|
186
|
-
terms
|
|
200
|
+
articles?: string | undefined;
|
|
201
|
+
terms?: string | undefined;
|
|
187
202
|
};
|
|
188
203
|
ownOrigins: string[];
|
|
189
204
|
privateRouteSegments: string[];
|
|
@@ -290,8 +305,8 @@ export declare const blog: import("@softure-ai/core").ModuleFactory<{
|
|
|
290
305
|
};
|
|
291
306
|
severity: Record<string, "error" | "warning" | "off">;
|
|
292
307
|
paths: {
|
|
293
|
-
articles
|
|
294
|
-
terms
|
|
308
|
+
articles?: string | undefined;
|
|
309
|
+
terms?: string | undefined;
|
|
295
310
|
};
|
|
296
311
|
ownOrigins: string[];
|
|
297
312
|
privateRouteSegments: string[];
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,SAAS,SAAS,CAAC;AAEhC;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;;;;CAE1B,CAAC;AAEX;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,SAAS,SAAS,CAAC;AAEhC;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;;;;CAE1B,CAAC;AAEX;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCAoCf,CAAC;AAEH,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,UAAU,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACnE,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC5D,2FAA2F;AAC3F,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ export const BLOG_RATE_LIMIT_BUCKETS = {
|
|
|
26
26
|
export const blog = defineModule({
|
|
27
27
|
manifest: {
|
|
28
28
|
id: MODULE_ID,
|
|
29
|
-
version: "0.1.
|
|
29
|
+
version: "0.1.8",
|
|
30
30
|
// seo is optional: with it the sitemap lists the texts and a publish pings IndexNow. security is
|
|
31
31
|
// optional too: only the cache refresh route needs it, for its rate limit.
|
|
32
32
|
dependsOn: { seo: "^0.1.0?", security: "^0.1.0?" },
|
package/dist/next/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { getBlogContext, getPageContext } from "./context.js";
|
|
2
2
|
export { serveBlogRss } from "./discovery.js";
|
|
3
|
+
export { buildArticleJsonLd, buildGlossaryJsonLd, buildTermJsonLd, getCrumbLabels } from "./json-ld.js";
|
|
4
|
+
export { buildArticleMetadata, buildBlogIndexMetadata, buildGlossaryIndexMetadata, buildMethodMetadata, buildTermMetadata, type ListingMetadataInput, } from "./metadata.js";
|
|
3
5
|
export { refreshBlogCache } from "./refresh.js";
|
|
4
6
|
export { BLOG_CACHE_TAG, getPublishedArticles, getPublishedTerms, getTextBySlug } from "./data.js";
|
|
5
7
|
export { createOgFontLoader, loadBrandOgFonts, type OgFontLoaderOptions, type OgFontsResult } from "./og-fonts.js";
|
package/dist/next/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACnG,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AACnH,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,oBAAoB,EAAE,KAAK,MAAM,EAAE,KAAK,yBAAyB,EAAE,MAAM,eAAe,CAAC;AACnK,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EACL,eAAe,EACf,aAAa,EACb,cAAc,EACd,uBAAuB,EACvB,yBAAyB,EACzB,wBAAwB,EACxB,6BAA6B,EAC7B,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,GAC3B,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACxG,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,oBAAoB,GAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACnG,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AACnH,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,oBAAoB,EAAE,KAAK,MAAM,EAAE,KAAK,yBAAyB,EAAE,MAAM,eAAe,CAAC;AACnK,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EACL,eAAe,EACf,aAAa,EACb,cAAc,EACd,uBAAuB,EACvB,yBAAyB,EACzB,wBAAwB,EACxB,6BAA6B,EAC7B,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,GAC3B,MAAM,YAAY,CAAC"}
|
package/dist/next/index.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// feed, the cache refresh route and the cached reads (docs/02-module-standard.md §8).
|
|
3
3
|
export { getBlogContext, getPageContext } from "./context.js";
|
|
4
4
|
export { serveBlogRss } from "./discovery.js";
|
|
5
|
+
export { buildArticleJsonLd, buildGlossaryJsonLd, buildTermJsonLd, getCrumbLabels } from "./json-ld.js";
|
|
6
|
+
export { buildArticleMetadata, buildBlogIndexMetadata, buildGlossaryIndexMetadata, buildMethodMetadata, buildTermMetadata, } from "./metadata.js";
|
|
5
7
|
export { refreshBlogCache } from "./refresh.js";
|
|
6
8
|
export { BLOG_CACHE_TAG, getPublishedArticles, getPublishedTerms, getTextBySlug } from "./data.js";
|
|
7
9
|
export { createOgFontLoader, loadBrandOgFonts } from "./og-fonts.js";
|
package/dist/next/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,sFAAsF;AACtF,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACnG,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAgD,MAAM,eAAe,CAAC;AACnH,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,oBAAoB,EAA+C,MAAM,eAAe,CAAC;AAEnK,OAAO,EACL,eAAe,EACf,aAAa,EACb,cAAc,EACd,uBAAuB,EACvB,yBAAyB,EACzB,wBAAwB,EACxB,6BAA6B,EAC7B,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,GAIjB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,sFAAsF;AACtF,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACxG,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,mBAAmB,EACnB,iBAAiB,GAElB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACnG,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAgD,MAAM,eAAe,CAAC;AACnH,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,oBAAoB,EAA+C,MAAM,eAAe,CAAC;AAEnK,OAAO,EACL,eAAe,EACf,aAAa,EACb,cAAc,EACd,uBAAuB,EACvB,yBAAyB,EACzB,wBAAwB,EACxB,6BAA6B,EAC7B,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,GAIjB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type SoftureConfig } from "@softure-ai/core";
|
|
2
|
+
import type { BlogArticle } from "../contract.js";
|
|
3
|
+
import { type CrumbLabels } from "../pages/listing.js";
|
|
4
|
+
import type { BlogPageContext } from "../ui/page-context.js";
|
|
5
|
+
/** The breadcrumb names the pages show: the blog, the glossary and the clusters' display names. */
|
|
6
|
+
export declare function getCrumbLabels(config: SoftureConfig, context?: BlogPageContext): CrumbLabels;
|
|
7
|
+
/** An article's `BlogPosting`, breadcrumbs and FAQ, serialized. */
|
|
8
|
+
export declare function buildArticleJsonLd(config: SoftureConfig, article: BlogArticle): string;
|
|
9
|
+
/** A glossary term's `DefinedTerm` and breadcrumbs, serialized. */
|
|
10
|
+
export declare function buildTermJsonLd(config: SoftureConfig, term: BlogArticle): string;
|
|
11
|
+
/** The glossary's `DefinedTermSet` over the published terms, in the index's order, serialized; `null` without terms. */
|
|
12
|
+
export declare function buildGlossaryJsonLd(config: SoftureConfig, terms: readonly BlogArticle[]): string | null;
|
|
13
|
+
//# sourceMappingURL=json-ld.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-ld.d.ts","sourceRoot":"","sources":["../../src/next/json-ld.ts"],"names":[],"mappings":"AAKA,OAAO,EAAe,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,EAA+D,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEpH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7D,mGAAmG;AACnG,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,GAAE,eAAwC,GAAG,WAAW,CAOpH;AAMD,mEAAmE;AACnE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM,CAItF;AAED,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM,CAIhF;AAED,wHAAwH;AACxH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,GAAG,IAAI,CAIvG"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// The structured data of the blog's pages, ready for `<script type="application/ld+json">`: built from
|
|
2
|
+
// what the caller already holds (no database read, no request scope) and serialized so no text can
|
|
3
|
+
// close the tag. The ready-made pages use these; an app with its own page components mounts them as
|
|
4
|
+
//
|
|
5
|
+
// <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: buildArticleJsonLd(config, article) }} />
|
|
6
|
+
import { getSiteUrls } from "@softure-ai/core";
|
|
7
|
+
import { getArticleJsonLd, getGlossaryJsonLd, getTermJsonLd, serializeJsonLd } from "../pages/json-ld.js";
|
|
8
|
+
import { getArticleCrumbs, getClusterLabel, getTermCrumbs, sortTerms } from "../pages/listing.js";
|
|
9
|
+
import { getBlogOptions } from "../server/options.js";
|
|
10
|
+
import { getPageContext } from "./context.js";
|
|
11
|
+
/** The breadcrumb names the pages show: the blog, the glossary and the clusters' display names. */
|
|
12
|
+
export function getCrumbLabels(config, context = getPageContext(config)) {
|
|
13
|
+
const clusters = getBlogOptions(config).clusters;
|
|
14
|
+
return {
|
|
15
|
+
blog: context.messages.pages.blogTitle,
|
|
16
|
+
glossary: context.messages.glossary.title,
|
|
17
|
+
cluster: (cluster) => getClusterLabel(cluster, clusters, config.locale),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function getJsonLdContext(config, context) {
|
|
21
|
+
return { urls: getSiteUrls(config), routes: context.routes, locale: config.locale, timezone: config.timezone, brand: context.brand };
|
|
22
|
+
}
|
|
23
|
+
/** An article's `BlogPosting`, breadcrumbs and FAQ, serialized. */
|
|
24
|
+
export function buildArticleJsonLd(config, article) {
|
|
25
|
+
const context = getPageContext(config);
|
|
26
|
+
const crumbs = getArticleCrumbs(article, context.routes, getCrumbLabels(config, context));
|
|
27
|
+
return serializeJsonLd(getArticleJsonLd(article, crumbs, getJsonLdContext(config, context)));
|
|
28
|
+
}
|
|
29
|
+
/** A glossary term's `DefinedTerm` and breadcrumbs, serialized. */
|
|
30
|
+
export function buildTermJsonLd(config, term) {
|
|
31
|
+
const context = getPageContext(config);
|
|
32
|
+
const crumbs = getTermCrumbs(term, context.routes, getCrumbLabels(config, context));
|
|
33
|
+
return serializeJsonLd(getTermJsonLd(term, crumbs, getJsonLdContext(config, context), context.messages.glossary.title));
|
|
34
|
+
}
|
|
35
|
+
/** The glossary's `DefinedTermSet` over the published terms, in the index's order, serialized; `null` without terms. */
|
|
36
|
+
export function buildGlossaryJsonLd(config, terms) {
|
|
37
|
+
if (terms.length === 0)
|
|
38
|
+
return null;
|
|
39
|
+
const context = getPageContext(config);
|
|
40
|
+
return serializeJsonLd(getGlossaryJsonLd(sortTerms(terms, config.locale), getJsonLdContext(config, context), context.messages.glossary.title));
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=json-ld.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-ld.js","sourceRoot":"","sources":["../../src/next/json-ld.ts"],"names":[],"mappings":"AAAA,uGAAuG;AACvG,mGAAmG;AACnG,oGAAoG;AACpG,EAAE;AACF,oHAAoH;AACpH,OAAO,EAAE,WAAW,EAAsB,MAAM,kBAAkB,CAAC;AAEnE,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAsB,MAAM,qBAAqB,CAAC;AAC9H,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,SAAS,EAAoB,MAAM,qBAAqB,CAAC;AACpH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,mGAAmG;AACnG,MAAM,UAAU,cAAc,CAAC,MAAqB,EAAE,UAA2B,cAAc,CAAC,MAAM,CAAC;IACrG,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC;IACjD,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS;QACtC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK;QACzC,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC;KACxE,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAqB,EAAE,OAAwB;IACvE,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;AACvI,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,kBAAkB,CAAC,MAAqB,EAAE,OAAoB;IAC5E,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1F,OAAO,eAAe,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/F,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,eAAe,CAAC,MAAqB,EAAE,IAAiB;IACtE,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACpF,OAAO,eAAe,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1H,CAAC;AAED,wHAAwH;AACxH,MAAM,UAAU,mBAAmB,CAAC,MAAqB,EAAE,KAA6B;IACtF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,eAAe,CAAC,iBAAiB,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACjJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type SoftureConfig } from "@softure-ai/core";
|
|
2
|
+
import type { Metadata } from "next/types.js";
|
|
3
|
+
import type { BlogArticle } from "../contract.js";
|
|
4
|
+
/** Whether a listing has no entry: an empty listing stays out of the index (thin content). */
|
|
5
|
+
export interface ListingMetadataInput {
|
|
6
|
+
readonly isEmpty: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** The listing's metadata, with the feed link. */
|
|
9
|
+
export declare function buildBlogIndexMetadata(config: SoftureConfig, { isEmpty }: ListingMetadataInput): Metadata;
|
|
10
|
+
/** An article's metadata, with the feed link. The caller checks the text is a published article. */
|
|
11
|
+
export declare function buildArticleMetadata(config: SoftureConfig, article: BlogArticle): Metadata;
|
|
12
|
+
/** The glossary index's metadata. */
|
|
13
|
+
export declare function buildGlossaryIndexMetadata(config: SoftureConfig, { isEmpty }: ListingMetadataInput): Metadata;
|
|
14
|
+
/** A glossary term's metadata. The caller checks the text is a published term. */
|
|
15
|
+
export declare function buildTermMetadata(config: SoftureConfig, term: BlogArticle): Metadata;
|
|
16
|
+
/** The method page's metadata. */
|
|
17
|
+
export declare function buildMethodMetadata(config: SoftureConfig): Metadata;
|
|
18
|
+
//# sourceMappingURL=metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/next/metadata.ts"],"names":[],"mappings":"AAWA,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGlF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAMlD,8FAA8F;AAC9F,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AA+CD,kDAAkD;AAClD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,EAAE,oBAAoB,GAAG,QAAQ,CAIzG;AAED,oGAAoG;AACpG,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,GAAG,QAAQ,CAG1F;AAED,qCAAqC;AACrC,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,EAAE,oBAAoB,GAAG,QAAQ,CAI7G;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,WAAW,GAAG,QAAQ,CAGpF;AAED,kCAAkC;AAClC,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,QAAQ,CAInE"}
|