@aglyn/plugins-ai 1.0.0-beta.143
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/LICENSE +201 -0
- package/README.md +25 -0
- package/package.json +60 -0
- package/src/index.d.ts +21 -0
- package/src/index.js +22 -0
- package/src/index.js.map +1 -0
- package/src/lib/activity/ai-activity-actions.d.ts +106 -0
- package/src/lib/activity/ai-activity-actions.js +209 -0
- package/src/lib/activity/ai-activity-actions.js.map +1 -0
- package/src/lib/activity/ai-activity.d.ts +219 -0
- package/src/lib/activity/ai-activity.js +251 -0
- package/src/lib/activity/ai-activity.js.map +1 -0
- package/src/lib/billing/ai-overage-charge.d.ts +102 -0
- package/src/lib/billing/ai-overage-charge.js +258 -0
- package/src/lib/billing/ai-overage-charge.js.map +1 -0
- package/src/lib/billing/ai-overage-close.d.ts +62 -0
- package/src/lib/billing/ai-overage-close.js +129 -0
- package/src/lib/billing/ai-overage-close.js.map +1 -0
- package/src/lib/billing/ai-overage-cutover.d.ts +63 -0
- package/src/lib/billing/ai-overage-cutover.js +114 -0
- package/src/lib/billing/ai-overage-cutover.js.map +1 -0
- package/src/lib/billing/ai-overage-events.d.ts +77 -0
- package/src/lib/billing/ai-overage-events.js +174 -0
- package/src/lib/billing/ai-overage-events.js.map +1 -0
- package/src/lib/billing/ai-overage-gate.d.ts +147 -0
- package/src/lib/billing/ai-overage-gate.js +177 -0
- package/src/lib/billing/ai-overage-gate.js.map +1 -0
- package/src/lib/billing/ai-overage-ledger.d.ts +135 -0
- package/src/lib/billing/ai-overage-ledger.js +278 -0
- package/src/lib/billing/ai-overage-ledger.js.map +1 -0
- package/src/lib/billing/ai-overage-standing-writes.d.ts +110 -0
- package/src/lib/billing/ai-overage-standing-writes.js +205 -0
- package/src/lib/billing/ai-overage-standing-writes.js.map +1 -0
- package/src/lib/billing/ai-overage-standing.d.ts +168 -0
- package/src/lib/billing/ai-overage-standing.js +215 -0
- package/src/lib/billing/ai-overage-standing.js.map +1 -0
- package/src/lib/billing/ai-overage-trigger.d.ts +30 -0
- package/src/lib/billing/ai-overage-trigger.js +76 -0
- package/src/lib/billing/ai-overage-trigger.js.map +1 -0
- package/src/lib/components/ai-allotment-editor.component.d.ts +40 -0
- package/src/lib/components/ai-allotment-editor.component.js +213 -0
- package/src/lib/components/ai-allotment-editor.component.js.map +1 -0
- package/src/lib/components/ai-assist-actions-context.d.ts +13 -0
- package/src/lib/components/ai-assist-actions-context.js +21 -0
- package/src/lib/components/ai-assist-actions-context.js.map +1 -0
- package/src/lib/components/ai-assist-provider.component.d.ts +51 -0
- package/src/lib/components/ai-assist-provider.component.js +519 -0
- package/src/lib/components/ai-assist-provider.component.js.map +1 -0
- package/src/lib/components/ai-brief-dialog.component.d.ts +56 -0
- package/src/lib/components/ai-brief-dialog.component.js +319 -0
- package/src/lib/components/ai-brief-dialog.component.js.map +1 -0
- package/src/lib/components/ai-collaborator-permissions-column.component.d.ts +32 -0
- package/src/lib/components/ai-collaborator-permissions-column.component.js +132 -0
- package/src/lib/components/ai-collaborator-permissions-column.component.js.map +1 -0
- package/src/lib/components/ai-credits-card.component.d.ts +34 -0
- package/src/lib/components/ai-credits-card.component.js +131 -0
- package/src/lib/components/ai-credits-card.component.js.map +1 -0
- package/src/lib/components/ai-credits-columns.component.d.ts +56 -0
- package/src/lib/components/ai-credits-columns.component.js +118 -0
- package/src/lib/components/ai-credits-columns.component.js.map +1 -0
- package/src/lib/components/ai-crm-email-draft.component.d.ts +17 -0
- package/src/lib/components/ai-crm-email-draft.component.js +159 -0
- package/src/lib/components/ai-crm-email-draft.component.js.map +1 -0
- package/src/lib/components/ai-crm-import-mapping.component.d.ts +20 -0
- package/src/lib/components/ai-crm-import-mapping.component.js +167 -0
- package/src/lib/components/ai-crm-import-mapping.component.js.map +1 -0
- package/src/lib/components/ai-crm-record-card.component.d.ts +27 -0
- package/src/lib/components/ai-crm-record-card.component.js +263 -0
- package/src/lib/components/ai-crm-record-card.component.js.map +1 -0
- package/src/lib/components/ai-describe-automation.component.d.ts +31 -0
- package/src/lib/components/ai-describe-automation.component.js +226 -0
- package/src/lib/components/ai-describe-automation.component.js.map +1 -0
- package/src/lib/components/ai-describe-button.component.d.ts +39 -0
- package/src/lib/components/ai-describe-button.component.js +87 -0
- package/src/lib/components/ai-describe-button.component.js.map +1 -0
- package/src/lib/components/ai-describe-page.component.d.ts +26 -0
- package/src/lib/components/ai-describe-page.component.js +18 -0
- package/src/lib/components/ai-describe-page.component.js.map +1 -0
- package/src/lib/components/ai-experiment-cards.component.d.ts +75 -0
- package/src/lib/components/ai-experiment-cards.component.js +573 -0
- package/src/lib/components/ai-experiment-cards.component.js.map +1 -0
- package/src/lib/components/ai-explain-automation.component.d.ts +31 -0
- package/src/lib/components/ai-explain-automation.component.js +265 -0
- package/src/lib/components/ai-explain-automation.component.js.map +1 -0
- package/src/lib/components/ai-insight-dialog.component.d.ts +37 -0
- package/src/lib/components/ai-insight-dialog.component.js +441 -0
- package/src/lib/components/ai-insight-dialog.component.js.map +1 -0
- package/src/lib/components/ai-job-plan.component.d.ts +46 -0
- package/src/lib/components/ai-job-plan.component.js +192 -0
- package/src/lib/components/ai-job-plan.component.js.map +1 -0
- package/src/lib/components/ai-model-selector.component.d.ts +21 -0
- package/src/lib/components/ai-model-selector.component.js +109 -0
- package/src/lib/components/ai-model-selector.component.js.map +1 -0
- package/src/lib/components/ai-page-brief-dialog.component.d.ts +29 -0
- package/src/lib/components/ai-page-brief-dialog.component.js +27 -0
- package/src/lib/components/ai-page-brief-dialog.component.js.map +1 -0
- package/src/lib/components/ai-permissions-on-host.component.d.ts +55 -0
- package/src/lib/components/ai-permissions-on-host.component.js +91 -0
- package/src/lib/components/ai-permissions-on-host.component.js.map +1 -0
- package/src/lib/components/ai-product-copy-card.component.d.ts +25 -0
- package/src/lib/components/ai-product-copy-card.component.js +328 -0
- package/src/lib/components/ai-product-copy-card.component.js.map +1 -0
- package/src/lib/components/ai-product-import-option.component.d.ts +14 -0
- package/src/lib/components/ai-product-import-option.component.js +58 -0
- package/src/lib/components/ai-product-import-option.component.js.map +1 -0
- package/src/lib/components/ai-products-hub-card.component.d.ts +15 -0
- package/src/lib/components/ai-products-hub-card.component.js +418 -0
- package/src/lib/components/ai-products-hub-card.component.js.map +1 -0
- package/src/lib/components/ai-products-proposals.component.d.ts +19 -0
- package/src/lib/components/ai-products-proposals.component.js +547 -0
- package/src/lib/components/ai-products-proposals.component.js.map +1 -0
- package/src/lib/components/ai-save-as-component.component.d.ts +38 -0
- package/src/lib/components/ai-save-as-component.component.js +231 -0
- package/src/lib/components/ai-save-as-component.component.js.map +1 -0
- package/src/lib/components/ai-seo-audit-card.component.d.ts +9 -0
- package/src/lib/components/ai-seo-audit-card.component.js +620 -0
- package/src/lib/components/ai-seo-audit-card.component.js.map +1 -0
- package/src/lib/components/ai-seo-fields-card.component.d.ts +10 -0
- package/src/lib/components/ai-seo-fields-card.component.js +453 -0
- package/src/lib/components/ai-seo-fields-card.component.js.map +1 -0
- package/src/lib/components/ai-site-batch-card.component.d.ts +32 -0
- package/src/lib/components/ai-site-batch-card.component.js +531 -0
- package/src/lib/components/ai-site-batch-card.component.js.map +1 -0
- package/src/lib/components/ai-site-seo-start-card.component.d.ts +26 -0
- package/src/lib/components/ai-site-seo-start-card.component.js +178 -0
- package/src/lib/components/ai-site-seo-start-card.component.js.map +1 -0
- package/src/lib/components/ai-site-start-card.component.d.ts +19 -0
- package/src/lib/components/ai-site-start-card.component.js +348 -0
- package/src/lib/components/ai-site-start-card.component.js.map +1 -0
- package/src/lib/components/ai-template-collection-field.component.d.ts +32 -0
- package/src/lib/components/ai-template-collection-field.component.js +63 -0
- package/src/lib/components/ai-template-collection-field.component.js.map +1 -0
- package/src/lib/components/ai-theme-proposal-card.component.d.ts +6 -0
- package/src/lib/components/ai-theme-proposal-card.component.js +619 -0
- package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -0
- package/src/lib/components/ai-usage-strip.component.d.ts +27 -0
- package/src/lib/components/ai-usage-strip.component.js +145 -0
- package/src/lib/components/ai-usage-strip.component.js.map +1 -0
- package/src/lib/components/assist-edit-canvas.d.ts +169 -0
- package/src/lib/components/assist-edit-canvas.js +636 -0
- package/src/lib/components/assist-edit-canvas.js.map +1 -0
- package/src/lib/components/assist-edit-card.component.d.ts +16 -0
- package/src/lib/components/assist-edit-card.component.js +181 -0
- package/src/lib/components/assist-edit-card.component.js.map +1 -0
- package/src/lib/components/assist-jobs-drawer.component.d.ts +72 -0
- package/src/lib/components/assist-jobs-drawer.component.js +626 -0
- package/src/lib/components/assist-jobs-drawer.component.js.map +1 -0
- package/src/lib/components/assist-panel.component.d.ts +136 -0
- package/src/lib/components/assist-panel.component.js +1099 -0
- package/src/lib/components/assist-panel.component.js.map +1 -0
- package/src/lib/components/assist-signals-page.component.d.ts +3 -0
- package/src/lib/components/assist-signals-page.component.js +1017 -0
- package/src/lib/components/assist-signals-page.component.js.map +1 -0
- package/src/lib/components/besigner-ai-controls.component.d.ts +29 -0
- package/src/lib/components/besigner-ai-controls.component.js +81 -0
- package/src/lib/components/besigner-ai-controls.component.js.map +1 -0
- package/src/lib/components/billing-ai-allotments.component.d.ts +36 -0
- package/src/lib/components/billing-ai-allotments.component.js +486 -0
- package/src/lib/components/billing-ai-allotments.component.js.map +1 -0
- package/src/lib/components/billing-ai-top-users.component.d.ts +44 -0
- package/src/lib/components/billing-ai-top-users.component.js +304 -0
- package/src/lib/components/billing-ai-top-users.component.js.map +1 -0
- package/src/lib/components/billing-assist-overage-card.component.d.ts +69 -0
- package/src/lib/components/billing-assist-overage-card.component.js +437 -0
- package/src/lib/components/billing-assist-overage-card.component.js.map +1 -0
- package/src/lib/components/host-ai-allotments.component.d.ts +40 -0
- package/src/lib/components/host-ai-allotments.component.js +239 -0
- package/src/lib/components/host-ai-allotments.component.js.map +1 -0
- package/src/lib/components/member-ai-allotment-card.component.d.ts +28 -0
- package/src/lib/components/member-ai-allotment-card.component.js +172 -0
- package/src/lib/components/member-ai-allotment-card.component.js.map +1 -0
- package/src/lib/components/member-ai-usage-card.component.d.ts +28 -0
- package/src/lib/components/member-ai-usage-card.component.js +240 -0
- package/src/lib/components/member-ai-usage-card.component.js.map +1 -0
- package/src/lib/components/staff-org-ai-card.component.d.ts +17 -0
- package/src/lib/components/staff-org-ai-card.component.js +739 -0
- package/src/lib/components/staff-org-ai-card.component.js.map +1 -0
- package/src/lib/components/staff-org-usage-ai-columns.component.d.ts +41 -0
- package/src/lib/components/staff-org-usage-ai-columns.component.js +65 -0
- package/src/lib/components/staff-org-usage-ai-columns.component.js.map +1 -0
- package/src/lib/components/staff-orgs-ai-spend-column.component.d.ts +28 -0
- package/src/lib/components/staff-orgs-ai-spend-column.component.js +89 -0
- package/src/lib/components/staff-orgs-ai-spend-column.component.js.map +1 -0
- package/src/lib/components/staff-user-ai-usage-card.component.d.ts +27 -0
- package/src/lib/components/staff-user-ai-usage-card.component.js +183 -0
- package/src/lib/components/staff-user-ai-usage-card.component.js.map +1 -0
- package/src/lib/components/use-ai-allotments.d.ts +49 -0
- package/src/lib/components/use-ai-allotments.js +171 -0
- package/src/lib/components/use-ai-allotments.js.map +1 -0
- package/src/lib/components/use-ai-crm-answer.d.ts +50 -0
- package/src/lib/components/use-ai-crm-answer.js +220 -0
- package/src/lib/components/use-ai-crm-answer.js.map +1 -0
- package/src/lib/components/use-ai-job-run.d.ts +51 -0
- package/src/lib/components/use-ai-job-run.js +176 -0
- package/src/lib/components/use-ai-job-run.js.map +1 -0
- package/src/lib/components/use-ai-model-choice.d.ts +47 -0
- package/src/lib/components/use-ai-model-choice.js +150 -0
- package/src/lib/components/use-ai-model-choice.js.map +1 -0
- package/src/lib/components/use-ai-products-jobs.d.ts +36 -0
- package/src/lib/components/use-ai-products-jobs.js +190 -0
- package/src/lib/components/use-ai-products-jobs.js.map +1 -0
- package/src/lib/components/use-ai-usage-meter.d.ts +11 -0
- package/src/lib/components/use-ai-usage-meter.js +96 -0
- package/src/lib/components/use-ai-usage-meter.js.map +1 -0
- package/src/lib/components/use-org-ai-usage.d.ts +42 -0
- package/src/lib/components/use-org-ai-usage.js +181 -0
- package/src/lib/components/use-org-ai-usage.js.map +1 -0
- package/src/lib/components/use-staff-orgs-ai-spend.d.ts +18 -0
- package/src/lib/components/use-staff-orgs-ai-spend.js +127 -0
- package/src/lib/components/use-staff-orgs-ai-spend.js.map +1 -0
- package/src/lib/constants.d.ts +24 -0
- package/src/lib/constants.js +23 -0
- package/src/lib/constants.js.map +1 -0
- package/src/lib/declarations.d.ts +48 -0
- package/src/lib/declarations.js +129 -0
- package/src/lib/declarations.js.map +1 -0
- package/src/lib/declarations.server.d.ts +35 -0
- package/src/lib/declarations.server.js +138 -0
- package/src/lib/declarations.server.js.map +1 -0
- package/src/lib/insights/ai-figure-readers.d.ts +90 -0
- package/src/lib/insights/ai-figure-readers.js +863 -0
- package/src/lib/insights/ai-figure-readers.js.map +1 -0
- package/src/lib/insights/ai-insight-digest.d.ts +165 -0
- package/src/lib/insights/ai-insight-digest.js +363 -0
- package/src/lib/insights/ai-insight-digest.js.map +1 -0
- package/src/lib/insights/ai-insight-readers.d.ts +71 -0
- package/src/lib/insights/ai-insight-readers.js +141 -0
- package/src/lib/insights/ai-insight-readers.js.map +1 -0
- package/src/lib/jobs/ai-crm-access.d.ts +61 -0
- package/src/lib/jobs/ai-crm-access.js +94 -0
- package/src/lib/jobs/ai-crm-access.js.map +1 -0
- package/src/lib/jobs/ai-email-bindings.d.ts +97 -0
- package/src/lib/jobs/ai-email-bindings.js +147 -0
- package/src/lib/jobs/ai-email-bindings.js.map +1 -0
- package/src/lib/jobs/ai-job-admission.d.ts +82 -0
- package/src/lib/jobs/ai-job-admission.js +45 -0
- package/src/lib/jobs/ai-job-admission.js.map +1 -0
- package/src/lib/jobs/ai-job-budget.d.ts +167 -0
- package/src/lib/jobs/ai-job-budget.js +161 -0
- package/src/lib/jobs/ai-job-budget.js.map +1 -0
- package/src/lib/jobs/ai-job-campaign-step.d.ts +108 -0
- package/src/lib/jobs/ai-job-campaign-step.js +340 -0
- package/src/lib/jobs/ai-job-campaign-step.js.map +1 -0
- package/src/lib/jobs/ai-job-component-checks.d.ts +74 -0
- package/src/lib/jobs/ai-job-component-checks.js +442 -0
- package/src/lib/jobs/ai-job-component-checks.js.map +1 -0
- package/src/lib/jobs/ai-job-component-step.d.ts +75 -0
- package/src/lib/jobs/ai-job-component-step.js +262 -0
- package/src/lib/jobs/ai-job-component-step.js.map +1 -0
- package/src/lib/jobs/ai-job-crm-step.d.ts +192 -0
- package/src/lib/jobs/ai-job-crm-step.js +734 -0
- package/src/lib/jobs/ai-job-crm-step.js.map +1 -0
- package/src/lib/jobs/ai-job-draft-ids.d.ts +62 -0
- package/src/lib/jobs/ai-job-draft-ids.js +132 -0
- package/src/lib/jobs/ai-job-draft-ids.js.map +1 -0
- package/src/lib/jobs/ai-job-drafts.d.ts +304 -0
- package/src/lib/jobs/ai-job-drafts.js +557 -0
- package/src/lib/jobs/ai-job-drafts.js.map +1 -0
- package/src/lib/jobs/ai-job-email-step.d.ts +195 -0
- package/src/lib/jobs/ai-job-email-step.js +547 -0
- package/src/lib/jobs/ai-job-email-step.js.map +1 -0
- package/src/lib/jobs/ai-job-experiment-step.d.ts +105 -0
- package/src/lib/jobs/ai-job-experiment-step.js +445 -0
- package/src/lib/jobs/ai-job-experiment-step.js.map +1 -0
- package/src/lib/jobs/ai-job-form-step.d.ts +250 -0
- package/src/lib/jobs/ai-job-form-step.js +634 -0
- package/src/lib/jobs/ai-job-form-step.js.map +1 -0
- package/src/lib/jobs/ai-job-generation.d.ts +114 -0
- package/src/lib/jobs/ai-job-generation.js +384 -0
- package/src/lib/jobs/ai-job-generation.js.map +1 -0
- package/src/lib/jobs/ai-job-insight-budget.d.ts +41 -0
- package/src/lib/jobs/ai-job-insight-budget.js +46 -0
- package/src/lib/jobs/ai-job-insight-budget.js.map +1 -0
- package/src/lib/jobs/ai-job-insight-step.d.ts +58 -0
- package/src/lib/jobs/ai-job-insight-step.js +350 -0
- package/src/lib/jobs/ai-job-insight-step.js.map +1 -0
- package/src/lib/jobs/ai-job-layout-step.d.ts +103 -0
- package/src/lib/jobs/ai-job-layout-step.js +340 -0
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -0
- package/src/lib/jobs/ai-job-page-budget.d.ts +57 -0
- package/src/lib/jobs/ai-job-page-budget.js +60 -0
- package/src/lib/jobs/ai-job-page-budget.js.map +1 -0
- package/src/lib/jobs/ai-job-page-sections.d.ts +150 -0
- package/src/lib/jobs/ai-job-page-sections.js +450 -0
- package/src/lib/jobs/ai-job-page-sections.js.map +1 -0
- package/src/lib/jobs/ai-job-page-step.d.ts +198 -0
- package/src/lib/jobs/ai-job-page-step.js +667 -0
- package/src/lib/jobs/ai-job-page-step.js.map +1 -0
- package/src/lib/jobs/ai-job-plan-conformance.d.ts +107 -0
- package/src/lib/jobs/ai-job-plan-conformance.js +164 -0
- package/src/lib/jobs/ai-job-plan-conformance.js.map +1 -0
- package/src/lib/jobs/ai-job-plan-step.d.ts +196 -0
- package/src/lib/jobs/ai-job-plan-step.js +458 -0
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -0
- package/src/lib/jobs/ai-job-plugin-drafts.d.ts +76 -0
- package/src/lib/jobs/ai-job-plugin-drafts.js +91 -0
- package/src/lib/jobs/ai-job-plugin-drafts.js.map +1 -0
- package/src/lib/jobs/ai-job-products-step.d.ts +106 -0
- package/src/lib/jobs/ai-job-products-step.js +436 -0
- package/src/lib/jobs/ai-job-products-step.js.map +1 -0
- package/src/lib/jobs/ai-job-seo-budget.d.ts +52 -0
- package/src/lib/jobs/ai-job-seo-budget.js +63 -0
- package/src/lib/jobs/ai-job-seo-budget.js.map +1 -0
- package/src/lib/jobs/ai-job-seo-step.d.ts +145 -0
- package/src/lib/jobs/ai-job-seo-step.js +809 -0
- package/src/lib/jobs/ai-job-seo-step.js.map +1 -0
- package/src/lib/jobs/ai-job-site-step.d.ts +252 -0
- package/src/lib/jobs/ai-job-site-step.js +538 -0
- package/src/lib/jobs/ai-job-site-step.js.map +1 -0
- package/src/lib/jobs/ai-job-template-step.d.ts +105 -0
- package/src/lib/jobs/ai-job-template-step.js +391 -0
- package/src/lib/jobs/ai-job-template-step.js.map +1 -0
- package/src/lib/jobs/ai-job-text-step.d.ts +125 -0
- package/src/lib/jobs/ai-job-text-step.js +128 -0
- package/src/lib/jobs/ai-job-text-step.js.map +1 -0
- package/src/lib/jobs/ai-job-theme-budget.d.ts +38 -0
- package/src/lib/jobs/ai-job-theme-budget.js +43 -0
- package/src/lib/jobs/ai-job-theme-budget.js.map +1 -0
- package/src/lib/jobs/ai-job-theme-step.d.ts +115 -0
- package/src/lib/jobs/ai-job-theme-step.js +337 -0
- package/src/lib/jobs/ai-job-theme-step.js.map +1 -0
- package/src/lib/jobs/ai-job-workflow-step.d.ts +139 -0
- package/src/lib/jobs/ai-job-workflow-step.js +530 -0
- package/src/lib/jobs/ai-job-workflow-step.js.map +1 -0
- package/src/lib/jobs/ai-jobs-beat.d.ts +78 -0
- package/src/lib/jobs/ai-jobs-beat.js +93 -0
- package/src/lib/jobs/ai-jobs-beat.js.map +1 -0
- package/src/lib/jobs/ai-jobs-pause.d.ts +38 -0
- package/src/lib/jobs/ai-jobs-pause.js +45 -0
- package/src/lib/jobs/ai-jobs-pause.js.map +1 -0
- package/src/lib/jobs/ai-jobs.d.ts +558 -0
- package/src/lib/jobs/ai-jobs.js +1410 -0
- package/src/lib/jobs/ai-jobs.js.map +1 -0
- package/src/lib/jobs/ai-media-asset-server.d.ts +34 -0
- package/src/lib/jobs/ai-media-asset-server.js +34 -0
- package/src/lib/jobs/ai-media-asset-server.js.map +1 -0
- package/src/lib/jobs/ai-media-asset.d.ts +59 -0
- package/src/lib/jobs/ai-media-asset.js +86 -0
- package/src/lib/jobs/ai-media-asset.js.map +1 -0
- package/src/lib/jobs/ai-product-image.d.ts +78 -0
- package/src/lib/jobs/ai-product-image.js +113 -0
- package/src/lib/jobs/ai-product-image.js.map +1 -0
- package/src/lib/jobs/ai-theme-brand-inputs.d.ts +125 -0
- package/src/lib/jobs/ai-theme-brand-inputs.js +378 -0
- package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -0
- package/src/lib/jobs/ai-theme-brand-server.d.ts +33 -0
- package/src/lib/jobs/ai-theme-brand-server.js +33 -0
- package/src/lib/jobs/ai-theme-brand-server.js.map +1 -0
- package/src/lib/jobs/ai-workflow-records.d.ts +84 -0
- package/src/lib/jobs/ai-workflow-records.js +158 -0
- package/src/lib/jobs/ai-workflow-records.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-free-page-built-recording.d.ts +31 -0
- package/src/lib/jobs/fixtures/ai-free-page-built-recording.js +367 -0
- package/src/lib/jobs/fixtures/ai-free-page-built-recording.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-free-page-recording.d.ts +69 -0
- package/src/lib/jobs/fixtures/ai-free-page-recording.js +442 -0
- package/src/lib/jobs/fixtures/ai-free-page-recording.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-page-briefs.d.ts +146 -0
- package/src/lib/jobs/fixtures/ai-page-briefs.js +1850 -0
- package/src/lib/jobs/fixtures/ai-page-briefs.js.map +1 -0
- package/src/lib/model/ai-allotments.d.ts +208 -0
- package/src/lib/model/ai-allotments.js +269 -0
- package/src/lib/model/ai-allotments.js.map +1 -0
- package/src/lib/model/ai-automation-draft.d.ts +74 -0
- package/src/lib/model/ai-automation-draft.js +310 -0
- package/src/lib/model/ai-automation-draft.js.map +1 -0
- package/src/lib/model/ai-automation-outline.d.ts +50 -0
- package/src/lib/model/ai-automation-outline.js +262 -0
- package/src/lib/model/ai-automation-outline.js.map +1 -0
- package/src/lib/model/ai-build-plan.d.ts +197 -0
- package/src/lib/model/ai-build-plan.js +438 -0
- package/src/lib/model/ai-build-plan.js.map +1 -0
- package/src/lib/model/ai-crm.d.ts +237 -0
- package/src/lib/model/ai-crm.js +225 -0
- package/src/lib/model/ai-crm.js.map +1 -0
- package/src/lib/model/ai-experiment-proposal.d.ts +68 -0
- package/src/lib/model/ai-experiment-proposal.js +146 -0
- package/src/lib/model/ai-experiment-proposal.js.map +1 -0
- package/src/lib/model/ai-experiment.d.ts +309 -0
- package/src/lib/model/ai-experiment.js +395 -0
- package/src/lib/model/ai-experiment.js.map +1 -0
- package/src/lib/model/ai-insight.d.ts +178 -0
- package/src/lib/model/ai-insight.js +201 -0
- package/src/lib/model/ai-insight.js.map +1 -0
- package/src/lib/model/ai-jobs.types.d.ts +412 -0
- package/src/lib/model/ai-jobs.types.js +42 -0
- package/src/lib/model/ai-jobs.types.js.map +1 -0
- package/src/lib/model/ai-page-job.d.ts +92 -0
- package/src/lib/model/ai-page-job.js +159 -0
- package/src/lib/model/ai-page-job.js.map +1 -0
- package/src/lib/model/ai-permissions.d.ts +49 -0
- package/src/lib/model/ai-permissions.js +97 -0
- package/src/lib/model/ai-permissions.js.map +1 -0
- package/src/lib/model/ai-plan-capabilities.d.ts +139 -0
- package/src/lib/model/ai-plan-capabilities.js +149 -0
- package/src/lib/model/ai-plan-capabilities.js.map +1 -0
- package/src/lib/model/ai-products.d.ts +251 -0
- package/src/lib/model/ai-products.js +253 -0
- package/src/lib/model/ai-products.js.map +1 -0
- package/src/lib/model/ai-seo.d.ts +208 -0
- package/src/lib/model/ai-seo.js +150 -0
- package/src/lib/model/ai-seo.js.map +1 -0
- package/src/lib/model/ai-site-inventory.d.ts +164 -0
- package/src/lib/model/ai-site-inventory.js +145 -0
- package/src/lib/model/ai-site-inventory.js.map +1 -0
- package/src/lib/model/ai-site-job.d.ts +247 -0
- package/src/lib/model/ai-site-job.js +314 -0
- package/src/lib/model/ai-site-job.js.map +1 -0
- package/src/lib/model/ai-site-start-seo.d.ts +103 -0
- package/src/lib/model/ai-site-start-seo.js +154 -0
- package/src/lib/model/ai-site-start-seo.js.map +1 -0
- package/src/lib/model/ai-site-start.d.ts +122 -0
- package/src/lib/model/ai-site-start.js +159 -0
- package/src/lib/model/ai-site-start.js.map +1 -0
- package/src/lib/model/ai-site-switch.d.ts +56 -0
- package/src/lib/model/ai-site-switch.js +73 -0
- package/src/lib/model/ai-site-switch.js.map +1 -0
- package/src/lib/model/ai-storefront-claims.d.ts +70 -0
- package/src/lib/model/ai-storefront-claims.js +130 -0
- package/src/lib/model/ai-storefront-claims.js.map +1 -0
- package/src/lib/model/ai-template-subjects.d.ts +82 -0
- package/src/lib/model/ai-template-subjects.js +136 -0
- package/src/lib/model/ai-template-subjects.js.map +1 -0
- package/src/lib/model/ai-theme-proposal.d.ts +210 -0
- package/src/lib/model/ai-theme-proposal.js +506 -0
- package/src/lib/model/ai-theme-proposal.js.map +1 -0
- package/src/lib/model/ai-tokens.d.ts +96 -0
- package/src/lib/model/ai-tokens.js +117 -0
- package/src/lib/model/ai-tokens.js.map +1 -0
- package/src/lib/model/ai-usage-by-user.d.ts +120 -0
- package/src/lib/model/ai-usage-by-user.js +139 -0
- package/src/lib/model/ai-usage-by-user.js.map +1 -0
- package/src/lib/model/ai-workflow-job.d.ts +111 -0
- package/src/lib/model/ai-workflow-job.js +183 -0
- package/src/lib/model/ai-workflow-job.js.map +1 -0
- package/src/lib/model/assist-edit.d.ts +261 -0
- package/src/lib/model/assist-edit.js +175 -0
- package/src/lib/model/assist-edit.js.map +1 -0
- package/src/lib/plugin-config.d.ts +33 -0
- package/src/lib/plugin-config.js +118 -0
- package/src/lib/plugin-config.js.map +1 -0
- package/src/lib/plugin.d.ts +30 -0
- package/src/lib/plugin.js +525 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/providers/anthropic.d.ts +84 -0
- package/src/lib/providers/anthropic.js +432 -0
- package/src/lib/providers/anthropic.js.map +1 -0
- package/src/lib/providers/catalog.d.ts +197 -0
- package/src/lib/providers/catalog.js +312 -0
- package/src/lib/providers/catalog.js.map +1 -0
- package/src/lib/providers/contract.d.ts +464 -0
- package/src/lib/providers/contract.js +274 -0
- package/src/lib/providers/contract.js.map +1 -0
- package/src/lib/providers/model-choice.d.ts +119 -0
- package/src/lib/providers/model-choice.js +416 -0
- package/src/lib/providers/model-choice.js.map +1 -0
- package/src/lib/providers/openai-compatible.d.ts +58 -0
- package/src/lib/providers/openai-compatible.js +361 -0
- package/src/lib/providers/openai-compatible.js.map +1 -0
- package/src/lib/providers/registry.d.ts +49 -0
- package/src/lib/providers/registry.js +71 -0
- package/src/lib/providers/registry.js.map +1 -0
- package/src/lib/providers/routing.d.ts +98 -0
- package/src/lib/providers/routing.js +450 -0
- package/src/lib/providers/routing.js.map +1 -0
- package/src/lib/runtime/ai-abuse-guards.d.ts +113 -0
- package/src/lib/runtime/ai-abuse-guards.js +148 -0
- package/src/lib/runtime/ai-abuse-guards.js.map +1 -0
- package/src/lib/runtime/ai-component-bindings.d.ts +67 -0
- package/src/lib/runtime/ai-component-bindings.js +106 -0
- package/src/lib/runtime/ai-component-bindings.js.map +1 -0
- package/src/lib/runtime/ai-device-audit.d.ts +109 -0
- package/src/lib/runtime/ai-device-audit.js +97 -0
- package/src/lib/runtime/ai-device-audit.js.map +1 -0
- package/src/lib/runtime/ai-doctrine-validators.d.ts +720 -0
- package/src/lib/runtime/ai-doctrine-validators.js +3133 -0
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -0
- package/src/lib/runtime/ai-doctrine.d.ts +372 -0
- package/src/lib/runtime/ai-doctrine.js +944 -0
- package/src/lib/runtime/ai-doctrine.js.map +1 -0
- package/src/lib/runtime/ai-eval-live.d.ts +321 -0
- package/src/lib/runtime/ai-eval-live.js +1257 -0
- package/src/lib/runtime/ai-eval-live.js.map +1 -0
- package/src/lib/runtime/ai-eval-memory-firestore.d.ts +51 -0
- package/src/lib/runtime/ai-eval-memory-firestore.js +183 -0
- package/src/lib/runtime/ai-eval-memory-firestore.js.map +1 -0
- package/src/lib/runtime/ai-eval.d.ts +441 -0
- package/src/lib/runtime/ai-eval.js +1151 -0
- package/src/lib/runtime/ai-eval.js.map +1 -0
- package/src/lib/runtime/ai-gate.d.ts +130 -0
- package/src/lib/runtime/ai-gate.js +272 -0
- package/src/lib/runtime/ai-gate.js.map +1 -0
- package/src/lib/runtime/ai-generation-bounds.d.ts +24 -0
- package/src/lib/runtime/ai-generation-bounds.js +23 -0
- package/src/lib/runtime/ai-generation-bounds.js.map +1 -0
- package/src/lib/runtime/ai-insight-check.d.ts +76 -0
- package/src/lib/runtime/ai-insight-check.js +281 -0
- package/src/lib/runtime/ai-insight-check.js.map +1 -0
- package/src/lib/runtime/ai-node-tree.d.ts +181 -0
- package/src/lib/runtime/ai-node-tree.js +931 -0
- package/src/lib/runtime/ai-node-tree.js.map +1 -0
- package/src/lib/runtime/ai-page-links.d.ts +79 -0
- package/src/lib/runtime/ai-page-links.js +135 -0
- package/src/lib/runtime/ai-page-links.js.map +1 -0
- package/src/lib/runtime/ai-palette.d.ts +252 -0
- package/src/lib/runtime/ai-palette.generated.d.ts +34 -0
- package/src/lib/runtime/ai-palette.generated.js +5263 -0
- package/src/lib/runtime/ai-palette.generated.js.map +1 -0
- package/src/lib/runtime/ai-palette.js +187 -0
- package/src/lib/runtime/ai-palette.js.map +1 -0
- package/src/lib/runtime/ai-products-generation.d.ts +107 -0
- package/src/lib/runtime/ai-products-generation.js +250 -0
- package/src/lib/runtime/ai-products-generation.js.map +1 -0
- package/src/lib/runtime/ai-repeated-items.d.ts +95 -0
- package/src/lib/runtime/ai-repeated-items.js +397 -0
- package/src/lib/runtime/ai-repeated-items.js.map +1 -0
- package/src/lib/runtime/ai-runtime.d.ts +148 -0
- package/src/lib/runtime/ai-runtime.js +237 -0
- package/src/lib/runtime/ai-runtime.js.map +1 -0
- package/src/lib/runtime/ai-template-examples.d.ts +71 -0
- package/src/lib/runtime/ai-template-examples.js +135 -0
- package/src/lib/runtime/ai-template-examples.js.map +1 -0
- package/src/lib/runtime/assist-answer-cache.d.ts +80 -0
- package/src/lib/runtime/assist-answer-cache.js +184 -0
- package/src/lib/runtime/assist-answer-cache.js.map +1 -0
- package/src/lib/runtime/seo-audit.d.ts +93 -0
- package/src/lib/runtime/seo-audit.js +260 -0
- package/src/lib/runtime/seo-audit.js.map +1 -0
- package/src/lib/runtime/seo-content-fixes.d.ts +41 -0
- package/src/lib/runtime/seo-content-fixes.js +168 -0
- package/src/lib/runtime/seo-content-fixes.js.map +1 -0
- package/src/lib/runtime/seo-fields.d.ts +152 -0
- package/src/lib/runtime/seo-fields.js +215 -0
- package/src/lib/runtime/seo-fields.js.map +1 -0
- package/src/lib/runtime/seo-page-facts.d.ts +61 -0
- package/src/lib/runtime/seo-page-facts.js +150 -0
- package/src/lib/runtime/seo-page-facts.js.map +1 -0
- package/src/lib/runtime/site-inventory.d.ts +63 -0
- package/src/lib/runtime/site-inventory.js +230 -0
- package/src/lib/runtime/site-inventory.js.map +1 -0
- package/src/lib/server/ai-admin-org.d.ts +33 -0
- package/src/lib/server/ai-admin-org.js +381 -0
- package/src/lib/server/ai-admin-org.js.map +1 -0
- package/src/lib/server/ai-admin-orgs-spend.d.ts +40 -0
- package/src/lib/server/ai-admin-orgs-spend.js +129 -0
- package/src/lib/server/ai-admin-orgs-spend.js.map +1 -0
- package/src/lib/server/ai-admin-overage.d.ts +19 -0
- package/src/lib/server/ai-admin-overage.js +246 -0
- package/src/lib/server/ai-admin-overage.js.map +1 -0
- package/src/lib/server/ai-admin-signals.d.ts +34 -0
- package/src/lib/server/ai-admin-signals.js +330 -0
- package/src/lib/server/ai-admin-signals.js.map +1 -0
- package/src/lib/server/ai-admin-user.d.ts +27 -0
- package/src/lib/server/ai-admin-user.js +128 -0
- package/src/lib/server/ai-admin-user.js.map +1 -0
- package/src/lib/server/ai-allotments.d.ts +27 -0
- package/src/lib/server/ai-allotments.js +544 -0
- package/src/lib/server/ai-allotments.js.map +1 -0
- package/src/lib/server/ai-assist-prompts.d.ts +102 -0
- package/src/lib/server/ai-assist-prompts.js +207 -0
- package/src/lib/server/ai-assist-prompts.js.map +1 -0
- package/src/lib/server/ai-assist.d.ts +119 -0
- package/src/lib/server/ai-assist.js +517 -0
- package/src/lib/server/ai-assist.js.map +1 -0
- package/src/lib/server/ai-crm-answer.d.ts +30 -0
- package/src/lib/server/ai-crm-answer.js +98 -0
- package/src/lib/server/ai-crm-answer.js.map +1 -0
- package/src/lib/server/ai-generate-component.d.ts +111 -0
- package/src/lib/server/ai-generate-component.js +643 -0
- package/src/lib/server/ai-generate-component.js.map +1 -0
- package/src/lib/server/ai-host-permissions.d.ts +46 -0
- package/src/lib/server/ai-host-permissions.js +204 -0
- package/src/lib/server/ai-host-permissions.js.map +1 -0
- package/src/lib/server/ai-insight-answer.d.ts +30 -0
- package/src/lib/server/ai-insight-answer.js +83 -0
- package/src/lib/server/ai-insight-answer.js.map +1 -0
- package/src/lib/server/ai-insight-digest-route.d.ts +30 -0
- package/src/lib/server/ai-insight-digest-route.js +156 -0
- package/src/lib/server/ai-insight-digest-route.js.map +1 -0
- package/src/lib/server/ai-jobs-batch.d.ts +48 -0
- package/src/lib/server/ai-jobs-batch.js +306 -0
- package/src/lib/server/ai-jobs-batch.js.map +1 -0
- package/src/lib/server/ai-jobs-beat-route.d.ts +36 -0
- package/src/lib/server/ai-jobs-beat-route.js +86 -0
- package/src/lib/server/ai-jobs-beat-route.js.map +1 -0
- package/src/lib/server/ai-jobs-cancel.d.ts +30 -0
- package/src/lib/server/ai-jobs-cancel.js +74 -0
- package/src/lib/server/ai-jobs-cancel.js.map +1 -0
- package/src/lib/server/ai-jobs-events-route.d.ts +31 -0
- package/src/lib/server/ai-jobs-events-route.js +51 -0
- package/src/lib/server/ai-jobs-events-route.js.map +1 -0
- package/src/lib/server/ai-jobs-events.d.ts +55 -0
- package/src/lib/server/ai-jobs-events.js +144 -0
- package/src/lib/server/ai-jobs-events.js.map +1 -0
- package/src/lib/server/ai-jobs-gate.d.ts +47 -0
- package/src/lib/server/ai-jobs-gate.js +106 -0
- package/src/lib/server/ai-jobs-gate.js.map +1 -0
- package/src/lib/server/ai-jobs-resume.d.ts +23 -0
- package/src/lib/server/ai-jobs-resume.js +209 -0
- package/src/lib/server/ai-jobs-resume.js.map +1 -0
- package/src/lib/server/ai-jobs-route.d.ts +32 -0
- package/src/lib/server/ai-jobs-route.js +307 -0
- package/src/lib/server/ai-jobs-route.js.map +1 -0
- package/src/lib/server/ai-models.d.ts +18 -0
- package/src/lib/server/ai-models.js +134 -0
- package/src/lib/server/ai-models.js.map +1 -0
- package/src/lib/server/ai-seo-apply.d.ts +53 -0
- package/src/lib/server/ai-seo-apply.js +294 -0
- package/src/lib/server/ai-seo-apply.js.map +1 -0
- package/src/lib/server/ai-usage.d.ts +18 -0
- package/src/lib/server/ai-usage.js +220 -0
- package/src/lib/server/ai-usage.js.map +1 -0
- package/src/lib/server/assist-chat.d.ts +234 -0
- package/src/lib/server/assist-chat.js +1446 -0
- package/src/lib/server/assist-chat.js.map +1 -0
- package/src/lib/server/assist-edit-applied.d.ts +22 -0
- package/src/lib/server/assist-edit-applied.js +239 -0
- package/src/lib/server/assist-edit-applied.js.map +1 -0
- package/src/lib/server/assist-edit.d.ts +124 -0
- package/src/lib/server/assist-edit.js +1000 -0
- package/src/lib/server/assist-edit.js.map +1 -0
- package/src/lib/server/assist-feedback.d.ts +31 -0
- package/src/lib/server/assist-feedback.js +115 -0
- package/src/lib/server/assist-feedback.js.map +1 -0
- package/src/lib/server/assist-view-context.d.ts +343 -0
- package/src/lib/server/assist-view-context.js +690 -0
- package/src/lib/server/assist-view-context.js.map +1 -0
- package/src/lib/server/billing-credits.d.ts +59 -0
- package/src/lib/server/billing-credits.js +146 -0
- package/src/lib/server/billing-credits.js.map +1 -0
- package/src/lib/server/billing-overage.d.ts +19 -0
- package/src/lib/server/billing-overage.js +337 -0
- package/src/lib/server/billing-overage.js.map +1 -0
- package/src/lib/server.d.ts +32 -0
- package/src/lib/server.js +265 -0
- package/src/lib/server.js.map +1 -0
- package/src/lib/subprocessors.d.ts +18 -0
- package/src/lib/subprocessors.js +52 -0
- package/src/lib/subprocessors.js.map +1 -0
- package/src/lib/tools/ai-component-tool.d.ts +99 -0
- package/src/lib/tools/ai-component-tool.js +369 -0
- package/src/lib/tools/ai-component-tool.js.map +1 -0
- package/src/lib/tools/ai-crm-tool.d.ts +106 -0
- package/src/lib/tools/ai-crm-tool.js +488 -0
- package/src/lib/tools/ai-crm-tool.js.map +1 -0
- package/src/lib/tools/ai-duplicate-resource-tool.d.ts +71 -0
- package/src/lib/tools/ai-duplicate-resource-tool.js +164 -0
- package/src/lib/tools/ai-duplicate-resource-tool.js.map +1 -0
- package/src/lib/tools/ai-experiment-tool.d.ts +40 -0
- package/src/lib/tools/ai-experiment-tool.js +155 -0
- package/src/lib/tools/ai-experiment-tool.js.map +1 -0
- package/src/lib/tools/ai-insight-tool.d.ts +46 -0
- package/src/lib/tools/ai-insight-tool.js +200 -0
- package/src/lib/tools/ai-insight-tool.js.map +1 -0
- package/src/lib/tools/ai-inventory-lookup-tool.d.ts +86 -0
- package/src/lib/tools/ai-inventory-lookup-tool.js +164 -0
- package/src/lib/tools/ai-inventory-lookup-tool.js.map +1 -0
- package/src/lib/tools/ai-products-tool.d.ts +65 -0
- package/src/lib/tools/ai-products-tool.js +644 -0
- package/src/lib/tools/ai-products-tool.js.map +1 -0
- package/src/lib/tools/ai-seo-tool.d.ts +162 -0
- package/src/lib/tools/ai-seo-tool.js +546 -0
- package/src/lib/tools/ai-seo-tool.js.map +1 -0
- package/src/lib/tools/ai-theme-tool.d.ts +101 -0
- package/src/lib/tools/ai-theme-tool.js +562 -0
- package/src/lib/tools/ai-theme-tool.js.map +1 -0
- package/src/lib/tools/ai-workflow-tool.d.ts +166 -0
- package/src/lib/tools/ai-workflow-tool.js +860 -0
- package/src/lib/tools/ai-workflow-tool.js.map +1 -0
- package/src/lib/usage/ai-allotment-alerts.d.ts +72 -0
- package/src/lib/usage/ai-allotment-alerts.js +157 -0
- package/src/lib/usage/ai-allotment-alerts.js.map +1 -0
- package/src/lib/usage/ai-allotments.d.ts +125 -0
- package/src/lib/usage/ai-allotments.js +239 -0
- package/src/lib/usage/ai-allotments.js.map +1 -0
- package/src/lib/usage/ai-model-sample.d.ts +36 -0
- package/src/lib/usage/ai-model-sample.js +68 -0
- package/src/lib/usage/ai-model-sample.js.map +1 -0
- package/src/lib/usage/ai-usage-alerts.d.ts +55 -0
- package/src/lib/usage/ai-usage-alerts.js +114 -0
- package/src/lib/usage/ai-usage-alerts.js.map +1 -0
- package/src/lib/usage/ai-usage-by-user.d.ts +161 -0
- package/src/lib/usage/ai-usage-by-user.js +211 -0
- package/src/lib/usage/ai-usage-by-user.js.map +1 -0
- package/src/lib/usage/ai-usage-eraser.d.ts +29 -0
- package/src/lib/usage/ai-usage-eraser.js +40 -0
- package/src/lib/usage/ai-usage-eraser.js.map +1 -0
- package/src/lib/usage/ai-usage-meter.d.ts +39 -0
- package/src/lib/usage/ai-usage-meter.js +85 -0
- package/src/lib/usage/ai-usage-meter.js.map +1 -0
- package/src/lib/usage/ai-usage-wire.d.ts +184 -0
- package/src/lib/usage/ai-usage-wire.js +98 -0
- package/src/lib/usage/ai-usage-wire.js.map +1 -0
- package/src/lib/usage/assist-ceiling.d.ts +87 -0
- package/src/lib/usage/assist-ceiling.js +110 -0
- package/src/lib/usage/assist-ceiling.js.map +1 -0
- package/src/lib/usage/assist-free-taste.d.ts +225 -0
- package/src/lib/usage/assist-free-taste.js +308 -0
- package/src/lib/usage/assist-free-taste.js.map +1 -0
- package/src/lib/usage/assist-refusals.d.ts +69 -0
- package/src/lib/usage/assist-refusals.js +79 -0
- package/src/lib/usage/assist-refusals.js.map +1 -0
- package/src/lib/usage/assist-signal-mining.d.ts +375 -0
- package/src/lib/usage/assist-signal-mining.js +344 -0
- package/src/lib/usage/assist-signal-mining.js.map +1 -0
- package/src/lib/usage/assist-usage.d.ts +571 -0
- package/src/lib/usage/assist-usage.js +978 -0
- package/src/lib/usage/assist-usage.js.map +1 -0
- package/src/lib/usage/staff-org-ai.d.ts +242 -0
- package/src/lib/usage/staff-org-ai.js +173 -0
- package/src/lib/usage/staff-org-ai.js.map +1 -0
- package/src/lib/usage/staff-org-usage-ai.d.ts +83 -0
- package/src/lib/usage/staff-org-usage-ai.js +59 -0
- package/src/lib/usage/staff-org-usage-ai.js.map +1 -0
- package/src/lib/usage/staff-orgs-ai-spend.d.ts +83 -0
- package/src/lib/usage/staff-orgs-ai-spend.js +114 -0
- package/src/lib/usage/staff-orgs-ai-spend.js.map +1 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ import { SEO_LISTING_FIELDS, seoListingFieldTooLong } from "@aglyn/aglyn/app-utils/seo-listing-fields";
|
|
18
|
+
import { aiSeoKeywordCoverage, aiSeoKeywordList } from "../tools/ai-seo-tool.js";
|
|
19
|
+
/**
|
|
20
|
+
* The site SEO audit's scoring (AGL-2910): every audited page held to what a
|
|
21
|
+
* search result and a crawler need, with nothing asked of a model. Pure, so
|
|
22
|
+
* the audit is proved against fixtures and a job only spends tokens on the
|
|
23
|
+
* fixes it cannot make without writing.
|
|
24
|
+
*
|
|
25
|
+
* Per page: a title and a description of its own, within their lengths and
|
|
26
|
+
* used on no other page; one main heading that says something; a description
|
|
27
|
+
* on every image; a link from somewhere else on the site; and the target
|
|
28
|
+
* keywords a person named, reported where the page already says them.
|
|
29
|
+
* Per site: whether search engines are told to stay away, whether the
|
|
30
|
+
* structured data names and describes the publisher, and whether agents get
|
|
31
|
+
* guidance of the author's own.
|
|
32
|
+
*
|
|
33
|
+
* Keyword coverage is reported, never forced. A page that does not say a
|
|
34
|
+
* keyword is told so; the fix a job proposes uses the keyword only where the
|
|
35
|
+
* page is about it, and the listing check refuses a keyword used past its
|
|
36
|
+
* per-field count.
|
|
37
|
+
*/ /** Pages one audit covers. A larger site is audited on its first pages by path, and says how many it left. */ export const AI_SEO_AUDIT_MAX_PAGES = 150;
|
|
38
|
+
/** Pages one batch of fixes carries: one model call a batch. */ export const AI_SEO_AUDIT_BATCH_SIZE = 8;
|
|
39
|
+
/** What each severity takes off a page's score. */ const SEVERITY_WEIGHT = {
|
|
40
|
+
high: 25,
|
|
41
|
+
medium: 10,
|
|
42
|
+
low: 3
|
|
43
|
+
};
|
|
44
|
+
/** A main heading this short or this generic says nothing a searcher can use. */ const THIN_H1_MIN_CHARS = 10;
|
|
45
|
+
const GENERIC_H1 = new Set([
|
|
46
|
+
'home',
|
|
47
|
+
'homepage',
|
|
48
|
+
'home page',
|
|
49
|
+
'welcome',
|
|
50
|
+
'hello',
|
|
51
|
+
'untitled',
|
|
52
|
+
'new page',
|
|
53
|
+
'page',
|
|
54
|
+
'title',
|
|
55
|
+
'heading'
|
|
56
|
+
]);
|
|
57
|
+
/** The findings a batch of generated fixes answers. */ const GENERATED_FIX_CODES = new Set([
|
|
58
|
+
'title-missing',
|
|
59
|
+
'title-too-long',
|
|
60
|
+
'title-duplicate',
|
|
61
|
+
'description-missing',
|
|
62
|
+
'description-too-long',
|
|
63
|
+
'description-duplicate',
|
|
64
|
+
'h1-missing',
|
|
65
|
+
'h1-thin',
|
|
66
|
+
'image-alt-missing',
|
|
67
|
+
'keyword-missing'
|
|
68
|
+
]);
|
|
69
|
+
const blank = (value)=>!String(value != null ? value : '').trim();
|
|
70
|
+
const normalized = (value)=>String(value != null ? value : '').replace(/\s+/g, ' ').trim().toLowerCase();
|
|
71
|
+
/** A path as the keyword lines and the routing map both spell it: leading slash, no trailing one. */ export function aiSeoNormalizePath(path) {
|
|
72
|
+
const trimmed = String(path != null ? path : '').trim();
|
|
73
|
+
if (!trimmed || trimmed === '/') return '/';
|
|
74
|
+
return `/${trimmed.replace(/^\/+/, '').replace(/\/+$/, '')}`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Target keywords per page, one line a page: `/pricing: plans, pricing`.
|
|
78
|
+
* A line without a path, or with a path the site does not have, names no
|
|
79
|
+
* page; the step reports the paths it could not match.
|
|
80
|
+
*/ export function parseAiSeoKeywordLines(raw) {
|
|
81
|
+
const out = {};
|
|
82
|
+
for (const line of String(raw != null ? raw : '').split('\n')){
|
|
83
|
+
var _out_path;
|
|
84
|
+
const at = line.indexOf(':');
|
|
85
|
+
if (at <= 0) continue;
|
|
86
|
+
const path = aiSeoNormalizePath(line.slice(0, at));
|
|
87
|
+
const keywords = aiSeoKeywordList(line.slice(at + 1));
|
|
88
|
+
if (keywords.length) out[path] = aiSeoKeywordList([
|
|
89
|
+
...(_out_path = out[path]) != null ? _out_path : [],
|
|
90
|
+
...keywords
|
|
91
|
+
]);
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
function finding(code, severity, message, extra = {}) {
|
|
96
|
+
return _extends({
|
|
97
|
+
code,
|
|
98
|
+
severity,
|
|
99
|
+
message
|
|
100
|
+
}, extra);
|
|
101
|
+
}
|
|
102
|
+
/** The pages that share one value, by that value. */ function sharedValues(pages, read) {
|
|
103
|
+
const groups = new Map();
|
|
104
|
+
for (const page of pages){
|
|
105
|
+
var _groups_get;
|
|
106
|
+
const key = normalized(read(page));
|
|
107
|
+
if (!key) continue;
|
|
108
|
+
groups.set(key, [
|
|
109
|
+
...(_groups_get = groups.get(key)) != null ? _groups_get : [],
|
|
110
|
+
page.screenId
|
|
111
|
+
]);
|
|
112
|
+
}
|
|
113
|
+
return new Map([
|
|
114
|
+
...groups
|
|
115
|
+
].filter(([, ids])=>ids.length > 1));
|
|
116
|
+
}
|
|
117
|
+
function pageFindings(page, titles, descriptions) {
|
|
118
|
+
var _h1s_;
|
|
119
|
+
const out = [];
|
|
120
|
+
const title = page.seo.title;
|
|
121
|
+
if (blank(title)) {
|
|
122
|
+
out.push(finding('title-missing', 'medium', 'This page has no search title, so results show its name beside the site title.'));
|
|
123
|
+
} else {
|
|
124
|
+
var _titles_get;
|
|
125
|
+
if (seoListingFieldTooLong('title', title)) {
|
|
126
|
+
out.push(finding('title-too-long', 'medium', `The search title is over ${SEO_LISTING_FIELDS.title.maxLength} characters and will be cut off in results.`));
|
|
127
|
+
}
|
|
128
|
+
const twins = (_titles_get = titles.get(normalized(title))) == null ? void 0 : _titles_get.filter((id)=>id !== page.screenId);
|
|
129
|
+
if (twins == null ? void 0 : twins.length) {
|
|
130
|
+
out.push(finding('title-duplicate', 'high', 'Another page uses the same search title, so results cannot tell them apart.', {
|
|
131
|
+
screenIds: twins
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const description = page.seo.description;
|
|
136
|
+
if (blank(description) && blank(page.description)) {
|
|
137
|
+
out.push(finding('description-missing', 'medium', 'This page has no search description, so results show the site’s.'));
|
|
138
|
+
} else if (!blank(description)) {
|
|
139
|
+
var _descriptions_get;
|
|
140
|
+
if (seoListingFieldTooLong('description', description)) {
|
|
141
|
+
out.push(finding('description-too-long', 'low', `The search description is over ${SEO_LISTING_FIELDS.description.maxLength} characters and will be cut off.`));
|
|
142
|
+
}
|
|
143
|
+
const twins = (_descriptions_get = descriptions.get(normalized(description))) == null ? void 0 : _descriptions_get.filter((id)=>id !== page.screenId);
|
|
144
|
+
if (twins == null ? void 0 : twins.length) {
|
|
145
|
+
out.push(finding('description-duplicate', 'medium', 'Another page uses the same search description.', {
|
|
146
|
+
screenIds: twins
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const { h1s } = page.facts;
|
|
151
|
+
if (!h1s.length) {
|
|
152
|
+
out.push(finding('h1-missing', 'high', 'This page has no main heading.'));
|
|
153
|
+
} else {
|
|
154
|
+
if (h1s.length > 1) {
|
|
155
|
+
out.push(finding('h1-multiple', 'medium', `This page has ${h1s.length} main headings; it should have one.`, {
|
|
156
|
+
nodeIds: h1s.slice(1).map((heading)=>heading.nodeId).filter((id)=>Boolean(id))
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
const first = h1s[0];
|
|
160
|
+
if (first.text.length < THIN_H1_MIN_CHARS || GENERIC_H1.has(normalized(first.text))) {
|
|
161
|
+
out.push(finding('h1-thin', 'medium', `The main heading “${first.text}” says little about the page.`, {
|
|
162
|
+
nodeIds: first.nodeId ? [
|
|
163
|
+
first.nodeId
|
|
164
|
+
] : []
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const missingAlt = page.facts.imagesMissingAlt;
|
|
169
|
+
if (missingAlt.length) {
|
|
170
|
+
out.push(finding('image-alt-missing', 'medium', `${missingAlt.length} ${missingAlt.length === 1 ? 'image has' : 'images have'} no description for readers who cannot see ${missingAlt.length === 1 ? 'it' : 'them'}.`, {
|
|
171
|
+
nodeIds: missingAlt.map((image)=>image.nodeId)
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
if (!page.linkedFrom && page.path !== '/') {
|
|
175
|
+
out.push(finding('orphan', 'medium', 'No other page or shared layout links here, so visitors and crawlers may never find it.'));
|
|
176
|
+
}
|
|
177
|
+
const coverage = aiSeoKeywordCoverage(page.keywords, {
|
|
178
|
+
title: page.seo.title,
|
|
179
|
+
description: page.seo.description,
|
|
180
|
+
h1: (_h1s_ = h1s[0]) == null ? void 0 : _h1s_.text,
|
|
181
|
+
body: page.facts.text
|
|
182
|
+
});
|
|
183
|
+
for (const entry of coverage){
|
|
184
|
+
if (!entry.inTitle && !entry.inDescription && !entry.inH1 && !entry.inBody) {
|
|
185
|
+
out.push(finding('keyword-missing', 'low', `The page never says “${entry.keyword}”. Only use it if the page is about it.`, {
|
|
186
|
+
keyword: entry.keyword
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return out;
|
|
191
|
+
}
|
|
192
|
+
function scoreOf(findings) {
|
|
193
|
+
return Math.max(0, 100 - findings.reduce((sum, entry)=>sum + SEVERITY_WEIGHT[entry.severity], 0));
|
|
194
|
+
}
|
|
195
|
+
/** Audit the pages and the site; nothing here reads, writes or generates. */ export function aiSeoAudit(pages, site, options = {}) {
|
|
196
|
+
var _options_skipped, _options_batchSize;
|
|
197
|
+
const titles = sharedValues(pages, (page)=>page.seo.title);
|
|
198
|
+
const descriptions = sharedValues(pages, (page)=>page.seo.description);
|
|
199
|
+
const reports = pages.map((page)=>{
|
|
200
|
+
var _page_facts_h1s_;
|
|
201
|
+
const findings = pageFindings(page, titles, descriptions);
|
|
202
|
+
return {
|
|
203
|
+
screenId: page.screenId,
|
|
204
|
+
path: page.path,
|
|
205
|
+
name: page.name,
|
|
206
|
+
versionId: page.versionId,
|
|
207
|
+
score: scoreOf(findings),
|
|
208
|
+
findings,
|
|
209
|
+
keywords: aiSeoKeywordCoverage(page.keywords, {
|
|
210
|
+
title: page.seo.title,
|
|
211
|
+
description: page.seo.description,
|
|
212
|
+
h1: (_page_facts_h1s_ = page.facts.h1s[0]) == null ? void 0 : _page_facts_h1s_.text,
|
|
213
|
+
body: page.facts.text
|
|
214
|
+
})
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
const siteFindings = [];
|
|
218
|
+
if (site.discouraged) {
|
|
219
|
+
siteFindings.push(finding('search-discouraged', 'high', 'Search engines are asked not to index this site, so none of its pages appear in results.'));
|
|
220
|
+
}
|
|
221
|
+
if (blank(site.entity.name) || blank(site.entity.description)) {
|
|
222
|
+
siteFindings.push(finding('entity-incomplete', 'low', 'The structured data does not name and describe who publishes the site.'));
|
|
223
|
+
}
|
|
224
|
+
if (blank(site.agent.whenToUse)) {
|
|
225
|
+
siteFindings.push(finding('llms-guidance-missing', 'low', '/llms.txt carries no guidance of your own for AI agents.'));
|
|
226
|
+
}
|
|
227
|
+
const queue = reports.filter((report)=>report.findings.some((entry)=>GENERATED_FIX_CODES.has(entry.code))).sort((a, b)=>a.score - b.score || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)).map((report)=>report.screenId);
|
|
228
|
+
return {
|
|
229
|
+
kind: 'audit',
|
|
230
|
+
pages: reports,
|
|
231
|
+
skipped: Math.max(0, (_options_skipped = options.skipped) != null ? _options_skipped : 0),
|
|
232
|
+
site: siteFindings,
|
|
233
|
+
siteProposal: siteFindings.some((entry)=>entry.code === 'entity-incomplete' || entry.code === 'llms-guidance-missing'),
|
|
234
|
+
queue,
|
|
235
|
+
batchSize: Math.max(1, (_options_batchSize = options.batchSize) != null ? _options_batchSize : AI_SEO_AUDIT_BATCH_SIZE),
|
|
236
|
+
score: reports.length ? Math.round(reports.reduce((sum, report)=>sum + report.score, 0) / reports.length) : 100,
|
|
237
|
+
notes: []
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* The content fixes that need no model: every main heading after the first
|
|
242
|
+
* editable one becomes an `h2`, so the page keeps one.
|
|
243
|
+
*/ export function aiSeoHeadingDemotions(facts) {
|
|
244
|
+
const editable = facts.h1s.filter((heading)=>heading.editable && heading.nodeId);
|
|
245
|
+
if (facts.h1s.length < 2 || !editable.length) return [];
|
|
246
|
+
const keep = editable[0].nodeId;
|
|
247
|
+
return editable.filter((heading)=>heading.nodeId !== keep).map((heading)=>({
|
|
248
|
+
kind: 'h1-demote',
|
|
249
|
+
nodeId: heading.nodeId
|
|
250
|
+
}));
|
|
251
|
+
}
|
|
252
|
+
/** The queue's batches, in order. */ export function aiSeoAuditBatches(report) {
|
|
253
|
+
const batches = [];
|
|
254
|
+
for(let start = 0; start < report.queue.length; start += report.batchSize){
|
|
255
|
+
batches.push(report.queue.slice(start, start + report.batchSize));
|
|
256
|
+
}
|
|
257
|
+
return batches;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
//# sourceMappingURL=seo-audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/runtime/seo-audit.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n SEO_LISTING_FIELDS,\n seoListingFieldTooLong,\n} from '@aglyn/aglyn/app-utils/seo-listing-fields'\nimport type {\n AiSeoAuditReport,\n AiSeoContentFix,\n AiSeoFinding,\n AiSeoFindingCode,\n AiSeoPageReport,\n AiSeoSeverity,\n} from '../model/ai-seo'\nimport { aiSeoKeywordCoverage, aiSeoKeywordList } from '../tools/ai-seo-tool'\nimport type { AiSeoPageFacts } from './seo-page-facts'\n\n/**\n * The site SEO audit's scoring (AGL-2910): every audited page held to what a\n * search result and a crawler need, with nothing asked of a model. Pure, so\n * the audit is proved against fixtures and a job only spends tokens on the\n * fixes it cannot make without writing.\n *\n * Per page: a title and a description of its own, within their lengths and\n * used on no other page; one main heading that says something; a description\n * on every image; a link from somewhere else on the site; and the target\n * keywords a person named, reported where the page already says them.\n * Per site: whether search engines are told to stay away, whether the\n * structured data names and describes the publisher, and whether agents get\n * guidance of the author's own.\n *\n * Keyword coverage is reported, never forced. A page that does not say a\n * keyword is told so; the fix a job proposes uses the keyword only where the\n * page is about it, and the listing check refuses a keyword used past its\n * per-field count.\n */\n\n/** Pages one audit covers. A larger site is audited on its first pages by path, and says how many it left. */\nexport const AI_SEO_AUDIT_MAX_PAGES = 150\n\n/** Pages one batch of fixes carries: one model call a batch. */\nexport const AI_SEO_AUDIT_BATCH_SIZE = 8\n\n/** What each severity takes off a page's score. */\nconst SEVERITY_WEIGHT: Record<AiSeoSeverity, number> = { high: 25, medium: 10, low: 3 }\n\n/** A main heading this short or this generic says nothing a searcher can use. */\nconst THIN_H1_MIN_CHARS = 10\nconst GENERIC_H1: ReadonlySet<string> = new Set([\n 'home',\n 'homepage',\n 'home page',\n 'welcome',\n 'hello',\n 'untitled',\n 'new page',\n 'page',\n 'title',\n 'heading',\n])\n\n/** The findings a batch of generated fixes answers. */\nconst GENERATED_FIX_CODES: ReadonlySet<AiSeoFindingCode> = new Set([\n 'title-missing',\n 'title-too-long',\n 'title-duplicate',\n 'description-missing',\n 'description-too-long',\n 'description-duplicate',\n 'h1-missing',\n 'h1-thin',\n 'image-alt-missing',\n 'keyword-missing',\n])\n\n/** One page as the audit reads it. */\nexport interface AiSeoAuditPage {\n screenId: string\n /** The public path, `/` for the home page. */\n path: string\n name: string\n versionId: string | null\n seo: {\n title?: string | null\n description?: string | null\n breadcrumb?: string | null\n image?: string | null\n imageAlt?: string | null\n }\n /** The screen's own description, which the head falls back to. */\n description?: string | null\n facts: AiSeoPageFacts\n /** Whether another audited page or a shared layout links here. */\n linkedFrom: boolean\n keywords: readonly string[]\n}\n\n/** The site as the audit reads it. */\nexport interface AiSeoAuditSite {\n discouraged: boolean\n entity: { name?: string | null; description?: string | null }\n agent: { whenToUse?: string | null }\n}\n\nconst blank = (value: string | null | undefined): boolean => !String(value ?? '').trim()\nconst normalized = (value: string | null | undefined): string =>\n String(value ?? '').replace(/\\s+/g, ' ').trim().toLowerCase()\n\n/** A path as the keyword lines and the routing map both spell it: leading slash, no trailing one. */\nexport function aiSeoNormalizePath(path: string): string {\n const trimmed = String(path ?? '').trim()\n if (!trimmed || trimmed === '/') return '/'\n return `/${trimmed.replace(/^\\/+/, '').replace(/\\/+$/, '')}`\n}\n\n/**\n * Target keywords per page, one line a page: `/pricing: plans, pricing`.\n * A line without a path, or with a path the site does not have, names no\n * page; the step reports the paths it could not match.\n */\nexport function parseAiSeoKeywordLines(raw: unknown): Record<string, string[]> {\n const out: Record<string, string[]> = {}\n for (const line of String(raw ?? '').split('\\n')) {\n const at = line.indexOf(':')\n if (at <= 0) continue\n const path = aiSeoNormalizePath(line.slice(0, at))\n const keywords = aiSeoKeywordList(line.slice(at + 1))\n if (keywords.length) out[path] = aiSeoKeywordList([...(out[path] ?? []), ...keywords])\n }\n return out\n}\n\nfunction finding(\n code: AiSeoFindingCode,\n severity: AiSeoSeverity,\n message: string,\n extra: Partial<Pick<AiSeoFinding, 'nodeIds' | 'screenIds' | 'keyword'>> = {},\n): AiSeoFinding {\n return { code, severity, message, ...extra }\n}\n\n/** The pages that share one value, by that value. */\nfunction sharedValues(\n pages: readonly AiSeoAuditPage[],\n read: (page: AiSeoAuditPage) => string | null | undefined,\n): Map<string, string[]> {\n const groups = new Map<string, string[]>()\n for (const page of pages) {\n const key = normalized(read(page))\n if (!key) continue\n groups.set(key, [...(groups.get(key) ?? []), page.screenId])\n }\n return new Map([...groups].filter(([, ids]) => ids.length > 1))\n}\n\nfunction pageFindings(\n page: AiSeoAuditPage,\n titles: Map<string, string[]>,\n descriptions: Map<string, string[]>,\n): AiSeoFinding[] {\n const out: AiSeoFinding[] = []\n const title = page.seo.title\n if (blank(title)) {\n out.push(finding('title-missing', 'medium', 'This page has no search title, so results show its name beside the site title.'))\n } else {\n if (seoListingFieldTooLong('title', title)) {\n out.push(finding('title-too-long', 'medium', `The search title is over ${SEO_LISTING_FIELDS.title.maxLength} characters and will be cut off in results.`))\n }\n const twins = titles.get(normalized(title))?.filter((id) => id !== page.screenId)\n if (twins?.length) {\n out.push(finding('title-duplicate', 'high', 'Another page uses the same search title, so results cannot tell them apart.', { screenIds: twins }))\n }\n }\n\n const description = page.seo.description\n if (blank(description) && blank(page.description)) {\n out.push(finding('description-missing', 'medium', 'This page has no search description, so results show the site’s.'))\n } else if (!blank(description)) {\n if (seoListingFieldTooLong('description', description)) {\n out.push(finding('description-too-long', 'low', `The search description is over ${SEO_LISTING_FIELDS.description.maxLength} characters and will be cut off.`))\n }\n const twins = descriptions.get(normalized(description))?.filter((id) => id !== page.screenId)\n if (twins?.length) {\n out.push(finding('description-duplicate', 'medium', 'Another page uses the same search description.', { screenIds: twins }))\n }\n }\n\n const { h1s } = page.facts\n if (!h1s.length) {\n out.push(finding('h1-missing', 'high', 'This page has no main heading.'))\n } else {\n if (h1s.length > 1) {\n out.push(\n finding('h1-multiple', 'medium', `This page has ${h1s.length} main headings; it should have one.`, {\n nodeIds: h1s.slice(1).map((heading) => heading.nodeId).filter((id): id is string => Boolean(id)),\n }),\n )\n }\n const first = h1s[0]\n if (first.text.length < THIN_H1_MIN_CHARS || GENERIC_H1.has(normalized(first.text))) {\n out.push(\n finding('h1-thin', 'medium', `The main heading “${first.text}” says little about the page.`, {\n nodeIds: first.nodeId ? [first.nodeId] : [],\n }),\n )\n }\n }\n\n const missingAlt = page.facts.imagesMissingAlt\n if (missingAlt.length) {\n out.push(\n finding(\n 'image-alt-missing',\n 'medium',\n `${missingAlt.length} ${missingAlt.length === 1 ? 'image has' : 'images have'} no description for readers who cannot see ${missingAlt.length === 1 ? 'it' : 'them'}.`,\n { nodeIds: missingAlt.map((image) => image.nodeId) },\n ),\n )\n }\n\n if (!page.linkedFrom && page.path !== '/') {\n out.push(finding('orphan', 'medium', 'No other page or shared layout links here, so visitors and crawlers may never find it.'))\n }\n\n const coverage = aiSeoKeywordCoverage(page.keywords, {\n title: page.seo.title,\n description: page.seo.description,\n h1: h1s[0]?.text,\n body: page.facts.text,\n })\n for (const entry of coverage) {\n if (!entry.inTitle && !entry.inDescription && !entry.inH1 && !entry.inBody) {\n out.push(\n finding('keyword-missing', 'low', `The page never says “${entry.keyword}”. Only use it if the page is about it.`, {\n keyword: entry.keyword,\n }),\n )\n }\n }\n return out\n}\n\nfunction scoreOf(findings: readonly AiSeoFinding[]): number {\n return Math.max(0, 100 - findings.reduce((sum, entry) => sum + SEVERITY_WEIGHT[entry.severity], 0))\n}\n\n/** Audit the pages and the site; nothing here reads, writes or generates. */\nexport function aiSeoAudit(\n pages: readonly AiSeoAuditPage[],\n site: AiSeoAuditSite,\n options: { skipped?: number; batchSize?: number } = {},\n): AiSeoAuditReport {\n const titles = sharedValues(pages, (page) => page.seo.title)\n const descriptions = sharedValues(pages, (page) => page.seo.description)\n const reports: AiSeoPageReport[] = pages.map((page) => {\n const findings = pageFindings(page, titles, descriptions)\n return {\n screenId: page.screenId,\n path: page.path,\n name: page.name,\n versionId: page.versionId,\n score: scoreOf(findings),\n findings,\n keywords: aiSeoKeywordCoverage(page.keywords, {\n title: page.seo.title,\n description: page.seo.description,\n h1: page.facts.h1s[0]?.text,\n body: page.facts.text,\n }),\n }\n })\n\n const siteFindings: AiSeoFinding[] = []\n if (site.discouraged) {\n siteFindings.push(finding('search-discouraged', 'high', 'Search engines are asked not to index this site, so none of its pages appear in results.'))\n }\n if (blank(site.entity.name) || blank(site.entity.description)) {\n siteFindings.push(finding('entity-incomplete', 'low', 'The structured data does not name and describe who publishes the site.'))\n }\n if (blank(site.agent.whenToUse)) {\n siteFindings.push(finding('llms-guidance-missing', 'low', '/llms.txt carries no guidance of your own for AI agents.'))\n }\n\n const queue = reports\n .filter((report) => report.findings.some((entry) => GENERATED_FIX_CODES.has(entry.code)))\n .sort((a, b) => a.score - b.score || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0))\n .map((report) => report.screenId)\n\n return {\n kind: 'audit',\n pages: reports,\n skipped: Math.max(0, options.skipped ?? 0),\n site: siteFindings,\n siteProposal: siteFindings.some((entry) => entry.code === 'entity-incomplete' || entry.code === 'llms-guidance-missing'),\n queue,\n batchSize: Math.max(1, options.batchSize ?? AI_SEO_AUDIT_BATCH_SIZE),\n score: reports.length\n ? Math.round(reports.reduce((sum, report) => sum + report.score, 0) / reports.length)\n : 100,\n notes: [],\n }\n}\n\n/**\n * The content fixes that need no model: every main heading after the first\n * editable one becomes an `h2`, so the page keeps one.\n */\nexport function aiSeoHeadingDemotions(facts: AiSeoPageFacts): AiSeoContentFix[] {\n const editable = facts.h1s.filter((heading) => heading.editable && heading.nodeId)\n if (facts.h1s.length < 2 || !editable.length) return []\n const keep = editable[0].nodeId\n return editable\n .filter((heading) => heading.nodeId !== keep)\n .map((heading) => ({ kind: 'h1-demote', nodeId: heading.nodeId as string }))\n}\n\n/** The queue's batches, in order. */\nexport function aiSeoAuditBatches(report: Pick<AiSeoAuditReport, 'queue' | 'batchSize'>): string[][] {\n const batches: string[][] = []\n for (let start = 0; start < report.queue.length; start += report.batchSize) {\n batches.push(report.queue.slice(start, start + report.batchSize))\n }\n return batches\n}\n"],"names":["SEO_LISTING_FIELDS","seoListingFieldTooLong","aiSeoKeywordCoverage","aiSeoKeywordList","AI_SEO_AUDIT_MAX_PAGES","AI_SEO_AUDIT_BATCH_SIZE","SEVERITY_WEIGHT","high","medium","low","THIN_H1_MIN_CHARS","GENERIC_H1","Set","GENERATED_FIX_CODES","blank","value","String","trim","normalized","replace","toLowerCase","aiSeoNormalizePath","path","trimmed","parseAiSeoKeywordLines","raw","out","line","split","at","indexOf","slice","keywords","length","finding","code","severity","message","extra","sharedValues","pages","read","groups","Map","page","key","set","get","screenId","filter","ids","pageFindings","titles","descriptions","h1s","title","seo","push","maxLength","twins","id","screenIds","description","facts","nodeIds","map","heading","nodeId","Boolean","first","text","has","missingAlt","imagesMissingAlt","image","linkedFrom","coverage","h1","body","entry","inTitle","inDescription","inH1","inBody","keyword","scoreOf","findings","Math","max","reduce","sum","aiSeoAudit","site","options","reports","name","versionId","score","siteFindings","discouraged","entity","agent","whenToUse","queue","report","some","sort","a","b","kind","skipped","siteProposal","batchSize","round","notes","aiSeoHeadingDemotions","editable","keep","aiSeoAuditBatches","batches","start"],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import type { AiSeoContentFix } from '../model/ai-seo';
|
|
18
|
+
/**
|
|
19
|
+
* A site audit's content fixes, applied to a COPY of a page's node map
|
|
20
|
+
* (AGL-2910). The caller stores the result as a new unpublished version;
|
|
21
|
+
* nothing here reads or writes a document, and the map it is handed is
|
|
22
|
+
* never changed.
|
|
23
|
+
*
|
|
24
|
+
* Each fix is checked against the page as it is now, not as it was audited:
|
|
25
|
+
* an image that has gained a description keeps it, a heading that has gone
|
|
26
|
+
* is skipped, and every skip is named. A heading's new text and a new
|
|
27
|
+
* heading pass the AI node-tree validator — the one path an AI-emitted node
|
|
28
|
+
* takes into storage — before they touch the copy.
|
|
29
|
+
*/
|
|
30
|
+
export interface AiSeoContentFixResult {
|
|
31
|
+
nodes: Record<string, Record<string, unknown>>;
|
|
32
|
+
/** Fixes that changed the copy. */
|
|
33
|
+
applied: AiSeoContentFix[];
|
|
34
|
+
/** Fixes that did not, each with the customer-safe reason. */
|
|
35
|
+
skipped: Array<{
|
|
36
|
+
fix: AiSeoContentFix;
|
|
37
|
+
reason: string;
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
40
|
+
/** Apply `fixes` to a copy of `nodes`, whose content region starts at `contentRootId`. */
|
|
41
|
+
export declare function applyAiSeoContentFixes(nodes: Record<string, unknown>, fixes: readonly AiSeoContentFix[], contentRootId: string | null): AiSeoContentFixResult;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ import { MEDIA_ALT_MAX_LENGTH } from "@aglyn/aglyn/app-utils/media-alt";
|
|
18
|
+
import { CANVAS_ROOT_ELEMENT_ID } from "@aglyn/aglyn/foundation/constants/canvas";
|
|
19
|
+
import { validateAiNodeTree } from "./ai-node-tree.js";
|
|
20
|
+
import { AI_TEXT_LIMITS } from "./ai-palette.js";
|
|
21
|
+
const isRecord = (value)=>typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
22
|
+
const TEXT_COMPONENTS = new Set([
|
|
23
|
+
'muiTypography',
|
|
24
|
+
'muiInlineText',
|
|
25
|
+
'muiListItemText'
|
|
26
|
+
]);
|
|
27
|
+
/**
|
|
28
|
+
* A heading as the validator would store it: the text held to a headline's
|
|
29
|
+
* length and the element to the palette. `null` when the validator refuses
|
|
30
|
+
* it — the text is not something a generated heading may say.
|
|
31
|
+
*/ function validatedHeading(level, text) {
|
|
32
|
+
var _ref, _ref1;
|
|
33
|
+
var _root_nodes;
|
|
34
|
+
const result = validateAiNodeTree({
|
|
35
|
+
rootId: CANVAS_ROOT_ELEMENT_ID,
|
|
36
|
+
nodes: {
|
|
37
|
+
[CANVAS_ROOT_ELEMENT_ID]: {
|
|
38
|
+
$id: CANVAS_ROOT_ELEMENT_ID,
|
|
39
|
+
componentId: 'div',
|
|
40
|
+
parentId: null,
|
|
41
|
+
nodes: [
|
|
42
|
+
'heading'
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
heading: {
|
|
46
|
+
$id: 'heading',
|
|
47
|
+
componentId: 'muiTypography',
|
|
48
|
+
parentId: CANVAS_ROOT_ELEMENT_ID,
|
|
49
|
+
props: {
|
|
50
|
+
variant: `h${level}`,
|
|
51
|
+
children: text.slice(0, AI_TEXT_LIMITS.headline)
|
|
52
|
+
},
|
|
53
|
+
nodes: []
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}, 'screen');
|
|
57
|
+
if (!result.ok) return null;
|
|
58
|
+
const root = result.nodes[result.rootId];
|
|
59
|
+
const node = result.nodes[(_ref = (_root_nodes = root.nodes) == null ? void 0 : _root_nodes[0]) != null ? _ref : ''];
|
|
60
|
+
const props = (_ref1 = node == null ? void 0 : node['props']) != null ? _ref1 : {};
|
|
61
|
+
const children = typeof props['children'] === 'string' ? props['children'].trim() : '';
|
|
62
|
+
return children && node ? {
|
|
63
|
+
text: children,
|
|
64
|
+
node
|
|
65
|
+
} : null;
|
|
66
|
+
}
|
|
67
|
+
const cloneNodes = (nodes)=>JSON.parse(JSON.stringify(nodes));
|
|
68
|
+
/** Apply `fixes` to a copy of `nodes`, whose content region starts at `contentRootId`. */ export function applyAiSeoContentFixes(nodes, fixes, contentRootId) {
|
|
69
|
+
const copy = cloneNodes(nodes);
|
|
70
|
+
const applied = [];
|
|
71
|
+
const skipped = [];
|
|
72
|
+
const skip = (fix, reason)=>skipped.push({
|
|
73
|
+
fix,
|
|
74
|
+
reason
|
|
75
|
+
});
|
|
76
|
+
for (const fix of fixes){
|
|
77
|
+
switch(fix.kind){
|
|
78
|
+
case 'image-alt':
|
|
79
|
+
{
|
|
80
|
+
var _props_alt;
|
|
81
|
+
const node = copy[fix.nodeId];
|
|
82
|
+
if (!node || node['componentId'] !== 'image') {
|
|
83
|
+
skip(fix, 'The image is no longer on the page.');
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
const props = isRecord(node.props) ? node.props : {};
|
|
87
|
+
if (String((_props_alt = props['alt']) != null ? _props_alt : '').trim()) {
|
|
88
|
+
skip(fix, 'The image has been given a description since the audit.');
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
const alt = fix.alt.replace(/\s+/g, ' ').trim().slice(0, MEDIA_ALT_MAX_LENGTH);
|
|
92
|
+
if (!alt) {
|
|
93
|
+
skip(fix, 'The proposed description was empty.');
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
node.props = _extends({}, props, {
|
|
97
|
+
alt
|
|
98
|
+
});
|
|
99
|
+
applied.push(fix);
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case 'h1-set':
|
|
103
|
+
case 'h1-demote':
|
|
104
|
+
{
|
|
105
|
+
const node = copy[fix.nodeId];
|
|
106
|
+
const props = node && isRecord(node.props) ? node.props : null;
|
|
107
|
+
if (!node || !props || !TEXT_COMPONENTS.has(String(node['componentId']))) {
|
|
108
|
+
skip(fix, 'The heading is no longer on the page.');
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
if (typeof props['html'] === 'string' && props['html'].trim()) {
|
|
112
|
+
skip(fix, 'The heading is rich text, which a fix does not rewrite.');
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
if (fix.kind === 'h1-demote') {
|
|
116
|
+
node.props = _extends({}, props, {
|
|
117
|
+
component: 'h2'
|
|
118
|
+
});
|
|
119
|
+
applied.push(fix);
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
const heading = validatedHeading(1, fix.text);
|
|
123
|
+
if (!heading) {
|
|
124
|
+
skip(fix, 'The proposed heading could not be used.');
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
node.props = _extends({}, props, {
|
|
128
|
+
component: 'h1',
|
|
129
|
+
children: heading.text
|
|
130
|
+
});
|
|
131
|
+
applied.push(fix);
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
case 'h1-insert':
|
|
135
|
+
{
|
|
136
|
+
const parent = contentRootId ? copy[contentRootId] : undefined;
|
|
137
|
+
if (!parent || !contentRootId) {
|
|
138
|
+
skip(fix, 'The page has no content region to add a heading to.');
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
const heading = validatedHeading(1, fix.text);
|
|
142
|
+
if (!heading) {
|
|
143
|
+
skip(fix, 'The proposed heading could not be used.');
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
const id = String(heading.node['$id']);
|
|
147
|
+
copy[id] = _extends({}, heading.node, {
|
|
148
|
+
parentId: contentRootId,
|
|
149
|
+
nodes: []
|
|
150
|
+
});
|
|
151
|
+
const children = Array.isArray(parent.nodes) ? parent.nodes : [];
|
|
152
|
+
parent.nodes = [
|
|
153
|
+
id,
|
|
154
|
+
...children
|
|
155
|
+
];
|
|
156
|
+
applied.push(fix);
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
nodes: copy,
|
|
163
|
+
applied,
|
|
164
|
+
skipped
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
//# sourceMappingURL=seo-content-fixes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/runtime/seo-content-fixes.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { MEDIA_ALT_MAX_LENGTH } from '@aglyn/aglyn/app-utils/media-alt'\nimport { CANVAS_ROOT_ELEMENT_ID } from '@aglyn/aglyn/foundation/constants/canvas'\nimport type { AiSeoContentFix } from '../model/ai-seo'\nimport { validateAiNodeTree } from './ai-node-tree'\nimport { AI_TEXT_LIMITS } from './ai-palette'\n\n/**\n * A site audit's content fixes, applied to a COPY of a page's node map\n * (AGL-2910). The caller stores the result as a new unpublished version;\n * nothing here reads or writes a document, and the map it is handed is\n * never changed.\n *\n * Each fix is checked against the page as it is now, not as it was audited:\n * an image that has gained a description keeps it, a heading that has gone\n * is skipped, and every skip is named. A heading's new text and a new\n * heading pass the AI node-tree validator — the one path an AI-emitted node\n * takes into storage — before they touch the copy.\n */\n\nexport interface AiSeoContentFixResult {\n nodes: Record<string, Record<string, unknown>>\n /** Fixes that changed the copy. */\n applied: AiSeoContentFix[]\n /** Fixes that did not, each with the customer-safe reason. */\n skipped: Array<{ fix: AiSeoContentFix; reason: string }>\n}\n\ntype StoredNode = Record<string, unknown> & { props?: Record<string, unknown>; nodes?: unknown }\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst TEXT_COMPONENTS: ReadonlySet<string> = new Set(['muiTypography', 'muiInlineText', 'muiListItemText'])\n\n/**\n * A heading as the validator would store it: the text held to a headline's\n * length and the element to the palette. `null` when the validator refuses\n * it — the text is not something a generated heading may say.\n */\nfunction validatedHeading(level: 1 | 2, text: string): { text: string; node: Record<string, unknown> } | null {\n const result = validateAiNodeTree(\n {\n rootId: CANVAS_ROOT_ELEMENT_ID,\n nodes: {\n [CANVAS_ROOT_ELEMENT_ID]: {\n $id: CANVAS_ROOT_ELEMENT_ID,\n componentId: 'div',\n parentId: null,\n nodes: ['heading'],\n },\n heading: {\n $id: 'heading',\n componentId: 'muiTypography',\n parentId: CANVAS_ROOT_ELEMENT_ID,\n props: { variant: `h${level}`, children: text.slice(0, AI_TEXT_LIMITS.headline) },\n nodes: [],\n },\n },\n },\n 'screen',\n )\n if (!result.ok) return null\n const root = result.nodes[result.rootId] as { nodes?: string[] }\n const node = result.nodes[root.nodes?.[0] ?? ''] as Record<string, unknown> | undefined\n const props = (node?.['props'] ?? {}) as Record<string, unknown>\n const children = typeof props['children'] === 'string' ? props['children'].trim() : ''\n return children && node ? { text: children, node } : null\n}\n\nconst cloneNodes = (nodes: Record<string, unknown>): Record<string, StoredNode> =>\n JSON.parse(JSON.stringify(nodes)) as Record<string, StoredNode>\n\n/** Apply `fixes` to a copy of `nodes`, whose content region starts at `contentRootId`. */\nexport function applyAiSeoContentFixes(\n nodes: Record<string, unknown>,\n fixes: readonly AiSeoContentFix[],\n contentRootId: string | null,\n): AiSeoContentFixResult {\n const copy = cloneNodes(nodes)\n const applied: AiSeoContentFix[] = []\n const skipped: AiSeoContentFixResult['skipped'] = []\n const skip = (fix: AiSeoContentFix, reason: string) => skipped.push({ fix, reason })\n\n for (const fix of fixes) {\n switch (fix.kind) {\n case 'image-alt': {\n const node = copy[fix.nodeId]\n if (!node || node['componentId'] !== 'image') {\n skip(fix, 'The image is no longer on the page.')\n break\n }\n const props = isRecord(node.props) ? node.props : {}\n if (String(props['alt'] ?? '').trim()) {\n skip(fix, 'The image has been given a description since the audit.')\n break\n }\n const alt = fix.alt.replace(/\\s+/g, ' ').trim().slice(0, MEDIA_ALT_MAX_LENGTH)\n if (!alt) {\n skip(fix, 'The proposed description was empty.')\n break\n }\n node.props = { ...props, alt }\n applied.push(fix)\n break\n }\n case 'h1-set':\n case 'h1-demote': {\n const node = copy[fix.nodeId]\n const props = node && isRecord(node.props) ? node.props : null\n if (!node || !props || !TEXT_COMPONENTS.has(String(node['componentId']))) {\n skip(fix, 'The heading is no longer on the page.')\n break\n }\n if (typeof props['html'] === 'string' && props['html'].trim()) {\n skip(fix, 'The heading is rich text, which a fix does not rewrite.')\n break\n }\n if (fix.kind === 'h1-demote') {\n node.props = { ...props, component: 'h2' }\n applied.push(fix)\n break\n }\n const heading = validatedHeading(1, fix.text)\n if (!heading) {\n skip(fix, 'The proposed heading could not be used.')\n break\n }\n node.props = { ...props, component: 'h1', children: heading.text }\n applied.push(fix)\n break\n }\n case 'h1-insert': {\n const parent = contentRootId ? copy[contentRootId] : undefined\n if (!parent || !contentRootId) {\n skip(fix, 'The page has no content region to add a heading to.')\n break\n }\n const heading = validatedHeading(1, fix.text)\n if (!heading) {\n skip(fix, 'The proposed heading could not be used.')\n break\n }\n const id = String(heading.node['$id'])\n copy[id] = { ...heading.node, parentId: contentRootId, nodes: [] }\n const children = Array.isArray(parent.nodes) ? (parent.nodes as unknown[]) : []\n parent.nodes = [id, ...children]\n applied.push(fix)\n break\n }\n }\n }\n return { nodes: copy, applied, skipped }\n}\n"],"names":["MEDIA_ALT_MAX_LENGTH","CANVAS_ROOT_ELEMENT_ID","validateAiNodeTree","AI_TEXT_LIMITS","isRecord","value","Array","isArray","TEXT_COMPONENTS","Set","validatedHeading","level","text","root","result","rootId","nodes","$id","componentId","parentId","heading","props","variant","children","slice","headline","ok","node","trim","cloneNodes","JSON","parse","stringify","applyAiSeoContentFixes","fixes","contentRootId","copy","applied","skipped","skip","fix","reason","push","kind","nodeId","String","alt","replace","has","component","parent","undefined","id"],"mappings":"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"}
|