@shapio/schema 0.3.1 → 0.4.1

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.
@@ -0,0 +1,91 @@
1
+ import { Static, Type } from "typebox";
2
+ //#region src/seo/ids.d.ts
3
+ /**
4
+ * The built-in SEO component (plan seo-fields). It is ordinary schema data, created through the change planner
5
+ * and always shared with every site; what makes it "the" SEO component is its stable ID, never its API ID, so
6
+ * a renamed or extended copy is still recognised and an unrelated `seo` component (an import) never is.
7
+ */
8
+ declare const SEO_COMPONENT_ID = "f3905a00-d2a3-4c62-899a-c894bfd6cb9b";
9
+ /** The API ID the built-in is created with (it may be renamed later; detection never relies on it). */
10
+ declare const SEO_COMPONENT_API_KEY = "seo";
11
+ /** Stable field IDs of the built-in's fields. Resolver and admin look fields up by these. */
12
+ declare const SEO_FIELD_IDS: {
13
+ readonly title: "3fe294a9-6af9-4019-8b32-43010822e45a";
14
+ readonly description: "6d1917f3-94a2-4391-ba1f-a98d14577b93";
15
+ readonly image: "d27c9354-4afc-4583-93b4-367214a7714a";
16
+ readonly canonical: "17b374b6-cd85-444e-8403-20c7458ed29e";
17
+ readonly noindex: "e8346f99-dc3c-4b5c-906f-4854e03c9a57";
18
+ };
19
+ type SeoFieldKey = keyof typeof SEO_FIELD_IDS;
20
+ /** The built-in editor for a field holding the SEO component (preview and counters in the admin). */
21
+ declare const SEO_EDITOR_ID = "seoEditor";
22
+ /** Admin-only counters: lengths past which search results usually truncate. Never enforced. */
23
+ declare const SEO_TITLE_SOFT_MAX = 70;
24
+ declare const SEO_DESCRIPTION_SOFT_MAX = 160;
25
+ /** The placeholder a title template must contain exactly once. */
26
+ declare const SEO_TITLE_PLACEHOLDER = "%s";
27
+ /** A title template holds the placeholder exactly once, e.g. `%s · Acme`. */
28
+ declare const SEO_TITLE_TEMPLATE_PATTERN: RegExp;
29
+ /** A Twitter/X handle with its `@`. */
30
+ declare const SEO_TWITTER_HANDLE_PATTERN: RegExp;
31
+ //#endregion
32
+ //#region src/seo/defaults.d.ts
33
+ /** One locale's default texts. Every key is optional: a missing one falls back along the locale chain. */
34
+ declare const SeoLocaleDefaultsSchema: Type.TObject<{
35
+ siteName: Type.TOptional<Type.TString>;
36
+ titleTemplate: Type.TOptional<Type.TString>;
37
+ description: Type.TOptional<Type.TString>;
38
+ }>;
39
+ /**
40
+ * A site's SEO defaults (`sites.seo_defaults`): texts per locale code, the default social image (a public
41
+ * image asset of the same site) and the Twitter handle for the whole site.
42
+ */
43
+ declare const SeoDefaultsSchema: Type.TObject<{
44
+ locales: Type.TRecord<"^.*$", Type.TObject<{
45
+ siteName: Type.TOptional<Type.TString>;
46
+ titleTemplate: Type.TOptional<Type.TString>;
47
+ description: Type.TOptional<Type.TString>;
48
+ }>>;
49
+ imageId: Type.TUnion<[Type.TString, Type.TNull]>;
50
+ twitterHandle: Type.TUnion<[Type.TString, Type.TNull]>;
51
+ }>;
52
+ type SeoLocaleDefaults = Static<typeof SeoLocaleDefaultsSchema>;
53
+ type SeoDefaults = Static<typeof SeoDefaultsSchema>;
54
+ //#endregion
55
+ //#region src/seo/locale.d.ts
56
+ /** No defaults saved yet. */
57
+ declare const EMPTY_SEO_DEFAULTS: SeoDefaults;
58
+ declare const isValidTitleTemplate: (template: string) => boolean;
59
+ /**
60
+ * One locale's effective default texts: each key from the first locale of the chain that sets it (the
61
+ * requested locale, then its fallbacks, then the default locale).
62
+ */
63
+ declare const seoDefaultsForLocale: (defaults: Pick<SeoDefaults, "locales">, localeChain: readonly string[]) => SeoLocaleDefaults;
64
+ /** Applies a title template (`%s` replaced once); an invalid template leaves the title as is. */
65
+ declare const applyTitleTemplate: (title: string, template: string | undefined) => string;
66
+ //#endregion
67
+ //#region src/seo/resolve.d.ts
68
+ /** The API IDs under which a delivered SEO value carries each built-in field (absent: removed or retyped). */
69
+ type SeoKeys = Partial<Record<SeoFieldKey, string>>;
70
+ /** The API IDs the built-in component is created with. */
71
+ declare const DEFAULT_SEO_KEYS: Required<SeoKeys>;
72
+ type ResolveSeoContext = {
73
+ /** The site's default texts for the entry's locale (`seoDefaultsForLocale`). */
74
+ defaults: SeoLocaleDefaults;
75
+ /** The default social image in the delivered asset shape, or null. */
76
+ image: unknown;
77
+ /** The entry's own title (its title field) when the SEO title is empty; null when none is readable. */
78
+ fallbackTitle: string | null;
79
+ /** Where each field sits in `raw`; defaults to the built-in API IDs. */
80
+ keys?: SeoKeys;
81
+ };
82
+ /**
83
+ * The effective SEO values of one delivered entry, in the same shape as the raw value (plan seo-fields): the
84
+ * title is the entry's SEO title, else its own title, through the site's template (the bare site name when
85
+ * neither exists, never templated); description and image fall back to the site's defaults; canonical stays
86
+ * the entry's value or null; noindex is a boolean. Other keys (fields a user added) pass through. Pure.
87
+ */
88
+ declare const resolveSeo: (raw: unknown, context: ResolveSeoContext) => Record<string, unknown>;
89
+ //#endregion
90
+ export { SeoFieldKey as S, SEO_FIELD_IDS as _, EMPTY_SEO_DEFAULTS as a, SEO_TITLE_TEMPLATE_PATTERN as b, seoDefaultsForLocale as c, SeoLocaleDefaults as d, SeoLocaleDefaultsSchema as f, SEO_EDITOR_ID as g, SEO_DESCRIPTION_SOFT_MAX as h, resolveSeo as i, SeoDefaults as l, SEO_COMPONENT_ID as m, ResolveSeoContext as n, applyTitleTemplate as o, SEO_COMPONENT_API_KEY as p, SeoKeys as r, isValidTitleTemplate as s, DEFAULT_SEO_KEYS as t, SeoDefaultsSchema as u, SEO_TITLE_PLACEHOLDER as v, SEO_TWITTER_HANDLE_PATTERN as x, SEO_TITLE_SOFT_MAX as y };
91
+ //# sourceMappingURL=resolve-7-z9VQqw.d.ts.map
@@ -0,0 +1,91 @@
1
+ //#region src/seo/ids.ts
2
+ /**
3
+ * The built-in SEO component (plan seo-fields). It is ordinary schema data, created through the change planner
4
+ * and always shared with every site; what makes it "the" SEO component is its stable ID, never its API ID, so
5
+ * a renamed or extended copy is still recognised and an unrelated `seo` component (an import) never is.
6
+ */
7
+ const SEO_COMPONENT_ID = "f3905a00-d2a3-4c62-899a-c894bfd6cb9b";
8
+ /** The API ID the built-in is created with (it may be renamed later; detection never relies on it). */
9
+ const SEO_COMPONENT_API_KEY = "seo";
10
+ /** Stable field IDs of the built-in's fields. Resolver and admin look fields up by these. */
11
+ const SEO_FIELD_IDS = {
12
+ title: "3fe294a9-6af9-4019-8b32-43010822e45a",
13
+ description: "6d1917f3-94a2-4391-ba1f-a98d14577b93",
14
+ image: "d27c9354-4afc-4583-93b4-367214a7714a",
15
+ canonical: "17b374b6-cd85-444e-8403-20c7458ed29e",
16
+ noindex: "e8346f99-dc3c-4b5c-906f-4854e03c9a57"
17
+ };
18
+ /** The built-in editor for a field holding the SEO component (preview and counters in the admin). */
19
+ const SEO_EDITOR_ID = "seoEditor";
20
+ /** Admin-only counters: lengths past which search results usually truncate. Never enforced. */
21
+ const SEO_TITLE_SOFT_MAX = 70;
22
+ const SEO_DESCRIPTION_SOFT_MAX = 160;
23
+ /** The placeholder a title template must contain exactly once. */
24
+ const SEO_TITLE_PLACEHOLDER = "%s";
25
+ /** A title template holds the placeholder exactly once, e.g. `%s · Acme`. */
26
+ const SEO_TITLE_TEMPLATE_PATTERN = /^(?:(?!%s)[\s\S])*%s(?:(?!%s)[\s\S])*$/;
27
+ /** A Twitter/X handle with its `@`. */
28
+ const SEO_TWITTER_HANDLE_PATTERN = /^@[A-Za-z0-9_]{1,15}$/;
29
+ //#endregion
30
+ //#region src/seo/locale.ts
31
+ /** No defaults saved yet. */
32
+ const EMPTY_SEO_DEFAULTS = {
33
+ locales: {},
34
+ imageId: null,
35
+ twitterHandle: null
36
+ };
37
+ const isValidTitleTemplate = (template) => SEO_TITLE_TEMPLATE_PATTERN.test(template);
38
+ /**
39
+ * One locale's effective default texts: each key from the first locale of the chain that sets it (the
40
+ * requested locale, then its fallbacks, then the default locale).
41
+ */
42
+ const seoDefaultsForLocale = (defaults, localeChain) => {
43
+ const pick = (key) => localeChain.map((code) => defaults.locales[code]?.[key]).find((value) => value !== void 0);
44
+ const siteName = pick("siteName");
45
+ const titleTemplate = pick("titleTemplate");
46
+ const description = pick("description");
47
+ return {
48
+ ...siteName !== void 0 ? { siteName } : {},
49
+ ...titleTemplate !== void 0 ? { titleTemplate } : {},
50
+ ...description !== void 0 ? { description } : {}
51
+ };
52
+ };
53
+ /** Applies a title template (`%s` replaced once); an invalid template leaves the title as is. */
54
+ const applyTitleTemplate = (title, template) => template !== void 0 && isValidTitleTemplate(template) ? template.replace("%s", () => title) : title;
55
+ //#endregion
56
+ //#region src/seo/resolve.ts
57
+ /** The API IDs the built-in component is created with. */
58
+ const DEFAULT_SEO_KEYS = {
59
+ title: "title",
60
+ description: "description",
61
+ image: "image",
62
+ canonical: "canonical",
63
+ noindex: "noindex"
64
+ };
65
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
66
+ const text = (value) => typeof value === "string" && value.trim() !== "" ? value : null;
67
+ /**
68
+ * The effective SEO values of one delivered entry, in the same shape as the raw value (plan seo-fields): the
69
+ * title is the entry's SEO title, else its own title, through the site's template (the bare site name when
70
+ * neither exists, never templated); description and image fall back to the site's defaults; canonical stays
71
+ * the entry's value or null; noindex is a boolean. Other keys (fields a user added) pass through. Pure.
72
+ */
73
+ const resolveSeo = (raw, context) => {
74
+ const keys = context.keys ?? DEFAULT_SEO_KEYS;
75
+ const output = isRecord(raw) ? { ...raw } : {};
76
+ const value = (key) => keys[key] === void 0 ? void 0 : output[keys[key]];
77
+ const set = (key, next) => {
78
+ if (keys[key] !== void 0) output[keys[key]] = next;
79
+ };
80
+ const base = text(value("title")) ?? text(context.fallbackTitle);
81
+ set("title", base !== null ? applyTitleTemplate(base, context.defaults.titleTemplate) : context.defaults.siteName ?? null);
82
+ set("description", text(value("description")) ?? context.defaults.description ?? null);
83
+ set("image", value("image") ?? context.image ?? null);
84
+ set("canonical", text(value("canonical")));
85
+ set("noindex", value("noindex") === true);
86
+ return output;
87
+ };
88
+ //#endregion
89
+ export { isValidTitleTemplate as a, SEO_COMPONENT_ID as c, SEO_FIELD_IDS as d, SEO_TITLE_PLACEHOLDER as f, SEO_TWITTER_HANDLE_PATTERN as h, applyTitleTemplate as i, SEO_DESCRIPTION_SOFT_MAX as l, SEO_TITLE_TEMPLATE_PATTERN as m, resolveSeo as n, seoDefaultsForLocale as o, SEO_TITLE_SOFT_MAX as p, EMPTY_SEO_DEFAULTS as r, SEO_COMPONENT_API_KEY as s, DEFAULT_SEO_KEYS as t, SEO_EDITOR_ID as u };
90
+
91
+ //# sourceMappingURL=resolve-viddCEYd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-viddCEYd.js","names":[],"sources":["../src/seo/ids.ts","../src/seo/locale.ts","../src/seo/resolve.ts"],"sourcesContent":["/**\n * The built-in SEO component (plan seo-fields). It is ordinary schema data, created through the change planner\n * and always shared with every site; what makes it \"the\" SEO component is its stable ID, never its API ID, so\n * a renamed or extended copy is still recognised and an unrelated `seo` component (an import) never is.\n */\nexport const SEO_COMPONENT_ID = 'f3905a00-d2a3-4c62-899a-c894bfd6cb9b';\n\n/** The API ID the built-in is created with (it may be renamed later; detection never relies on it). */\nexport const SEO_COMPONENT_API_KEY = 'seo';\n\n/** Stable field IDs of the built-in's fields. Resolver and admin look fields up by these. */\nexport const SEO_FIELD_IDS = {\n title: '3fe294a9-6af9-4019-8b32-43010822e45a',\n description: '6d1917f3-94a2-4391-ba1f-a98d14577b93',\n image: 'd27c9354-4afc-4583-93b4-367214a7714a',\n canonical: '17b374b6-cd85-444e-8403-20c7458ed29e',\n noindex: 'e8346f99-dc3c-4b5c-906f-4854e03c9a57',\n} as const;\n\nexport type SeoFieldKey = keyof typeof SEO_FIELD_IDS;\n\n/** The built-in editor for a field holding the SEO component (preview and counters in the admin). */\nexport const SEO_EDITOR_ID = 'seoEditor';\n\n/** Admin-only counters: lengths past which search results usually truncate. Never enforced. */\nexport const SEO_TITLE_SOFT_MAX = 70;\nexport const SEO_DESCRIPTION_SOFT_MAX = 160;\n\n/** The placeholder a title template must contain exactly once. */\nexport const SEO_TITLE_PLACEHOLDER = '%s';\n\n/** A title template holds the placeholder exactly once, e.g. `%s · Acme`. */\nexport const SEO_TITLE_TEMPLATE_PATTERN = /^(?:(?!%s)[\\s\\S])*%s(?:(?!%s)[\\s\\S])*$/;\n\n/** A Twitter/X handle with its `@`. */\nexport const SEO_TWITTER_HANDLE_PATTERN = /^@[A-Za-z0-9_]{1,15}$/;\n","import type { SeoDefaults, SeoLocaleDefaults } from './defaults.js';\nimport { SEO_TITLE_PLACEHOLDER, SEO_TITLE_TEMPLATE_PATTERN } from './ids.js';\n\n/** No defaults saved yet. */\nexport const EMPTY_SEO_DEFAULTS: SeoDefaults = { locales: {}, imageId: null, twitterHandle: null };\n\nexport const isValidTitleTemplate = (template: string): boolean => SEO_TITLE_TEMPLATE_PATTERN.test(template);\n\n/**\n * One locale's effective default texts: each key from the first locale of the chain that sets it (the\n * requested locale, then its fallbacks, then the default locale).\n */\nexport const seoDefaultsForLocale = (\n defaults: Pick<SeoDefaults, 'locales'>,\n localeChain: readonly string[],\n): SeoLocaleDefaults => {\n const pick = (key: keyof SeoLocaleDefaults) =>\n localeChain.map((code) => defaults.locales[code]?.[key]).find((value) => value !== undefined);\n const siteName = pick('siteName');\n const titleTemplate = pick('titleTemplate');\n const description = pick('description');\n return {\n ...(siteName !== undefined ? { siteName } : {}),\n ...(titleTemplate !== undefined ? { titleTemplate } : {}),\n ...(description !== undefined ? { description } : {}),\n };\n};\n\n/** Applies a title template (`%s` replaced once); an invalid template leaves the title as is. */\nexport const applyTitleTemplate = (title: string, template: string | undefined): string =>\n template !== undefined && isValidTitleTemplate(template)\n ? template.replace(SEO_TITLE_PLACEHOLDER, () => title)\n : title;\n","import type { SeoLocaleDefaults } from './defaults.js';\nimport type { SeoFieldKey } from './ids.js';\nimport { applyTitleTemplate } from './locale.js';\n\n/** The API IDs under which a delivered SEO value carries each built-in field (absent: removed or retyped). */\nexport type SeoKeys = Partial<Record<SeoFieldKey, string>>;\n\n/** The API IDs the built-in component is created with. */\nexport const DEFAULT_SEO_KEYS: Required<SeoKeys> = {\n title: 'title',\n description: 'description',\n image: 'image',\n canonical: 'canonical',\n noindex: 'noindex',\n};\n\nexport type ResolveSeoContext = {\n /** The site's default texts for the entry's locale (`seoDefaultsForLocale`). */\n defaults: SeoLocaleDefaults;\n /** The default social image in the delivered asset shape, or null. */\n image: unknown;\n /** The entry's own title (its title field) when the SEO title is empty; null when none is readable. */\n fallbackTitle: string | null;\n /** Where each field sits in `raw`; defaults to the built-in API IDs. */\n keys?: SeoKeys;\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst text = (value: unknown): string | null =>\n typeof value === 'string' && value.trim() !== '' ? value : null;\n\n/**\n * The effective SEO values of one delivered entry, in the same shape as the raw value (plan seo-fields): the\n * title is the entry's SEO title, else its own title, through the site's template (the bare site name when\n * neither exists, never templated); description and image fall back to the site's defaults; canonical stays\n * the entry's value or null; noindex is a boolean. Other keys (fields a user added) pass through. Pure.\n */\nexport const resolveSeo = (raw: unknown, context: ResolveSeoContext): Record<string, unknown> => {\n const keys = context.keys ?? DEFAULT_SEO_KEYS;\n const output: Record<string, unknown> = isRecord(raw) ? { ...raw } : {};\n const value = (key: SeoFieldKey) => (keys[key] === undefined ? undefined : output[keys[key]]);\n const set = (key: SeoFieldKey, next: unknown) => {\n if (keys[key] !== undefined) {\n output[keys[key]] = next;\n }\n };\n const base = text(value('title')) ?? text(context.fallbackTitle);\n set(\n 'title',\n base !== null\n ? applyTitleTemplate(base, context.defaults.titleTemplate)\n : (context.defaults.siteName ?? null),\n );\n set('description', text(value('description')) ?? context.defaults.description ?? null);\n set('image', value('image') ?? context.image ?? null);\n set('canonical', text(value('canonical')));\n set('noindex', value('noindex') === true);\n return output;\n};\n"],"mappings":";;;;;;AAKA,MAAa,mBAAmB;;AAGhC,MAAa,wBAAwB;;AAGrC,MAAa,gBAAgB;CAC3B,OAAO;CACP,aAAa;CACb,OAAO;CACP,WAAW;CACX,SAAS;AACX;;AAKA,MAAa,gBAAgB;;AAG7B,MAAa,qBAAqB;AAClC,MAAa,2BAA2B;;AAGxC,MAAa,wBAAwB;;AAGrC,MAAa,6BAA6B;;AAG1C,MAAa,6BAA6B;;;;AC/B1C,MAAa,qBAAkC;CAAE,SAAS,CAAC;CAAG,SAAS;CAAM,eAAe;AAAK;AAEjG,MAAa,wBAAwB,aAA8B,2BAA2B,KAAK,QAAQ;;;;;AAM3G,MAAa,wBACX,UACA,gBACsB;CACtB,MAAM,QAAQ,QACZ,YAAY,KAAK,SAAS,SAAS,QAAQ,KAAK,GAAG,IAAI,CAAC,CAAC,MAAM,UAAU,UAAU,KAAA,CAAS;CAC9F,MAAM,WAAW,KAAK,UAAU;CAChC,MAAM,gBAAgB,KAAK,eAAe;CAC1C,MAAM,cAAc,KAAK,aAAa;CACtC,OAAO;EACL,GAAI,aAAa,KAAA,IAAY,EAAE,SAAS,IAAI,CAAC;EAC7C,GAAI,kBAAkB,KAAA,IAAY,EAAE,cAAc,IAAI,CAAC;EACvD,GAAI,gBAAgB,KAAA,IAAY,EAAE,YAAY,IAAI,CAAC;CACrD;AACF;;AAGA,MAAa,sBAAsB,OAAe,aAChD,aAAa,KAAA,KAAa,qBAAqB,QAAQ,IACnD,SAAS,QAAA,YAAqC,KAAK,IACnD;;;;ACxBN,MAAa,mBAAsC;CACjD,OAAO;CACP,aAAa;CACb,OAAO;CACP,WAAW;CACX,SAAS;AACX;AAaA,MAAM,YAAY,UAChB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAErE,MAAM,QAAQ,UACZ,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,KAAK,QAAQ;;;;;;;AAQ7D,MAAa,cAAc,KAAc,YAAwD;CAC/F,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,SAAkC,SAAS,GAAG,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC;CACtE,MAAM,SAAS,QAAsB,KAAK,SAAS,KAAA,IAAY,KAAA,IAAY,OAAO,KAAK;CACvF,MAAM,OAAO,KAAkB,SAAkB;EAC/C,IAAI,KAAK,SAAS,KAAA,GAChB,OAAO,KAAK,QAAQ;CAExB;CACA,MAAM,OAAO,KAAK,MAAM,OAAO,CAAC,KAAK,KAAK,QAAQ,aAAa;CAC/D,IACE,SACA,SAAS,OACL,mBAAmB,MAAM,QAAQ,SAAS,aAAa,IACtD,QAAQ,SAAS,YAAY,IACpC;CACA,IAAI,eAAe,KAAK,MAAM,aAAa,CAAC,KAAK,QAAQ,SAAS,eAAe,IAAI;CACrF,IAAI,SAAS,MAAM,OAAO,KAAK,QAAQ,SAAS,IAAI;CACpD,IAAI,aAAa,KAAK,MAAM,WAAW,CAAC,CAAC;CACzC,IAAI,WAAW,MAAM,SAAS,MAAM,IAAI;CACxC,OAAO;AACT"}
@@ -0,0 +1,2 @@
1
+ import { S as SeoFieldKey, _ as SEO_FIELD_IDS, a as EMPTY_SEO_DEFAULTS, b as SEO_TITLE_TEMPLATE_PATTERN, c as seoDefaultsForLocale, d as SeoLocaleDefaults, g as SEO_EDITOR_ID, h as SEO_DESCRIPTION_SOFT_MAX, i as resolveSeo, l as SeoDefaults, m as SEO_COMPONENT_ID, n as ResolveSeoContext, o as applyTitleTemplate, p as SEO_COMPONENT_API_KEY, r as SeoKeys, s as isValidTitleTemplate, t as DEFAULT_SEO_KEYS, v as SEO_TITLE_PLACEHOLDER, x as SEO_TWITTER_HANDLE_PATTERN, y as SEO_TITLE_SOFT_MAX } from "./resolve-7-z9VQqw.js";
2
+ export { DEFAULT_SEO_KEYS, EMPTY_SEO_DEFAULTS, ResolveSeoContext, SEO_COMPONENT_API_KEY, SEO_COMPONENT_ID, SEO_DESCRIPTION_SOFT_MAX, SEO_EDITOR_ID, SEO_FIELD_IDS, SEO_TITLE_PLACEHOLDER, SEO_TITLE_SOFT_MAX, SEO_TITLE_TEMPLATE_PATTERN, SEO_TWITTER_HANDLE_PATTERN, type SeoDefaults, SeoFieldKey, SeoKeys, type SeoLocaleDefaults, applyTitleTemplate, isValidTitleTemplate, resolveSeo, seoDefaultsForLocale };
@@ -0,0 +1,2 @@
1
+ import { a as isValidTitleTemplate, c as SEO_COMPONENT_ID, d as SEO_FIELD_IDS, f as SEO_TITLE_PLACEHOLDER, h as SEO_TWITTER_HANDLE_PATTERN, i as applyTitleTemplate, l as SEO_DESCRIPTION_SOFT_MAX, m as SEO_TITLE_TEMPLATE_PATTERN, n as resolveSeo, o as seoDefaultsForLocale, p as SEO_TITLE_SOFT_MAX, r as EMPTY_SEO_DEFAULTS, s as SEO_COMPONENT_API_KEY, t as DEFAULT_SEO_KEYS, u as SEO_EDITOR_ID } from "./resolve-viddCEYd.js";
2
+ export { DEFAULT_SEO_KEYS, EMPTY_SEO_DEFAULTS, SEO_COMPONENT_API_KEY, SEO_COMPONENT_ID, SEO_DESCRIPTION_SOFT_MAX, SEO_EDITOR_ID, SEO_FIELD_IDS, SEO_TITLE_PLACEHOLDER, SEO_TITLE_SOFT_MAX, SEO_TITLE_TEMPLATE_PATTERN, SEO_TWITTER_HANDLE_PATTERN, applyTitleTemplate, isValidTitleTemplate, resolveSeo, seoDefaultsForLocale };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapio/schema",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "Shapio model definition types, validators, diff and schema file format.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://shapio.dev",
@@ -26,6 +26,11 @@
26
26
  "@shapio/source": "./src/html.ts",
27
27
  "types": "./dist/html.d.ts",
28
28
  "default": "./dist/html.js"
29
+ },
30
+ "./seo": {
31
+ "@shapio/source": "./src/seoResolve.ts",
32
+ "types": "./dist/seoResolve.d.ts",
33
+ "default": "./dist/seoResolve.js"
29
34
  }
30
35
  },
31
36
  "files": [