@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,156 @@
|
|
|
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
|
+
*/ // lockdown-423: exempt — server-internal cron (x-cron-secret) with no user
|
|
18
|
+
// caller; it asks each workspace's ai-generate pause before it creates a job,
|
|
19
|
+
// and the jobs it creates are held by the same pause on the beat.
|
|
20
|
+
import { writeCronBeat } from "@aglyn/aglyn/app-utils/health-report";
|
|
21
|
+
import { rateLimitedRetryAtMs, sendEmail } from "@aglyn/shared-util-email";
|
|
22
|
+
import { filterSuppressedEmails } from "@aglyn/tenant-data-admin/server/email-suppression";
|
|
23
|
+
import { meterPlatformEmail } from "@aglyn/tenant-data-admin/server/email-metering";
|
|
24
|
+
import { firebaseAdmin } from "@aglyn/tenant-data-admin/server/firebase-admin";
|
|
25
|
+
import { featureLockdownRefusal } from "@aglyn/tenant-data-admin/server/lockdown";
|
|
26
|
+
import { notifyUsers } from "@aglyn/tenant-data-admin/server/notifications";
|
|
27
|
+
import { listOrgMembers, memberHasPermissionOnHost } from "@aglyn/tenant-data-admin/server/organizations";
|
|
28
|
+
import { getServerReleaseFlagValues } from "@aglyn/tenant-data-admin/server/release-flags";
|
|
29
|
+
import { safeEqual } from "@aglyn/tenant-data-admin/server/safe-equal";
|
|
30
|
+
import { runAiInsightDigestSweep } from "../insights/ai-insight-digest.js";
|
|
31
|
+
/**
|
|
32
|
+
* The weekly insights' scheduled route (AGL-2915):
|
|
33
|
+
* `POST /api/admin/ai-insights-digest`.
|
|
34
|
+
*
|
|
35
|
+
* Cloud Scheduler calls it at 06:00 and 14:00 UTC through
|
|
36
|
+
* `consoleAiInsightsDigest` in `cloud/functions`, on the console's
|
|
37
|
+
* `CRON_SECRET`: 501 while the secret is unset, 401 without it. Monday's
|
|
38
|
+
* first run makes the week's digests, which the AI jobs beat then writes, and
|
|
39
|
+
* every run after it delivers what is written — see `ai-insight-digest.ts`.
|
|
40
|
+
* `/api/admin/` is the path because the console's edge lets the cron secret's
|
|
41
|
+
* header through there. It stamps `ai-insights-digest` for
|
|
42
|
+
* `/api/health/crons` on every authorized call.
|
|
43
|
+
*/ export async function POST(request) {
|
|
44
|
+
if (request.method !== 'POST') {
|
|
45
|
+
return Response.json({
|
|
46
|
+
error: 'Method not allowed'
|
|
47
|
+
}, {
|
|
48
|
+
status: 405
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const secret = process.env.CRON_SECRET;
|
|
52
|
+
if (!secret) {
|
|
53
|
+
return Response.json({
|
|
54
|
+
error: 'The weekly insights are not configured (CRON_SECRET).'
|
|
55
|
+
}, {
|
|
56
|
+
status: 501
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (!safeEqual(request.headers.get('x-cron-secret'), secret) && !safeEqual(request.headers.get('authorization'), `Bearer ${secret}`)) {
|
|
60
|
+
return Response.json({
|
|
61
|
+
error: 'Unauthenticated'
|
|
62
|
+
}, {
|
|
63
|
+
status: 401
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const firestore = firebaseAdmin.app().firestore();
|
|
67
|
+
// The inventory row's id, written out: `cron-beat-wiring.spec.ts` finds a
|
|
68
|
+
// job's stamp by the quoted id beside the call.
|
|
69
|
+
await writeCronBeat(firestore, 'ai-insights-digest');
|
|
70
|
+
let cursor = null;
|
|
71
|
+
try {
|
|
72
|
+
const body = await request.json();
|
|
73
|
+
const raw = body == null ? void 0 : body.cursor;
|
|
74
|
+
cursor = typeof raw === 'string' && raw && !raw.includes('/') ? raw : null;
|
|
75
|
+
} catch (unused) {
|
|
76
|
+
// A bodyless POST is the first call of a run.
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
var _process_env_NEXT_PUBLIC_CONSOLE_URL;
|
|
80
|
+
// The platform switch holds the whole run, as it holds the jobs beat.
|
|
81
|
+
if (await featureLockdownRefusal({
|
|
82
|
+
feature: 'ai-generate'
|
|
83
|
+
})) {
|
|
84
|
+
return Response.json({
|
|
85
|
+
held: true,
|
|
86
|
+
done: true,
|
|
87
|
+
nextCursor: null
|
|
88
|
+
}, {
|
|
89
|
+
status: 200
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const flags = await getServerReleaseFlagValues();
|
|
93
|
+
const deps = {
|
|
94
|
+
firestore,
|
|
95
|
+
now: new Date(),
|
|
96
|
+
flagValue: flags['release_ai_generative'],
|
|
97
|
+
listMembers: listOrgMembers,
|
|
98
|
+
mayGenerate: (orgId, hostId, member)=>memberHasPermissionOnHost(orgId, hostId, member, 'ai.generate'),
|
|
99
|
+
paused: async (orgId)=>Boolean(await featureLockdownRefusal({
|
|
100
|
+
feature: 'ai-generate',
|
|
101
|
+
orgId
|
|
102
|
+
})),
|
|
103
|
+
notify: (uid, payload)=>notifyUsers([
|
|
104
|
+
uid
|
|
105
|
+
], _extends({
|
|
106
|
+
type: 'content.insightsDigest'
|
|
107
|
+
}, payload)),
|
|
108
|
+
send: async (email)=>{
|
|
109
|
+
const recipients = await filterSuppressedEmails([
|
|
110
|
+
email.to
|
|
111
|
+
], firestore);
|
|
112
|
+
if (!recipients.length) return {
|
|
113
|
+
sent: false,
|
|
114
|
+
rateLimited: false
|
|
115
|
+
};
|
|
116
|
+
const result = await sendEmail({
|
|
117
|
+
to: recipients,
|
|
118
|
+
subject: email.subject,
|
|
119
|
+
text: email.text,
|
|
120
|
+
fromName: email.fromName,
|
|
121
|
+
context: 'ai-insights-digest',
|
|
122
|
+
priority: 'bulk'
|
|
123
|
+
});
|
|
124
|
+
if (result.sent) {
|
|
125
|
+
await meterPlatformEmail().catch(()=>undefined);
|
|
126
|
+
return {
|
|
127
|
+
sent: true,
|
|
128
|
+
rateLimited: false
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
sent: false,
|
|
133
|
+
rateLimited: rateLimitedRetryAtMs(result) !== null
|
|
134
|
+
};
|
|
135
|
+
},
|
|
136
|
+
// An email link must be absolute; with no console URL configured the
|
|
137
|
+
// digest says where to look without one.
|
|
138
|
+
consoleOrigin: ((_process_env_NEXT_PUBLIC_CONSOLE_URL = process.env.NEXT_PUBLIC_CONSOLE_URL) != null ? _process_env_NEXT_PUBLIC_CONSOLE_URL : '').trim().replace(/\/+$/, '')
|
|
139
|
+
};
|
|
140
|
+
const report = await runAiInsightDigestSweep(deps, {
|
|
141
|
+
cursor
|
|
142
|
+
});
|
|
143
|
+
return Response.json(report, {
|
|
144
|
+
status: 200
|
|
145
|
+
});
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.error('ai insights digest run failed', error);
|
|
148
|
+
return Response.json({
|
|
149
|
+
error: 'The weekly insights run failed'
|
|
150
|
+
}, {
|
|
151
|
+
status: 500
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
//# sourceMappingURL=ai-insight-digest-route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/server/ai-insight-digest-route.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\n// lockdown-423: exempt — server-internal cron (x-cron-secret) with no user\n// caller; it asks each workspace's ai-generate pause before it creates a job,\n// and the jobs it creates are held by the same pause on the beat.\n\nimport { writeCronBeat } from '@aglyn/aglyn/app-utils/health-report'\nimport { rateLimitedRetryAtMs, sendEmail } from '@aglyn/shared-util-email'\nimport { filterSuppressedEmails } from '@aglyn/tenant-data-admin/server/email-suppression'\nimport { meterPlatformEmail } from '@aglyn/tenant-data-admin/server/email-metering'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin/server/firebase-admin'\nimport { featureLockdownRefusal } from '@aglyn/tenant-data-admin/server/lockdown'\nimport { notifyUsers } from '@aglyn/tenant-data-admin/server/notifications'\nimport { listOrgMembers, memberHasPermissionOnHost } from '@aglyn/tenant-data-admin/server/organizations'\nimport { getServerReleaseFlagValues } from '@aglyn/tenant-data-admin/server/release-flags'\nimport { safeEqual } from '@aglyn/tenant-data-admin/server/safe-equal'\nimport {\n AI_INSIGHTS_DIGEST_CRON_ID,\n runAiInsightDigestSweep,\n type AiInsightDigestDeps,\n} from '../insights/ai-insight-digest'\n\n/**\n * The weekly insights' scheduled route (AGL-2915):\n * `POST /api/admin/ai-insights-digest`.\n *\n * Cloud Scheduler calls it at 06:00 and 14:00 UTC through\n * `consoleAiInsightsDigest` in `cloud/functions`, on the console's\n * `CRON_SECRET`: 501 while the secret is unset, 401 without it. Monday's\n * first run makes the week's digests, which the AI jobs beat then writes, and\n * every run after it delivers what is written — see `ai-insight-digest.ts`.\n * `/api/admin/` is the path because the console's edge lets the cron secret's\n * header through there. It stamps `ai-insights-digest` for\n * `/api/health/crons` on every authorized call.\n */\nexport async function POST(request: Request): Promise<Response> {\n if (request.method !== 'POST') {\n return Response.json({ error: 'Method not allowed' }, { status: 405 })\n }\n const secret = process.env.CRON_SECRET\n if (!secret) {\n return Response.json({ error: 'The weekly insights are not configured (CRON_SECRET).' }, { status: 501 })\n }\n if (\n !safeEqual(request.headers.get('x-cron-secret'), secret) &&\n !safeEqual(request.headers.get('authorization'), `Bearer ${secret}`)\n ) {\n return Response.json({ error: 'Unauthenticated' }, { status: 401 })\n }\n const firestore = firebaseAdmin.app().firestore()\n // The inventory row's id, written out: `cron-beat-wiring.spec.ts` finds a\n // job's stamp by the quoted id beside the call.\n await writeCronBeat(firestore, 'ai-insights-digest' satisfies typeof AI_INSIGHTS_DIGEST_CRON_ID)\n\n let cursor: string | null = null\n try {\n const body = (await request.json()) as { cursor?: unknown } | null\n const raw = body?.cursor\n cursor = typeof raw === 'string' && raw && !raw.includes('/') ? raw : null\n } catch {\n // A bodyless POST is the first call of a run.\n }\n\n try {\n // The platform switch holds the whole run, as it holds the jobs beat.\n if (await featureLockdownRefusal({ feature: 'ai-generate' })) {\n return Response.json({ held: true, done: true, nextCursor: null }, { status: 200 })\n }\n const flags = await getServerReleaseFlagValues()\n const deps: AiInsightDigestDeps = {\n firestore,\n now: new Date(),\n flagValue: flags['release_ai_generative'],\n listMembers: listOrgMembers,\n mayGenerate: (orgId, hostId, member) => memberHasPermissionOnHost(orgId, hostId, member, 'ai.generate'),\n paused: async (orgId) => Boolean(await featureLockdownRefusal({ feature: 'ai-generate', orgId })),\n notify: (uid, payload) => notifyUsers([uid], { type: 'content.insightsDigest', ...payload }),\n send: async (email) => {\n const recipients = await filterSuppressedEmails([email.to], firestore)\n if (!recipients.length) return { sent: false, rateLimited: false }\n const result = await sendEmail({\n to: recipients,\n subject: email.subject,\n text: email.text,\n fromName: email.fromName,\n context: 'ai-insights-digest',\n priority: 'bulk',\n })\n if (result.sent) {\n await meterPlatformEmail().catch(() => undefined)\n return { sent: true, rateLimited: false }\n }\n return { sent: false, rateLimited: rateLimitedRetryAtMs(result) !== null }\n },\n // An email link must be absolute; with no console URL configured the\n // digest says where to look without one.\n consoleOrigin: (process.env.NEXT_PUBLIC_CONSOLE_URL ?? '').trim().replace(/\\/+$/, ''),\n }\n const report = await runAiInsightDigestSweep(deps, { cursor })\n return Response.json(report, { status: 200 })\n } catch (error) {\n console.error('ai insights digest run failed', error)\n return Response.json({ error: 'The weekly insights run failed' }, { status: 500 })\n }\n}\n"],"names":["writeCronBeat","rateLimitedRetryAtMs","sendEmail","filterSuppressedEmails","meterPlatformEmail","firebaseAdmin","featureLockdownRefusal","notifyUsers","listOrgMembers","memberHasPermissionOnHost","getServerReleaseFlagValues","safeEqual","runAiInsightDigestSweep","POST","request","method","Response","json","error","status","secret","process","env","CRON_SECRET","headers","get","firestore","app","cursor","body","raw","includes","feature","held","done","nextCursor","flags","deps","now","Date","flagValue","listMembers","mayGenerate","orgId","hostId","member","paused","Boolean","notify","uid","payload","type","send","email","recipients","to","length","sent","rateLimited","result","subject","text","fromName","context","priority","catch","undefined","consoleOrigin","NEXT_PUBLIC_CONSOLE_URL","trim","replace","report","console"],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
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 AiSiteSubmissions } from '../model/ai-site-job';
|
|
18
|
+
export declare const AI_SITE_BATCH_PLAN_REFUSAL: string;
|
|
19
|
+
export interface AiSiteBatchSite {
|
|
20
|
+
hostId: string;
|
|
21
|
+
businessName: string;
|
|
22
|
+
city: string;
|
|
23
|
+
brand: string;
|
|
24
|
+
}
|
|
25
|
+
export interface CreateAiSiteBatchBody {
|
|
26
|
+
orgId: string;
|
|
27
|
+
brief: string;
|
|
28
|
+
businessType: string;
|
|
29
|
+
pages: number;
|
|
30
|
+
welcomeEmail: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Where every site in the run routes its contact form's submissions
|
|
33
|
+
* (AGL-2918); `null` where the caller did not say, which leaves each form
|
|
34
|
+
* step's own proposal standing as it always did.
|
|
35
|
+
*
|
|
36
|
+
* One answer for the whole run, because a batch is one brief built again
|
|
37
|
+
* and again: the forms it makes are the same form, and twenty of them
|
|
38
|
+
* routed by a model's guess is the run where a wrong default costs most.
|
|
39
|
+
*/
|
|
40
|
+
submissions: AiSiteSubmissions | null;
|
|
41
|
+
sites: AiSiteBatchSite[];
|
|
42
|
+
model: string | null;
|
|
43
|
+
}
|
|
44
|
+
/** Validate + clamp the request body; a string names what is wrong. */
|
|
45
|
+
export declare function parseAiSiteBatchBody(payload: unknown): CreateAiSiteBatchBody | string;
|
|
46
|
+
/** A batch id: a plain token the job inputs and the console group by. */
|
|
47
|
+
export declare function newAiSiteBatchId(): string;
|
|
48
|
+
export declare function POST(request: Request): Promise<Response>;
|
|
@@ -0,0 +1,306 @@
|
|
|
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
|
+
*/ // lockdown-423: via libs/plugins/ai/src/lib/runtime/ai-gate.ts
|
|
17
|
+
// The POST climbs `aiGateLadder`, whose lockdown rung is the verdict.
|
|
18
|
+
import { randomUUID } from "crypto";
|
|
19
|
+
import { resolveOrgEntitlements } from "@aglyn/aglyn/app-utils/plan-entitlements";
|
|
20
|
+
import { getOrgForUser, memberHasPermissionOnHost } from "@aglyn/tenant-data-admin/server/organizations";
|
|
21
|
+
import { aiJobAdmissionRefusal, aiJobSiteRefusal } from "../jobs/ai-job-admission.js";
|
|
22
|
+
import { AI_JOB_BRIEF_MAX_CHARS } from "../jobs/ai-job-text-step.js";
|
|
23
|
+
import { aiJobSummary, createAiJob } from "../jobs/ai-jobs.js";
|
|
24
|
+
import { AI_SITE_BATCH_MAX, AI_SITE_BATCH_MIN_HOST_LIMIT, AI_SITE_INPUT_MAX_CHARS, AI_SITE_PAGES, aiSiteSubmissions } from "../model/ai-site-job.js";
|
|
25
|
+
import { aiGateLadder } from "../runtime/ai-gate.js";
|
|
26
|
+
import { releaseAssistMessage } from "../usage/assist-usage.js";
|
|
27
|
+
/**
|
|
28
|
+
* The agency batch (AGL-2911): one brief, many sites.
|
|
29
|
+
*
|
|
30
|
+
* An agency builds the same site again and again with the business name, the
|
|
31
|
+
* city and the brand changed, so this door takes ONE brief and a list of the
|
|
32
|
+
* org's sites with those variables per site, and creates one `site` job per
|
|
33
|
+
* site under one batch id. The jobs are ordinary scaffolds — the beat runs
|
|
34
|
+
* them, each plans and waits for its own confirmation, each writes only
|
|
35
|
+
* drafts — and the batch id is what lets the org Sites page show them as one
|
|
36
|
+
* run with a link into each.
|
|
37
|
+
*
|
|
38
|
+
* ── The one answer that is not per site (AGL-2918) ───────────────────────
|
|
39
|
+
*
|
|
40
|
+
* Where a contact form's submissions go is asked once and carried onto every
|
|
41
|
+
* job, because a batch is one brief built again and again and the forms it
|
|
42
|
+
* makes are the same form. It is the one thing about a contact form a model
|
|
43
|
+
* cannot know — a note to read or a lead to chase is a decision about how the
|
|
44
|
+
* business runs — so each job binds the form step with it exactly as the
|
|
45
|
+
* guided start does, rather than twenty forms each keeping a guess.
|
|
46
|
+
*
|
|
47
|
+
* ── Why the batch has a door of its own ──────────────────────────────────
|
|
48
|
+
*
|
|
49
|
+
* Twenty-five calls to the create door would meet its per-minute window and
|
|
50
|
+
* its inline first step, and would leave the batch half made when the window
|
|
51
|
+
* closed. This door creates them in one request and runs NO step: it spends
|
|
52
|
+
* no tokens, so the message the ladder reserved goes straight back, and every
|
|
53
|
+
* job's own steps reserve and meter as they run. What the batch costs is
|
|
54
|
+
* therefore metered per step exactly as a single scaffold is, and the org's
|
|
55
|
+
* ceiling binds it the same way.
|
|
56
|
+
*
|
|
57
|
+
* ── Who may run it ───────────────────────────────────────────────────────
|
|
58
|
+
*
|
|
59
|
+
* The ladder answers for the org — `aiGenerative`, the release flag, the
|
|
60
|
+
* `ai-generate` switch and `ai.generate` on the org axis — and then each
|
|
61
|
+
* named site is asked for on its own: it must be this org's, and the caller
|
|
62
|
+
* must hold `ai.generate` THERE (AGL-2927), so a collaborator's permission on
|
|
63
|
+
* one site never starts a scaffold on another. A site the caller cannot use
|
|
64
|
+
* is reported back beside the ones that started, never silently dropped.
|
|
65
|
+
*
|
|
66
|
+
* The plan band is the issue's own: the batch is for the plans that sell
|
|
67
|
+
* enough sites to need it, which `hostLimit` is what distinguishes.
|
|
68
|
+
*/ const AI_JOBS_BATCH_RATE_LIMIT = {
|
|
69
|
+
key: 'ai-jobs-batch',
|
|
70
|
+
limit: 3,
|
|
71
|
+
windowMs: 60000
|
|
72
|
+
};
|
|
73
|
+
const ID_CHARS = /^[A-Za-z0-9_-]{1,100}$/;
|
|
74
|
+
/** The longest model id a body may carry; the catalog's ids are far shorter. */ const MAX_MODEL_CHARS = 100;
|
|
75
|
+
export const AI_SITE_BATCH_PLAN_REFUSAL = 'Generating for many sites is included in the plans that hold at least ' + `${AI_SITE_BATCH_MIN_HOST_LIMIT} sites — upgrade in Billing`;
|
|
76
|
+
/** Validate + clamp the request body; a string names what is wrong. */ export function parseAiSiteBatchBody(payload) {
|
|
77
|
+
var _body_orgId, _body_brief, _body_businessType;
|
|
78
|
+
const body = payload != null ? payload : {};
|
|
79
|
+
const orgId = String((_body_orgId = body['orgId']) != null ? _body_orgId : '').trim();
|
|
80
|
+
if (!orgId) return 'Open a workspace before using this feature';
|
|
81
|
+
const brief = String((_body_brief = body['brief']) != null ? _body_brief : '').trim();
|
|
82
|
+
if (!brief) return 'Write a brief for the sites';
|
|
83
|
+
if (brief.length > AI_JOB_BRIEF_MAX_CHARS) {
|
|
84
|
+
return `Keep the brief under ${AI_JOB_BRIEF_MAX_CHARS.toLocaleString('en-US')} characters`;
|
|
85
|
+
}
|
|
86
|
+
const businessType = String((_body_businessType = body['businessType']) != null ? _body_businessType : '').trim();
|
|
87
|
+
if (!businessType) return 'Say what kind of business the sites are for';
|
|
88
|
+
if (businessType.length > AI_SITE_INPUT_MAX_CHARS) {
|
|
89
|
+
return `businessType must be text under ${AI_SITE_INPUT_MAX_CHARS} characters`;
|
|
90
|
+
}
|
|
91
|
+
const rawPages = body['pages'];
|
|
92
|
+
const pages = typeof rawPages === 'number' ? rawPages : Number(rawPages != null ? rawPages : NaN);
|
|
93
|
+
if (!Number.isInteger(pages) || pages < AI_SITE_PAGES.min || pages > AI_SITE_PAGES.max) {
|
|
94
|
+
return `pages must be a whole number from ${AI_SITE_PAGES.min} to ${AI_SITE_PAGES.max}`;
|
|
95
|
+
}
|
|
96
|
+
const rawSites = body['sites'];
|
|
97
|
+
if (!Array.isArray(rawSites) || rawSites.length === 0) return 'Pick the sites to generate for';
|
|
98
|
+
if (rawSites.length > AI_SITE_BATCH_MAX) {
|
|
99
|
+
return `Generate for up to ${AI_SITE_BATCH_MAX} sites at a time`;
|
|
100
|
+
}
|
|
101
|
+
const sites = [];
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
for (const raw of rawSites){
|
|
104
|
+
var _ref;
|
|
105
|
+
const hostId = String((_ref = raw == null ? void 0 : raw['hostId']) != null ? _ref : '').trim();
|
|
106
|
+
if (!ID_CHARS.test(hostId)) return 'sites[].hostId is not a site id';
|
|
107
|
+
if (seen.has(hostId)) return 'The same site is listed twice';
|
|
108
|
+
seen.add(hostId);
|
|
109
|
+
const variable = (key)=>{
|
|
110
|
+
const value = raw == null ? void 0 : raw[key];
|
|
111
|
+
if (value === undefined || value === null || value === '') return '';
|
|
112
|
+
if (typeof value !== 'string') return null;
|
|
113
|
+
const trimmed = value.trim();
|
|
114
|
+
return trimmed.length > AI_SITE_INPUT_MAX_CHARS ? null : trimmed;
|
|
115
|
+
};
|
|
116
|
+
const businessName = variable('businessName');
|
|
117
|
+
const city = variable('city');
|
|
118
|
+
const brand = variable('brand');
|
|
119
|
+
if (businessName === null || city === null || brand === null) {
|
|
120
|
+
return `Keep each site's name, city and brand under ${AI_SITE_INPUT_MAX_CHARS} characters`;
|
|
121
|
+
}
|
|
122
|
+
sites.push({
|
|
123
|
+
hostId,
|
|
124
|
+
businessName,
|
|
125
|
+
city,
|
|
126
|
+
brand
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
const rawModel = typeof body['model'] === 'string' ? body['model'].trim() : '';
|
|
130
|
+
if (rawModel.length > MAX_MODEL_CHARS) return 'model is not a model id';
|
|
131
|
+
return {
|
|
132
|
+
orgId,
|
|
133
|
+
brief,
|
|
134
|
+
businessType,
|
|
135
|
+
pages,
|
|
136
|
+
welcomeEmail: body['welcomeEmail'] !== false,
|
|
137
|
+
// Admitted only as one of the two the form step can bind, exactly as the
|
|
138
|
+
// single-site door admits it: anything else is nobody having said, and
|
|
139
|
+
// the whole run is not refused over an answer that is not a refusal.
|
|
140
|
+
submissions: aiSiteSubmissions(body),
|
|
141
|
+
sites,
|
|
142
|
+
model: rawModel && rawModel !== 'auto' ? rawModel : null
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/** A batch id: a plain token the job inputs and the console group by. */ export function newAiSiteBatchId() {
|
|
146
|
+
return randomUUID().replace(/-/g, '').slice(0, 20);
|
|
147
|
+
}
|
|
148
|
+
export async function POST(request) {
|
|
149
|
+
var _ref;
|
|
150
|
+
let payload;
|
|
151
|
+
try {
|
|
152
|
+
payload = await request.json();
|
|
153
|
+
} catch (unused) {
|
|
154
|
+
payload = null;
|
|
155
|
+
}
|
|
156
|
+
const parsed = parseAiSiteBatchBody(payload);
|
|
157
|
+
const orgId = typeof parsed === 'string' ? String((_ref = payload == null ? void 0 : payload['orgId']) != null ? _ref : '') : parsed.orgId;
|
|
158
|
+
// The org axis: the batch belongs to no one site, and each named site is
|
|
159
|
+
// asked for on its own below.
|
|
160
|
+
const gate = await aiGateLadder({
|
|
161
|
+
request,
|
|
162
|
+
orgId,
|
|
163
|
+
hostId: null
|
|
164
|
+
}, {
|
|
165
|
+
feature: 'aiGenerative',
|
|
166
|
+
releaseFlag: 'release_ai_generative',
|
|
167
|
+
lockdownFeature: 'ai-generate',
|
|
168
|
+
permission: 'ai.generate',
|
|
169
|
+
rateLimit: AI_JOBS_BATCH_RATE_LIMIT
|
|
170
|
+
});
|
|
171
|
+
if (gate instanceof Response) return gate;
|
|
172
|
+
// No step runs here, so nothing is spent and the message goes back whatever
|
|
173
|
+
// this door answers.
|
|
174
|
+
await releaseAssistMessage(gate.firestore, gate.orgId, gate.reservation).catch(()=>undefined);
|
|
175
|
+
if (typeof parsed === 'string') {
|
|
176
|
+
return Response.json({
|
|
177
|
+
error: parsed
|
|
178
|
+
}, {
|
|
179
|
+
status: 400
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
const entitlements = resolveOrgEntitlements(gate.org);
|
|
183
|
+
if (!gate.staff && entitlements.hostLimit < AI_SITE_BATCH_MIN_HOST_LIMIT) {
|
|
184
|
+
return Response.json({
|
|
185
|
+
error: AI_SITE_BATCH_PLAN_REFUSAL,
|
|
186
|
+
reason: 'entitlement'
|
|
187
|
+
}, {
|
|
188
|
+
status: 403
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const membership = gate.staff ? null : await getOrgForUser(gate.uid, gate.orgId);
|
|
192
|
+
if (!gate.staff && (membership == null ? void 0 : membership.orgId) !== gate.orgId) {
|
|
193
|
+
return Response.json({
|
|
194
|
+
error: 'You are not a member of that organization'
|
|
195
|
+
}, {
|
|
196
|
+
status: 403
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
const batchId = newAiSiteBatchId();
|
|
200
|
+
const now = new Date();
|
|
201
|
+
const started = [];
|
|
202
|
+
const refused = [];
|
|
203
|
+
for (const site of parsed.sites){
|
|
204
|
+
const permitted = gate.staff || await memberHasPermissionOnHost(gate.orgId, site.hostId, membership == null ? void 0 : membership.member, 'ai.generate');
|
|
205
|
+
if (!permitted) {
|
|
206
|
+
refused.push({
|
|
207
|
+
hostId: site.hostId,
|
|
208
|
+
error: 'You cannot generate on that site'
|
|
209
|
+
});
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
const inputs = {
|
|
213
|
+
businessType: parsed.businessType,
|
|
214
|
+
pages: parsed.pages,
|
|
215
|
+
welcomeEmail: parsed.welcomeEmail,
|
|
216
|
+
submissions: parsed.submissions,
|
|
217
|
+
businessName: site.businessName,
|
|
218
|
+
city: site.city,
|
|
219
|
+
brand: site.brand,
|
|
220
|
+
batchId
|
|
221
|
+
};
|
|
222
|
+
// What only a scaffold can say about this site (AGL-2909): its inputs, the
|
|
223
|
+
// site being this org's, and a step that can build its pages.
|
|
224
|
+
let refusal;
|
|
225
|
+
try {
|
|
226
|
+
var _ref1;
|
|
227
|
+
// A site that switched AI off is refused on its own (AGL-3028): the
|
|
228
|
+
// dispatcher cannot see a site named inside `sites[]`, and the rest of
|
|
229
|
+
// the batch still starts.
|
|
230
|
+
refusal = (_ref1 = await aiJobSiteRefusal({
|
|
231
|
+
firestore: gate.firestore,
|
|
232
|
+
org: gate.org,
|
|
233
|
+
hostId: site.hostId
|
|
234
|
+
})) != null ? _ref1 : await aiJobAdmissionRefusal('site', {
|
|
235
|
+
firestore: gate.firestore,
|
|
236
|
+
orgId: gate.orgId,
|
|
237
|
+
hostId: site.hostId,
|
|
238
|
+
inputs,
|
|
239
|
+
org: gate.org
|
|
240
|
+
});
|
|
241
|
+
} catch (error) {
|
|
242
|
+
console.error('ai site batch admission failed', {
|
|
243
|
+
orgId: gate.orgId,
|
|
244
|
+
error
|
|
245
|
+
});
|
|
246
|
+
refused.push({
|
|
247
|
+
hostId: site.hostId,
|
|
248
|
+
error: 'This site could not be started'
|
|
249
|
+
});
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (refusal) {
|
|
253
|
+
refused.push({
|
|
254
|
+
hostId: site.hostId,
|
|
255
|
+
error: refusal.error
|
|
256
|
+
});
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
try {
|
|
260
|
+
var _gate_decoded_email;
|
|
261
|
+
const job = await createAiJob(gate.firestore, {
|
|
262
|
+
orgId: gate.orgId,
|
|
263
|
+
hostId: site.hostId,
|
|
264
|
+
kind: 'site',
|
|
265
|
+
brief: parsed.brief,
|
|
266
|
+
inputs,
|
|
267
|
+
model: parsed.model,
|
|
268
|
+
createdBy: gate.uid,
|
|
269
|
+
createdByEmail: (_gate_decoded_email = gate.decoded.email) != null ? _gate_decoded_email : null
|
|
270
|
+
}, now);
|
|
271
|
+
started.push(aiJobSummary(job, now));
|
|
272
|
+
} catch (error) {
|
|
273
|
+
console.error('ai site batch create failed', {
|
|
274
|
+
orgId: gate.orgId,
|
|
275
|
+
error
|
|
276
|
+
});
|
|
277
|
+
refused.push({
|
|
278
|
+
hostId: site.hostId,
|
|
279
|
+
error: 'This site could not be started'
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (!started.length) {
|
|
284
|
+
var _ref2;
|
|
285
|
+
var _refused_;
|
|
286
|
+
return Response.json({
|
|
287
|
+
error: (_ref2 = (_refused_ = refused[0]) == null ? void 0 : _refused_.error) != null ? _ref2 : 'No site could be started',
|
|
288
|
+
batchId,
|
|
289
|
+
jobs: [],
|
|
290
|
+
refused
|
|
291
|
+
}, {
|
|
292
|
+
status: 403
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
// The jobs are queued, not run: the beat plans each one, and each waits for
|
|
296
|
+
// its own confirmation before it builds anything.
|
|
297
|
+
return Response.json({
|
|
298
|
+
batchId,
|
|
299
|
+
jobs: started,
|
|
300
|
+
refused
|
|
301
|
+
}, {
|
|
302
|
+
status: 202
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
//# sourceMappingURL=ai-jobs-batch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/server/ai-jobs-batch.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\n// lockdown-423: via libs/plugins/ai/src/lib/runtime/ai-gate.ts\n// The POST climbs `aiGateLadder`, whose lockdown rung is the verdict.\n\nimport { randomUUID } from 'crypto'\nimport { resolveOrgEntitlements } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport {\n getOrgForUser,\n memberHasPermissionOnHost,\n} from '@aglyn/tenant-data-admin/server/organizations'\nimport { aiJobAdmissionRefusal, aiJobSiteRefusal } from '../jobs/ai-job-admission'\nimport { AI_JOB_BRIEF_MAX_CHARS } from '../jobs/ai-job-text-step'\nimport { aiJobSummary, createAiJob } from '../jobs/ai-jobs'\nimport {\n AI_SITE_BATCH_MAX,\n AI_SITE_BATCH_MIN_HOST_LIMIT,\n AI_SITE_INPUT_MAX_CHARS,\n AI_SITE_PAGES,\n aiSiteSubmissions,\n type AiSiteSubmissions,\n} from '../model/ai-site-job'\nimport { aiGateLadder } from '../runtime/ai-gate'\nimport { releaseAssistMessage } from '../usage/assist-usage'\n\n/**\n * The agency batch (AGL-2911): one brief, many sites.\n *\n * An agency builds the same site again and again with the business name, the\n * city and the brand changed, so this door takes ONE brief and a list of the\n * org's sites with those variables per site, and creates one `site` job per\n * site under one batch id. The jobs are ordinary scaffolds — the beat runs\n * them, each plans and waits for its own confirmation, each writes only\n * drafts — and the batch id is what lets the org Sites page show them as one\n * run with a link into each.\n *\n * ── The one answer that is not per site (AGL-2918) ───────────────────────\n *\n * Where a contact form's submissions go is asked once and carried onto every\n * job, because a batch is one brief built again and again and the forms it\n * makes are the same form. It is the one thing about a contact form a model\n * cannot know — a note to read or a lead to chase is a decision about how the\n * business runs — so each job binds the form step with it exactly as the\n * guided start does, rather than twenty forms each keeping a guess.\n *\n * ── Why the batch has a door of its own ──────────────────────────────────\n *\n * Twenty-five calls to the create door would meet its per-minute window and\n * its inline first step, and would leave the batch half made when the window\n * closed. This door creates them in one request and runs NO step: it spends\n * no tokens, so the message the ladder reserved goes straight back, and every\n * job's own steps reserve and meter as they run. What the batch costs is\n * therefore metered per step exactly as a single scaffold is, and the org's\n * ceiling binds it the same way.\n *\n * ── Who may run it ───────────────────────────────────────────────────────\n *\n * The ladder answers for the org — `aiGenerative`, the release flag, the\n * `ai-generate` switch and `ai.generate` on the org axis — and then each\n * named site is asked for on its own: it must be this org's, and the caller\n * must hold `ai.generate` THERE (AGL-2927), so a collaborator's permission on\n * one site never starts a scaffold on another. A site the caller cannot use\n * is reported back beside the ones that started, never silently dropped.\n *\n * The plan band is the issue's own: the batch is for the plans that sell\n * enough sites to need it, which `hostLimit` is what distinguishes.\n */\n\nconst AI_JOBS_BATCH_RATE_LIMIT = {\n key: 'ai-jobs-batch',\n limit: 3,\n windowMs: 60_000,\n}\n\nconst ID_CHARS = /^[A-Za-z0-9_-]{1,100}$/\n\n/** The longest model id a body may carry; the catalog's ids are far shorter. */\nconst MAX_MODEL_CHARS = 100\n\nexport const AI_SITE_BATCH_PLAN_REFUSAL =\n 'Generating for many sites is included in the plans that hold at least ' +\n `${AI_SITE_BATCH_MIN_HOST_LIMIT} sites — upgrade in Billing`\n\nexport interface AiSiteBatchSite {\n hostId: string\n businessName: string\n city: string\n brand: string\n}\n\nexport interface CreateAiSiteBatchBody {\n orgId: string\n brief: string\n businessType: string\n pages: number\n welcomeEmail: boolean\n /**\n * Where every site in the run routes its contact form's submissions\n * (AGL-2918); `null` where the caller did not say, which leaves each form\n * step's own proposal standing as it always did.\n *\n * One answer for the whole run, because a batch is one brief built again\n * and again: the forms it makes are the same form, and twenty of them\n * routed by a model's guess is the run where a wrong default costs most.\n */\n submissions: AiSiteSubmissions | null\n sites: AiSiteBatchSite[]\n model: string | null\n}\n\n/** Validate + clamp the request body; a string names what is wrong. */\nexport function parseAiSiteBatchBody(\n payload: unknown,\n): CreateAiSiteBatchBody | string {\n const body = (payload ?? {}) as Record<string, unknown>\n const orgId = String(body['orgId'] ?? '').trim()\n if (!orgId) return 'Open a workspace before using this feature'\n const brief = String(body['brief'] ?? '').trim()\n if (!brief) return 'Write a brief for the sites'\n if (brief.length > AI_JOB_BRIEF_MAX_CHARS) {\n return `Keep the brief under ${AI_JOB_BRIEF_MAX_CHARS.toLocaleString('en-US')} characters`\n }\n const businessType = String(body['businessType'] ?? '').trim()\n if (!businessType) return 'Say what kind of business the sites are for'\n if (businessType.length > AI_SITE_INPUT_MAX_CHARS) {\n return `businessType must be text under ${AI_SITE_INPUT_MAX_CHARS} characters`\n }\n const rawPages = body['pages']\n const pages =\n typeof rawPages === 'number' ? rawPages : Number(rawPages ?? NaN)\n if (\n !Number.isInteger(pages) ||\n pages < AI_SITE_PAGES.min ||\n pages > AI_SITE_PAGES.max\n ) {\n return `pages must be a whole number from ${AI_SITE_PAGES.min} to ${AI_SITE_PAGES.max}`\n }\n const rawSites = body['sites']\n if (!Array.isArray(rawSites) || rawSites.length === 0)\n return 'Pick the sites to generate for'\n if (rawSites.length > AI_SITE_BATCH_MAX) {\n return `Generate for up to ${AI_SITE_BATCH_MAX} sites at a time`\n }\n const sites: AiSiteBatchSite[] = []\n const seen = new Set<string>()\n for (const raw of rawSites as Array<Record<string, unknown>>) {\n const hostId = String(raw?.['hostId'] ?? '').trim()\n if (!ID_CHARS.test(hostId)) return 'sites[].hostId is not a site id'\n if (seen.has(hostId)) return 'The same site is listed twice'\n seen.add(hostId)\n const variable = (key: string): string | null => {\n const value = raw?.[key]\n if (value === undefined || value === null || value === '') return ''\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n return trimmed.length > AI_SITE_INPUT_MAX_CHARS ? null : trimmed\n }\n const businessName = variable('businessName')\n const city = variable('city')\n const brand = variable('brand')\n if (businessName === null || city === null || brand === null) {\n return `Keep each site's name, city and brand under ${AI_SITE_INPUT_MAX_CHARS} characters`\n }\n sites.push({ hostId, businessName, city, brand })\n }\n const rawModel = typeof body['model'] === 'string' ? body['model'].trim() : ''\n if (rawModel.length > MAX_MODEL_CHARS) return 'model is not a model id'\n return {\n orgId,\n brief,\n businessType,\n pages,\n welcomeEmail: body['welcomeEmail'] !== false,\n // Admitted only as one of the two the form step can bind, exactly as the\n // single-site door admits it: anything else is nobody having said, and\n // the whole run is not refused over an answer that is not a refusal.\n submissions: aiSiteSubmissions(body),\n sites,\n model: rawModel && rawModel !== 'auto' ? rawModel : null,\n }\n}\n\n/** A batch id: a plain token the job inputs and the console group by. */\nexport function newAiSiteBatchId(): string {\n return randomUUID().replace(/-/g, '').slice(0, 20)\n}\n\nexport async function POST(request: Request): Promise<Response> {\n let payload: unknown\n try {\n payload = await request.json()\n } catch {\n payload = null\n }\n const parsed = parseAiSiteBatchBody(payload)\n const orgId =\n typeof parsed === 'string'\n ? String((payload as Record<string, unknown> | null)?.['orgId'] ?? '')\n : parsed.orgId\n // The org axis: the batch belongs to no one site, and each named site is\n // asked for on its own below.\n const gate = await aiGateLadder(\n { request, orgId, hostId: null },\n {\n feature: 'aiGenerative',\n releaseFlag: 'release_ai_generative',\n lockdownFeature: 'ai-generate',\n permission: 'ai.generate',\n rateLimit: AI_JOBS_BATCH_RATE_LIMIT,\n },\n )\n if (gate instanceof Response) return gate\n // No step runs here, so nothing is spent and the message goes back whatever\n // this door answers.\n await releaseAssistMessage(\n gate.firestore,\n gate.orgId,\n gate.reservation,\n ).catch(() => undefined)\n if (typeof parsed === 'string') {\n return Response.json({ error: parsed }, { status: 400 })\n }\n const entitlements = resolveOrgEntitlements(\n gate.org as Partial<AglynOrgBilling>,\n )\n if (!gate.staff && entitlements.hostLimit < AI_SITE_BATCH_MIN_HOST_LIMIT) {\n return Response.json(\n { error: AI_SITE_BATCH_PLAN_REFUSAL, reason: 'entitlement' },\n { status: 403 },\n )\n }\n const membership = gate.staff\n ? null\n : await getOrgForUser(gate.uid, gate.orgId)\n if (!gate.staff && membership?.orgId !== gate.orgId) {\n return Response.json(\n { error: 'You are not a member of that organization' },\n { status: 403 },\n )\n }\n\n const batchId = newAiSiteBatchId()\n const now = new Date()\n const started: ReturnType<typeof aiJobSummary>[] = []\n const refused: Array<{ hostId: string; error: string }> = []\n for (const site of parsed.sites) {\n const permitted =\n gate.staff ||\n (await memberHasPermissionOnHost(\n gate.orgId,\n site.hostId,\n membership?.member,\n 'ai.generate',\n ))\n if (!permitted) {\n refused.push({\n hostId: site.hostId,\n error: 'You cannot generate on that site',\n })\n continue\n }\n const inputs = {\n businessType: parsed.businessType,\n pages: parsed.pages,\n welcomeEmail: parsed.welcomeEmail,\n submissions: parsed.submissions,\n businessName: site.businessName,\n city: site.city,\n brand: site.brand,\n batchId,\n }\n // What only a scaffold can say about this site (AGL-2909): its inputs, the\n // site being this org's, and a step that can build its pages.\n let refusal: Awaited<ReturnType<typeof aiJobAdmissionRefusal>>\n try {\n // A site that switched AI off is refused on its own (AGL-3028): the\n // dispatcher cannot see a site named inside `sites[]`, and the rest of\n // the batch still starts.\n refusal =\n (await aiJobSiteRefusal({\n firestore: gate.firestore,\n org: gate.org,\n hostId: site.hostId,\n })) ??\n (await aiJobAdmissionRefusal('site', {\n firestore: gate.firestore,\n orgId: gate.orgId,\n hostId: site.hostId,\n inputs,\n org: gate.org,\n }))\n } catch (error) {\n console.error('ai site batch admission failed', {\n orgId: gate.orgId,\n error,\n })\n refused.push({\n hostId: site.hostId,\n error: 'This site could not be started',\n })\n continue\n }\n if (refusal) {\n refused.push({ hostId: site.hostId, error: refusal.error })\n continue\n }\n try {\n const job = await createAiJob(\n gate.firestore,\n {\n orgId: gate.orgId,\n hostId: site.hostId,\n kind: 'site',\n brief: parsed.brief,\n inputs,\n model: parsed.model,\n createdBy: gate.uid,\n createdByEmail: gate.decoded.email ?? null,\n },\n now,\n )\n started.push(aiJobSummary(job, now))\n } catch (error) {\n console.error('ai site batch create failed', { orgId: gate.orgId, error })\n refused.push({\n hostId: site.hostId,\n error: 'This site could not be started',\n })\n }\n }\n if (!started.length) {\n return Response.json(\n {\n error: refused[0]?.error ?? 'No site could be started',\n batchId,\n jobs: [],\n refused,\n },\n { status: 403 },\n )\n }\n // The jobs are queued, not run: the beat plans each one, and each waits for\n // its own confirmation before it builds anything.\n return Response.json({ batchId, jobs: started, refused }, { status: 202 })\n}\n"],"names":["randomUUID","resolveOrgEntitlements","getOrgForUser","memberHasPermissionOnHost","aiJobAdmissionRefusal","aiJobSiteRefusal","AI_JOB_BRIEF_MAX_CHARS","aiJobSummary","createAiJob","AI_SITE_BATCH_MAX","AI_SITE_BATCH_MIN_HOST_LIMIT","AI_SITE_INPUT_MAX_CHARS","AI_SITE_PAGES","aiSiteSubmissions","aiGateLadder","releaseAssistMessage","AI_JOBS_BATCH_RATE_LIMIT","key","limit","windowMs","ID_CHARS","MAX_MODEL_CHARS","AI_SITE_BATCH_PLAN_REFUSAL","parseAiSiteBatchBody","payload","body","orgId","String","trim","brief","length","toLocaleString","businessType","rawPages","pages","Number","NaN","isInteger","min","max","rawSites","Array","isArray","sites","seen","Set","raw","hostId","test","has","add","variable","value","undefined","trimmed","businessName","city","brand","push","rawModel","welcomeEmail","submissions","model","newAiSiteBatchId","replace","slice","POST","request","json","parsed","gate","feature","releaseFlag","lockdownFeature","permission","rateLimit","Response","firestore","reservation","catch","error","status","entitlements","org","staff","hostLimit","reason","membership","uid","batchId","now","Date","started","refused","site","permitted","member","inputs","refusal","console","job","kind","createdBy","createdByEmail","decoded","email","jobs"],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
/**
|
|
18
|
+
* THE AI JOBS BEAT (AGL-3026): `POST /api/admin/ai-jobs-beat`.
|
|
19
|
+
*
|
|
20
|
+
* Cloud Scheduler calls it every minute through `consoleAiJobsBeat` in
|
|
21
|
+
* `cloud/functions`, carrying the console's `CRON_SECRET` as
|
|
22
|
+
* `x-cron-secret`: the same secret, headers and refusals as the console's
|
|
23
|
+
* other scheduled sweeps, so rotating the secret is still one act. It answers
|
|
24
|
+
* 405 to anything but a POST, 501 while the secret is unset, so an
|
|
25
|
+
* unconfigured deployment cannot be made to spend, and 401 for anything but
|
|
26
|
+
* the secret.
|
|
27
|
+
*
|
|
28
|
+
* The console app serves it from a route of its own at the same path, which
|
|
29
|
+
* gives a sweep the function time the slowest step needs; the plugin
|
|
30
|
+
* dispatcher's ceiling is a door's. See `AI_JOB_SWEEP_BUDGET_MS`.
|
|
31
|
+
*
|
|
32
|
+
* It answers 200 with what the beat did, a beat the switch held included:
|
|
33
|
+
* a lock is an operator's decision rather than a fault, and the caller logs
|
|
34
|
+
* every refusal it gets.
|
|
35
|
+
*/
|
|
36
|
+
export declare function POST(request: Request): Promise<Response>;
|