@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 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.9",
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":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -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"}
@@ -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";
@@ -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"}
@@ -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";
@@ -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"}
@@ -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;AAkBvC,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;AAWD,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"}
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"}
@@ -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
- import { getSiteUrls } from "@softure-ai/core";
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, context, terms));
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, context, terms);
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 }));
@@ -1 +1 @@
1
- {"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/next/pages.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/next/pages.tsx"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { Locale } from "@softure-ai/core";
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,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,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,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGnE;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"}
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"}
@@ -1,7 +1,9 @@
1
- /** The calendar day of a moment in a time zone, `YYYY-MM-DD`. */
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
- // `en-CA` formats a date as YYYY-MM-DD.
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
@@ -1 +1 @@
1
- {"version":3,"file":"dates.js","sourceRoot":"","sources":["../../src/pages/dates.ts"],"names":[],"mappings":"AAcA,iEAAiE;AACjE,MAAM,UAAU,YAAY,CAAC,MAAY,EAAE,QAAgB;IACzD,wCAAwC;IACxC,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AACpI,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
+ {"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 { SoftureConfig } from "@softure-ai/core";
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,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,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,+CAA+C;AAC/C,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"}
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"}
@@ -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 new Intl.DateTimeFormat("en-CA", { timeZone, year: "numeric", month: "2-digit", day: "2-digit" }).format(moment);
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":"AAMA,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,+CAA+C;AAC/C,MAAM,UAAU,YAAY,CAAC,MAAY,EAAE,QAAgB;IACzD,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC1H,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"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "blog",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "dependsOn": { "seo": "^0.1.0?", "security": "^0.1.0?" },
5
5
  "dbSchema": "blog",
6
6
  "tables": ["articles", "slug_history"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softure-ai/blog",
3
- "version": "0.1.9",
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.0",
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.9",
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?" },
@@ -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";
@@ -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
- import { getSiteUrls, type SoftureConfig } from "@softure-ai/core";
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, type RenderPageBodyOptions } from "../pages/body.js";
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 type { BlogPageContext } from "../ui/page-context.js";
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, context, terms));
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, context, terms);
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 (
@@ -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 { Locale } from "@softure-ai/core";
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
- // `en-CA` formats a date as YYYY-MM-DD.
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
  /**
@@ -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 { SoftureConfig } from "@softure-ai/core";
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 new Intl.DateTimeFormat("en-CA", { timeZone, year: "numeric", month: "2-digit", day: "2-digit" }).format(moment);
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". */