@softure-ai/blog 0.1.9 → 0.1.10
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 +10 -0
- package/README.md +13 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/next/body.d.ts +16 -0
- package/dist/next/body.d.ts.map +1 -0
- package/dist/next/body.js +22 -0
- package/dist/next/body.js.map +1 -0
- package/dist/next/index.d.ts +1 -0
- package/dist/next/index.d.ts.map +1 -1
- package/dist/next/index.js +1 -0
- package/dist/next/index.js.map +1 -1
- package/dist/next/pages.d.ts.map +1 -1
- package/dist/next/pages.js +5 -10
- package/dist/next/pages.js.map +1 -1
- package/dist/pages/dates.d.ts +2 -2
- package/dist/pages/dates.d.ts.map +1 -1
- package/dist/pages/dates.js +5 -3
- package/dist/pages/dates.js.map +1 -1
- package/dist/quality/settings.d.ts +2 -2
- package/dist/quality/settings.d.ts.map +1 -1
- package/dist/quality/settings.js +5 -2
- package/dist/quality/settings.js.map +1 -1
- package/module.json +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -1
- package/src/next/body.ts +33 -0
- package/src/next/index.ts +1 -0
- package/src/next/pages.tsx +6 -13
- package/src/pages/dates.ts +3 -4
- package/src/quality/settings.ts +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@ Newest first. Each version lists what changed for an app that uses `@softure-ai/
|
|
|
4
4
|
production, the version gets a line `verified in: <app>@<commit>` ([docs/05](../../docs/05-adoption-playbook.md),
|
|
5
5
|
"Definition of done"). Versions before the first one below are described in their GitHub Releases (`blog@x.y.z`).
|
|
6
6
|
|
|
7
|
+
## 0.1.10
|
|
8
|
+
|
|
9
|
+
- `/next` exports `getBodyOptions(config, terms)`, the `RenderPageBodyOptions` the ready-made pages render
|
|
10
|
+
bodies with, and `findArticlesLinkingTermFor(config, { articles, termSlug, terms })`, a glossary term page's
|
|
11
|
+
"explained in these texts" list. An app with its own page components no longer copies the binding, so its
|
|
12
|
+
list and body links follow the package's rule. The ready-made pages go through the same functions.
|
|
13
|
+
- `getDayInZone` (`/pages`) and `getLocalDate` (`/quality`) compute the day with `toCalendarDay` from
|
|
14
|
+
`@softure-ai/core` instead of a local `en-CA` formatter, whose date pattern has changed between ICU versions. Same
|
|
15
|
+
results; requires `@softure-ai/core` `^0.1.7` (#270).
|
|
16
|
+
|
|
7
17
|
## 0.1.9
|
|
8
18
|
|
|
9
19
|
- `og:locale` of articles and terms is an Open Graph locale now: `en_US` / `pl_PL` by default, not the bare
|
package/README.md
CHANGED
|
@@ -346,6 +346,19 @@ The builders: `buildBlogIndexMetadata(config, { isEmpty })`, `buildArticleMetada
|
|
|
346
346
|
`<script>`. `getCrumbLabels(config)` gives the breadcrumb names for `getArticleCrumbs`/`getTermCrumbs`
|
|
347
347
|
(`/server`); `getPageContext`, `renderPageBody` and `getRelatedArticles` render the rest.
|
|
348
348
|
|
|
349
|
+
A body and a term's "explained in these texts" list take the input the ready-made pages build, so an own page
|
|
350
|
+
links and lists exactly as they do:
|
|
351
|
+
|
|
352
|
+
```tsx
|
|
353
|
+
const [articles, terms] = await Promise.all([getPublishedArticles(config), getPublishedTerms(config)]);
|
|
354
|
+
const body = renderPageBody(term, getBodyOptions(config, terms)); // renderPageBody from /server
|
|
355
|
+
const explainedIn = findArticlesLinkingTermFor(config, { articles, termSlug: term.slug, terms });
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
`getBodyOptions(config, terms)` is the `RenderPageBodyOptions` of the pages (the glossary, routes, blog options,
|
|
359
|
+
`appOrigin` and the canonical site origin, the copy); `findArticlesLinkingTermFor` is `findArticlesLinkingTerm`
|
|
360
|
+
(`/server`) over it.
|
|
361
|
+
|
|
349
362
|
What the builders write, so an app moving published pages onto them can match its old output:
|
|
350
363
|
|
|
351
364
|
- the JSON-LD `@id` fragments, the cluster anchor and the language tags come from `jsonLd`, `anchors` and
|
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.10",
|
|
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/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,oGAAoG;AACpG,0EAA0E;AAC1E,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,8BAA8B,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjG,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC;AAEhC;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,CAAC,8BAA8B,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE;CAC1D,CAAC;AAEX;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,YAAY,CAAC;IAC/B,QAAQ,EAAE;QACR,EAAE,EAAE,SAAS;QACb,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,oGAAoG;AACpG,0EAA0E;AAC1E,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,8BAA8B,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjG,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC;AAEhC;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,CAAC,8BAA8B,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE;CAC1D,CAAC;AAEX;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,YAAY,CAAC;IAC/B,QAAQ,EAAE;QACR,EAAE,EAAE,SAAS;QACb,OAAO,EAAE,QAAQ;QACjB,iGAAiG;QACjG,2EAA2E;QAC3E,SAAS,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE;QAClD,QAAQ,EAAE,MAAM;QAChB,MAAM,EAAE,CAAC,UAAU,EAAE,cAAc,CAAC;QACpC,GAAG,EAAE;YACH;gBACE,IAAI,EAAE,uBAAuB;gBAC7B,QAAQ,EAAE,KAAK;gBACf,WAAW,EACT,+LAA+L;aAClM;SACF;QACD,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,oBAAoB,EAAE,GAAG,EAAE,eAAe,EAAE,OAAO,EAAE,mBAAmB,EAAE;QACxI,KAAK,EAAE;YACL,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,eAAe,EAAE;YACpE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,0BAA0B,EAAE,MAAM,EAAE,iBAAiB,EAAE;YAC7E,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,qCAAqC,EAAE,MAAM,EAAE,oBAAoB,EAAE;YACpG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,EAAE,MAAM,EAAE,mBAAmB,EAAE;YACjF,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mCAAmC,EAAE,MAAM,EAAE,kBAAkB,EAAE;YACvF,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gCAAgC,EAAE,MAAM,EAAE,gBAAgB,EAAE;YAClF,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,2BAA2B,EAAE,MAAM,EAAE,cAAc,EAAE;YACpF,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,+BAA+B,EAAE,MAAM,EAAE,kBAAkB,EAAE;YAC5F,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,qBAAqB,EAAE;SACxE;QACD,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE;KAC5C;IACD,QAAQ,EAAE,YAAY;IACtB,OAAO,EAAE,iBAAiB;IAC1B,UAAU,EAAE,EAAE,GAAG,EAAE,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,EAAE;IAC5E,MAAM,EAAE,kBAAkB;CAC3B,CAAC,CAAC;AAEH,OAAO,EACL,kBAAkB,EAClB,qBAAqB,GAatB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAqB,MAAM,qBAAqB,CAAC;AACtE,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,gBAAgB,GAOjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAEnE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC5D,2FAA2F;AAC3F,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type SoftureConfig } from "@softure-ai/core";
|
|
2
|
+
import type { BlogArticle } from "../contract.js";
|
|
3
|
+
import { type RenderPageBodyOptions } from "../pages/body.js";
|
|
4
|
+
import type { BlogPageContext } from "../ui/page-context.js";
|
|
5
|
+
/** What `renderPageBody` and `findArticlesLinkingTerm` (`/server`) take, as the ready-made pages build it. */
|
|
6
|
+
export declare function getBodyOptions(config: SoftureConfig, terms: readonly BlogArticle[], context?: BlogPageContext): RenderPageBodyOptions;
|
|
7
|
+
export interface ArticlesLinkingTermInput {
|
|
8
|
+
/** The published articles to look through, e.g. `getPublishedArticles(config)`. */
|
|
9
|
+
readonly articles: readonly BlogArticle[];
|
|
10
|
+
readonly termSlug: string;
|
|
11
|
+
/** The published terms, e.g. `getPublishedTerms(config)`: the glossary the bodies link. */
|
|
12
|
+
readonly terms: readonly BlogArticle[];
|
|
13
|
+
}
|
|
14
|
+
/** The published articles whose body links the term: the list under a glossary term's page. */
|
|
15
|
+
export declare function findArticlesLinkingTermFor(config: SoftureConfig, input: ArticlesLinkingTermInput): BlogArticle[];
|
|
16
|
+
//# sourceMappingURL=body.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"body.d.ts","sourceRoot":"","sources":["../../src/next/body.ts"],"names":[],"mappings":"AAOA,OAAO,EAAe,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAA2B,KAAK,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAGvF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7D,8GAA8G;AAC9G,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,WAAW,EAAE,EAAE,OAAO,GAAE,eAAwC,GAAG,qBAAqB,CAG7J;AAED,MAAM,WAAW,wBAAwB;IACvC,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2FAA2F;IAC3F,QAAQ,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;CACxC;AAED,+FAA+F;AAC/F,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,wBAAwB,GAAG,WAAW,EAAE,CAEhH"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// The body input of the blog's pages, bound to the config: the glossary from the published terms, the
|
|
2
|
+
// routes, the blog options, the site's own origins and the copy. The ready-made pages render with it,
|
|
3
|
+
// and an app with its own page components uses the same function, so its "explained in these texts"
|
|
4
|
+
// list and its body links follow the same rule as the package's pages:
|
|
5
|
+
//
|
|
6
|
+
// const articles = findArticlesLinkingTermFor(config, { articles: published, termSlug: term.slug, terms });
|
|
7
|
+
// const body = renderPageBody(term, getBodyOptions(config, terms));
|
|
8
|
+
import { getSiteUrls } from "@softure-ai/core";
|
|
9
|
+
import { findArticlesLinkingTerm } from "../pages/body.js";
|
|
10
|
+
import { toGlossary } from "../render/glossary.js";
|
|
11
|
+
import { getBlogOptions } from "../server/options.js";
|
|
12
|
+
import { getPageContext } from "./context.js";
|
|
13
|
+
/** What `renderPageBody` and `findArticlesLinkingTerm` (`/server`) take, as the ready-made pages build it. */
|
|
14
|
+
export function getBodyOptions(config, terms, context = getPageContext(config)) {
|
|
15
|
+
const origins = [config.appOrigin, getSiteUrls(config).origin];
|
|
16
|
+
return { glossary: toGlossary(terms), routes: context.routes, options: getBlogOptions(config), origins, messages: context.messages };
|
|
17
|
+
}
|
|
18
|
+
/** The published articles whose body links the term: the list under a glossary term's page. */
|
|
19
|
+
export function findArticlesLinkingTermFor(config, input) {
|
|
20
|
+
return findArticlesLinkingTerm(input.articles, input.termSlug, getBodyOptions(config, input.terms));
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=body.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"body.js","sourceRoot":"","sources":["../../src/next/body.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,sGAAsG;AACtG,oGAAoG;AACpG,uEAAuE;AACvE,EAAE;AACF,8GAA8G;AAC9G,sEAAsE;AACtE,OAAO,EAAE,WAAW,EAAsB,MAAM,kBAAkB,CAAC;AAEnE,OAAO,EAAE,uBAAuB,EAA8B,MAAM,kBAAkB,CAAC;AACvF,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,8GAA8G;AAC9G,MAAM,UAAU,cAAc,CAAC,MAAqB,EAAE,KAA6B,EAAE,UAA2B,cAAc,CAAC,MAAM,CAAC;IACpI,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;IAC/D,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;AACvI,CAAC;AAUD,+FAA+F;AAC/F,MAAM,UAAU,0BAA0B,CAAC,MAAqB,EAAE,KAA+B;IAC/F,OAAO,uBAAuB,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AACtG,CAAC"}
|
package/dist/next/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { findArticlesLinkingTermFor, getBodyOptions, type ArticlesLinkingTermInput } from "./body.js";
|
|
1
2
|
export { getBlogContext, getPageContext } from "./context.js";
|
|
2
3
|
export { serveBlogRss } from "./discovery.js";
|
|
3
4
|
export { buildArticleJsonLd, buildGlossaryJsonLd, buildTermJsonLd, getCrumbLabels } from "./json-ld.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,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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,cAAc,EAAE,KAAK,wBAAwB,EAAE,MAAM,WAAW,CAAC;AACtG,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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// The Next.js adapter of @softure-ai/blog: the pages, their metadata, the article's OG image, the RSS
|
|
2
2
|
// feed, the cache refresh route and the cached reads (docs/02-module-standard.md §8).
|
|
3
|
+
export { findArticlesLinkingTermFor, getBodyOptions } from "./body.js";
|
|
3
4
|
export { getBlogContext, getPageContext } from "./context.js";
|
|
4
5
|
export { serveBlogRss } from "./discovery.js";
|
|
5
6
|
export { buildArticleJsonLd, buildGlossaryJsonLd, buildTermJsonLd, getCrumbLabels } from "./json-ld.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,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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,sFAAsF;AACtF,OAAO,EAAE,0BAA0B,EAAE,cAAc,EAAiC,MAAM,WAAW,CAAC;AACtG,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"}
|
package/dist/next/pages.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/next/pages.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/next/pages.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAgBvC,KAAK,UAAU,GAAG,OAAO,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,qDAAqD;IACrD,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC;IACzB,+EAA+E;IAC/E,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC;CACnC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC;CAC1B;AAED,2FAA2F;AAC3F,wBAAgB,wBAAwB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAE7D;AAMD,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,QAAQ,CAAC,CAInE;AAED,uGAAuG;AACvG,wBAAsB,aAAa,CAAC,EAAE,GAAG,EAAE,GAAE,kBAAuB,wCAOnE;AAED,wBAAsB,uBAAuB,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAK5G;AAED,oGAAoG;AACpG,wBAAsB,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,oBAAoB,wCAuBxF;AAED,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,QAAQ,CAAC,CAIvE;AAED,kEAAkE;AAClE,wBAAsB,iBAAiB,yCAMtC;AAED,wBAAsB,oBAAoB,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAKzG;AAED,mHAAmH;AACnH,wBAAsB,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,qBAAqB,wCAsB5E;AAED,wBAAgB,sBAAsB,IAAI,QAAQ,CAEjD;AAED,sGAAsG;AACtG,wBAAgB,cAAc,gCAK7B"}
|
package/dist/next/pages.js
CHANGED
|
@@ -18,20 +18,19 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
18
18
|
//
|
|
19
19
|
// An app with its own page components keeps the rest: `generate*Metadata` and `BlogArticleOgImage`
|
|
20
20
|
// mount next to its own page, and `build*Metadata` (metadata.ts) and `build*JsonLd` (json-ld.ts) take
|
|
21
|
-
// a text it already read.
|
|
22
|
-
|
|
21
|
+
// a text it already read; `getBodyOptions` and `findArticlesLinkingTermFor` (body.ts) give the body
|
|
22
|
+
// input and a term's "explained in these texts" list.
|
|
23
23
|
import { getSoftureConfig } from "@softure-ai/core/next";
|
|
24
24
|
import { notFound } from "next/navigation";
|
|
25
25
|
import { getRelatedArticles } from "../discovery/related.js";
|
|
26
26
|
import { findArticlesLinkingTerm, renderPageBody } from "../pages/body.js";
|
|
27
27
|
import { getArticleDates } from "../pages/dates.js";
|
|
28
28
|
import { getArticleCrumbs, groupByCluster, getTermCrumbs, sortTerms } from "../pages/listing.js";
|
|
29
|
-
import { toGlossary } from "../render/glossary.js";
|
|
30
|
-
import { getBlogOptions } from "../server/options.js";
|
|
31
29
|
import { BlogArticleView } from "../ui/blog-article.js";
|
|
32
30
|
import { GlossaryIndexView, GlossaryTermView } from "../ui/blog-glossary.js";
|
|
33
31
|
import { BlogListingView } from "../ui/blog-listing.js";
|
|
34
32
|
import { BlogMethodView } from "../ui/blog-method.js";
|
|
33
|
+
import { getBodyOptions } from "./body.js";
|
|
35
34
|
import { getPageContext } from "./context.js";
|
|
36
35
|
import { getPublishedArticles, getPublishedTerms, getTextBySlug } from "./data.js";
|
|
37
36
|
import { buildArticleJsonLd, buildGlossaryJsonLd, buildTermJsonLd, getCrumbLabels } from "./json-ld.js";
|
|
@@ -43,10 +42,6 @@ export function generateBlogStaticParams() {
|
|
|
43
42
|
function isPublished(text, kind) {
|
|
44
43
|
return text !== null && text.status === "published" && text.kind === kind;
|
|
45
44
|
}
|
|
46
|
-
function getBodyOptions(config, context, terms) {
|
|
47
|
-
const origins = [config.appOrigin, getSiteUrls(config).origin];
|
|
48
|
-
return { glossary: toGlossary(terms), routes: context.routes, options: getBlogOptions(config), origins, messages: context.messages };
|
|
49
|
-
}
|
|
50
45
|
export async function generateBlogIndexMetadata() {
|
|
51
46
|
const config = getSoftureConfig();
|
|
52
47
|
const articles = await getPublishedArticles(config);
|
|
@@ -76,7 +71,7 @@ export async function BlogArticlePage({ params, cta, afterArticle }) {
|
|
|
76
71
|
notFound();
|
|
77
72
|
const context = getPageContext(config);
|
|
78
73
|
const [terms, published] = await Promise.all([getPublishedTerms(config), getPublishedArticles(config)]);
|
|
79
|
-
const body = renderPageBody(article, getBodyOptions(config,
|
|
74
|
+
const body = renderPageBody(article, getBodyOptions(config, terms, context));
|
|
80
75
|
const crumbs = getArticleCrumbs(article, context.routes, getCrumbLabels(config, context), { clusterAnchorPrefix: context.clusterAnchorPrefix });
|
|
81
76
|
const jsonLd = buildArticleJsonLd(config, article);
|
|
82
77
|
return (_jsx(BlogArticleView, { context: context, article: article, dates: getArticleDates(article, config.timezone), body: body, crumbs: crumbs, jsonLd: jsonLd, cta: cta, afterArticle: afterArticle, related: getRelatedArticles(article, published) }));
|
|
@@ -109,7 +104,7 @@ export async function GlossaryTermPage({ params, cta }) {
|
|
|
109
104
|
notFound();
|
|
110
105
|
const context = getPageContext(config);
|
|
111
106
|
const [terms, articles] = await Promise.all([getPublishedTerms(config), getPublishedArticles(config)]);
|
|
112
|
-
const bodyOptions = getBodyOptions(config,
|
|
107
|
+
const bodyOptions = getBodyOptions(config, terms, context);
|
|
113
108
|
const crumbs = getTermCrumbs(term, context.routes, getCrumbLabels(config, context));
|
|
114
109
|
const jsonLd = buildTermJsonLd(config, term);
|
|
115
110
|
return (_jsx(GlossaryTermView, { context: context, term: term, dates: getArticleDates(term, config.timezone), body: renderPageBody(term, bodyOptions), crumbs: crumbs, jsonLd: jsonLd, articles: findArticlesLinkingTerm(articles, term.slug, bodyOptions), cta: cta }));
|
package/dist/next/pages.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/next/pages.tsx"],"names":[],"mappings":";AAAA,uFAAuF;AACvF,EAAE;AACF,wJAAwJ;AACxJ,+EAA+E;AAC/E,0MAA0M;AAC1M,sEAAsE;AACtE,iGAAiG;AACjG,oHAAoH;AACpH,kHAAkH;AAClH,uFAAuF;AACvF,EAAE;AACF,kGAAkG;AAClG,iGAAiG;AACjG,gGAAgG;AAChG,oGAAoG;AACpG,mDAAmD;AACnD,EAAE;AACF,mGAAmG;AACnG,sGAAsG;AACtG,
|
|
1
|
+
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/next/pages.tsx"],"names":[],"mappings":"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"}
|
package/dist/pages/dates.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Locale } from "@softure-ai/core";
|
|
2
2
|
import type { BlogArticle } from "../contract.js";
|
|
3
3
|
export interface ArticleDates {
|
|
4
4
|
/** The day of first publication, `YYYY-MM-DD`. */
|
|
@@ -8,7 +8,7 @@ export interface ArticleDates {
|
|
|
8
8
|
/** The day the facts were checked, `YYYY-MM-DD`. */
|
|
9
9
|
readonly currentAsOf: string;
|
|
10
10
|
}
|
|
11
|
-
/** The calendar day of a moment in a time zone, `YYYY-MM-DD
|
|
11
|
+
/** The calendar day of a moment in a time zone, `YYYY-MM-DD`: core's `toCalendarDay` under the name this module exports. */
|
|
12
12
|
export declare function getDayInZone(moment: Date, timezone: string): string;
|
|
13
13
|
/**
|
|
14
14
|
* The visible dates of a published text. Two equal days one under the other read like a mistake, so
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../../src/pages/dates.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../../src/pages/dates.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uGAAuG;IACvG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,oDAAoD;IACpD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,4HAA4H;AAC5H,wBAAgB,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,WAAW,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAOhJ;AAED,kFAAkF;AAClF,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAG7D"}
|
package/dist/pages/dates.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
// The days a page shows for a text, in the app's time zone. JSON-LD takes the same days, so the dates
|
|
2
|
+
// a search engine compares (`dateModified` against the visible update) cannot drift apart.
|
|
3
|
+
import { toCalendarDay } from "@softure-ai/core";
|
|
4
|
+
/** The calendar day of a moment in a time zone, `YYYY-MM-DD`: core's `toCalendarDay` under the name this module exports. */
|
|
2
5
|
export function getDayInZone(moment, timezone) {
|
|
3
|
-
|
|
4
|
-
return new Intl.DateTimeFormat("en-CA", { timeZone: timezone, year: "numeric", month: "2-digit", day: "2-digit" }).format(moment);
|
|
6
|
+
return toCalendarDay(moment, timezone);
|
|
5
7
|
}
|
|
6
8
|
/**
|
|
7
9
|
* The visible dates of a published text. Two equal days one under the other read like a mistake, so
|
package/dist/pages/dates.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dates.js","sourceRoot":"","sources":["../../src/pages/dates.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dates.js","sourceRoot":"","sources":["../../src/pages/dates.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,2FAA2F;AAC3F,OAAO,EAAE,aAAa,EAAe,MAAM,kBAAkB,CAAC;AAY9D,4HAA4H;AAC5H,MAAM,UAAU,YAAY,CAAC,MAAY,EAAE,QAAgB;IACzD,OAAO,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,OAAgF,EAAE,QAAgB;IAChI,IAAI,OAAO,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,4BAA4B,OAAO,CAAC,IAAI,uDAAuD,CAAC,CAAC;IACnH,CAAC;IACD,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC9F,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;AAC1G,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,MAAc;IACnD,6FAA6F;IAC7F,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC;AACtH,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type SoftureConfig } from "@softure-ai/core";
|
|
2
2
|
import type { ArticleImagePolicy } from "../render/images.js";
|
|
3
3
|
import type { QualitySeverity } from "./finding.js";
|
|
4
4
|
import type { QualityOptions } from "./options.js";
|
|
@@ -30,7 +30,7 @@ export declare function resolveQualitySettings(options: QualityOptions, config:
|
|
|
30
30
|
readonly glossary: string;
|
|
31
31
|
};
|
|
32
32
|
}, images?: ArticleImagePolicy | null): QualitySettings;
|
|
33
|
-
/** `YYYY-MM-DD` of a moment in a time zone. */
|
|
33
|
+
/** `YYYY-MM-DD` of a moment in a time zone: core's `toCalendarDay` under the name this module exports. */
|
|
34
34
|
export declare function getLocalDate(moment: Date, timeZone: string): string;
|
|
35
35
|
/** The severity a finding of `rule` gets: the override, else its own; `null` for "off". */
|
|
36
36
|
export declare function getEffectiveSeverity(settings: QualitySettings, rule: string, severity: QualitySeverity): QualitySeverity | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/quality/settings.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/quality/settings.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEzE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,2FAA2F;IAC3F,QAAQ,CAAC,aAAa,EAAE,SAAS,YAAY,EAAE,CAAC;IAChD,0GAA0G;IAC1G,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,iCAAiC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,yFAAyF;IACzF,QAAQ,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC3C,wFAAwF;IACxF,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAKD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,GAAG,UAAU,CAAC,GAAG;IACtD,kGAAkG;IAClG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,wGAAwG;IACxG,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CACzE,EACD,MAAM,GAAE,kBAAkB,GAAG,IAAW,GACvC,eAAe,CAsBjB;AAED,0GAA0G;AAC1G,wBAAgB,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,2FAA2F;AAC3F,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,eAAe,GAAG,IAAI,CAI/H"}
|
package/dist/quality/settings.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// The gate's resolved settings: the parsed options plus what the app config adds (its origins and time
|
|
2
|
+
// zone) and the blog's image policy, with the ruleset and voice patterns compiled once.
|
|
3
|
+
import { toCalendarDay } from "@softure-ai/core";
|
|
1
4
|
import { QUALITY_RULESETS } from "./rulesets/index.js";
|
|
2
5
|
/** The paths a caller without the blog's routes gets: the module's default routes. */
|
|
3
6
|
const DEFAULT_PATHS = { articles: "/blog", terms: "/blog/glossary" };
|
|
@@ -24,9 +27,9 @@ export function resolveQualitySettings(options, config, images = null) {
|
|
|
24
27
|
};
|
|
25
28
|
return { options, ruleset, voicePatterns, ownOrigins: [...new Set(origins)], timeZone: config.timezone, images, paths };
|
|
26
29
|
}
|
|
27
|
-
/** `YYYY-MM-DD` of a moment in a time zone. */
|
|
30
|
+
/** `YYYY-MM-DD` of a moment in a time zone: core's `toCalendarDay` under the name this module exports. */
|
|
28
31
|
export function getLocalDate(moment, timeZone) {
|
|
29
|
-
return
|
|
32
|
+
return toCalendarDay(moment, timeZone);
|
|
30
33
|
}
|
|
31
34
|
/** The severity a finding of `rule` gets: the override, else its own; `null` for "off". */
|
|
32
35
|
export function getEffectiveSeverity(settings, rule, severity) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/quality/settings.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/quality/settings.ts"],"names":[],"mappings":"AAAA,uGAAuG;AACvG,wFAAwF;AACxF,OAAO,EAAE,aAAa,EAAsB,MAAM,kBAAkB,CAAC;AAIrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAuBvD,sFAAsF;AACtF,MAAM,aAAa,GAAiB,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;AAEnF,MAAM,UAAU,sBAAsB,CACpC,OAAuB,EACvB,MAKC,EACD,SAAoC,IAAI;IAExC,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnD,MAAM,aAAa,GAAmB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3E,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC,CAAC,CAAC;IACJ,IAAI,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,CAAC;QAC5C,aAAa,CAAC,IAAI,CAAC;YACjB,EAAE,EAAE,uBAAuB;YAC3B,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,OAAO,CAAC,mBAAmB;YACpC,OAAO,EAAE,2FAA2F;SACrG,CAAC,CAAC;IACL,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;IACnK,MAAM,KAAK,GAAiB;QAC1B,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,aAAa,CAAC,QAAQ;QAClF,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,QAAQ,IAAI,aAAa,CAAC,KAAK;KAC7E,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC1H,CAAC;AAED,0GAA0G;AAC1G,MAAM,UAAU,YAAY,CAAC,MAAY,EAAE,QAAgB;IACzD,OAAO,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AACzC,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,oBAAoB,CAAC,QAAyB,EAAE,IAAY,EAAE,QAAyB;IACrG,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAC5C,OAAO,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC9C,CAAC"}
|
package/module.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softure-ai/blog",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "SOFTURE AI blog module: articles and glossary terms kept as Markdown files with a strict YAML frontmatter (extendable by the app's own fields), stored in the module's Postgres schema by the softure-blog publish command (dry run by default, all or nothing, content hash, slug history, one pillar per cluster), a server-side Markdown renderer (no raw HTML, safe links, glossary links, block plugins), a text quality gate (softure-blog check, run before every publish) with language rulesets and rule plugins, the blog's pages ready to mount in Next.js (listing, article, glossary, method page, OG image, JSON-LD) with a proxy piece for 301 and 410, an article writing skill (softure-blog skill install) generated from the gate's rules, and discovery: an RSS feed, read next, sitemap entries and an IndexNow submit on publish through the optional @softure-ai/seo, with a rate-limited cache refresh route the publish calls first (through the optional @softure-ai/security).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"build": "tsc -p tsconfig.build.json"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"@softure-ai/core": "^0.1.
|
|
73
|
+
"@softure-ai/core": "^0.1.7",
|
|
74
74
|
"@softure-ai/db": "^0.1.0",
|
|
75
75
|
"markdown-it": "^15.0.2",
|
|
76
76
|
"markdown-it-footnote": "^4.0.0",
|
package/src/index.ts
CHANGED
|
@@ -29,7 +29,7 @@ export const BLOG_RATE_LIMIT_BUCKETS = {
|
|
|
29
29
|
export const blog = defineModule({
|
|
30
30
|
manifest: {
|
|
31
31
|
id: MODULE_ID,
|
|
32
|
-
version: "0.1.
|
|
32
|
+
version: "0.1.10",
|
|
33
33
|
// seo is optional: with it the sitemap lists the texts and a publish pings IndexNow. security is
|
|
34
34
|
// optional too: only the cache refresh route needs it, for its rate limit.
|
|
35
35
|
dependsOn: { seo: "^0.1.0?", security: "^0.1.0?" },
|
package/src/next/body.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// The body input of the blog's pages, bound to the config: the glossary from the published terms, the
|
|
2
|
+
// routes, the blog options, the site's own origins and the copy. The ready-made pages render with it,
|
|
3
|
+
// and an app with its own page components uses the same function, so its "explained in these texts"
|
|
4
|
+
// list and its body links follow the same rule as the package's pages:
|
|
5
|
+
//
|
|
6
|
+
// const articles = findArticlesLinkingTermFor(config, { articles: published, termSlug: term.slug, terms });
|
|
7
|
+
// const body = renderPageBody(term, getBodyOptions(config, terms));
|
|
8
|
+
import { getSiteUrls, type SoftureConfig } from "@softure-ai/core";
|
|
9
|
+
import type { BlogArticle } from "../contract.js";
|
|
10
|
+
import { findArticlesLinkingTerm, type RenderPageBodyOptions } from "../pages/body.js";
|
|
11
|
+
import { toGlossary } from "../render/glossary.js";
|
|
12
|
+
import { getBlogOptions } from "../server/options.js";
|
|
13
|
+
import type { BlogPageContext } from "../ui/page-context.js";
|
|
14
|
+
import { getPageContext } from "./context.js";
|
|
15
|
+
|
|
16
|
+
/** What `renderPageBody` and `findArticlesLinkingTerm` (`/server`) take, as the ready-made pages build it. */
|
|
17
|
+
export function getBodyOptions(config: SoftureConfig, terms: readonly BlogArticle[], context: BlogPageContext = getPageContext(config)): RenderPageBodyOptions {
|
|
18
|
+
const origins = [config.appOrigin, getSiteUrls(config).origin];
|
|
19
|
+
return { glossary: toGlossary(terms), routes: context.routes, options: getBlogOptions(config), origins, messages: context.messages };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ArticlesLinkingTermInput {
|
|
23
|
+
/** The published articles to look through, e.g. `getPublishedArticles(config)`. */
|
|
24
|
+
readonly articles: readonly BlogArticle[];
|
|
25
|
+
readonly termSlug: string;
|
|
26
|
+
/** The published terms, e.g. `getPublishedTerms(config)`: the glossary the bodies link. */
|
|
27
|
+
readonly terms: readonly BlogArticle[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** The published articles whose body links the term: the list under a glossary term's page. */
|
|
31
|
+
export function findArticlesLinkingTermFor(config: SoftureConfig, input: ArticlesLinkingTermInput): BlogArticle[] {
|
|
32
|
+
return findArticlesLinkingTerm(input.articles, input.termSlug, getBodyOptions(config, input.terms));
|
|
33
|
+
}
|
package/src/next/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// The Next.js adapter of @softure-ai/blog: the pages, their metadata, the article's OG image, the RSS
|
|
2
2
|
// feed, the cache refresh route and the cached reads (docs/02-module-standard.md §8).
|
|
3
|
+
export { findArticlesLinkingTermFor, getBodyOptions, type ArticlesLinkingTermInput } from "./body.js";
|
|
3
4
|
export { getBlogContext, getPageContext } from "./context.js";
|
|
4
5
|
export { serveBlogRss } from "./discovery.js";
|
|
5
6
|
export { buildArticleJsonLd, buildGlossaryJsonLd, buildTermJsonLd, getCrumbLabels } from "./json-ld.js";
|
package/src/next/pages.tsx
CHANGED
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
//
|
|
18
18
|
// An app with its own page components keeps the rest: `generate*Metadata` and `BlogArticleOgImage`
|
|
19
19
|
// mount next to its own page, and `build*Metadata` (metadata.ts) and `build*JsonLd` (json-ld.ts) take
|
|
20
|
-
// a text it already read.
|
|
21
|
-
|
|
20
|
+
// a text it already read; `getBodyOptions` and `findArticlesLinkingTermFor` (body.ts) give the body
|
|
21
|
+
// input and a term's "explained in these texts" list.
|
|
22
22
|
import { getSoftureConfig } from "@softure-ai/core/next";
|
|
23
23
|
// `next/types.js`, not `next`: the root entry adds Next's globals (a read-only NODE_ENV) to every
|
|
24
24
|
// program that includes this file.
|
|
@@ -27,16 +27,14 @@ import { notFound } from "next/navigation";
|
|
|
27
27
|
import type { ReactNode } from "react";
|
|
28
28
|
import type { BlogArticle } from "../contract.js";
|
|
29
29
|
import { getRelatedArticles } from "../discovery/related.js";
|
|
30
|
-
import { findArticlesLinkingTerm, renderPageBody
|
|
30
|
+
import { findArticlesLinkingTerm, renderPageBody } from "../pages/body.js";
|
|
31
31
|
import { getArticleDates } from "../pages/dates.js";
|
|
32
32
|
import { getArticleCrumbs, groupByCluster, getTermCrumbs, sortTerms } from "../pages/listing.js";
|
|
33
|
-
import { toGlossary } from "../render/glossary.js";
|
|
34
|
-
import { getBlogOptions } from "../server/options.js";
|
|
35
33
|
import { BlogArticleView } from "../ui/blog-article.js";
|
|
36
34
|
import { GlossaryIndexView, GlossaryTermView } from "../ui/blog-glossary.js";
|
|
37
35
|
import { BlogListingView } from "../ui/blog-listing.js";
|
|
38
36
|
import { BlogMethodView } from "../ui/blog-method.js";
|
|
39
|
-
import
|
|
37
|
+
import { getBodyOptions } from "./body.js";
|
|
40
38
|
import { getPageContext } from "./context.js";
|
|
41
39
|
import { getPublishedArticles, getPublishedTerms, getTextBySlug } from "./data.js";
|
|
42
40
|
import { buildArticleJsonLd, buildGlossaryJsonLd, buildTermJsonLd, getCrumbLabels } from "./json-ld.js";
|
|
@@ -71,11 +69,6 @@ function isPublished(text: BlogArticle | null, kind: BlogArticle["kind"]): text
|
|
|
71
69
|
return text !== null && text.status === "published" && text.kind === kind;
|
|
72
70
|
}
|
|
73
71
|
|
|
74
|
-
function getBodyOptions(config: SoftureConfig, context: BlogPageContext, terms: readonly BlogArticle[]): RenderPageBodyOptions {
|
|
75
|
-
const origins = [config.appOrigin, getSiteUrls(config).origin];
|
|
76
|
-
return { glossary: toGlossary(terms), routes: context.routes, options: getBlogOptions(config), origins, messages: context.messages };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
72
|
export async function generateBlogIndexMetadata(): Promise<Metadata> {
|
|
80
73
|
const config = getSoftureConfig();
|
|
81
74
|
const articles = await getPublishedArticles(config);
|
|
@@ -107,7 +100,7 @@ export async function BlogArticlePage({ params, cta, afterArticle }: BlogArticle
|
|
|
107
100
|
if (!isPublished(article, "article")) notFound();
|
|
108
101
|
const context = getPageContext(config);
|
|
109
102
|
const [terms, published] = await Promise.all([getPublishedTerms(config), getPublishedArticles(config)]);
|
|
110
|
-
const body = renderPageBody<ReactNode>(article, getBodyOptions(config,
|
|
103
|
+
const body = renderPageBody<ReactNode>(article, getBodyOptions(config, terms, context));
|
|
111
104
|
const crumbs = getArticleCrumbs(article, context.routes, getCrumbLabels(config, context), { clusterAnchorPrefix: context.clusterAnchorPrefix });
|
|
112
105
|
const jsonLd = buildArticleJsonLd(config, article);
|
|
113
106
|
return (
|
|
@@ -155,7 +148,7 @@ export async function GlossaryTermPage({ params, cta }: GlossaryTermPageProps) {
|
|
|
155
148
|
if (!isPublished(term, "term")) notFound();
|
|
156
149
|
const context = getPageContext(config);
|
|
157
150
|
const [terms, articles] = await Promise.all([getPublishedTerms(config), getPublishedArticles(config)]);
|
|
158
|
-
const bodyOptions = getBodyOptions(config,
|
|
151
|
+
const bodyOptions = getBodyOptions(config, terms, context);
|
|
159
152
|
const crumbs = getTermCrumbs(term, context.routes, getCrumbLabels(config, context));
|
|
160
153
|
const jsonLd = buildTermJsonLd(config, term);
|
|
161
154
|
return (
|
package/src/pages/dates.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// The days a page shows for a text, in the app's time zone. JSON-LD takes the same days, so the dates
|
|
2
2
|
// a search engine compares (`dateModified` against the visible update) cannot drift apart.
|
|
3
|
-
import type
|
|
3
|
+
import { toCalendarDay, type Locale } from "@softure-ai/core";
|
|
4
4
|
import type { BlogArticle } from "../contract.js";
|
|
5
5
|
|
|
6
6
|
export interface ArticleDates {
|
|
@@ -12,10 +12,9 @@ export interface ArticleDates {
|
|
|
12
12
|
readonly currentAsOf: string;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
/** The calendar day of a moment in a time zone, `YYYY-MM-DD
|
|
15
|
+
/** The calendar day of a moment in a time zone, `YYYY-MM-DD`: core's `toCalendarDay` under the name this module exports. */
|
|
16
16
|
export function getDayInZone(moment: Date, timezone: string): string {
|
|
17
|
-
|
|
18
|
-
return new Intl.DateTimeFormat("en-CA", { timeZone: timezone, year: "numeric", month: "2-digit", day: "2-digit" }).format(moment);
|
|
17
|
+
return toCalendarDay(moment, timezone);
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
/**
|
package/src/quality/settings.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// The gate's resolved settings: the parsed options plus what the app config adds (its origins and time
|
|
2
2
|
// zone) and the blog's image policy, with the ruleset and voice patterns compiled once.
|
|
3
|
-
import type
|
|
3
|
+
import { toCalendarDay, type SoftureConfig } from "@softure-ai/core";
|
|
4
4
|
import type { ArticleImagePolicy } from "../render/images.js";
|
|
5
5
|
import type { QualitySeverity } from "./finding.js";
|
|
6
6
|
import type { QualityOptions } from "./options.js";
|
|
@@ -63,9 +63,9 @@ export function resolveQualitySettings(
|
|
|
63
63
|
return { options, ruleset, voicePatterns, ownOrigins: [...new Set(origins)], timeZone: config.timezone, images, paths };
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
/** `YYYY-MM-DD` of a moment in a time zone. */
|
|
66
|
+
/** `YYYY-MM-DD` of a moment in a time zone: core's `toCalendarDay` under the name this module exports. */
|
|
67
67
|
export function getLocalDate(moment: Date, timeZone: string): string {
|
|
68
|
-
return
|
|
68
|
+
return toCalendarDay(moment, timeZone);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/** The severity a finding of `rule` gets: the override, else its own; `null` for "off". */
|