@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,38 @@
|
|
|
1
|
+
import { getTitleProgressGuarded } from "../engine/helpers/title-progress";
|
|
2
|
+
import { DESCRIPTION_RANGE, TITLE_RANGE } from "../constants/generation";
|
|
3
|
+
function statusFor(value, min, max) {
|
|
4
|
+
if (value > max)
|
|
5
|
+
return "long";
|
|
6
|
+
if (value < min)
|
|
7
|
+
return "short";
|
|
8
|
+
return "good";
|
|
9
|
+
}
|
|
10
|
+
function measureTitle(text, range) {
|
|
11
|
+
const progress = getTitleProgressGuarded(text ?? "");
|
|
12
|
+
const min = range?.min ?? TITLE_RANGE.min;
|
|
13
|
+
const max = range?.max ?? progress.max ?? TITLE_RANGE.max;
|
|
14
|
+
return {
|
|
15
|
+
unit: "px",
|
|
16
|
+
value: progress.actual,
|
|
17
|
+
min,
|
|
18
|
+
max,
|
|
19
|
+
status: statusFor(progress.actual, min, max)
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function measureDescription(text, range) {
|
|
23
|
+
const value = (text ?? "").length;
|
|
24
|
+
const min = range?.min ?? DESCRIPTION_RANGE.min;
|
|
25
|
+
const max = range?.max ?? DESCRIPTION_RANGE.max;
|
|
26
|
+
return {
|
|
27
|
+
unit: "char",
|
|
28
|
+
value,
|
|
29
|
+
min,
|
|
30
|
+
max,
|
|
31
|
+
status: statusFor(value, min, max)
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
measureDescription,
|
|
36
|
+
measureTitle
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=measure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/measure/measure.ts"],"sourcesContent":["import { getTitleProgressGuarded } from \"../engine/helpers/title-progress\";\nimport { DESCRIPTION_RANGE, TITLE_RANGE } from \"../constants/generation\";\n\nexport type LengthStatus = \"good\" | \"short\" | \"long\";\nexport type LengthUnit = \"px\" | \"char\";\n\nexport interface Measurement {\n unit: LengthUnit;\n value: number;\n min: number;\n max: number;\n status: LengthStatus;\n}\n\nexport interface RangeOverride {\n min?: number;\n max?: number;\n}\n\nfunction statusFor(value: number, min: number, max: number): LengthStatus {\n if (value > max) return \"long\";\n if (value < min) return \"short\";\n return \"good\";\n}\n\nexport function measureTitle(text: string, range?: RangeOverride): Measurement {\n const progress = getTitleProgressGuarded(text ?? \"\");\n const min = range?.min ?? TITLE_RANGE.min;\n const max = range?.max ?? progress.max ?? TITLE_RANGE.max;\n\n return {\n unit: \"px\",\n value: progress.actual,\n min,\n max,\n status: statusFor(progress.actual, min, max),\n };\n}\n\nexport function measureDescription(text: string, range?: RangeOverride): Measurement {\n const value = (text ?? \"\").length;\n const min = range?.min ?? DESCRIPTION_RANGE.min;\n const max = range?.max ?? DESCRIPTION_RANGE.max;\n\n return {\n unit: \"char\",\n value,\n min,\n max,\n status: statusFor(value, min, max),\n };\n}\n"],"mappings":"AAAA,SAAS,+BAA+B;AACxC,SAAS,mBAAmB,mBAAmB;AAkB/C,SAAS,UAAU,OAAe,KAAa,KAA2B;AACxE,MAAI,QAAQ;AAAK,WAAO;AACxB,MAAI,QAAQ;AAAK,WAAO;AACxB,SAAO;AACT;AAEO,SAAS,aAAa,MAAc,OAAoC;AAC7E,QAAM,WAAW,wBAAwB,QAAQ,EAAE;AACnD,QAAM,MAAM,OAAO,OAAO,YAAY;AACtC,QAAM,MAAM,OAAO,OAAO,SAAS,OAAO,YAAY;AAEtD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,SAAS;AAAA,IAChB;AAAA,IACA;AAAA,IACA,QAAQ,UAAU,SAAS,QAAQ,KAAK,GAAG;AAAA,EAC7C;AACF;AAEO,SAAS,mBAAmB,MAAc,OAAoC;AACnF,QAAM,SAAS,QAAQ,IAAI;AAC3B,QAAM,MAAM,OAAO,OAAO,kBAAkB;AAC5C,QAAM,MAAM,OAAO,OAAO,kBAAkB;AAE5C,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,UAAU,OAAO,KAAK,GAAG;AAAA,EACnC;AACF;","names":[]}
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,MAAM,EAAE,MAAM,SAAS,CAAC;AAG9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAOtD,eAAO,MAAM,SAAS,WACX,eAAe,KAAG,
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,MAAM,EAAE,MAAM,SAAS,CAAC;AAG9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAOtD,eAAO,MAAM,SAAS,WACX,eAAe,KAAG,MA0C1B,CAAC"}
|
package/dist/plugin.js
CHANGED
|
@@ -13,16 +13,31 @@ const seoPlugin = (config) => (incomingConfig) => {
|
|
|
13
13
|
);
|
|
14
14
|
return incomingConfig;
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
const collections = config.collections.filter((c) => {
|
|
17
|
+
if (typeof c.extractContentPath === "string" && c.extractContentPath.trim())
|
|
18
|
+
return true;
|
|
19
|
+
console.warn(
|
|
20
|
+
`${PREFIX} Collection "${c.slug}" is missing a required extractContentPath; SEO analysis disabled for it.`
|
|
21
|
+
);
|
|
22
|
+
return false;
|
|
23
|
+
});
|
|
24
|
+
if (collections.length === 0) {
|
|
25
|
+
console.warn(
|
|
26
|
+
`${PREFIX} Disabled: no collection has a valid extractContentPath. Plugin not registered.`
|
|
27
|
+
);
|
|
28
|
+
return incomingConfig;
|
|
29
|
+
}
|
|
30
|
+
const effectiveConfig = { ...config, collections };
|
|
31
|
+
setPluginConfig(effectiveConfig);
|
|
17
32
|
const merged = mergeTranslations(
|
|
18
33
|
incomingConfig.i18n?.translations ?? {},
|
|
19
|
-
mergeTranslations(en,
|
|
34
|
+
mergeTranslations(en, effectiveConfig.translations ?? {})
|
|
20
35
|
);
|
|
21
36
|
const withTranslations = {
|
|
22
37
|
...incomingConfig,
|
|
23
38
|
i18n: { ...incomingConfig.i18n, translations: merged }
|
|
24
39
|
};
|
|
25
|
-
return overrideAdmin(withTranslations,
|
|
40
|
+
return overrideAdmin(withTranslations, effectiveConfig);
|
|
26
41
|
};
|
|
27
42
|
export {
|
|
28
43
|
seoPlugin
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Config, Plugin } from \"payload\";\nimport { setPluginConfig } from \"./config\";\nimport { PLUGIN_NAME } from \"./constants\";\nimport type { SeoPluginConfig } from \"./types/config\";\nimport { overrideAdmin } from \"./utils/config/overrideAdmin\";\nimport { mergeTranslations } from \"./utils/config/mergeTranslations\";\nimport { en } from \"./translations/en\";\n\nconst PREFIX = `[${PLUGIN_NAME}]`;\n\nexport const seoPlugin =\n (config: SeoPluginConfig): Plugin =>\n (incomingConfig: Config): Config => {\n if (config.disabled) return incomingConfig;\n\n if (!config.collections?.length) {\n console.warn(\n `${PREFIX} Disabled: config.collections must list at least one collection slug. Plugin not registered.`\n );\n return incomingConfig;\n }\n\n setPluginConfig(
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Config, Plugin } from \"payload\";\nimport { setPluginConfig } from \"./config\";\nimport { PLUGIN_NAME } from \"./constants\";\nimport type { SeoPluginConfig } from \"./types/config\";\nimport { overrideAdmin } from \"./utils/config/overrideAdmin\";\nimport { mergeTranslations } from \"./utils/config/mergeTranslations\";\nimport { en } from \"./translations/en\";\n\nconst PREFIX = `[${PLUGIN_NAME}]`;\n\nexport const seoPlugin =\n (config: SeoPluginConfig): Plugin =>\n (incomingConfig: Config): Config => {\n if (config.disabled) return incomingConfig;\n\n if (!config.collections?.length) {\n console.warn(\n `${PREFIX} Disabled: config.collections must list at least one collection slug. Plugin not registered.`\n );\n return incomingConfig;\n }\n\n const collections = config.collections.filter((c) => {\n if (typeof c.extractContentPath === \"string\" && c.extractContentPath.trim()) return true;\n\n console.warn(\n `${PREFIX} Collection \"${c.slug}\" is missing a required extractContentPath; SEO analysis disabled for it.`\n );\n\n return false;\n });\n\n if (collections.length === 0) {\n console.warn(\n `${PREFIX} Disabled: no collection has a valid extractContentPath. Plugin not registered.`\n );\n return incomingConfig;\n }\n\n const effectiveConfig: SeoPluginConfig = { ...config, collections };\n setPluginConfig(effectiveConfig);\n\n const merged = mergeTranslations(\n (incomingConfig.i18n?.translations as never) ?? {},\n mergeTranslations(en, effectiveConfig.translations ?? {})\n );\n\n const withTranslations: Config = {\n ...incomingConfig,\n i18n: { ...incomingConfig.i18n, translations: merged as never },\n };\n\n return overrideAdmin(withTranslations, effectiveConfig);\n };\n"],"mappings":"AACA,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAE5B,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,UAAU;AAEnB,MAAM,SAAS,IAAI,WAAW;AAEvB,MAAM,YACX,CAAC,WACD,CAAC,mBAAmC;AAClC,MAAI,OAAO;AAAU,WAAO;AAE5B,MAAI,CAAC,OAAO,aAAa,QAAQ;AAC/B,YAAQ;AAAA,MACN,GAAG,MAAM;AAAA,IACX;AACA,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,OAAO,YAAY,OAAO,CAAC,MAAM;AACnD,QAAI,OAAO,EAAE,uBAAuB,YAAY,EAAE,mBAAmB,KAAK;AAAG,aAAO;AAEpF,YAAQ;AAAA,MACN,GAAG,MAAM,gBAAgB,EAAE,IAAI;AAAA,IACjC;AAEA,WAAO;AAAA,EACT,CAAC;AAED,MAAI,YAAY,WAAW,GAAG;AAC5B,YAAQ;AAAA,MACN,GAAG,MAAM;AAAA,IACX;AACA,WAAO;AAAA,EACT;AAEA,QAAM,kBAAmC,EAAE,GAAG,QAAQ,YAAY;AAClE,kBAAgB,eAAe;AAE/B,QAAM,SAAS;AAAA,IACZ,eAAe,MAAM,gBAA0B,CAAC;AAAA,IACjD,kBAAkB,IAAI,gBAAgB,gBAAgB,CAAC,CAAC;AAAA,EAC1D;AAEA,QAAM,mBAA2B;AAAA,IAC/B,GAAG;AAAA,IACH,MAAM,EAAE,GAAG,eAAe,MAAM,cAAc,OAAgB;AAAA,EAChE;AAEA,SAAO,cAAc,kBAAkB,eAAe;AACxD;","names":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { SeoClientConfig } from "../client-config/registry";
|
|
3
|
+
export declare function SeoClientConfigProvider({ config, children, }: {
|
|
4
|
+
config: SeoClientConfig;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default SeoClientConfigProvider;
|
|
8
|
+
//# sourceMappingURL=SeoClientConfigProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SeoClientConfigProvider.d.ts","sourceRoot":"","sources":["../../src/providers/SeoClientConfigProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,wBAAgB,uBAAuB,CAAC,EACtC,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,SAAS,CAAC;CACrB,2CAIA;AAED,eAAe,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
3
|
+
import { registerSeoClientConfig } from "../client-config/registry";
|
|
4
|
+
function SeoClientConfigProvider({
|
|
5
|
+
config,
|
|
6
|
+
children
|
|
7
|
+
}) {
|
|
8
|
+
registerSeoClientConfig(config);
|
|
9
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
10
|
+
}
|
|
11
|
+
var SeoClientConfigProvider_default = SeoClientConfigProvider;
|
|
12
|
+
export {
|
|
13
|
+
SeoClientConfigProvider,
|
|
14
|
+
SeoClientConfigProvider_default as default
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=SeoClientConfigProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/providers/SeoClientConfigProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { registerSeoClientConfig } from \"../client-config/registry\";\nimport type { SeoClientConfig } from \"../client-config/registry\";\n\nexport function SeoClientConfigProvider({\n config,\n children,\n}: {\n config: SeoClientConfig;\n children: ReactNode;\n}) {\n registerSeoClientConfig(config);\n\n return <>{children}</>;\n}\n\nexport default SeoClientConfigProvider;\n"],"mappings":";AAeS;AAZT,SAAS,+BAA+B;AAGjC,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AACF,GAGG;AACD,0BAAwB,MAAM;AAE9B,SAAO,gCAAG,UAAS;AACrB;AAEA,IAAO,kCAAQ;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiKey.d.ts","sourceRoot":"","sources":["../../../src/server/generate/apiKey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,wBAAgB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAMzF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
function resolveApiKey(config) {
|
|
2
|
+
const explicit = config?.apiKey?.trim();
|
|
3
|
+
if (explicit)
|
|
4
|
+
return explicit;
|
|
5
|
+
const env = process.env.OPENAI_API_KEY?.trim();
|
|
6
|
+
return env || void 0;
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
resolveApiKey
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=apiKey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/server/generate/apiKey.ts"],"sourcesContent":["import type { SeoGenerationConfig } from \"../../types/config\";\n\nexport function resolveApiKey(config: SeoGenerationConfig | undefined): string | undefined {\n const explicit = config?.apiKey?.trim();\n if (explicit) return explicit;\n\n const env = process.env.OPENAI_API_KEY?.trim();\n return env || undefined;\n}\n"],"mappings":"AAEO,SAAS,cAAc,QAA6D;AACzF,QAAM,WAAW,QAAQ,QAAQ,KAAK;AACtC,MAAI;AAAU,WAAO;AAErB,QAAM,MAAM,QAAQ,IAAI,gBAAgB,KAAK;AAC7C,SAAO,OAAO;AAChB;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.d.ts","sourceRoot":"","sources":["../../../src/server/generate/endpoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,SAAS,CAAC;AAuBxD,wBAAgB,sBAAsB,IAAI,QAAQ,CAsCjD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getPluginConfig } from "../../config";
|
|
2
|
+
import { PLUGIN_NAME } from "../../constants";
|
|
3
|
+
import { GENERATE_ENDPOINT_PATH } from "../../constants/generation";
|
|
4
|
+
import { resolveApiKey } from "./apiKey";
|
|
5
|
+
import { generateForField } from "./generateForField";
|
|
6
|
+
function json(data, status) {
|
|
7
|
+
return Response.json(data, {
|
|
8
|
+
status,
|
|
9
|
+
headers: { "Content-Type": "application/json" }
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function createGenerateEndpoint() {
|
|
13
|
+
return {
|
|
14
|
+
path: GENERATE_ENDPOINT_PATH,
|
|
15
|
+
method: "post",
|
|
16
|
+
handler: async (req) => {
|
|
17
|
+
if (!req.user)
|
|
18
|
+
return json({ error: "Unauthorized" }, 401);
|
|
19
|
+
const config = getPluginConfig();
|
|
20
|
+
const apiKey = resolveApiKey(config.generation);
|
|
21
|
+
if (!apiKey)
|
|
22
|
+
return json({ error: "Generation is not configured" }, 503);
|
|
23
|
+
const body = await req.json?.() ?? {};
|
|
24
|
+
if (body.kind !== "title" && body.kind !== "description" || typeof body.contentHtml !== "string" || !body.range) {
|
|
25
|
+
return json({ error: "Invalid request body" }, 400);
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const text = await generateForField({
|
|
29
|
+
kind: body.kind,
|
|
30
|
+
contentHtml: body.contentHtml,
|
|
31
|
+
range: body.range,
|
|
32
|
+
locale: body.locale,
|
|
33
|
+
config: config.generation ?? {},
|
|
34
|
+
apiKey
|
|
35
|
+
});
|
|
36
|
+
return json({ text }, 200);
|
|
37
|
+
} catch (err) {
|
|
38
|
+
req.payload.logger.error(`[${PLUGIN_NAME}] generation failed: ${err.message}`);
|
|
39
|
+
return json({ error: "Generation failed" }, 502);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
createGenerateEndpoint
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/server/generate/endpoint.ts"],"sourcesContent":["import type { Endpoint, PayloadRequest } from \"payload\";\nimport { getPluginConfig } from \"../../config\";\nimport { PLUGIN_NAME } from \"../../constants\";\nimport { GENERATE_ENDPOINT_PATH } from \"../../constants/generation\";\nimport type { LengthUnit } from \"../../measure/measure\";\nimport { resolveApiKey } from \"./apiKey\";\nimport { generateForField } from \"./generateForField\";\nimport type { SeoFieldKind } from \"./prompts\";\n\ninterface GenerateBody {\n kind?: SeoFieldKind;\n contentHtml?: string;\n locale?: string;\n range?: { min: number; max: number; unit: LengthUnit };\n}\n\nfunction json(data: unknown, status: number): Response {\n return Response.json(data, {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\nexport function createGenerateEndpoint(): Endpoint {\n return {\n path: GENERATE_ENDPOINT_PATH,\n method: \"post\",\n handler: async (req: PayloadRequest): Promise<Response> => {\n if (!req.user) return json({ error: \"Unauthorized\" }, 401);\n\n const config = getPluginConfig();\n const apiKey = resolveApiKey(config.generation);\n if (!apiKey) return json({ error: \"Generation is not configured\" }, 503);\n\n const body = ((await req.json?.()) ?? {}) as GenerateBody;\n if (\n (body.kind !== \"title\" && body.kind !== \"description\") ||\n typeof body.contentHtml !== \"string\" ||\n !body.range\n ) {\n return json({ error: \"Invalid request body\" }, 400);\n }\n\n try {\n const text = await generateForField({\n kind: body.kind,\n contentHtml: body.contentHtml,\n range: body.range,\n locale: body.locale,\n config: config.generation ?? {},\n apiKey,\n });\n\n return json({ text }, 200);\n } catch (err) {\n req.payload.logger.error(`[${PLUGIN_NAME}] generation failed: ${(err as Error).message}`);\n\n return json({ error: \"Generation failed\" }, 502);\n }\n },\n };\n}\n"],"mappings":"AACA,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAC5B,SAAS,8BAA8B;AAEvC,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AAUjC,SAAS,KAAK,MAAe,QAA0B;AACrD,SAAO,SAAS,KAAK,MAAM;AAAA,IACzB;AAAA,IACA,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,EAChD,CAAC;AACH;AAEO,SAAS,yBAAmC;AACjD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS,OAAO,QAA2C;AACzD,UAAI,CAAC,IAAI;AAAM,eAAO,KAAK,EAAE,OAAO,eAAe,GAAG,GAAG;AAEzD,YAAM,SAAS,gBAAgB;AAC/B,YAAM,SAAS,cAAc,OAAO,UAAU;AAC9C,UAAI,CAAC;AAAQ,eAAO,KAAK,EAAE,OAAO,+BAA+B,GAAG,GAAG;AAEvE,YAAM,OAAS,MAAM,IAAI,OAAO,KAAM,CAAC;AACvC,UACG,KAAK,SAAS,WAAW,KAAK,SAAS,iBACxC,OAAO,KAAK,gBAAgB,YAC5B,CAAC,KAAK,OACN;AACA,eAAO,KAAK,EAAE,OAAO,uBAAuB,GAAG,GAAG;AAAA,MACpD;AAEA,UAAI;AACF,cAAM,OAAO,MAAM,iBAAiB;AAAA,UAClC,MAAM,KAAK;AAAA,UACX,aAAa,KAAK;AAAA,UAClB,OAAO,KAAK;AAAA,UACZ,QAAQ,KAAK;AAAA,UACb,QAAQ,OAAO,cAAc,CAAC;AAAA,UAC9B;AAAA,QACF,CAAC;AAED,eAAO,KAAK,EAAE,KAAK,GAAG,GAAG;AAAA,MAC3B,SAAS,KAAK;AACZ,YAAI,QAAQ,OAAO,MAAM,IAAI,WAAW,wBAAyB,IAAc,OAAO,EAAE;AAExF,eAAO,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SeoGenerationConfig } from "../../types/config";
|
|
2
|
+
import type { LengthUnit } from "../../measure/measure";
|
|
3
|
+
import type { SeoFieldKind } from "./prompts";
|
|
4
|
+
export interface GenerateForFieldArgs {
|
|
5
|
+
kind: SeoFieldKind;
|
|
6
|
+
contentHtml: string;
|
|
7
|
+
range: {
|
|
8
|
+
min: number;
|
|
9
|
+
max: number;
|
|
10
|
+
unit: LengthUnit;
|
|
11
|
+
};
|
|
12
|
+
locale?: string;
|
|
13
|
+
config: SeoGenerationConfig;
|
|
14
|
+
apiKey: string;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
}
|
|
17
|
+
export declare function generateForField(args: GenerateForFieldArgs): Promise<string>;
|
|
18
|
+
//# sourceMappingURL=generateForField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateForField.d.ts","sourceRoot":"","sources":["../../../src/server/generate/generateForField.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,YAAY,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE;QACL,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,UAAU,CAAC;KAClB,CAAC;IACF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAoBD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqBlF"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { DEFAULT_MAX_CONTENT_CHARS, DEFAULT_MODEL } from "../../constants/generation";
|
|
2
|
+
import { callOpenAIChat } from "./openai";
|
|
3
|
+
import { buildPrompt } from "./prompts";
|
|
4
|
+
const QUOTE_PAIRS = [
|
|
5
|
+
['"', '"'],
|
|
6
|
+
["'", "'"],
|
|
7
|
+
["\u201C", "\u201D"]
|
|
8
|
+
];
|
|
9
|
+
function stripQuotes(s) {
|
|
10
|
+
const t = s.trim();
|
|
11
|
+
if (t.length < 2)
|
|
12
|
+
return t;
|
|
13
|
+
for (const [open, close] of QUOTE_PAIRS) {
|
|
14
|
+
if (t.startsWith(open) && t.endsWith(close))
|
|
15
|
+
return t.slice(1, -1).trim();
|
|
16
|
+
}
|
|
17
|
+
return t;
|
|
18
|
+
}
|
|
19
|
+
async function generateForField(args) {
|
|
20
|
+
const max = args.config.maxContentChars ?? DEFAULT_MAX_CONTENT_CHARS;
|
|
21
|
+
const contentHtml = args.contentHtml.slice(0, max);
|
|
22
|
+
const { system, user } = buildPrompt({
|
|
23
|
+
kind: args.kind,
|
|
24
|
+
contentHtml,
|
|
25
|
+
range: args.range,
|
|
26
|
+
locale: args.locale,
|
|
27
|
+
config: args.config
|
|
28
|
+
});
|
|
29
|
+
const text = await callOpenAIChat({
|
|
30
|
+
apiKey: args.apiKey,
|
|
31
|
+
model: args.config.model ?? DEFAULT_MODEL,
|
|
32
|
+
system,
|
|
33
|
+
user,
|
|
34
|
+
signal: args.signal
|
|
35
|
+
});
|
|
36
|
+
return stripQuotes(text);
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
generateForField
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=generateForField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/server/generate/generateForField.ts"],"sourcesContent":["import { DEFAULT_MAX_CONTENT_CHARS, DEFAULT_MODEL } from \"../../constants/generation\";\nimport type { SeoGenerationConfig } from \"../../types/config\";\nimport type { LengthUnit } from \"../../measure/measure\";\nimport { callOpenAIChat } from \"./openai\";\nimport type { SeoFieldKind } from \"./prompts\";\nimport { buildPrompt } from \"./prompts\";\n\nexport interface GenerateForFieldArgs {\n kind: SeoFieldKind;\n contentHtml: string;\n range: {\n min: number;\n max: number;\n unit: LengthUnit;\n };\n locale?: string;\n config: SeoGenerationConfig;\n apiKey: string;\n signal?: AbortSignal;\n}\n\nconst QUOTE_PAIRS: ReadonlyArray<readonly [string, string]> = [\n ['\"', '\"'],\n [\"'\", \"'\"],\n [\"“\", \"”\"],\n];\n\nfunction stripQuotes(s: string): string {\n const t = s.trim();\n\n if (t.length < 2) return t;\n\n for (const [open, close] of QUOTE_PAIRS) {\n if (t.startsWith(open) && t.endsWith(close)) return t.slice(1, -1).trim();\n }\n\n return t;\n}\n\nexport async function generateForField(args: GenerateForFieldArgs): Promise<string> {\n const max = args.config.maxContentChars ?? DEFAULT_MAX_CONTENT_CHARS;\n const contentHtml = args.contentHtml.slice(0, max);\n\n const { system, user } = buildPrompt({\n kind: args.kind,\n contentHtml,\n range: args.range,\n locale: args.locale,\n config: args.config,\n });\n\n const text = await callOpenAIChat({\n apiKey: args.apiKey,\n model: args.config.model ?? DEFAULT_MODEL,\n system,\n user,\n signal: args.signal,\n });\n\n return stripQuotes(text);\n}\n"],"mappings":"AAAA,SAAS,2BAA2B,qBAAqB;AAGzD,SAAS,sBAAsB;AAE/B,SAAS,mBAAmB;AAgB5B,MAAM,cAAwD;AAAA,EAC5D,CAAC,KAAK,GAAG;AAAA,EACT,CAAC,KAAK,GAAG;AAAA,EACT,CAAC,UAAK,QAAG;AACX;AAEA,SAAS,YAAY,GAAmB;AACtC,QAAM,IAAI,EAAE,KAAK;AAEjB,MAAI,EAAE,SAAS;AAAG,WAAO;AAEzB,aAAW,CAAC,MAAM,KAAK,KAAK,aAAa;AACvC,QAAI,EAAE,WAAW,IAAI,KAAK,EAAE,SAAS,KAAK;AAAG,aAAO,EAAE,MAAM,GAAG,EAAE,EAAE,KAAK;AAAA,EAC1E;AAEA,SAAO;AACT;AAEA,eAAsB,iBAAiB,MAA6C;AAClF,QAAM,MAAM,KAAK,OAAO,mBAAmB;AAC3C,QAAM,cAAc,KAAK,YAAY,MAAM,GAAG,GAAG;AAEjD,QAAM,EAAE,QAAQ,KAAK,IAAI,YAAY;AAAA,IACnC,MAAM,KAAK;AAAA,IACX;AAAA,IACA,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,QAAQ,KAAK;AAAA,EACf,CAAC;AAED,QAAM,OAAO,MAAM,eAAe;AAAA,IAChC,QAAQ,KAAK;AAAA,IACb,OAAO,KAAK,OAAO,SAAS;AAAA,IAC5B;AAAA,IACA;AAAA,IACA,QAAQ,KAAK;AAAA,EACf,CAAC;AAED,SAAO,YAAY,IAAI;AACzB;","names":[]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface OpenAIChatArgs {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
model: string;
|
|
4
|
+
system: string;
|
|
5
|
+
user: string;
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
}
|
|
8
|
+
export declare function callOpenAIChat({ apiKey, model, system, user, signal, }: OpenAIChatArgs): Promise<string>;
|
|
9
|
+
//# sourceMappingURL=openai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/server/generate/openai.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAQD,wBAAsB,cAAc,CAAC,EACnC,MAAM,EACN,KAAK,EACL,MAAM,EACN,IAAI,EACJ,MAAM,GACP,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAqClC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const ENDPOINT = "https://api.openai.com/v1/chat/completions";
|
|
2
|
+
async function callOpenAIChat({
|
|
3
|
+
apiKey,
|
|
4
|
+
model,
|
|
5
|
+
system,
|
|
6
|
+
user,
|
|
7
|
+
signal
|
|
8
|
+
}) {
|
|
9
|
+
const res = await fetch(ENDPOINT, {
|
|
10
|
+
method: "POST",
|
|
11
|
+
headers: {
|
|
12
|
+
"Content-Type": "application/json",
|
|
13
|
+
Authorization: `Bearer ${apiKey}`
|
|
14
|
+
},
|
|
15
|
+
body: JSON.stringify({
|
|
16
|
+
model,
|
|
17
|
+
temperature: 0.5,
|
|
18
|
+
messages: [
|
|
19
|
+
{ role: "system", content: system },
|
|
20
|
+
{ role: "user", content: user }
|
|
21
|
+
]
|
|
22
|
+
}),
|
|
23
|
+
signal
|
|
24
|
+
});
|
|
25
|
+
if (!res.ok) {
|
|
26
|
+
let kind = "";
|
|
27
|
+
try {
|
|
28
|
+
const errBody = await res.json();
|
|
29
|
+
kind = errBody.error?.code ?? errBody.error?.type ?? "";
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
throw new Error(`OpenAI request failed (${res.status}${kind ? `, ${kind}` : ""})`);
|
|
33
|
+
}
|
|
34
|
+
const body = await res.json();
|
|
35
|
+
const text = body.choices?.[0]?.message?.content?.trim();
|
|
36
|
+
if (!text)
|
|
37
|
+
throw new Error("OpenAI returned an empty completion");
|
|
38
|
+
return text;
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
callOpenAIChat
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/server/generate/openai.ts"],"sourcesContent":["export interface OpenAIChatArgs {\n apiKey: string;\n model: string;\n system: string;\n user: string;\n signal?: AbortSignal;\n}\n\ninterface ChatCompletionResponse {\n choices?: Array<{ message?: { content?: string } }>;\n}\n\nconst ENDPOINT = \"https://api.openai.com/v1/chat/completions\";\n\nexport async function callOpenAIChat({\n apiKey,\n model,\n system,\n user,\n signal,\n}: OpenAIChatArgs): Promise<string> {\n const res = await fetch(ENDPOINT, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model,\n temperature: 0.5,\n messages: [\n { role: \"system\", content: system },\n { role: \"user\", content: user },\n ],\n }),\n signal,\n });\n\n if (!res.ok) {\n let kind = \"\";\n\n try {\n const errBody = (await res.json()) as { error?: { type?: string; code?: string } };\n kind = errBody.error?.code ?? errBody.error?.type ?? \"\";\n } catch {\n // non-JSON error body — ignore it; do not surface raw text\n }\n\n throw new Error(`OpenAI request failed (${res.status}${kind ? `, ${kind}` : \"\"})`);\n }\n\n const body = (await res.json()) as ChatCompletionResponse;\n\n const text = body.choices?.[0]?.message?.content?.trim();\n if (!text) throw new Error(\"OpenAI returned an empty completion\");\n\n return text;\n}\n"],"mappings":"AAYA,MAAM,WAAW;AAEjB,eAAsB,eAAe;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoC;AAClC,QAAM,MAAM,MAAM,MAAM,UAAU;AAAA,IAChC,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,eAAe,UAAU,MAAM;AAAA,IACjC;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACnB;AAAA,MACA,aAAa;AAAA,MACb,UAAU;AAAA,QACR,EAAE,MAAM,UAAU,SAAS,OAAO;AAAA,QAClC,EAAE,MAAM,QAAQ,SAAS,KAAK;AAAA,MAChC;AAAA,IACF,CAAC;AAAA,IACD;AAAA,EACF,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,OAAO;AAEX,QAAI;AACF,YAAM,UAAW,MAAM,IAAI,KAAK;AAChC,aAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,QAAQ;AAAA,IACvD,QAAQ;AAAA,IAER;AAEA,UAAM,IAAI,MAAM,0BAA0B,IAAI,MAAM,GAAG,OAAO,KAAK,IAAI,KAAK,EAAE,GAAG;AAAA,EACnF;AAEA,QAAM,OAAQ,MAAM,IAAI,KAAK;AAE7B,QAAM,OAAO,KAAK,UAAU,CAAC,GAAG,SAAS,SAAS,KAAK;AACvD,MAAI,CAAC;AAAM,UAAM,IAAI,MAAM,qCAAqC;AAEhE,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SeoGenerationConfig } from "../../types/config";
|
|
2
|
+
import type { LengthUnit } from "../../measure/measure";
|
|
3
|
+
export type SeoFieldKind = "title" | "description";
|
|
4
|
+
export interface PromptArgs {
|
|
5
|
+
kind: SeoFieldKind;
|
|
6
|
+
contentHtml: string;
|
|
7
|
+
range: {
|
|
8
|
+
min: number;
|
|
9
|
+
max: number;
|
|
10
|
+
unit: LengthUnit;
|
|
11
|
+
};
|
|
12
|
+
locale?: string;
|
|
13
|
+
config: SeoGenerationConfig;
|
|
14
|
+
}
|
|
15
|
+
export declare function buildPrompt(args: PromptArgs): {
|
|
16
|
+
system: string;
|
|
17
|
+
user: string;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/server/generate/prompts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,aAAa,CAAC;AAEnD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE;QACL,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,UAAU,CAAC;KAClB,CAAC;IACF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,mBAAmB,CAAC;CAC7B;AA2BD,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAO9E"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AVG_GLYPH_PX } from "../../constants/generation";
|
|
2
|
+
function charRangeFromPx(minPx, maxPx) {
|
|
3
|
+
return {
|
|
4
|
+
min: Math.ceil(minPx / AVG_GLYPH_PX),
|
|
5
|
+
max: Math.floor(maxPx / AVG_GLYPH_PX)
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
function defaultSystem(kind, range, locale) {
|
|
9
|
+
const { min, max } = range.unit === "px" ? charRangeFromPx(range.min, range.max) : range;
|
|
10
|
+
const what = kind === "title" ? "an SEO meta title for the web page described by the content below" : "an SEO meta description for the web page described by the content below";
|
|
11
|
+
const lines = [
|
|
12
|
+
`You write ${what}.`,
|
|
13
|
+
`The text MUST be strictly between ${min} and ${max} characters long \u2014 never fewer than ${min} and never more than ${max}, including spaces.`,
|
|
14
|
+
"Summarize the page's actual subject; do not invent facts not present in the content.",
|
|
15
|
+
"Return ONLY the text \u2014 no quotes, no markdown, no labels, no trailing punctuation unless natural."
|
|
16
|
+
];
|
|
17
|
+
if (locale)
|
|
18
|
+
lines.push(`Write in the locale "${locale}".`);
|
|
19
|
+
return lines.join(" ");
|
|
20
|
+
}
|
|
21
|
+
function buildPrompt(args) {
|
|
22
|
+
const override = args.kind === "title" ? args.config.titlePrompt : args.config.descriptionPrompt;
|
|
23
|
+
const system = override ?? defaultSystem(args.kind, args.range, args.locale);
|
|
24
|
+
const user = `Page content:
|
|
25
|
+
|
|
26
|
+
${args.contentHtml}`;
|
|
27
|
+
return { system, user };
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
buildPrompt
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/server/generate/prompts.ts"],"sourcesContent":["import { AVG_GLYPH_PX } from \"../../constants/generation\";\nimport type { SeoGenerationConfig } from \"../../types/config\";\nimport type { LengthUnit } from \"../../measure/measure\";\n\nexport type SeoFieldKind = \"title\" | \"description\";\n\nexport interface PromptArgs {\n kind: SeoFieldKind;\n contentHtml: string;\n range: {\n min: number;\n max: number;\n unit: LengthUnit;\n };\n locale?: string;\n config: SeoGenerationConfig;\n}\n\nfunction charRangeFromPx(minPx: number, maxPx: number): { min: number; max: number } {\n return {\n min: Math.ceil(minPx / AVG_GLYPH_PX),\n max: Math.floor(maxPx / AVG_GLYPH_PX),\n };\n}\n\nfunction defaultSystem(kind: SeoFieldKind, range: PromptArgs[\"range\"], locale?: string): string {\n const { min, max } = range.unit === \"px\" ? charRangeFromPx(range.min, range.max) : range;\n const what =\n kind === \"title\"\n ? \"an SEO meta title for the web page described by the content below\"\n : \"an SEO meta description for the web page described by the content below\";\n const lines = [\n `You write ${what}.`,\n `The text MUST be strictly between ${min} and ${max} characters long — never fewer than ${min} and never more than ${max}, including spaces.`,\n \"Summarize the page's actual subject; do not invent facts not present in the content.\",\n \"Return ONLY the text — no quotes, no markdown, no labels, no trailing punctuation unless natural.\",\n ];\n\n if (locale) lines.push(`Write in the locale \"${locale}\".`);\n\n return lines.join(\" \");\n}\n\nexport function buildPrompt(args: PromptArgs): { system: string; user: string } {\n const override = args.kind === \"title\" ? args.config.titlePrompt : args.config.descriptionPrompt;\n\n const system = override ?? defaultSystem(args.kind, args.range, args.locale);\n const user = `Page content:\\n\\n${args.contentHtml}`;\n\n return { system, user };\n}\n"],"mappings":"AAAA,SAAS,oBAAoB;AAkB7B,SAAS,gBAAgB,OAAe,OAA6C;AACnF,SAAO;AAAA,IACL,KAAK,KAAK,KAAK,QAAQ,YAAY;AAAA,IACnC,KAAK,KAAK,MAAM,QAAQ,YAAY;AAAA,EACtC;AACF;AAEA,SAAS,cAAc,MAAoB,OAA4B,QAAyB;AAC9F,QAAM,EAAE,KAAK,IAAI,IAAI,MAAM,SAAS,OAAO,gBAAgB,MAAM,KAAK,MAAM,GAAG,IAAI;AACnF,QAAM,OACJ,SAAS,UACL,sEACA;AACN,QAAM,QAAQ;AAAA,IACZ,aAAa,IAAI;AAAA,IACjB,qCAAqC,GAAG,QAAQ,GAAG,4CAAuC,GAAG,wBAAwB,GAAG;AAAA,IACxH;AAAA,IACA;AAAA,EACF;AAEA,MAAI;AAAQ,UAAM,KAAK,wBAAwB,MAAM,IAAI;AAEzD,SAAO,MAAM,KAAK,GAAG;AACvB;AAEO,SAAS,YAAY,MAAoD;AAC9E,QAAM,WAAW,KAAK,SAAS,UAAU,KAAK,OAAO,cAAc,KAAK,OAAO;AAE/E,QAAM,SAAS,YAAY,cAAc,KAAK,MAAM,KAAK,OAAO,KAAK,MAAM;AAC3E,QAAM,OAAO;AAAA;AAAA,EAAoB,KAAK,WAAW;AAEjD,SAAO,EAAE,QAAQ,KAAK;AACxB;","names":[]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Payload } from "payload";
|
|
2
|
+
import type { DocQuery, DocStore } from "../../types/config";
|
|
3
|
+
export declare function createServerResolveDocs(payload: Payload, locale: string | undefined): (queries: DocQuery[]) => Promise<DocStore>;
|
|
4
|
+
//# sourceMappingURL=serverResolveDocs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverResolveDocs.d.ts","sourceRoot":"","sources":["../../../src/server/generate/serverResolveDocs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAqC7D,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,CAW5C"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function key(collection, id) {
|
|
2
|
+
return `${collection}:${id}`;
|
|
3
|
+
}
|
|
4
|
+
async function runQuery(payload, query, locale) {
|
|
5
|
+
const ids = [...new Set(query.ids.map(String))];
|
|
6
|
+
if (ids.length === 0)
|
|
7
|
+
return [];
|
|
8
|
+
const select = query.select ? Object.fromEntries(query.select.map((f) => [f, true])) : void 0;
|
|
9
|
+
const result = await payload.find({
|
|
10
|
+
collection: query.collection,
|
|
11
|
+
where: { id: { in: ids } },
|
|
12
|
+
depth: query.depth ?? 0,
|
|
13
|
+
limit: ids.length,
|
|
14
|
+
pagination: false,
|
|
15
|
+
overrideAccess: true,
|
|
16
|
+
...locale ? { locale } : {},
|
|
17
|
+
...select ? { select } : {}
|
|
18
|
+
});
|
|
19
|
+
return result.docs.filter(
|
|
20
|
+
(d) => typeof d.id === "string" || typeof d.id === "number"
|
|
21
|
+
).map((d) => [key(query.collection, d.id), d]);
|
|
22
|
+
}
|
|
23
|
+
function createServerResolveDocs(payload, locale) {
|
|
24
|
+
return async function resolveDocs(queries) {
|
|
25
|
+
const store = /* @__PURE__ */ new Map();
|
|
26
|
+
const results = await Promise.all(queries.map((q) => runQuery(payload, q, locale)));
|
|
27
|
+
for (const entries of results)
|
|
28
|
+
for (const [k, doc] of entries)
|
|
29
|
+
store.set(k, doc);
|
|
30
|
+
return {
|
|
31
|
+
get: (collection, id) => store.get(key(collection, id))
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
createServerResolveDocs
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=serverResolveDocs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/server/generate/serverResolveDocs.ts"],"sourcesContent":["import type { Payload } from \"payload\";\nimport type { DocQuery, DocStore } from \"../../types/config\";\n\ntype Doc = Record<string, unknown>;\n\nfunction key(collection: string, id: string | number): string {\n return `${collection}:${id}`;\n}\n\nasync function runQuery(\n payload: Payload,\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 select = query.select ? Object.fromEntries(query.select.map((f) => [f, true])) : undefined;\n\n const result = await payload.find({\n collection: query.collection as never,\n where: { id: { in: ids } },\n depth: query.depth ?? 0,\n limit: ids.length,\n pagination: false,\n overrideAccess: true,\n ...(locale ? { locale: locale as never } : {}),\n ...(select ? { select: select as never } : {}),\n });\n\n return (result.docs as Array<Doc & { id?: unknown }>)\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}\n\nexport function createServerResolveDocs(\n payload: Payload,\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 const results = await Promise.all(queries.map((q) => runQuery(payload, q, locale)));\n\n for (const entries of results) for (const [k, doc] of entries) store.set(k, doc);\n\n return {\n get: (collection, id) => store.get(key(collection, id)),\n };\n };\n}\n"],"mappings":"AAKA,SAAS,IAAI,YAAoB,IAA6B;AAC5D,SAAO,GAAG,UAAU,IAAI,EAAE;AAC5B;AAEA,eAAe,SACb,SACA,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,MAAM,SAAS,OAAO,YAAY,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI;AAEvF,QAAM,SAAS,MAAM,QAAQ,KAAK;AAAA,IAChC,YAAY,MAAM;AAAA,IAClB,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE;AAAA,IACzB,OAAO,MAAM,SAAS;AAAA,IACtB,OAAO,IAAI;AAAA,IACX,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,GAAI,SAAS,EAAE,OAAwB,IAAI,CAAC;AAAA,IAC5C,GAAI,SAAS,EAAE,OAAwB,IAAI,CAAC;AAAA,EAC9C,CAAC;AAED,SAAQ,OAAO,KACZ;AAAA,IACC,CAAC,MACC,OAAO,EAAE,OAAO,YAAY,OAAO,EAAE,OAAO;AAAA,EAChD,EACC,IAAI,CAAC,MAAM,CAAC,IAAI,MAAM,YAAY,EAAE,EAAE,GAAG,CAAC,CAAkB;AACjE;AAEO,SAAS,wBACd,SACA,QAC4C;AAC5C,SAAO,eAAe,YAAY,SAAwC;AACxE,UAAM,QAAQ,oBAAI,IAAiB;AACnC,UAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ,IAAI,CAAC,MAAM,SAAS,SAAS,GAAG,MAAM,CAAC,CAAC;AAElF,eAAW,WAAW;AAAS,iBAAW,CAAC,GAAG,GAAG,KAAK;AAAS,cAAM,IAAI,GAAG,GAAG;AAE/E,WAAO;AAAA,MACL,KAAK,CAAC,YAAY,OAAO,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;AAAA,IACxD;AAAA,EACF;AACF;","names":[]}
|
package/dist/types/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ContentNode } from "../content/schema/nodes";
|
|
1
|
+
import type { ContentNode, HeadingLevel } from "../content/schema/nodes";
|
|
2
2
|
import type { Translations } from "../translations/types";
|
|
3
3
|
/** Runtime context handed to a content extractor so it can resolve references and locale-correct hrefs. */
|
|
4
4
|
export interface ExtractContext {
|
|
@@ -7,17 +7,10 @@ export interface ExtractContext {
|
|
|
7
7
|
/** Payload REST API route (e.g. "/api") for client-side reference fetches. */
|
|
8
8
|
apiRoute?: string;
|
|
9
9
|
}
|
|
10
|
-
/**
|
|
11
|
-
export type ContentExtractor = (values: Record<string, unknown>, ctx
|
|
12
|
-
/** Which parts of the document the built-in extractor walks. */
|
|
13
|
-
export interface ContentSelection {
|
|
14
|
-
/** Dot-paths to walk, in order. Omitted or empty = whole document root. */
|
|
15
|
-
include?: string[];
|
|
16
|
-
/** Dot-paths to skip (merged with auto-excluded seoTitle/metaDescription/slug). */
|
|
17
|
-
exclude?: string[];
|
|
18
|
-
}
|
|
10
|
+
/** Developer-authored extractor: raw form values + runtime ctx + injected toolkit → content schema (Intermediate Representation). */
|
|
11
|
+
export type ContentExtractor = (values: Record<string, unknown>, ctx: ExtractContext, toolkit: ExtractToolkit) => ContentNode[] | Promise<ContentNode[]>;
|
|
19
12
|
export interface SeoFieldPaths {
|
|
20
|
-
/** Dot-path to the SEO title. Falls back to
|
|
13
|
+
/** Dot-path to the SEO title. Falls back to `title` if absent. */
|
|
21
14
|
seoTitle?: string;
|
|
22
15
|
/** Dot-path to the meta description. Absent → meta-desc checks disabled + snippet has no description. */
|
|
23
16
|
metaDescription?: string;
|
|
@@ -26,37 +19,80 @@ export interface SeoFieldPaths {
|
|
|
26
19
|
* @default "slug"
|
|
27
20
|
*/
|
|
28
21
|
slug?: string;
|
|
29
|
-
/**
|
|
30
|
-
* Built-in content selection. A string is a single field path.
|
|
31
|
-
* An object selects include/exclude paths over the whole document.
|
|
32
|
-
* Ignored when `extractContentPath` is set and registered.
|
|
33
|
-
*/
|
|
34
|
-
content?: string | ContentSelection;
|
|
35
22
|
}
|
|
36
23
|
export interface SeoCollectionConfig {
|
|
37
24
|
slug: string;
|
|
38
25
|
fields?: SeoFieldPaths;
|
|
39
26
|
/**
|
|
40
|
-
* importMap path string used as the lookup key for a registered ContentExtractor
|
|
41
|
-
* Register the function via registerContentExtractors from
|
|
27
|
+
* importMap path string used as the lookup key for a registered ContentExtractor.
|
|
28
|
+
* Register the function via registerContentExtractors from
|
|
29
|
+
* "@focus-reactive/payload-plugin-seo/content" in an admin-mounted client module.
|
|
42
30
|
*/
|
|
43
|
-
extractContentPath
|
|
31
|
+
extractContentPath: string;
|
|
44
32
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
33
|
+
* Server-side content extractor for on-publish generation. Same contract as the
|
|
34
|
+
* client ContentExtractor, but `toolkit.resolveDocs` is backed by the Payload Local API and
|
|
35
|
+
* `values` is the document being saved. May be the SAME function as the client extractor when
|
|
36
|
+
* it only reads ids + injected resolveDocs (it is runtime-agnostic).
|
|
47
37
|
*/
|
|
48
|
-
|
|
38
|
+
serverExtractContent?: ContentExtractor;
|
|
49
39
|
}
|
|
50
40
|
export interface SeoSiteConfig {
|
|
51
41
|
name?: string;
|
|
52
42
|
baseUrl?: string;
|
|
53
43
|
faviconUrl?: string;
|
|
54
44
|
}
|
|
45
|
+
export interface SeoGenerationConfig {
|
|
46
|
+
/** OpenAI chat model.
|
|
47
|
+
* @default "gpt-4o-mini"
|
|
48
|
+
*/
|
|
49
|
+
model?: string;
|
|
50
|
+
/** Explicit API key.
|
|
51
|
+
* @default process.env.OPENAI_API_KEY
|
|
52
|
+
*/
|
|
53
|
+
apiKey?: string;
|
|
54
|
+
/** Max chars of serialized page content sent to the model.
|
|
55
|
+
* @default 6000
|
|
56
|
+
*/
|
|
57
|
+
maxContentChars?: number;
|
|
58
|
+
/** Override the system prompt for title generation. */
|
|
59
|
+
titlePrompt?: string;
|
|
60
|
+
/** Override the system prompt for description generation. */
|
|
61
|
+
descriptionPrompt?: string;
|
|
62
|
+
}
|
|
55
63
|
export interface SeoPluginConfig {
|
|
56
64
|
disabled?: boolean;
|
|
57
65
|
collections: SeoCollectionConfig[];
|
|
58
66
|
site?: SeoSiteConfig;
|
|
59
67
|
supportedLocales?: string[];
|
|
60
68
|
translations?: Translations;
|
|
69
|
+
generation?: SeoGenerationConfig;
|
|
70
|
+
}
|
|
71
|
+
export interface DocQuery {
|
|
72
|
+
collection: string;
|
|
73
|
+
ids: (string | number)[];
|
|
74
|
+
/** Payload field-projection: only these top-level fields are returned. */
|
|
75
|
+
select?: string[];
|
|
76
|
+
/** Payload relationship-population depth.
|
|
77
|
+
* @default 0
|
|
78
|
+
*/
|
|
79
|
+
depth?: number;
|
|
80
|
+
}
|
|
81
|
+
export interface DocStore {
|
|
82
|
+
get(collection: string, id: string | number): Record<string, unknown> | undefined;
|
|
83
|
+
}
|
|
84
|
+
export interface ContentHelpers {
|
|
85
|
+
heading: (level: HeadingLevel, text?: string | null) => ContentNode | null;
|
|
86
|
+
paragraph: (text?: string | null) => ContentNode | null;
|
|
87
|
+
link: (href?: string | null, text?: string | null) => ContentNode | null;
|
|
88
|
+
image: (src?: string | null, alt?: string | null) => ContentNode | null;
|
|
89
|
+
video: (src?: string | null, poster?: string | null) => ContentNode | null;
|
|
90
|
+
html: (raw?: string | null) => ContentNode | null;
|
|
91
|
+
richText: (value: unknown) => ContentNode | null;
|
|
92
|
+
compact: (nodes: (ContentNode | null | undefined)[]) => ContentNode[];
|
|
93
|
+
}
|
|
94
|
+
export interface ExtractToolkit {
|
|
95
|
+
resolveDocs: (queries: DocQuery[]) => Promise<DocStore>;
|
|
96
|
+
helpers: ContentHelpers;
|
|
61
97
|
}
|
|
62
98
|
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,2GAA2G;AAC3G,MAAM,WAAW,cAAc;IAC7B,+FAA+F;IAC/F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qIAAqI;AACrI,MAAM,MAAM,gBAAgB,GAAG,CAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,cAAc,KACpB,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yGAAyG;IACzG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB;;;;OAIG;IACH,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,gBAAgB,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,UAAU,CAAC,EAAE,mBAAmB,CAAC;CAClC;AAED,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACzB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CACnF;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,WAAW,GAAG,IAAI,CAAC;IAC3E,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,WAAW,GAAG,IAAI,CAAC;IACxD,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,WAAW,GAAG,IAAI,CAAC;IACzE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,WAAW,GAAG,IAAI,CAAC;IACxE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,WAAW,GAAG,IAAI,CAAC;IAC3E,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,WAAW,GAAG,IAAI,CAAC;IAClD,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,WAAW,GAAG,IAAI,CAAC;IACjD,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,KAAK,WAAW,EAAE,CAAC;CACvE;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxD,OAAO,EAAE,cAAc,CAAC;CACzB"}
|