@focus-reactive/payload-plugin-seo 1.4.0 → 1.6.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.
- package/README.md +331 -124
- package/dist/admin.css +97 -1
- package/dist/client-config/registry.d.ts +7 -0
- package/dist/client-config/registry.d.ts.map +1 -0
- package/dist/client-config/registry.js +16 -0
- package/dist/client-config/registry.js.map +1 -0
- package/dist/components/SeoButton/SeoButtonInner.d.ts +2 -4
- package/dist/components/SeoButton/SeoButtonInner.d.ts.map +1 -1
- package/dist/components/SeoButton/SeoButtonInner.js +10 -7
- package/dist/components/SeoButton/SeoButtonInner.js.map +1 -1
- package/dist/components/SeoDrawer/build-analysis-input.d.ts +1 -8
- package/dist/components/SeoDrawer/build-analysis-input.d.ts.map +1 -1
- package/dist/components/SeoDrawer/build-analysis-input.js +22 -34
- package/dist/components/SeoDrawer/build-analysis-input.js.map +1 -1
- package/dist/components/SeoDrawer/buildInput.js +1 -1
- package/dist/components/SeoDrawer/buildInput.js.map +1 -1
- package/dist/components/SeoDrawer/useLiveDocument.d.ts +2 -5
- package/dist/components/SeoDrawer/useLiveDocument.d.ts.map +1 -1
- package/dist/components/SeoDrawer/useLiveDocument.js +14 -62
- package/dist/components/SeoDrawer/useLiveDocument.js.map +1 -1
- package/dist/components/SeoField/Meter.d.ts +10 -0
- package/dist/components/SeoField/Meter.d.ts.map +1 -0
- package/dist/components/SeoField/Meter.js +59 -0
- package/dist/components/SeoField/Meter.js.map +1 -0
- package/dist/components/SeoField/icons.d.ts +5 -0
- package/dist/components/SeoField/icons.d.ts.map +1 -0
- package/dist/components/SeoField/icons.js +12 -0
- package/dist/components/SeoField/icons.js.map +1 -0
- package/dist/components/SeoField/index.d.ts +20 -0
- package/dist/components/SeoField/index.d.ts.map +1 -0
- package/dist/components/SeoField/index.js +118 -0
- package/dist/components/SeoField/index.js.map +1 -0
- package/dist/components/SeoField/useGenerate.d.ts +15 -0
- package/dist/components/SeoField/useGenerate.d.ts.map +1 -0
- package/dist/components/SeoField/useGenerate.js +102 -0
- package/dist/components/SeoField/useGenerate.js.map +1 -0
- package/dist/constants/generation.d.ts +13 -0
- package/dist/constants/generation.d.ts.map +1 -0
- package/dist/constants/generation.js +21 -0
- package/dist/constants/generation.js.map +1 -0
- package/dist/content/index.d.ts +2 -2
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +2 -1
- package/dist/content/index.js.map +1 -1
- package/dist/content/resolve/resolve-docs.d.ts +3 -0
- package/dist/content/resolve/resolve-docs.d.ts.map +1 -0
- package/dist/content/resolve/resolve-docs.js +48 -0
- package/dist/content/resolve/resolve-docs.js.map +1 -0
- package/dist/content/schema/helpers.d.ts +1 -0
- package/dist/content/schema/helpers.d.ts.map +1 -1
- package/dist/content/schema/helpers.js +4 -0
- package/dist/content/schema/helpers.js.map +1 -1
- package/dist/engine/helpers/title-progress.d.ts +2 -1
- package/dist/engine/helpers/title-progress.d.ts.map +1 -1
- package/dist/engine/helpers/title-progress.js +1 -1
- package/dist/engine/helpers/title-progress.js.map +1 -1
- package/dist/fields/index.d.ts +3 -0
- package/dist/fields/index.d.ts.map +1 -0
- package/dist/fields/index.js +5 -0
- package/dist/fields/index.js.map +1 -0
- package/dist/fields/onPublishHook.d.ts +8 -0
- package/dist/fields/onPublishHook.d.ts.map +1 -0
- package/dist/fields/onPublishHook.js +95 -0
- package/dist/fields/onPublishHook.js.map +1 -0
- package/dist/fields/seoTextField.d.ts +23 -0
- package/dist/fields/seoTextField.d.ts.map +1 -0
- package/dist/fields/seoTextField.js +43 -0
- package/dist/fields/seoTextField.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/measure/measure.d.ts +16 -0
- package/dist/measure/measure.d.ts.map +1 -0
- package/dist/measure/measure.js +38 -0
- package/dist/measure/measure.js.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +18 -3
- package/dist/plugin.js.map +1 -1
- package/dist/providers/SeoClientConfigProvider.d.ts +8 -0
- package/dist/providers/SeoClientConfigProvider.d.ts.map +1 -0
- package/dist/providers/SeoClientConfigProvider.js +16 -0
- package/dist/providers/SeoClientConfigProvider.js.map +1 -0
- package/dist/server/generate/apiKey.d.ts +3 -0
- package/dist/server/generate/apiKey.d.ts.map +1 -0
- package/dist/server/generate/apiKey.js +11 -0
- package/dist/server/generate/apiKey.js.map +1 -0
- package/dist/server/generate/endpoint.d.ts +3 -0
- package/dist/server/generate/endpoint.d.ts.map +1 -0
- package/dist/server/generate/endpoint.js +47 -0
- package/dist/server/generate/endpoint.js.map +1 -0
- package/dist/server/generate/generateForField.d.ts +18 -0
- package/dist/server/generate/generateForField.d.ts.map +1 -0
- package/dist/server/generate/generateForField.js +41 -0
- package/dist/server/generate/generateForField.js.map +1 -0
- package/dist/server/generate/openai.d.ts +9 -0
- package/dist/server/generate/openai.d.ts.map +1 -0
- package/dist/server/generate/openai.js +43 -0
- package/dist/server/generate/openai.js.map +1 -0
- package/dist/server/generate/prompts.d.ts +19 -0
- package/dist/server/generate/prompts.d.ts.map +1 -0
- package/dist/server/generate/prompts.js +32 -0
- package/dist/server/generate/prompts.js.map +1 -0
- package/dist/server/generate/serverResolveDocs.d.ts +4 -0
- package/dist/server/generate/serverResolveDocs.d.ts.map +1 -0
- package/dist/server/generate/serverResolveDocs.js +38 -0
- package/dist/server/generate/serverResolveDocs.js.map +1 -0
- package/dist/types/config.d.ts +59 -23
- package/dist/types/config.d.ts.map +1 -1
- package/dist/utils/config/overrideAdmin.d.ts.map +1 -1
- package/dist/utils/config/overrideAdmin.js +29 -11
- package/dist/utils/config/overrideAdmin.js.map +1 -1
- package/package.json +13 -1
- package/dist/content/extract/context.d.ts +0 -11
- package/dist/content/extract/context.d.ts.map +0 -1
- package/dist/content/extract/context.js +0 -1
- package/dist/content/extract/context.js.map +0 -1
- package/dist/content/extract/extract.d.ts +0 -18
- package/dist/content/extract/extract.d.ts.map +0 -1
- package/dist/content/extract/extract.js +0 -211
- package/dist/content/extract/extract.js.map +0 -1
- package/dist/content/extract/selection.d.ts +0 -3
- package/dist/content/extract/selection.d.ts.map +0 -1
- package/dist/content/extract/selection.js +0 -32
- package/dist/content/extract/selection.js.map +0 -1
- package/dist/content/lexical/transform.d.ts +0 -5
- package/dist/content/lexical/transform.d.ts.map +0 -1
- package/dist/content/lexical/transform.js +0 -56
- package/dist/content/lexical/transform.js.map +0 -1
- package/dist/content/resolve/collect-refs.d.ts +0 -8
- package/dist/content/resolve/collect-refs.d.ts.map +0 -1
- package/dist/content/resolve/collect-refs.js +0 -79
- package/dist/content/resolve/collect-refs.js.map +0 -1
- package/dist/content/resolve/hydrate.d.ts +0 -7
- package/dist/content/resolve/hydrate.d.ts.map +0 -1
- package/dist/content/resolve/hydrate.js +0 -123
- package/dist/content/resolve/hydrate.js.map +0 -1
- package/dist/content/resolve/resolver.d.ts +0 -7
- package/dist/content/resolve/resolver.d.ts.map +0 -1
- package/dist/content/resolve/resolver.js +0 -65
- package/dist/content/resolve/resolver.js.map +0 -1
- package/dist/content/resolve/types.d.ts +0 -12
- package/dist/content/resolve/types.d.ts.map +0 -1
- package/dist/content/resolve/types.js +0 -7
- package/dist/content/resolve/types.js.map +0 -1
- package/dist/content/walk/walkFields.d.ts +0 -17
- package/dist/content/walk/walkFields.d.ts.map +0 -1
- package/dist/content/walk/walkFields.js +0 -88
- package/dist/content/walk/walkFields.js.map +0 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useAllFormFields, useConfig, useDocumentInfo, useLocale } from "@payloadcms/ui";
|
|
3
|
+
import { reduceFieldsToValues } from "payload/shared";
|
|
4
|
+
import { useCallback, useRef, useState } from "react";
|
|
5
|
+
import { getSeoClientConfig } from "../../client-config/registry";
|
|
6
|
+
import { GENERATE_ENDPOINT_PATH } from "../../constants/generation";
|
|
7
|
+
import { createResolveDocs } from "../../content/resolve/resolve-docs";
|
|
8
|
+
import { resolveContentExtractor } from "../../content/registry";
|
|
9
|
+
import {
|
|
10
|
+
compact,
|
|
11
|
+
heading,
|
|
12
|
+
html,
|
|
13
|
+
image,
|
|
14
|
+
link,
|
|
15
|
+
paragraph,
|
|
16
|
+
richText,
|
|
17
|
+
video
|
|
18
|
+
} from "../../content/schema/helpers";
|
|
19
|
+
import { serialize } from "../../content/schema/serialize";
|
|
20
|
+
const helpers = {
|
|
21
|
+
heading,
|
|
22
|
+
paragraph,
|
|
23
|
+
link,
|
|
24
|
+
image,
|
|
25
|
+
video,
|
|
26
|
+
html,
|
|
27
|
+
richText,
|
|
28
|
+
compact
|
|
29
|
+
};
|
|
30
|
+
function useGenerate({ kind, measurement, setValue }) {
|
|
31
|
+
const [formFields] = useAllFormFields();
|
|
32
|
+
const { config } = useConfig();
|
|
33
|
+
const { collectionSlug } = useDocumentInfo();
|
|
34
|
+
const locale = useLocale();
|
|
35
|
+
const [status, setStatus] = useState("idle");
|
|
36
|
+
const [error, setError] = useState(null);
|
|
37
|
+
const ref = useRef({
|
|
38
|
+
formFields,
|
|
39
|
+
collectionSlug,
|
|
40
|
+
locale,
|
|
41
|
+
apiRoute: config.routes.api
|
|
42
|
+
});
|
|
43
|
+
ref.current = {
|
|
44
|
+
formFields,
|
|
45
|
+
collectionSlug,
|
|
46
|
+
locale,
|
|
47
|
+
apiRoute: config.routes.api
|
|
48
|
+
};
|
|
49
|
+
const generate = useCallback(async () => {
|
|
50
|
+
const { formFields: ff, collectionSlug: slug, locale: loc, apiRoute } = ref.current;
|
|
51
|
+
const clientConfig = getSeoClientConfig();
|
|
52
|
+
const extractPath = slug ? clientConfig.extractByCollection[slug] : void 0;
|
|
53
|
+
const extractor = resolveContentExtractor(extractPath);
|
|
54
|
+
if (!extractor) {
|
|
55
|
+
setStatus("error");
|
|
56
|
+
setError("No content extractor is registered for this collection.");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
setStatus("loading");
|
|
60
|
+
setError(null);
|
|
61
|
+
try {
|
|
62
|
+
const values = reduceFieldsToValues(ff, true);
|
|
63
|
+
const localeCode = loc?.code;
|
|
64
|
+
const ir = await extractor(
|
|
65
|
+
values,
|
|
66
|
+
{ locale: localeCode, apiRoute },
|
|
67
|
+
{ resolveDocs: createResolveDocs(apiRoute, localeCode), helpers }
|
|
68
|
+
);
|
|
69
|
+
const contentHtml = serialize(ir);
|
|
70
|
+
const res = await fetch(`${apiRoute}${GENERATE_ENDPOINT_PATH}`, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
credentials: "include",
|
|
73
|
+
headers: { "Content-Type": "application/json" },
|
|
74
|
+
body: JSON.stringify({
|
|
75
|
+
kind,
|
|
76
|
+
contentHtml,
|
|
77
|
+
locale: localeCode,
|
|
78
|
+
range: { min: measurement.min, max: measurement.max, unit: measurement.unit }
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
if (!res.ok)
|
|
82
|
+
throw new Error(`Request failed (${res.status})`);
|
|
83
|
+
const body = await res.json();
|
|
84
|
+
if (!body.text)
|
|
85
|
+
throw new Error("Empty response");
|
|
86
|
+
setValue(body.text);
|
|
87
|
+
setStatus("idle");
|
|
88
|
+
} catch (err) {
|
|
89
|
+
setStatus("error");
|
|
90
|
+
setError(err.message || "Generation failed");
|
|
91
|
+
}
|
|
92
|
+
}, [kind, measurement.min, measurement.max, measurement.unit, setValue]);
|
|
93
|
+
return {
|
|
94
|
+
generate,
|
|
95
|
+
status,
|
|
96
|
+
error
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export {
|
|
100
|
+
useGenerate
|
|
101
|
+
};
|
|
102
|
+
//# sourceMappingURL=useGenerate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/SeoField/useGenerate.ts"],"sourcesContent":["\"use client\";\n\nimport { useAllFormFields, useConfig, useDocumentInfo, useLocale } from \"@payloadcms/ui\";\nimport { reduceFieldsToValues } from \"payload/shared\";\nimport { useCallback, useRef, useState } from \"react\";\nimport { getSeoClientConfig } from \"../../client-config/registry\";\nimport { GENERATE_ENDPOINT_PATH } from \"../../constants/generation\";\nimport { createResolveDocs } from \"../../content/resolve/resolve-docs\";\nimport { resolveContentExtractor } from \"../../content/registry\";\nimport {\n compact,\n heading,\n html,\n image,\n link,\n paragraph,\n richText,\n video,\n} from \"../../content/schema/helpers\";\nimport { serialize } from \"../../content/schema/serialize\";\nimport type { ContentHelpers } from \"../../types/config\";\nimport type { Measurement } from \"../../measure/measure\";\nimport type { SeoFieldKind } from \"../../server/generate/prompts\";\n\nconst helpers: ContentHelpers = {\n heading,\n paragraph,\n link,\n image,\n video,\n html,\n richText,\n compact,\n};\n\nexport type GenerateStatus = \"idle\" | \"loading\" | \"error\";\n\ninterface UseGenerateProps {\n kind: SeoFieldKind;\n measurement: Measurement;\n setValue: (v: string) => void;\n}\n\nexport function useGenerate({ kind, measurement, setValue }: UseGenerateProps) {\n const [formFields] = useAllFormFields();\n const { config } = useConfig();\n const { collectionSlug } = useDocumentInfo();\n const locale = useLocale();\n\n const [status, setStatus] = useState<GenerateStatus>(\"idle\");\n const [error, setError] = useState<string | null>(null);\n\n const ref = useRef({\n formFields,\n collectionSlug,\n locale,\n apiRoute: config.routes.api,\n });\n ref.current = {\n formFields,\n collectionSlug,\n locale,\n apiRoute: config.routes.api,\n };\n\n const generate = useCallback(async () => {\n const { formFields: ff, collectionSlug: slug, locale: loc, apiRoute } = ref.current;\n\n const clientConfig = getSeoClientConfig();\n const extractPath = slug ? clientConfig.extractByCollection[slug] : undefined;\n\n const extractor = resolveContentExtractor(extractPath);\n if (!extractor) {\n setStatus(\"error\");\n setError(\"No content extractor is registered for this collection.\");\n\n return;\n }\n\n setStatus(\"loading\");\n setError(null);\n\n try {\n const values = reduceFieldsToValues(ff, true) as Record<string, unknown>;\n const localeCode = loc?.code;\n const ir = await extractor(\n values,\n { locale: localeCode, apiRoute },\n { resolveDocs: createResolveDocs(apiRoute, localeCode), helpers }\n );\n const contentHtml = serialize(ir);\n\n const res = await fetch(`${apiRoute}${GENERATE_ENDPOINT_PATH}`, {\n method: \"POST\",\n credentials: \"include\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n kind,\n contentHtml,\n locale: localeCode,\n range: { min: measurement.min, max: measurement.max, unit: measurement.unit },\n }),\n });\n if (!res.ok) throw new Error(`Request failed (${res.status})`);\n\n const body = (await res.json()) as { text?: string };\n if (!body.text) throw new Error(\"Empty response\");\n\n setValue(body.text);\n setStatus(\"idle\");\n } catch (err) {\n setStatus(\"error\");\n setError((err as Error).message || \"Generation failed\");\n }\n }, [kind, measurement.min, measurement.max, measurement.unit, setValue]);\n\n return {\n generate,\n status,\n error,\n };\n}\n"],"mappings":";AAEA,SAAS,kBAAkB,WAAW,iBAAiB,iBAAiB;AACxE,SAAS,4BAA4B;AACrC,SAAS,aAAa,QAAQ,gBAAgB;AAC9C,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,yBAAyB;AAClC,SAAS,+BAA+B;AACxC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAK1B,MAAM,UAA0B;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAUO,SAAS,YAAY,EAAE,MAAM,aAAa,SAAS,GAAqB;AAC7E,QAAM,CAAC,UAAU,IAAI,iBAAiB;AACtC,QAAM,EAAE,OAAO,IAAI,UAAU;AAC7B,QAAM,EAAE,eAAe,IAAI,gBAAgB;AAC3C,QAAM,SAAS,UAAU;AAEzB,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAyB,MAAM;AAC3D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AAEtD,QAAM,MAAM,OAAO;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,OAAO,OAAO;AAAA,EAC1B,CAAC;AACD,MAAI,UAAU;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,OAAO,OAAO;AAAA,EAC1B;AAEA,QAAM,WAAW,YAAY,YAAY;AACvC,UAAM,EAAE,YAAY,IAAI,gBAAgB,MAAM,QAAQ,KAAK,SAAS,IAAI,IAAI;AAE5E,UAAM,eAAe,mBAAmB;AACxC,UAAM,cAAc,OAAO,aAAa,oBAAoB,IAAI,IAAI;AAEpE,UAAM,YAAY,wBAAwB,WAAW;AACrD,QAAI,CAAC,WAAW;AACd,gBAAU,OAAO;AACjB,eAAS,yDAAyD;AAElE;AAAA,IACF;AAEA,cAAU,SAAS;AACnB,aAAS,IAAI;AAEb,QAAI;AACF,YAAM,SAAS,qBAAqB,IAAI,IAAI;AAC5C,YAAM,aAAa,KAAK;AACxB,YAAM,KAAK,MAAM;AAAA,QACf;AAAA,QACA,EAAE,QAAQ,YAAY,SAAS;AAAA,QAC/B,EAAE,aAAa,kBAAkB,UAAU,UAAU,GAAG,QAAQ;AAAA,MAClE;AACA,YAAM,cAAc,UAAU,EAAE;AAEhC,YAAM,MAAM,MAAM,MAAM,GAAG,QAAQ,GAAG,sBAAsB,IAAI;AAAA,QAC9D,QAAQ;AAAA,QACR,aAAa;AAAA,QACb,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU;AAAA,UACnB;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR,OAAO,EAAE,KAAK,YAAY,KAAK,KAAK,YAAY,KAAK,MAAM,YAAY,KAAK;AAAA,QAC9E,CAAC;AAAA,MACH,CAAC;AACD,UAAI,CAAC,IAAI;AAAI,cAAM,IAAI,MAAM,mBAAmB,IAAI,MAAM,GAAG;AAE7D,YAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,UAAI,CAAC,KAAK;AAAM,cAAM,IAAI,MAAM,gBAAgB;AAEhD,eAAS,KAAK,IAAI;AAClB,gBAAU,MAAM;AAAA,IAClB,SAAS,KAAK;AACZ,gBAAU,OAAO;AACjB,eAAU,IAAc,WAAW,mBAAmB;AAAA,IACxD;AAAA,EACF,GAAG,CAAC,MAAM,YAAY,KAAK,YAAY,KAAK,YAAY,MAAM,QAAQ,CAAC;AAEvE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const GENERATE_ENDPOINT_PATH = "/seo/generate";
|
|
2
|
+
export declare const DEFAULT_MODEL = "gpt-4o-mini";
|
|
3
|
+
export declare const DEFAULT_MAX_CONTENT_CHARS = 6000;
|
|
4
|
+
export declare const AVG_GLYPH_PX = 8.5;
|
|
5
|
+
export declare const TITLE_RANGE: {
|
|
6
|
+
readonly min: 400;
|
|
7
|
+
readonly max: 600;
|
|
8
|
+
};
|
|
9
|
+
export declare const DESCRIPTION_RANGE: {
|
|
10
|
+
readonly min: 120;
|
|
11
|
+
readonly max: 160;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=generation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generation.d.ts","sourceRoot":"","sources":["../../src/constants/generation.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,kBAAkB,CAAC;AACtD,eAAO,MAAM,aAAa,gBAAgB,CAAC;AAC3C,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAE9C,eAAO,MAAM,YAAY,MAAM,CAAC;AAEhC,eAAO,MAAM,WAAW;;;CAGd,CAAC;AAEX,eAAO,MAAM,iBAAiB;;;CAGpB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const GENERATE_ENDPOINT_PATH = "/seo/generate";
|
|
2
|
+
const DEFAULT_MODEL = "gpt-4o-mini";
|
|
3
|
+
const DEFAULT_MAX_CONTENT_CHARS = 6e3;
|
|
4
|
+
const AVG_GLYPH_PX = 8.5;
|
|
5
|
+
const TITLE_RANGE = {
|
|
6
|
+
min: 400,
|
|
7
|
+
max: 600
|
|
8
|
+
};
|
|
9
|
+
const DESCRIPTION_RANGE = {
|
|
10
|
+
min: 120,
|
|
11
|
+
max: 160
|
|
12
|
+
};
|
|
13
|
+
export {
|
|
14
|
+
AVG_GLYPH_PX,
|
|
15
|
+
DEFAULT_MAX_CONTENT_CHARS,
|
|
16
|
+
DEFAULT_MODEL,
|
|
17
|
+
DESCRIPTION_RANGE,
|
|
18
|
+
GENERATE_ENDPOINT_PATH,
|
|
19
|
+
TITLE_RANGE
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=generation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/constants/generation.ts"],"sourcesContent":["export const GENERATE_ENDPOINT_PATH = \"/seo/generate\";\nexport const DEFAULT_MODEL = \"gpt-4o-mini\";\nexport const DEFAULT_MAX_CONTENT_CHARS = 6000;\n\nexport const AVG_GLYPH_PX = 8.5;\n\nexport const TITLE_RANGE = {\n min: 400,\n max: 600,\n} as const;\n\nexport const DESCRIPTION_RANGE = {\n min: 120,\n max: 160,\n} as const;\n"],"mappings":"AAAO,MAAM,yBAAyB;AAC/B,MAAM,gBAAgB;AACtB,MAAM,4BAA4B;AAElC,MAAM,eAAe;AAErB,MAAM,cAAc;AAAA,EACzB,KAAK;AAAA,EACL,KAAK;AACP;AAEO,MAAM,oBAAoB;AAAA,EAC/B,KAAK;AAAA,EACL,KAAK;AACP;","names":[]}
|
package/dist/content/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { heading, paragraph, link, image, video, richText, html } from "./schema/helpers";
|
|
1
|
+
export { heading, paragraph, link, image, video, richText, html, compact } from "./schema/helpers";
|
|
2
2
|
export type { ContentNode, HeadingLevel } from "./schema/nodes";
|
|
3
3
|
export { registerContentExtractors, resolveContentExtractor } from "./registry";
|
|
4
|
-
export type { ContentExtractor,
|
|
4
|
+
export type { ContentExtractor, ExtractContext, ExtractToolkit, DocQuery, DocStore, ContentHelpers, } from "../types/config";
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACnG,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAChF,YAAY,EACV,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,cAAc,GACf,MAAM,iBAAiB,CAAC"}
|
package/dist/content/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { heading, paragraph, link, image, video, richText, html } from "./schema/helpers";
|
|
1
|
+
import { heading, paragraph, link, image, video, richText, html, compact } from "./schema/helpers";
|
|
2
2
|
import { registerContentExtractors, resolveContentExtractor } from "./registry";
|
|
3
3
|
export {
|
|
4
|
+
compact,
|
|
4
5
|
heading,
|
|
5
6
|
html,
|
|
6
7
|
image,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/content/index.ts"],"sourcesContent":["export { heading, paragraph, link, image, video, richText, html } from \"./schema/helpers\";\nexport type { ContentNode, HeadingLevel } from \"./schema/nodes\";\nexport { registerContentExtractors, resolveContentExtractor } from \"./registry\";\nexport type {
|
|
1
|
+
{"version":3,"sources":["../../src/content/index.ts"],"sourcesContent":["export { heading, paragraph, link, image, video, richText, html, compact } from \"./schema/helpers\";\nexport type { ContentNode, HeadingLevel } from \"./schema/nodes\";\nexport { registerContentExtractors, resolveContentExtractor } from \"./registry\";\nexport type {\n ContentExtractor,\n ExtractContext,\n ExtractToolkit,\n DocQuery,\n DocStore,\n ContentHelpers,\n} from \"../types/config\";\n"],"mappings":"AAAA,SAAS,SAAS,WAAW,MAAM,OAAO,OAAO,UAAU,MAAM,eAAe;AAEhF,SAAS,2BAA2B,+BAA+B;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-docs.d.ts","sourceRoot":"","sources":["../../../src/content/resolve/resolve-docs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAkD7D,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,CAc5C"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
function key(collection, id) {
|
|
2
|
+
return `${collection}:${id}`;
|
|
3
|
+
}
|
|
4
|
+
async function fetchQuery(apiRoute, query, locale) {
|
|
5
|
+
const ids = [...new Set(query.ids.map(String))];
|
|
6
|
+
if (ids.length === 0)
|
|
7
|
+
return [];
|
|
8
|
+
const params = new URLSearchParams({
|
|
9
|
+
depth: String(query.depth ?? 0),
|
|
10
|
+
limit: String(ids.length)
|
|
11
|
+
});
|
|
12
|
+
if (locale)
|
|
13
|
+
params.set("locale", locale);
|
|
14
|
+
ids.forEach((id, i) => params.set(`where[id][in][${i}]`, id));
|
|
15
|
+
for (const field of query.select ?? [])
|
|
16
|
+
params.set(`select[${field}]`, "true");
|
|
17
|
+
try {
|
|
18
|
+
const res = await fetch(`${apiRoute}/${query.collection}?${params.toString()}`, {
|
|
19
|
+
credentials: "include"
|
|
20
|
+
});
|
|
21
|
+
if (!res.ok)
|
|
22
|
+
return [];
|
|
23
|
+
const body = await res.json();
|
|
24
|
+
return (body.docs ?? []).filter(
|
|
25
|
+
(d) => typeof d.id === "string" || typeof d.id === "number"
|
|
26
|
+
).map((d) => [key(query.collection, d.id), d]);
|
|
27
|
+
} catch {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function createResolveDocs(apiRoute, locale) {
|
|
32
|
+
return async function resolveDocs(queries) {
|
|
33
|
+
const store = /* @__PURE__ */ new Map();
|
|
34
|
+
if (apiRoute) {
|
|
35
|
+
const results = await Promise.all(queries.map((q) => fetchQuery(apiRoute, q, locale)));
|
|
36
|
+
for (const entries of results)
|
|
37
|
+
for (const [k, doc] of entries)
|
|
38
|
+
store.set(k, doc);
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
get: (collection, id) => store.get(key(collection, id))
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
createResolveDocs
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=resolve-docs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/content/resolve/resolve-docs.ts"],"sourcesContent":["import type { DocQuery, DocStore } from \"../../types/config\";\n\ntype Doc = Record<string, unknown>;\n\ninterface FindResponse {\n docs?: Array<Doc & { id?: unknown }>;\n}\n\nfunction key(collection: string, id: string | number): string {\n return `${collection}:${id}`;\n}\n\nasync function fetchQuery(\n apiRoute: string,\n query: DocQuery,\n locale: string | undefined\n): Promise<Array<[string, Doc]>> {\n const ids = [...new Set(query.ids.map(String))];\n if (ids.length === 0) return [];\n\n const params = new URLSearchParams({\n depth: String(query.depth ?? 0),\n limit: String(ids.length),\n });\n\n if (locale) params.set(\"locale\", locale);\n\n ids.forEach((id, i) => params.set(`where[id][in][${i}]`, id));\n\n for (const field of query.select ?? []) params.set(`select[${field}]`, \"true\");\n\n try {\n const res = await fetch(`${apiRoute}/${query.collection}?${params.toString()}`, {\n credentials: \"include\",\n });\n if (!res.ok) return [];\n\n const body = (await res.json()) as FindResponse;\n\n return (body.docs ?? [])\n .filter(\n (d): d is Doc & { id: string | number } =>\n typeof d.id === \"string\" || typeof d.id === \"number\"\n )\n .map((d) => [key(query.collection, d.id), d] as [string, Doc]);\n } catch {\n return [];\n }\n}\n\nexport function createResolveDocs(\n apiRoute: string | undefined,\n locale: string | undefined\n): (queries: DocQuery[]) => Promise<DocStore> {\n return async function resolveDocs(queries: DocQuery[]): Promise<DocStore> {\n const store = new Map<string, Doc>();\n\n if (apiRoute) {\n const results = await Promise.all(queries.map((q) => fetchQuery(apiRoute, q, locale)));\n\n for (const entries of results) for (const [k, doc] of entries) store.set(k, doc);\n }\n\n return {\n get: (collection, id) => store.get(key(collection, id)),\n };\n };\n}\n"],"mappings":"AAQA,SAAS,IAAI,YAAoB,IAA6B;AAC5D,SAAO,GAAG,UAAU,IAAI,EAAE;AAC5B;AAEA,eAAe,WACb,UACA,OACA,QAC+B;AAC/B,QAAM,MAAM,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,IAAI,MAAM,CAAC,CAAC;AAC9C,MAAI,IAAI,WAAW;AAAG,WAAO,CAAC;AAE9B,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,OAAO,OAAO,MAAM,SAAS,CAAC;AAAA,IAC9B,OAAO,OAAO,IAAI,MAAM;AAAA,EAC1B,CAAC;AAED,MAAI;AAAQ,WAAO,IAAI,UAAU,MAAM;AAEvC,MAAI,QAAQ,CAAC,IAAI,MAAM,OAAO,IAAI,iBAAiB,CAAC,KAAK,EAAE,CAAC;AAE5D,aAAW,SAAS,MAAM,UAAU,CAAC;AAAG,WAAO,IAAI,UAAU,KAAK,KAAK,MAAM;AAE7E,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,GAAG,QAAQ,IAAI,MAAM,UAAU,IAAI,OAAO,SAAS,CAAC,IAAI;AAAA,MAC9E,aAAa;AAAA,IACf,CAAC;AACD,QAAI,CAAC,IAAI;AAAI,aAAO,CAAC;AAErB,UAAM,OAAQ,MAAM,IAAI,KAAK;AAE7B,YAAQ,KAAK,QAAQ,CAAC,GACnB;AAAA,MACC,CAAC,MACC,OAAO,EAAE,OAAO,YAAY,OAAO,EAAE,OAAO;AAAA,IAChD,EACC,IAAI,CAAC,MAAM,CAAC,IAAI,MAAM,YAAY,EAAE,EAAE,GAAG,CAAC,CAAkB;AAAA,EACjE,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEO,SAAS,kBACd,UACA,QAC4C;AAC5C,SAAO,eAAe,YAAY,SAAwC;AACxE,UAAM,QAAQ,oBAAI,IAAiB;AAEnC,QAAI,UAAU;AACZ,YAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ,IAAI,CAAC,MAAM,WAAW,UAAU,GAAG,MAAM,CAAC,CAAC;AAErF,iBAAW,WAAW;AAAS,mBAAW,CAAC,GAAG,GAAG,KAAK;AAAS,gBAAM,IAAI,GAAG,GAAG;AAAA,IACjF;AAEA,WAAO;AAAA,MACL,KAAK,CAAC,YAAY,OAAO,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;AAAA,IACxD;AAAA,EACF;AACF;","names":[]}
|
|
@@ -6,4 +6,5 @@ export declare function image(src?: string | null, alt?: string | null): Content
|
|
|
6
6
|
export declare function video(src?: string | null, poster?: string | null): ContentNode | null;
|
|
7
7
|
export declare function richText(value: unknown): ContentNode | null;
|
|
8
8
|
export declare function html(raw?: string | null): ContentNode | null;
|
|
9
|
+
export declare function compact(nodes: (ContentNode | null | undefined)[]): ContentNode[];
|
|
9
10
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/content/schema/helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAQzD,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAGrF;AAED,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAGlE;AAED,wBAAgB,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAInF;AAED,wBAAgB,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAGlF;AAED,wBAAgB,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAKrF;AAUD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CAI3D;AAED,wBAAgB,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAG5D"}
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/content/schema/helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAQzD,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAGrF;AAED,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAGlE;AAED,wBAAgB,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAInF;AAED,wBAAgB,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAGlF;AAED,wBAAgB,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAKrF;AAUD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CAI3D;AAED,wBAAgB,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAG5D;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,CAAC,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG,WAAW,EAAE,CAEhF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/content/schema/helpers.ts"],"sourcesContent":["import { lexicalToHtml } from \"../lexicalToHtml\";\nimport type { ContentNode, HeadingLevel } from \"./nodes\";\n\nfunction clean(v?: string | null): string | undefined {\n if (typeof v !== \"string\") return undefined;\n const t = v.trim();\n return t ? v : undefined;\n}\n\nexport function heading(level: HeadingLevel, text?: string | null): ContentNode | null {\n const t = clean(text);\n return t ? { type: \"heading\", level, text: t } : null;\n}\n\nexport function paragraph(text?: string | null): ContentNode | null {\n const t = clean(text);\n return t ? { type: \"paragraph\", text: t } : null;\n}\n\nexport function link(href?: string | null, text?: string | null): ContentNode | null {\n const h = clean(href);\n const t = clean(text);\n return h && t ? { type: \"link\", href: h, text: t } : null;\n}\n\nexport function image(src?: string | null, alt?: string | null): ContentNode | null {\n const s = clean(src);\n return s ? { type: \"image\", src: s, alt: clean(alt) ?? \"\" } : null;\n}\n\nexport function video(src?: string | null, poster?: string | null): ContentNode | null {\n const s = clean(src);\n if (!s) return null;\n const p = clean(poster);\n return p ? { type: \"video\", src: s, poster: p } : { type: \"video\", src: s };\n}\n\nfunction hasLexicalContent(value: unknown): boolean {\n if (typeof value !== \"object\" || value === null) return false;\n const root = (value as Record<string, unknown>).root;\n if (typeof root !== \"object\" || root === null) return false;\n const children = (root as Record<string, unknown>).children;\n return Array.isArray(children) && children.length > 0;\n}\n\nexport function richText(value: unknown): ContentNode | null {\n if (!hasLexicalContent(value)) return null;\n const out = lexicalToHtml(value as never);\n return out ? { type: \"html\", html: out } : null;\n}\n\nexport function html(raw?: string | null): ContentNode | null {\n const r = clean(raw);\n return r ? { type: \"html\", html: r } : null;\n}\n"],"mappings":"AAAA,SAAS,qBAAqB;AAG9B,SAAS,MAAM,GAAuC;AACpD,MAAI,OAAO,MAAM;AAAU,WAAO;AAClC,QAAM,IAAI,EAAE,KAAK;AACjB,SAAO,IAAI,IAAI;AACjB;AAEO,SAAS,QAAQ,OAAqB,MAA0C;AACrF,QAAM,IAAI,MAAM,IAAI;AACpB,SAAO,IAAI,EAAE,MAAM,WAAW,OAAO,MAAM,EAAE,IAAI;AACnD;AAEO,SAAS,UAAU,MAA0C;AAClE,QAAM,IAAI,MAAM,IAAI;AACpB,SAAO,IAAI,EAAE,MAAM,aAAa,MAAM,EAAE,IAAI;AAC9C;AAEO,SAAS,KAAK,MAAsB,MAA0C;AACnF,QAAM,IAAI,MAAM,IAAI;AACpB,QAAM,IAAI,MAAM,IAAI;AACpB,SAAO,KAAK,IAAI,EAAE,MAAM,QAAQ,MAAM,GAAG,MAAM,EAAE,IAAI;AACvD;AAEO,SAAS,MAAM,KAAqB,KAAyC;AAClF,QAAM,IAAI,MAAM,GAAG;AACnB,SAAO,IAAI,EAAE,MAAM,SAAS,KAAK,GAAG,KAAK,MAAM,GAAG,KAAK,GAAG,IAAI;AAChE;AAEO,SAAS,MAAM,KAAqB,QAA4C;AACrF,QAAM,IAAI,MAAM,GAAG;AACnB,MAAI,CAAC;AAAG,WAAO;AACf,QAAM,IAAI,MAAM,MAAM;AACtB,SAAO,IAAI,EAAE,MAAM,SAAS,KAAK,GAAG,QAAQ,EAAE,IAAI,EAAE,MAAM,SAAS,KAAK,EAAE;AAC5E;AAEA,SAAS,kBAAkB,OAAyB;AAClD,MAAI,OAAO,UAAU,YAAY,UAAU;AAAM,WAAO;AACxD,QAAM,OAAQ,MAAkC;AAChD,MAAI,OAAO,SAAS,YAAY,SAAS;AAAM,WAAO;AACtD,QAAM,WAAY,KAAiC;AACnD,SAAO,MAAM,QAAQ,QAAQ,KAAK,SAAS,SAAS;AACtD;AAEO,SAAS,SAAS,OAAoC;AAC3D,MAAI,CAAC,kBAAkB,KAAK;AAAG,WAAO;AACtC,QAAM,MAAM,cAAc,KAAc;AACxC,SAAO,MAAM,EAAE,MAAM,QAAQ,MAAM,IAAI,IAAI;AAC7C;AAEO,SAAS,KAAK,KAAyC;AAC5D,QAAM,IAAI,MAAM,GAAG;AACnB,SAAO,IAAI,EAAE,MAAM,QAAQ,MAAM,EAAE,IAAI;AACzC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/content/schema/helpers.ts"],"sourcesContent":["import { lexicalToHtml } from \"../lexicalToHtml\";\nimport type { ContentNode, HeadingLevel } from \"./nodes\";\n\nfunction clean(v?: string | null): string | undefined {\n if (typeof v !== \"string\") return undefined;\n const t = v.trim();\n return t ? v : undefined;\n}\n\nexport function heading(level: HeadingLevel, text?: string | null): ContentNode | null {\n const t = clean(text);\n return t ? { type: \"heading\", level, text: t } : null;\n}\n\nexport function paragraph(text?: string | null): ContentNode | null {\n const t = clean(text);\n return t ? { type: \"paragraph\", text: t } : null;\n}\n\nexport function link(href?: string | null, text?: string | null): ContentNode | null {\n const h = clean(href);\n const t = clean(text);\n return h && t ? { type: \"link\", href: h, text: t } : null;\n}\n\nexport function image(src?: string | null, alt?: string | null): ContentNode | null {\n const s = clean(src);\n return s ? { type: \"image\", src: s, alt: clean(alt) ?? \"\" } : null;\n}\n\nexport function video(src?: string | null, poster?: string | null): ContentNode | null {\n const s = clean(src);\n if (!s) return null;\n const p = clean(poster);\n return p ? { type: \"video\", src: s, poster: p } : { type: \"video\", src: s };\n}\n\nfunction hasLexicalContent(value: unknown): boolean {\n if (typeof value !== \"object\" || value === null) return false;\n const root = (value as Record<string, unknown>).root;\n if (typeof root !== \"object\" || root === null) return false;\n const children = (root as Record<string, unknown>).children;\n return Array.isArray(children) && children.length > 0;\n}\n\nexport function richText(value: unknown): ContentNode | null {\n if (!hasLexicalContent(value)) return null;\n const out = lexicalToHtml(value as never);\n return out ? { type: \"html\", html: out } : null;\n}\n\nexport function html(raw?: string | null): ContentNode | null {\n const r = clean(raw);\n return r ? { type: \"html\", html: r } : null;\n}\n\nexport function compact(nodes: (ContentNode | null | undefined)[]): ContentNode[] {\n return nodes.filter((n): n is ContentNode => n != null);\n}\n"],"mappings":"AAAA,SAAS,qBAAqB;AAG9B,SAAS,MAAM,GAAuC;AACpD,MAAI,OAAO,MAAM;AAAU,WAAO;AAClC,QAAM,IAAI,EAAE,KAAK;AACjB,SAAO,IAAI,IAAI;AACjB;AAEO,SAAS,QAAQ,OAAqB,MAA0C;AACrF,QAAM,IAAI,MAAM,IAAI;AACpB,SAAO,IAAI,EAAE,MAAM,WAAW,OAAO,MAAM,EAAE,IAAI;AACnD;AAEO,SAAS,UAAU,MAA0C;AAClE,QAAM,IAAI,MAAM,IAAI;AACpB,SAAO,IAAI,EAAE,MAAM,aAAa,MAAM,EAAE,IAAI;AAC9C;AAEO,SAAS,KAAK,MAAsB,MAA0C;AACnF,QAAM,IAAI,MAAM,IAAI;AACpB,QAAM,IAAI,MAAM,IAAI;AACpB,SAAO,KAAK,IAAI,EAAE,MAAM,QAAQ,MAAM,GAAG,MAAM,EAAE,IAAI;AACvD;AAEO,SAAS,MAAM,KAAqB,KAAyC;AAClF,QAAM,IAAI,MAAM,GAAG;AACnB,SAAO,IAAI,EAAE,MAAM,SAAS,KAAK,GAAG,KAAK,MAAM,GAAG,KAAK,GAAG,IAAI;AAChE;AAEO,SAAS,MAAM,KAAqB,QAA4C;AACrF,QAAM,IAAI,MAAM,GAAG;AACnB,MAAI,CAAC;AAAG,WAAO;AACf,QAAM,IAAI,MAAM,MAAM;AACtB,SAAO,IAAI,EAAE,MAAM,SAAS,KAAK,GAAG,QAAQ,EAAE,IAAI,EAAE,MAAM,SAAS,KAAK,EAAE;AAC5E;AAEA,SAAS,kBAAkB,OAAyB;AAClD,MAAI,OAAO,UAAU,YAAY,UAAU;AAAM,WAAO;AACxD,QAAM,OAAQ,MAAkC;AAChD,MAAI,OAAO,SAAS,YAAY,SAAS;AAAM,WAAO;AACtD,QAAM,WAAY,KAAiC;AACnD,SAAO,MAAM,QAAQ,QAAQ,KAAK,SAAS,SAAS;AACtD;AAEO,SAAS,SAAS,OAAoC;AAC3D,MAAI,CAAC,kBAAkB,KAAK;AAAG,WAAO;AACtC,QAAM,MAAM,cAAc,KAAc;AACxC,SAAO,MAAM,EAAE,MAAM,QAAQ,MAAM,IAAI,IAAI;AAC7C;AAEO,SAAS,KAAK,KAAyC;AAC5D,QAAM,IAAI,MAAM,GAAG;AACnB,SAAO,IAAI,EAAE,MAAM,QAAQ,MAAM,EAAE,IAAI;AACzC;AAEO,SAAS,QAAQ,OAA0D;AAChF,SAAO,MAAM,OAAO,CAAC,MAAwB,KAAK,IAAI;AACxD;","names":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { LengthProgress } from "@yoast/search-metadata-previews/build/helpers/progress";
|
|
2
|
-
|
|
2
|
+
import { AVG_GLYPH_PX } from "../../constants/generation";
|
|
3
|
+
export { AVG_GLYPH_PX };
|
|
3
4
|
export declare const TITLE_FALLBACK_MAX_PX = 600;
|
|
4
5
|
export declare function getTitleProgressGuarded(title: string): LengthProgress;
|
|
5
6
|
//# sourceMappingURL=title-progress.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"title-progress.d.ts","sourceRoot":"","sources":["../../../src/engine/helpers/title-progress.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wDAAwD,CAAC;
|
|
1
|
+
{"version":3,"file":"title-progress.d.ts","sourceRoot":"","sources":["../../../src/engine/helpers/title-progress.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wDAAwD,CAAC;AAC7F,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAarE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getTitleProgress } from "@yoast/search-metadata-previews/build/helpers/progress";
|
|
2
|
-
|
|
2
|
+
import { AVG_GLYPH_PX } from "../../constants/generation";
|
|
3
3
|
const TITLE_FALLBACK_MAX_PX = 600;
|
|
4
4
|
function getTitleProgressGuarded(title) {
|
|
5
5
|
if (typeof document !== "undefined") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/engine/helpers/title-progress.ts"],"sourcesContent":["import { getTitleProgress } from \"@yoast/search-metadata-previews/build/helpers/progress\";\nimport type { LengthProgress } from \"@yoast/search-metadata-previews/build/helpers/progress\";\n\nexport
|
|
1
|
+
{"version":3,"sources":["../../../src/engine/helpers/title-progress.ts"],"sourcesContent":["import { getTitleProgress } from \"@yoast/search-metadata-previews/build/helpers/progress\";\nimport type { LengthProgress } from \"@yoast/search-metadata-previews/build/helpers/progress\";\nimport { AVG_GLYPH_PX } from \"../../constants/generation\";\n\nexport { AVG_GLYPH_PX };\nexport const TITLE_FALLBACK_MAX_PX = 600;\n\nexport function getTitleProgressGuarded(title: string): LengthProgress {\n if (typeof document !== \"undefined\") {\n return getTitleProgress(title);\n }\n\n const actual = Math.round(title.length * AVG_GLYPH_PX);\n const score = actual <= TITLE_FALLBACK_MAX_PX ? 9 : 1;\n\n return {\n actual,\n max: TITLE_FALLBACK_MAX_PX,\n score,\n };\n}\n"],"mappings":"AAAA,SAAS,wBAAwB;AAEjC,SAAS,oBAAoB;AAGtB,MAAM,wBAAwB;AAE9B,SAAS,wBAAwB,OAA+B;AACrE,MAAI,OAAO,aAAa,aAAa;AACnC,WAAO,iBAAiB,KAAK;AAAA,EAC/B;AAEA,QAAM,SAAS,KAAK,MAAM,MAAM,SAAS,YAAY;AACrD,QAAM,QAAQ,UAAU,wBAAwB,IAAI;AAEpD,SAAO;AAAA,IACL;AAAA,IACA,KAAK;AAAA,IACL;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fields/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/fields/index.ts"],"sourcesContent":["export { seoTextField } from \"./seoTextField\";\nexport type { SeoTextFieldOptions } from \"./seoTextField\";\n"],"mappings":"AAAA,SAAS,oBAAoB;","names":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FieldHook } from "payload";
|
|
2
|
+
import type { RangeOverride } from "../measure/measure";
|
|
3
|
+
import type { SeoFieldKind } from "../server/generate/prompts";
|
|
4
|
+
export declare function makeGenerateOnPublishHook(args: {
|
|
5
|
+
kind: SeoFieldKind;
|
|
6
|
+
range: RangeOverride | undefined;
|
|
7
|
+
}): FieldHook;
|
|
8
|
+
//# sourceMappingURL=onPublishHook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onPublishHook.d.ts","sourceRoot":"","sources":["../../src/fields/onPublishHook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAgBzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AA6B/D,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,aAAa,GAAG,SAAS,CAAC;CAClC,GAAG,SAAS,CAqDZ"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { getPluginConfig } from "../config";
|
|
2
|
+
import { PLUGIN_NAME } from "../constants";
|
|
3
|
+
import { DESCRIPTION_RANGE, TITLE_RANGE } from "../constants/generation";
|
|
4
|
+
import {
|
|
5
|
+
compact,
|
|
6
|
+
heading,
|
|
7
|
+
html,
|
|
8
|
+
image,
|
|
9
|
+
link,
|
|
10
|
+
paragraph,
|
|
11
|
+
richText,
|
|
12
|
+
video
|
|
13
|
+
} from "../content/schema/helpers";
|
|
14
|
+
import { serialize } from "../content/schema/serialize";
|
|
15
|
+
import { resolveApiKey } from "../server/generate/apiKey";
|
|
16
|
+
import { createServerResolveDocs } from "../server/generate/serverResolveDocs";
|
|
17
|
+
import { generateForField } from "../server/generate/generateForField";
|
|
18
|
+
const helpers = {
|
|
19
|
+
heading,
|
|
20
|
+
paragraph,
|
|
21
|
+
link,
|
|
22
|
+
image,
|
|
23
|
+
video,
|
|
24
|
+
html,
|
|
25
|
+
richText,
|
|
26
|
+
compact
|
|
27
|
+
};
|
|
28
|
+
const CONTEXT_KEY = "__fr_seo_content__";
|
|
29
|
+
function isEmpty(v) {
|
|
30
|
+
return typeof v !== "string" || v.trim().length === 0;
|
|
31
|
+
}
|
|
32
|
+
function rangeFor(kind, override) {
|
|
33
|
+
const base = kind === "title" ? TITLE_RANGE : DESCRIPTION_RANGE;
|
|
34
|
+
return {
|
|
35
|
+
min: override?.min ?? base.min,
|
|
36
|
+
max: override?.max ?? base.max,
|
|
37
|
+
unit: kind === "title" ? "px" : "char"
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function makeGenerateOnPublishHook(args) {
|
|
41
|
+
return async ({ value, data, collection, req, operation }) => {
|
|
42
|
+
if (!isEmpty(value))
|
|
43
|
+
return value;
|
|
44
|
+
if (operation !== "create" && operation !== "update")
|
|
45
|
+
return value;
|
|
46
|
+
const status = data?._status;
|
|
47
|
+
if (status && status !== "published")
|
|
48
|
+
return value;
|
|
49
|
+
const config = getPluginConfig();
|
|
50
|
+
const apiKey = resolveApiKey(config.generation);
|
|
51
|
+
if (!apiKey)
|
|
52
|
+
return value;
|
|
53
|
+
const slug = collection?.slug;
|
|
54
|
+
const seoCfg = config.collections.find((c) => c.slug === slug);
|
|
55
|
+
const extractor = seoCfg?.serverExtractContent;
|
|
56
|
+
if (!extractor || !slug)
|
|
57
|
+
return value;
|
|
58
|
+
try {
|
|
59
|
+
const localeCode = typeof req.locale === "string" ? req.locale : void 0;
|
|
60
|
+
const bucket = req.context[CONTEXT_KEY] ??= {};
|
|
61
|
+
const cacheKey = `${slug}:${localeCode ?? ""}`;
|
|
62
|
+
let contentHtml = bucket[cacheKey];
|
|
63
|
+
if (contentHtml === void 0) {
|
|
64
|
+
const toolkit = {
|
|
65
|
+
resolveDocs: createServerResolveDocs(req.payload, localeCode),
|
|
66
|
+
helpers
|
|
67
|
+
};
|
|
68
|
+
const ir = await extractor(
|
|
69
|
+
data,
|
|
70
|
+
{ locale: localeCode },
|
|
71
|
+
toolkit
|
|
72
|
+
);
|
|
73
|
+
contentHtml = serialize(ir);
|
|
74
|
+
bucket[cacheKey] = contentHtml;
|
|
75
|
+
}
|
|
76
|
+
return await generateForField({
|
|
77
|
+
kind: args.kind,
|
|
78
|
+
contentHtml,
|
|
79
|
+
range: rangeFor(args.kind, args.range),
|
|
80
|
+
locale: localeCode,
|
|
81
|
+
config: config.generation ?? {},
|
|
82
|
+
apiKey
|
|
83
|
+
});
|
|
84
|
+
} catch (err) {
|
|
85
|
+
req.payload.logger.error(
|
|
86
|
+
`[${PLUGIN_NAME}] on-publish generation failed: ${err.message}`
|
|
87
|
+
);
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export {
|
|
93
|
+
makeGenerateOnPublishHook
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=onPublishHook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/fields/onPublishHook.ts"],"sourcesContent":["import type { FieldHook } from \"payload\";\nimport { getPluginConfig } from \"../config\";\nimport { PLUGIN_NAME } from \"../constants\";\nimport { DESCRIPTION_RANGE, TITLE_RANGE } from \"../constants/generation\";\nimport {\n compact,\n heading,\n html,\n image,\n link,\n paragraph,\n richText,\n video,\n} from \"../content/schema/helpers\";\nimport { serialize } from \"../content/schema/serialize\";\nimport type { ContentHelpers, ExtractToolkit, SeoCollectionConfig } from \"../types/config\";\nimport type { RangeOverride } from \"../measure/measure\";\nimport { resolveApiKey } from \"../server/generate/apiKey\";\nimport { createServerResolveDocs } from \"../server/generate/serverResolveDocs\";\nimport { generateForField } from \"../server/generate/generateForField\";\nimport type { SeoFieldKind } from \"../server/generate/prompts\";\n\nconst helpers: ContentHelpers = {\n heading,\n paragraph,\n link,\n image,\n video,\n html,\n richText,\n compact,\n};\n\nconst CONTEXT_KEY = \"__fr_seo_content__\";\n\nfunction isEmpty(v: unknown): boolean {\n return typeof v !== \"string\" || v.trim().length === 0;\n}\n\nfunction rangeFor(kind: SeoFieldKind, override: RangeOverride | undefined) {\n const base = kind === \"title\" ? TITLE_RANGE : DESCRIPTION_RANGE;\n\n return {\n min: override?.min ?? base.min,\n max: override?.max ?? base.max,\n unit: (kind === \"title\" ? \"px\" : \"char\") as \"px\" | \"char\",\n };\n}\n\nexport function makeGenerateOnPublishHook(args: {\n kind: SeoFieldKind;\n range: RangeOverride | undefined;\n}): FieldHook {\n return async ({ value, data, collection, req, operation }) => {\n if (!isEmpty(value)) return value;\n if (operation !== \"create\" && operation !== \"update\") return value;\n\n const status = (data as { _status?: string } | undefined)?._status;\n if (status && status !== \"published\") return value;\n\n const config = getPluginConfig();\n const apiKey = resolveApiKey(config.generation);\n if (!apiKey) return value;\n\n const slug = collection?.slug;\n const seoCfg = config.collections.find((c: SeoCollectionConfig) => c.slug === slug);\n const extractor = seoCfg?.serverExtractContent;\n if (!extractor || !slug) return value;\n\n try {\n const localeCode = typeof req.locale === \"string\" ? req.locale : undefined;\n\n const bucket = (req.context[CONTEXT_KEY] ??= {}) as Record<string, string>;\n const cacheKey = `${slug}:${localeCode ?? \"\"}`;\n let contentHtml = bucket[cacheKey];\n if (contentHtml === undefined) {\n const toolkit: ExtractToolkit = {\n resolveDocs: createServerResolveDocs(req.payload, localeCode),\n helpers,\n };\n const ir = await extractor(\n data as Record<string, unknown>,\n { locale: localeCode },\n toolkit\n );\n contentHtml = serialize(ir);\n bucket[cacheKey] = contentHtml;\n }\n\n return await generateForField({\n kind: args.kind,\n contentHtml,\n range: rangeFor(args.kind, args.range),\n locale: localeCode,\n config: config.generation ?? {},\n apiKey,\n });\n } catch (err) {\n req.payload.logger.error(\n `[${PLUGIN_NAME}] on-publish generation failed: ${(err as Error).message}`\n );\n\n return value;\n }\n };\n}\n"],"mappings":"AACA,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB,mBAAmB;AAC/C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAG1B,SAAS,qBAAqB;AAC9B,SAAS,+BAA+B;AACxC,SAAS,wBAAwB;AAGjC,MAAM,UAA0B;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,MAAM,cAAc;AAEpB,SAAS,QAAQ,GAAqB;AACpC,SAAO,OAAO,MAAM,YAAY,EAAE,KAAK,EAAE,WAAW;AACtD;AAEA,SAAS,SAAS,MAAoB,UAAqC;AACzE,QAAM,OAAO,SAAS,UAAU,cAAc;AAE9C,SAAO;AAAA,IACL,KAAK,UAAU,OAAO,KAAK;AAAA,IAC3B,KAAK,UAAU,OAAO,KAAK;AAAA,IAC3B,MAAO,SAAS,UAAU,OAAO;AAAA,EACnC;AACF;AAEO,SAAS,0BAA0B,MAG5B;AACZ,SAAO,OAAO,EAAE,OAAO,MAAM,YAAY,KAAK,UAAU,MAAM;AAC5D,QAAI,CAAC,QAAQ,KAAK;AAAG,aAAO;AAC5B,QAAI,cAAc,YAAY,cAAc;AAAU,aAAO;AAE7D,UAAM,SAAU,MAA2C;AAC3D,QAAI,UAAU,WAAW;AAAa,aAAO;AAE7C,UAAM,SAAS,gBAAgB;AAC/B,UAAM,SAAS,cAAc,OAAO,UAAU;AAC9C,QAAI,CAAC;AAAQ,aAAO;AAEpB,UAAM,OAAO,YAAY;AACzB,UAAM,SAAS,OAAO,YAAY,KAAK,CAAC,MAA2B,EAAE,SAAS,IAAI;AAClF,UAAM,YAAY,QAAQ;AAC1B,QAAI,CAAC,aAAa,CAAC;AAAM,aAAO;AAEhC,QAAI;AACF,YAAM,aAAa,OAAO,IAAI,WAAW,WAAW,IAAI,SAAS;AAEjE,YAAM,SAAU,IAAI,QAAQ,WAAW,MAAM,CAAC;AAC9C,YAAM,WAAW,GAAG,IAAI,IAAI,cAAc,EAAE;AAC5C,UAAI,cAAc,OAAO,QAAQ;AACjC,UAAI,gBAAgB,QAAW;AAC7B,cAAM,UAA0B;AAAA,UAC9B,aAAa,wBAAwB,IAAI,SAAS,UAAU;AAAA,UAC5D;AAAA,QACF;AACA,cAAM,KAAK,MAAM;AAAA,UACf;AAAA,UACA,EAAE,QAAQ,WAAW;AAAA,UACrB;AAAA,QACF;AACA,sBAAc,UAAU,EAAE;AAC1B,eAAO,QAAQ,IAAI;AAAA,MACrB;AAEA,aAAO,MAAM,iBAAiB;AAAA,QAC5B,MAAM,KAAK;AAAA,QACX;AAAA,QACA,OAAO,SAAS,KAAK,MAAM,KAAK,KAAK;AAAA,QACrC,QAAQ;AAAA,QACR,QAAQ,OAAO,cAAc,CAAC;AAAA,QAC9B;AAAA,MACF,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,UAAI,QAAQ,OAAO;AAAA,QACjB,IAAI,WAAW,mCAAoC,IAAc,OAAO;AAAA,MAC1E;AAEA,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TextareaField, TextField } from "payload";
|
|
2
|
+
import type { RangeOverride } from "../measure/measure";
|
|
3
|
+
import type { SeoFieldKind } from "../server/generate/prompts";
|
|
4
|
+
export interface SeoTextFieldOptions {
|
|
5
|
+
name: string;
|
|
6
|
+
kind: SeoFieldKind;
|
|
7
|
+
label?: TextField["label"];
|
|
8
|
+
required?: boolean;
|
|
9
|
+
localized?: boolean;
|
|
10
|
+
admin?: TextField["admin"];
|
|
11
|
+
/** Show the manual Generate button.
|
|
12
|
+
* @default false
|
|
13
|
+
*/
|
|
14
|
+
showButton?: boolean;
|
|
15
|
+
/** Generate on publish when the field is empty
|
|
16
|
+
* @default false
|
|
17
|
+
*/
|
|
18
|
+
generateOnPublish?: boolean;
|
|
19
|
+
/** Length range override in the kind's unit (px for title, chars for description). */
|
|
20
|
+
range?: RangeOverride;
|
|
21
|
+
}
|
|
22
|
+
export declare function seoTextField(options: SeoTextFieldOptions): TextField | TextareaField;
|
|
23
|
+
//# sourceMappingURL=seoTextField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seoTextField.d.ts","sourceRoot":"","sources":["../../src/fields/seoTextField.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IAC3B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,sFAAsF;IACtF,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,SAAS,GAAG,aAAa,CA2CpF"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { getComponentPath } from "../utils/config/getComponentPath";
|
|
2
|
+
import { makeGenerateOnPublishHook } from "./onPublishHook";
|
|
3
|
+
function seoTextField(options) {
|
|
4
|
+
const { name, kind, label, required, localized, admin, range } = options;
|
|
5
|
+
const showButton = options.showButton ?? false;
|
|
6
|
+
const generateOnPublish = options.generateOnPublish ?? false;
|
|
7
|
+
const common = {
|
|
8
|
+
name,
|
|
9
|
+
...label === void 0 ? {} : { label },
|
|
10
|
+
...required === void 0 ? {} : { required },
|
|
11
|
+
...localized === void 0 ? {} : { localized },
|
|
12
|
+
admin: {
|
|
13
|
+
...admin,
|
|
14
|
+
components: {
|
|
15
|
+
...admin?.components,
|
|
16
|
+
Field: {
|
|
17
|
+
path: getComponentPath("components/SeoField", "SeoField"),
|
|
18
|
+
clientProps: {
|
|
19
|
+
kind,
|
|
20
|
+
showButton,
|
|
21
|
+
generateOnPublish,
|
|
22
|
+
range
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const field = kind === "description" ? { ...common, type: "textarea" } : { ...common, type: "text" };
|
|
29
|
+
if (generateOnPublish) {
|
|
30
|
+
field.hooks = {
|
|
31
|
+
...field.hooks,
|
|
32
|
+
beforeChange: [
|
|
33
|
+
...field.hooks?.beforeChange ?? [],
|
|
34
|
+
makeGenerateOnPublishHook({ kind, range })
|
|
35
|
+
]
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return field;
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
seoTextField
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=seoTextField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/fields/seoTextField.ts"],"sourcesContent":["import type { TextareaField, TextField } from \"payload\";\nimport { getComponentPath } from \"../utils/config/getComponentPath\";\nimport { makeGenerateOnPublishHook } from \"./onPublishHook\";\nimport type { RangeOverride } from \"../measure/measure\";\nimport type { SeoFieldKind } from \"../server/generate/prompts\";\n\nexport interface SeoTextFieldOptions {\n name: string;\n kind: SeoFieldKind;\n label?: TextField[\"label\"];\n required?: boolean;\n localized?: boolean;\n admin?: TextField[\"admin\"];\n /** Show the manual Generate button.\n * @default false\n */\n showButton?: boolean;\n /** Generate on publish when the field is empty\n * @default false\n */\n generateOnPublish?: boolean;\n /** Length range override in the kind's unit (px for title, chars for description). */\n range?: RangeOverride;\n}\n\nexport function seoTextField(options: SeoTextFieldOptions): TextField | TextareaField {\n const { name, kind, label, required, localized, admin, range } = options;\n const showButton = options.showButton ?? false;\n const generateOnPublish = options.generateOnPublish ?? false;\n\n const common = {\n name,\n ...(label === undefined ? {} : { label }),\n ...(required === undefined ? {} : { required }),\n ...(localized === undefined ? {} : { localized }),\n admin: {\n ...admin,\n components: {\n ...admin?.components,\n Field: {\n path: getComponentPath(\"components/SeoField\", \"SeoField\"),\n clientProps: {\n kind,\n showButton,\n generateOnPublish,\n range,\n },\n },\n },\n },\n };\n\n const field: TextField | TextareaField =\n kind === \"description\"\n ? ({ ...common, type: \"textarea\" } as TextareaField)\n : ({ ...common, type: \"text\" } as TextField);\n\n if (generateOnPublish) {\n field.hooks = {\n ...field.hooks,\n beforeChange: [\n ...(field.hooks?.beforeChange ?? []),\n makeGenerateOnPublishHook({ kind, range }),\n ],\n };\n }\n\n return field;\n}\n"],"mappings":"AACA,SAAS,wBAAwB;AACjC,SAAS,iCAAiC;AAuBnC,SAAS,aAAa,SAAyD;AACpF,QAAM,EAAE,MAAM,MAAM,OAAO,UAAU,WAAW,OAAO,MAAM,IAAI;AACjE,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,oBAAoB,QAAQ,qBAAqB;AAEvD,QAAM,SAAS;AAAA,IACb;AAAA,IACA,GAAI,UAAU,SAAY,CAAC,IAAI,EAAE,MAAM;AAAA,IACvC,GAAI,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS;AAAA,IAC7C,GAAI,cAAc,SAAY,CAAC,IAAI,EAAE,UAAU;AAAA,IAC/C,OAAO;AAAA,MACL,GAAG;AAAA,MACH,YAAY;AAAA,QACV,GAAG,OAAO;AAAA,QACV,OAAO;AAAA,UACL,MAAM,iBAAiB,uBAAuB,UAAU;AAAA,UACxD,aAAa;AAAA,YACX;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QACJ,SAAS,gBACJ,EAAE,GAAG,QAAQ,MAAM,WAAW,IAC9B,EAAE,GAAG,QAAQ,MAAM,OAAO;AAEjC,MAAI,mBAAmB;AACrB,UAAM,QAAQ;AAAA,MACZ,GAAG,MAAM;AAAA,MACT,cAAc;AAAA,QACZ,GAAI,MAAM,OAAO,gBAAgB,CAAC;AAAA,QAClC,0BAA0B,EAAE,MAAM,MAAM,CAAC;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { seoPlugin } from "./plugin";
|
|
2
|
-
export
|
|
2
|
+
export { seoTextField } from "./fields/seoTextField";
|
|
3
|
+
export type { SeoTextFieldOptions } from "./fields/seoTextField";
|
|
4
|
+
export type { ContentExtractor, SeoPluginConfig, SeoCollectionConfig, SeoFieldPaths, SeoSiteConfig, SeoGenerationConfig, } from "./types/config";
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACjE,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,aAAa,EACb,mBAAmB,GACpB,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { seoPlugin } from \"./plugin\";\nexport type { ContentExtractor
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { seoPlugin } from \"./plugin\";\nexport { seoTextField } from \"./fields/seoTextField\";\nexport type { SeoTextFieldOptions } from \"./fields/seoTextField\";\nexport type {\n ContentExtractor,\n SeoPluginConfig,\n SeoCollectionConfig,\n SeoFieldPaths,\n SeoSiteConfig,\n SeoGenerationConfig,\n} from \"./types/config\";\n"],"mappings":"AAAA,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB;","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type LengthStatus = "good" | "short" | "long";
|
|
2
|
+
export type LengthUnit = "px" | "char";
|
|
3
|
+
export interface Measurement {
|
|
4
|
+
unit: LengthUnit;
|
|
5
|
+
value: number;
|
|
6
|
+
min: number;
|
|
7
|
+
max: number;
|
|
8
|
+
status: LengthStatus;
|
|
9
|
+
}
|
|
10
|
+
export interface RangeOverride {
|
|
11
|
+
min?: number;
|
|
12
|
+
max?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function measureTitle(text: string, range?: RangeOverride): Measurement;
|
|
15
|
+
export declare function measureDescription(text: string, range?: RangeOverride): Measurement;
|
|
16
|
+
//# sourceMappingURL=measure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../../src/measure/measure.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AACrD,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,MAAM,CAAC;AAEvC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAQD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,WAAW,CAY7E;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,WAAW,CAYnF"}
|