@lupinum/ginko 0.4.0 → 0.5.0

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.
Files changed (89) hide show
  1. package/CHANGELOG.md +150 -0
  2. package/README.md +2 -2
  3. package/dist/basics.d.mts +492 -0
  4. package/dist/basics.d.ts +492 -0
  5. package/dist/basics.mjs +416 -0
  6. package/dist/cli/index.mjs +54 -55
  7. package/dist/index.d.mts +5 -4
  8. package/dist/index.d.ts +5 -4
  9. package/dist/index.mjs +3 -3
  10. package/dist/internal/search.mjs +6 -3
  11. package/dist/internal.d.mts +387 -41
  12. package/dist/internal.d.ts +387 -41
  13. package/dist/internal.mjs +267 -101
  14. package/dist/nuxt/module.d.mts +2 -2
  15. package/dist/nuxt/module.d.ts +2 -2
  16. package/dist/nuxt/module.mjs +105 -13
  17. package/dist/nuxt/runtime/GinkoImage.d.mts +1 -1
  18. package/dist/nuxt/runtime/GinkoMarkdown.mjs +2 -2
  19. package/dist/nuxt/runtime/composables.d.mts +4 -3
  20. package/dist/nuxt/runtime/composables.mjs +19 -15
  21. package/dist/nuxt/runtime/fetch.d.mts +3 -1
  22. package/dist/nuxt/runtime/fetch.mjs +12 -6
  23. package/dist/nuxt/runtime/markdown.d.mts +3 -0
  24. package/dist/nuxt/runtime/markdown.mjs +15 -3
  25. package/dist/nuxt/runtime/plugin.mjs +6 -35
  26. package/dist/nuxt/runtime/preview-listener.d.mts +13 -0
  27. package/dist/nuxt/runtime/preview-listener.mjs +37 -0
  28. package/dist/nuxt/runtime/preview.vue +3 -1
  29. package/dist/nuxt/runtime/schema.d.ts +6 -0
  30. package/dist/nuxt/runtime/server/bundles.d.ts +4 -0
  31. package/dist/nuxt/runtime/server/files-md.d.ts +2 -0
  32. package/dist/nuxt/runtime/server/files.d.ts +2 -0
  33. package/dist/nuxt/runtime/server/headers.d.ts +2 -0
  34. package/dist/nuxt/runtime/server/items.d.mts +12 -0
  35. package/dist/nuxt/runtime/server/items.d.ts +12 -0
  36. package/dist/nuxt/runtime/server/items.mjs +17 -0
  37. package/dist/nuxt/runtime/server/llms-full.d.ts +2 -0
  38. package/dist/nuxt/runtime/server/llms.d.ts +2 -0
  39. package/dist/nuxt/runtime/server/markdown-trees.d.ts +2 -0
  40. package/dist/nuxt/runtime/server/markdown.d.ts +2 -0
  41. package/dist/nuxt/runtime/server/markdown.mjs +1 -1
  42. package/dist/nuxt/runtime/server/platform-md.d.mts +3 -0
  43. package/dist/nuxt/runtime/server/platform-md.d.ts +3 -0
  44. package/dist/nuxt/runtime/server/platform-md.mjs +71 -0
  45. package/dist/nuxt/runtime/server/redirects.d.ts +2 -0
  46. package/dist/nuxt/runtime/server/robots.d.ts +2 -0
  47. package/dist/nuxt/runtime/server/search.d.ts +2 -0
  48. package/dist/nuxt/runtime/server/site-config.d.ts +14 -0
  49. package/dist/nuxt/runtime/server/sitemap-source.d.ts +2 -0
  50. package/dist/nuxt/runtime/server/sitemap-xml.d.ts +24 -0
  51. package/dist/nuxt/runtime/server/sitemap.d.ts +2 -0
  52. package/dist/nuxt/runtime/shared.d.mts +10 -3
  53. package/dist/nuxt/runtime/shared.mjs +2 -2
  54. package/dist/shared/ginko.1wwZv4B_.d.ts +1622 -0
  55. package/dist/shared/{ginko.BBkZW2nW.d.ts → ginko.6cI8KXZP.d.mts} +2 -2
  56. package/dist/shared/{ginko.CQvxhyez.mjs → ginko.AprJymER.mjs} +30 -1
  57. package/dist/shared/ginko.BNVC-g9n.mjs +10389 -0
  58. package/dist/shared/{ginko.Bwan3BB-.d.mts → ginko.B_pACpVU.d.ts} +2 -2
  59. package/dist/shared/{ginko.CrNRBkS5.mjs → ginko.C4gcOovG.mjs} +253 -309
  60. package/dist/shared/{ginko.C90fPpMP.mjs → ginko.CXA2R3aS.mjs} +128 -101
  61. package/dist/shared/ginko.CjWB8N7f.d.ts +128 -0
  62. package/dist/shared/ginko.D1PeQ3ds.mjs +36 -0
  63. package/dist/shared/ginko.DIl7l-75.mjs +26 -0
  64. package/dist/shared/ginko.DY7RbCEw.mjs +601 -0
  65. package/dist/shared/ginko.Dmgixfpf.mjs +130 -0
  66. package/dist/shared/{ginko.D-fNojn9.d.mts → ginko.DrkUeYFP.d.mts} +824 -10
  67. package/dist/shared/{ginko.D-fNojn9.d.ts → ginko.DrkUeYFP.d.ts} +824 -10
  68. package/dist/shared/{ginko.akHewCGt.d.mts → ginko.DvPtlHIz.d.mts} +50 -5
  69. package/dist/shared/{ginko.BDF3bW0C.d.ts → ginko.EelR5dt9.d.ts} +50 -5
  70. package/dist/shared/ginko.ULKQnAWd.d.ts +91 -0
  71. package/dist/shared/ginko.loGIxGZg.d.mts +91 -0
  72. package/dist/shared/ginko.o1yIKlgj.d.mts +128 -0
  73. package/dist/shared/ginko.plW4dLmm.d.mts +1622 -0
  74. package/dist/shared/{ginko.Dht0xxE5.mjs → ginko.raCzOPYC.mjs} +1 -2
  75. package/dist/shared/ginko.yKMIjJ68.mjs +84 -0
  76. package/dist/vue.d.mts +5 -4
  77. package/dist/vue.d.ts +5 -4
  78. package/dist/vue.mjs +1 -1
  79. package/i18n/ar.json +212 -0
  80. package/i18n/de.json +9 -1
  81. package/i18n/en.json +9 -1
  82. package/i18n/es.json +12 -4
  83. package/i18n/fr.json +212 -0
  84. package/i18n/it.json +212 -0
  85. package/package.json +7 -3
  86. package/dist/shared/ginko.BTUfZCfa.d.mts +0 -172
  87. package/dist/shared/ginko.C-QjDn3O.mjs +0 -4944
  88. package/dist/shared/ginko.Dc0oNcDv.d.ts +0 -172
  89. package/dist/shared/ginko.Mn30dmlm.mjs +0 -20
@@ -0,0 +1,12 @@
1
+ import { type RequestEvent } from 'nuxt/server';
2
+ import { type BundleItem } from '../../../internal.mjs';
3
+ /** An entry as `getGinkoItems` returns it: `url` is its path in the requested language (collections with a route). */
4
+ export type GinkoServerItem = BundleItem & {
5
+ url?: string;
6
+ };
7
+ /**
8
+ * The visible entries of collection `brick` in `locale` (default: the main language), in the collection's order, as
9
+ * `useGinko(brick).items` has them on a page: drafts and entries past their `visible` date are left out. Throws a 404
10
+ * for a language the site does not have or a key that is no collection, and a 503 when the platform cannot be reached.
11
+ */
12
+ export declare function getGinkoItems(event: RequestEvent, brick: string, locale?: string): Promise<GinkoServerItem[]>;
@@ -0,0 +1,17 @@
1
+ import { createError, useRuntimeConfig } from "nuxt/server";
2
+ import schema from "#ginko/schema";
3
+ import { isVisible, todayIn } from "../../../internal.mjs";
4
+ import { withUrl } from "../shared.mjs";
5
+ import { loadServerBundles } from "./bundles.mjs";
6
+ export async function getGinkoItems(event, brick, locale) {
7
+ const config = useRuntimeConfig().public.ginko;
8
+ const code = locale ?? config.mainLocale;
9
+ const def = schema.bricks[brick];
10
+ if (!config.locales.includes(code) || def?.kind !== "collection") throw createError({ statusCode: 404, statusMessage: "Not found" });
11
+ const bundle = (await loadServerBundles(event, config, [code]))[code];
12
+ const value = bundle?.bricks[brick];
13
+ if (!bundle || value?.kind !== "collection") return [];
14
+ const today = todayIn(config.timeZone);
15
+ const items = value.items.filter((item) => isVisible(def, item.data, today));
16
+ return def.route ? withUrl(items, bundle.locale, bundle.mainLocale) : items;
17
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: import("nuxt/server").EventHandler<Promise<string>>;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("nuxt/server").EventHandler<Promise<string>>;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ import type { MarkdownTree } from '../../../internal.mjs';
2
+ export declare const markdownTrees: ReadonlyMap<string, MarkdownTree>;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("nuxt/server").EventHandler<Promise<string | undefined>>;
2
+ export default _default;
@@ -28,7 +28,7 @@ export default defineEventHandler(async (event) => {
28
28
  event.res.headers.set("content-type", "text/markdown; charset=utf-8");
29
29
  if (!match) {
30
30
  setResponseStatus(event, 404);
31
- return markdownNotFound(bundle, path, { origin: config.url });
31
+ return markdownNotFound(bundle, path, { origin: config.url, schema });
32
32
  }
33
33
  event.res.headers.set("x-ginko-rev", `${bundle.schemaRev}.${bundle.contentRev}`);
34
34
  return entryMarkdown(match.item, match.brick, { schema, trees: markdownTrees });
@@ -0,0 +1,3 @@
1
+ import { type MarkdownTree } from '../../../internal.mjs';
2
+ declare const _default: import("nuxt/server").EventHandler<Promise<MarkdownTree>>;
3
+ export default _default;
@@ -0,0 +1,3 @@
1
+ import { type MarkdownTree } from '../../../internal.mjs';
2
+ declare const _default: import("nuxt/server").EventHandler<Promise<MarkdownTree>>;
3
+ export default _default;
@@ -0,0 +1,71 @@
1
+ import { createError, defineEventHandler, getRequestURL, useRuntimeConfig } from "nuxt/server";
2
+ import schema from "#ginko/schema";
3
+ import { platformMarkdownRef, withMarkdownRefs } from "../../../internal.mjs";
4
+ import { fetchBundle, PlatformError } from "../fetch.mjs";
5
+ const PATH = /^\/__ginko\/platform\/([^/]+)\/(\d+\.\d+)\/md\//;
6
+ const copies = /* @__PURE__ */ new Map();
7
+ const flights = /* @__PURE__ */ new Map();
8
+ const ahead = /* @__PURE__ */ new Map();
9
+ const AHEAD_MS = 1e4;
10
+ const newer = (a, b) => {
11
+ const [as = 0, ac = 0] = a.split(".").map(Number);
12
+ const [bs = 0, bc = 0] = b.split(".").map(Number);
13
+ return as !== bs ? as > bs : ac > bc;
14
+ };
15
+ const stale = (error) => error instanceof PlatformError && error.platformStatus === 409;
16
+ function covering(locale, rev) {
17
+ const copy = copies.get(locale);
18
+ return copy && !newer(rev, copy.rev) ? copy : void 0;
19
+ }
20
+ function isAhead(locale, rev) {
21
+ const known = ahead.get(locale);
22
+ return !!known && known.until > Date.now() && !newer(known.rev, rev);
23
+ }
24
+ function flightFor(config, locale, rev) {
25
+ const running = flights.get(locale);
26
+ if (running) return running;
27
+ const siteToken = useRuntimeConfig().ginkoRevalidateToken;
28
+ const copy = fetchBundle(config, locale, rev, siteToken).then((bundle) => {
29
+ const actual = `${bundle.schemaRev}.${bundle.contentRev}`;
30
+ const trees = /* @__PURE__ */ new Map();
31
+ withMarkdownRefs(bundle, schema, trees, (brick, id, field) => platformMarkdownRef(locale, actual, brick, id, field));
32
+ const fresh = { rev: actual, trees };
33
+ const current = copies.get(locale);
34
+ if (!current || newer(actual, current.rev)) copies.set(locale, fresh);
35
+ return fresh;
36
+ }, (error) => {
37
+ if (stale(error)) ahead.set(locale, { rev, until: Date.now() + AHEAD_MS });
38
+ throw error;
39
+ }).finally(() => flights.delete(locale));
40
+ flights.set(locale, copy);
41
+ return copy;
42
+ }
43
+ async function copyFor(config, locale, rev) {
44
+ for (let round = 0; round < 2; round++) {
45
+ const copy = covering(locale, rev);
46
+ if (copy) return copy;
47
+ if (isAhead(locale, rev)) return void 0;
48
+ try {
49
+ await flightFor(config, locale, rev);
50
+ } catch (error) {
51
+ if (!stale(error)) throw error;
52
+ }
53
+ }
54
+ return covering(locale, rev);
55
+ }
56
+ export default defineEventHandler(async (event) => {
57
+ const config = useRuntimeConfig().public.ginko;
58
+ const path = getRequestURL(event).pathname;
59
+ const [, locale = "", rev = ""] = PATH.exec(path) ?? [];
60
+ if (!config.locales.includes(locale)) throw createError({ statusCode: 404, statusMessage: "Text not found" });
61
+ let copy;
62
+ try {
63
+ copy = await copyFor(config, locale, rev);
64
+ } catch (error) {
65
+ if (error instanceof PlatformError) throw createError({ statusCode: error.statusCode, statusMessage: error.message, cause: error.cause });
66
+ throw error;
67
+ }
68
+ const tree = copy?.trees.get(path.replace(PATH, `/__ginko/platform/${locale}/${copy.rev}/md/`));
69
+ if (!tree) throw createError({ statusCode: 404, statusMessage: "Text not found" });
70
+ return tree;
71
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("nuxt/server").EventHandler<string | undefined>;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("nuxt/server").EventHandler<string>;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("nuxt/server").EventHandler<import("../../../search").SearchIndexJson>;
2
+ export default _default;
@@ -0,0 +1,14 @@
1
+ import { getRequestHost } from 'nuxt/server';
2
+ type SiteConfigInit = {
3
+ event: Parameters<typeof getRequestHost>[0];
4
+ siteConfig: {
5
+ push: (input: Record<string, unknown>) => void;
6
+ };
7
+ };
8
+ type ServerApp = {
9
+ hooks: {
10
+ hook: (name: 'site-config:init', fn: (ctx: SiteConfigInit) => void) => void;
11
+ };
12
+ };
13
+ declare const _default: (app: ServerApp) => void;
14
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("nuxt/server").EventHandler<Promise<import("./sitemap-xml.mjs").SitemapUrl[]>>;
2
+ export default _default;
@@ -0,0 +1,24 @@
1
+ import { type LocaleConfig } from '@lupinum/ginko-i18n/core';
2
+ import { type Bundle, type Locale, type Schema } from '../../../internal.mjs';
3
+ /** One `<url>`, in the shape @nuxtjs/sitemap reads from a source. All URLs are absolute. */
4
+ export interface SitemapUrl {
5
+ loc: string;
6
+ /** ISO 8601 time of the entry's last change (`updatedAt`); static pages have none. */
7
+ lastmod?: string;
8
+ /** hreflang alternates, `x-default` included; only for pages with more than one locale. */
9
+ alternatives?: {
10
+ hreflang: string;
11
+ href: string;
12
+ }[];
13
+ images?: {
14
+ loc: string;
15
+ }[];
16
+ }
17
+ /**
18
+ * `bundles` must hold every locale of the site for routed entries; `today` is the site's date
19
+ * (todayIn of its time zone), so the visibility rule matches the pages. `locales` is ginko-i18n's
20
+ * config: hreflang uses its languages and `x-default`, exactly as the page head does.
21
+ */
22
+ export declare function sitemapUrls(site: Schema, bundles: Partial<Record<Locale, Bundle>>, today: string, locales: Pick<LocaleConfig, 'locales' | 'defaultLocale'>): SitemapUrl[];
23
+ /** The sitemap document of `sitemapUrls`. */
24
+ export declare function sitemapXml(site: Schema, bundles: Partial<Record<Locale, Bundle>>, today: string, locales: Pick<LocaleConfig, 'locales' | 'defaultLocale'>): string;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("nuxt/server").EventHandler<Promise<string>>;
2
+ export default _default;
@@ -1,4 +1,4 @@
1
- import { type Locale, type SiteInput } from '../../internal.mjs';
1
+ import { type Locale, type SiteInput, type StoredHolidays } from '../../internal.mjs';
2
2
  export interface GinkoPublicConfig {
3
3
  site: string;
4
4
  name: string;
@@ -7,6 +7,10 @@ export interface GinkoPublicConfig {
7
7
  locales: Locale[];
8
8
  mainLocale: Locale;
9
9
  timeZone: string;
10
+ /** `country` of the site config (ISO 3166-1), or '' when unset. */
11
+ country: string;
12
+ /** The stored holiday calendar (`AT`, `DE`, `SG`, `none`, `custom`), or '' when the config sets neither `calendar` nor `country`. */
13
+ holidays: StoredHolidays | '';
10
14
  /** `seo` of the site config (`useGinkoSeo` defaults). */
11
15
  seo: NonNullable<SiteInput['seo']>;
12
16
  /** `agents` of the site config (llms.txt, Markdown routes). */
@@ -27,9 +31,12 @@ export declare function agentRequest(path: string): {
27
31
  page: string;
28
32
  asMarkdown: boolean;
29
33
  } | undefined;
30
- /** The items of a routed brick, each with `url`: its address in `locale`. */
34
+ /**
35
+ * The items of a routed brick, each with `url`: its address in `locale`. An entry without a page there (listed under
36
+ * `untranslated: 'fallback'`) links to its page in the main language `main`.
37
+ */
31
38
  export declare function withUrl<T extends {
32
39
  urls?: Partial<Record<string, string>>;
33
- }>(items: T[], locale: Locale): (T & {
40
+ }>(items: T[], locale: Locale, main: Locale): (T & {
34
41
  url?: string;
35
42
  })[];
@@ -4,6 +4,6 @@ export function agentRequest(path) {
4
4
  const page = markdownRequestPath(path);
5
5
  return page === void 0 ? { page: path, asMarkdown: false } : { page, asMarkdown: true };
6
6
  }
7
- export function withUrl(items, locale) {
8
- return items.map((item) => ({ ...item, url: item.urls?.[locale] }));
7
+ export function withUrl(items, locale, main) {
8
+ return items.map((item) => ({ ...item, url: item.urls?.[locale] ?? item.urls?.[main] }));
9
9
  }