@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,246 @@
|
|
|
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
|
+
*/ import { pluginRequestFromWeb } from "@aglyn/aglyn/server";
|
|
17
|
+
import { emailUnverifiedResponse, firebaseAdmin, isImpersonationSession } from "@aglyn/tenant-data-admin";
|
|
18
|
+
import { recordAdminAudit } from "@aglyn/tenant-data-admin/server/admin-audit";
|
|
19
|
+
import { invalidIdTokenResponse } from "@aglyn/tenant-data-admin/server/id-token-refusal";
|
|
20
|
+
import { assistUsageMonth } from "../usage/assist-usage.js";
|
|
21
|
+
import { AI_BILLING_STANDING_DOC, AI_BILLING_SUBCOLLECTION, AI_OVERAGE_CHARGES_SUBCOLLECTION, readAiOverageMonthLedger } from "../billing/ai-overage-ledger.js";
|
|
22
|
+
import { AI_OVERAGE_CEILING_LADDER_USD, AI_OVERAGE_STAFF_CEILING_MAX_USD, AI_OVERAGE_STAFF_CEILING_MIN_USD, AI_OVERAGE_THRESHOLD_USD, AI_OVERAGE_UNPAID_LIMIT_USD, aiOverageCardOnFile, aiOverageEffectiveCeilingUsd, aiOverageStandingCeilingUsd, aiOverageStep, readAiOverageStanding } from "../billing/ai-overage-standing.js";
|
|
23
|
+
import { resetAiOverageStep, resumeAiOverage, setAiOverageStaffOverride } from "../billing/ai-overage-standing-writes.js";
|
|
24
|
+
import { aiOverageBillsByInvoice } from "../billing/ai-overage-cutover.js";
|
|
25
|
+
/**
|
|
26
|
+
* STAFF'S CONTROLS OVER ONE WORKSPACE'S OVERAGE STANDING (AGL-3011).
|
|
27
|
+
*
|
|
28
|
+
* The ladder rises on payment history and a dispute takes it back to the
|
|
29
|
+
* bottom. Both are rules, and a rule that nobody can override is a rule that
|
|
30
|
+
* strands the customer it gets wrong: an enterprise-shaped workspace on its
|
|
31
|
+
* first month, a dispute that turns out to be fraud on the cardholder rather
|
|
32
|
+
* than by them, a failed charge whose cause was ours.
|
|
33
|
+
*
|
|
34
|
+
* So four acts, staff-only, every one of them audited:
|
|
35
|
+
*
|
|
36
|
+
* `get` the standing in full, with the month's charges
|
|
37
|
+
* `setCeiling` a ceiling that outranks the ladder, with a reason and an
|
|
38
|
+
* optional expiry
|
|
39
|
+
* `liftPause` resume accrual, with a reason — the ONLY way a dispute
|
|
40
|
+
* pause comes off
|
|
41
|
+
* `resetStep` put the workspace back at the bottom of the ladder
|
|
42
|
+
*
|
|
43
|
+
* A reason is required on every act that changes something, because the
|
|
44
|
+
* question a month later is never "what was the ceiling" — the document says
|
|
45
|
+
* that — but "why did someone raise it".
|
|
46
|
+
*
|
|
47
|
+
* The emergency stop is not here and does not change: Lockdown, scoped to
|
|
48
|
+
* the organization, which stops AI along with everything else.
|
|
49
|
+
*/ /** How many of the month's charge rows the card lists. */ const CHARGES_LISTED = 20;
|
|
50
|
+
/** The longest a staff reason may be, so a paste cannot fill the document. */ const REASON_MAX = 500;
|
|
51
|
+
function badRequest(error, code) {
|
|
52
|
+
return Response.json({
|
|
53
|
+
error,
|
|
54
|
+
code
|
|
55
|
+
}, {
|
|
56
|
+
status: 400
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async function handler(request) {
|
|
60
|
+
var _headers_authorization, _ref, _ref1;
|
|
61
|
+
const { method, body, headers: rawHeaders } = await pluginRequestFromWeb(request);
|
|
62
|
+
const headers = rawHeaders;
|
|
63
|
+
if (method !== 'POST') {
|
|
64
|
+
return Response.json({
|
|
65
|
+
error: 'Method not allowed'
|
|
66
|
+
}, {
|
|
67
|
+
status: 405
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
const authorization = (_headers_authorization = headers.authorization) != null ? _headers_authorization : '';
|
|
71
|
+
const idToken = authorization.startsWith('Bearer ') ? authorization.slice('Bearer '.length) : undefined;
|
|
72
|
+
if (!idToken) return Response.json({
|
|
73
|
+
error: 'Unauthenticated'
|
|
74
|
+
}, {
|
|
75
|
+
status: 401
|
|
76
|
+
});
|
|
77
|
+
const orgId = String((_ref = body == null ? void 0 : body.orgId) != null ? _ref : '');
|
|
78
|
+
const action = String((_ref1 = body == null ? void 0 : body.action) != null ? _ref1 : '');
|
|
79
|
+
const actions = [
|
|
80
|
+
'get',
|
|
81
|
+
'setCeiling',
|
|
82
|
+
'liftPause',
|
|
83
|
+
'resetStep'
|
|
84
|
+
];
|
|
85
|
+
if (!orgId || !actions.includes(action)) {
|
|
86
|
+
return Response.json({
|
|
87
|
+
error: 'Bad request'
|
|
88
|
+
}, {
|
|
89
|
+
status: 400
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
var _orgSnapshot_data, _ref2, _standingSnapshot_data, _usageSnapshot_data, _standing_paymentMethodType, _aiOverageCardOnFile;
|
|
94
|
+
const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken);
|
|
95
|
+
if (!decoded.email_verified && !isImpersonationSession(decoded)) {
|
|
96
|
+
return emailUnverifiedResponse();
|
|
97
|
+
}
|
|
98
|
+
// The staff claim, the same test `ai/admin/org` makes. Not a permission
|
|
99
|
+
// on the workspace: these controls are Aglyn's side of the relationship,
|
|
100
|
+
// and a workspace admin raising their own ceiling is the thing the
|
|
101
|
+
// ladder exists to prevent.
|
|
102
|
+
if (!decoded['staff']) {
|
|
103
|
+
return Response.json({
|
|
104
|
+
error: 'Staff only'
|
|
105
|
+
}, {
|
|
106
|
+
status: 403
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const now = new Date();
|
|
110
|
+
const month = assistUsageMonth(now);
|
|
111
|
+
const db = firebaseAdmin.app().firestore();
|
|
112
|
+
const orgRef = db.collection('orgs').doc(orgId);
|
|
113
|
+
const orgSnapshot = await orgRef.get();
|
|
114
|
+
if (!orgSnapshot.exists) {
|
|
115
|
+
return Response.json({
|
|
116
|
+
error: 'No such organization'
|
|
117
|
+
}, {
|
|
118
|
+
status: 404
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
const org = (_orgSnapshot_data = orgSnapshot.data()) != null ? _orgSnapshot_data : {};
|
|
122
|
+
const reason = String((_ref2 = body == null ? void 0 : body.reason) != null ? _ref2 : '').trim().slice(0, REASON_MAX);
|
|
123
|
+
if (action === 'setCeiling') {
|
|
124
|
+
const clearing = (body == null ? void 0 : body.ceilingUsd) === null;
|
|
125
|
+
const ceilingUsd = Number(body == null ? void 0 : body.ceilingUsd);
|
|
126
|
+
if (!reason) {
|
|
127
|
+
return badRequest('Say why the ceiling is being changed', 'reason_required');
|
|
128
|
+
}
|
|
129
|
+
if (!clearing && (!Number.isFinite(ceilingUsd) || ceilingUsd < AI_OVERAGE_STAFF_CEILING_MIN_USD || ceilingUsd > AI_OVERAGE_STAFF_CEILING_MAX_USD)) {
|
|
130
|
+
return badRequest(`Set a ceiling between $${AI_OVERAGE_STAFF_CEILING_MIN_USD} and ` + `$${AI_OVERAGE_STAFF_CEILING_MAX_USD.toLocaleString('en-US')}, or clear it.`, 'invalid_ceiling');
|
|
131
|
+
}
|
|
132
|
+
// An expiry that does not parse is refused rather than dropped: a
|
|
133
|
+
// ceiling meant to last a week and stored with no end is the failure
|
|
134
|
+
// this field exists to avoid.
|
|
135
|
+
const rawExpiry = body == null ? void 0 : body.expiresAt;
|
|
136
|
+
const expiresAt = rawExpiry === null || rawExpiry === undefined ? null : String(rawExpiry);
|
|
137
|
+
if (expiresAt !== null && !Number.isFinite(Date.parse(expiresAt))) {
|
|
138
|
+
return badRequest('The expiry is not a date', 'invalid_expiry');
|
|
139
|
+
}
|
|
140
|
+
await setAiOverageStaffOverride(db, orgId, clearing ? null : {
|
|
141
|
+
ceilingUsd,
|
|
142
|
+
reason,
|
|
143
|
+
setBy: decoded.uid,
|
|
144
|
+
expiresAt
|
|
145
|
+
}, now);
|
|
146
|
+
await recordAdminAudit({
|
|
147
|
+
actorUid: decoded.uid,
|
|
148
|
+
action: clearing ? 'ai.overage.clearCeiling' : 'ai.overage.setCeiling',
|
|
149
|
+
target: `orgs/${orgId}/${AI_BILLING_SUBCOLLECTION}/${AI_BILLING_STANDING_DOC}`,
|
|
150
|
+
note: clearing ? reason : `${reason} — ceiling $${ceilingUsd}${expiresAt ? `, until ${expiresAt}` : ''}`
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (action === 'liftPause') {
|
|
154
|
+
if (!reason) {
|
|
155
|
+
return badRequest('Say why the pause is being lifted', 'reason_required');
|
|
156
|
+
}
|
|
157
|
+
// `force`, because staff lifting a pause is the one path a DISPUTE
|
|
158
|
+
// pause has out. Every other pause lifts on its own when the payment
|
|
159
|
+
// that set it succeeds.
|
|
160
|
+
await resumeAiOverage(db, orgId, {
|
|
161
|
+
force: true
|
|
162
|
+
});
|
|
163
|
+
await recordAdminAudit({
|
|
164
|
+
actorUid: decoded.uid,
|
|
165
|
+
action: 'ai.overage.liftPause',
|
|
166
|
+
target: `orgs/${orgId}/${AI_BILLING_SUBCOLLECTION}/${AI_BILLING_STANDING_DOC}`,
|
|
167
|
+
note: reason
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
if (action === 'resetStep') {
|
|
171
|
+
if (!reason) {
|
|
172
|
+
return badRequest('Say why the step is being reset', 'reason_required');
|
|
173
|
+
}
|
|
174
|
+
await resetAiOverageStep(db, orgId);
|
|
175
|
+
await recordAdminAudit({
|
|
176
|
+
actorUid: decoded.uid,
|
|
177
|
+
action: 'ai.overage.resetStep',
|
|
178
|
+
target: `orgs/${orgId}/${AI_BILLING_SUBCOLLECTION}/${AI_BILLING_STANDING_DOC}`,
|
|
179
|
+
note: reason
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
// Read AFTER any write, so the answer is the state the act produced
|
|
183
|
+
// rather than the state it found — a staff card that showed the old
|
|
184
|
+
// ceiling after raising it would be read as the raise having failed.
|
|
185
|
+
const [standingSnapshot, usageSnapshot, chargesSnapshot] = await Promise.all([
|
|
186
|
+
orgRef.collection(AI_BILLING_SUBCOLLECTION).doc(AI_BILLING_STANDING_DOC).get(),
|
|
187
|
+
orgRef.collection('assistUsage').doc(month).get(),
|
|
188
|
+
orgRef.collection(AI_OVERAGE_CHARGES_SUBCOLLECTION).where('month', '==', month).limit(CHARGES_LISTED).get()
|
|
189
|
+
]);
|
|
190
|
+
const standing = readAiOverageStanding(standingSnapshot.exists ? (_standingSnapshot_data = standingSnapshot.data()) != null ? _standingSnapshot_data : null : null);
|
|
191
|
+
const ledger = readAiOverageMonthLedger(usageSnapshot.exists ? (_usageSnapshot_data = usageSnapshot.data()) != null ? _usageSnapshot_data : null : null);
|
|
192
|
+
return Response.json({
|
|
193
|
+
month,
|
|
194
|
+
// Whether any of this is live yet. Staff looking at a standing that
|
|
195
|
+
// nothing consults should be told so rather than left to infer it
|
|
196
|
+
// from a ceiling that never refuses.
|
|
197
|
+
billsByInvoice: aiOverageBillsByInvoice(month),
|
|
198
|
+
standing: {
|
|
199
|
+
paymentMethodType: (_standing_paymentMethodType = standing.paymentMethodType) != null ? _standing_paymentMethodType : null,
|
|
200
|
+
cardOnFile: (_aiOverageCardOnFile = aiOverageCardOnFile(standing)) != null ? _aiOverageCardOnFile : null,
|
|
201
|
+
firstPaidMonth: standing.firstPaidMonth,
|
|
202
|
+
qualifyingMonths: standing.qualifyingMonths,
|
|
203
|
+
step: aiOverageStep(standing),
|
|
204
|
+
staffOverride: standing.staffOverride,
|
|
205
|
+
pause: standing.pause,
|
|
206
|
+
lastDisputeAt: standing.lastDisputeAt
|
|
207
|
+
},
|
|
208
|
+
ceiling: {
|
|
209
|
+
ladderUsd: [
|
|
210
|
+
...AI_OVERAGE_CEILING_LADDER_USD
|
|
211
|
+
],
|
|
212
|
+
standingUsd: aiOverageStandingCeilingUsd(standing, now),
|
|
213
|
+
effectiveUsd: aiOverageEffectiveCeilingUsd(org, standing, now),
|
|
214
|
+
thresholdUsd: AI_OVERAGE_THRESHOLD_USD,
|
|
215
|
+
unpaidLimitUsd: AI_OVERAGE_UNPAID_LIMIT_USD
|
|
216
|
+
},
|
|
217
|
+
ledger,
|
|
218
|
+
charges: chargesSnapshot.docs.map((doc)=>{
|
|
219
|
+
var _doc_get, _doc_get1, _doc_get2, _doc_get3, _doc_get4;
|
|
220
|
+
return {
|
|
221
|
+
chargeId: doc.id,
|
|
222
|
+
kind: (_doc_get = doc.get('kind')) != null ? _doc_get : null,
|
|
223
|
+
amountUsd: Number((_doc_get1 = doc.get('amountUsd')) != null ? _doc_get1 : 0),
|
|
224
|
+
credits: Number((_doc_get2 = doc.get('credits')) != null ? _doc_get2 : 0),
|
|
225
|
+
invoiceId: (_doc_get3 = doc.get('invoiceId')) != null ? _doc_get3 : null,
|
|
226
|
+
status: (_doc_get4 = doc.get('status')) != null ? _doc_get4 : null
|
|
227
|
+
};
|
|
228
|
+
})
|
|
229
|
+
}, {
|
|
230
|
+
status: 200
|
|
231
|
+
});
|
|
232
|
+
} catch (error) {
|
|
233
|
+
const unauthenticated = invalidIdTokenResponse(error);
|
|
234
|
+
if (unauthenticated) return unauthenticated;
|
|
235
|
+
console.error(error);
|
|
236
|
+
return Response.json({
|
|
237
|
+
error: 'AI overage standing failed'
|
|
238
|
+
}, {
|
|
239
|
+
status: 500
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
export const dynamic = 'force-dynamic';
|
|
244
|
+
export { handler as POST };
|
|
245
|
+
|
|
246
|
+
//# sourceMappingURL=ai-admin-overage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/server/ai-admin-overage.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 { pluginRequestFromWeb } from '@aglyn/aglyn/server'\nimport {\n emailUnverifiedResponse,\n firebaseAdmin,\n isImpersonationSession,\n} from '@aglyn/tenant-data-admin'\nimport { recordAdminAudit } from '@aglyn/tenant-data-admin/server/admin-audit'\nimport { invalidIdTokenResponse } from '@aglyn/tenant-data-admin/server/id-token-refusal'\nimport { assistUsageMonth } from '../usage/assist-usage'\nimport {\n AI_BILLING_STANDING_DOC,\n AI_BILLING_SUBCOLLECTION,\n AI_OVERAGE_CHARGES_SUBCOLLECTION,\n readAiOverageMonthLedger,\n} from '../billing/ai-overage-ledger'\nimport {\n AI_OVERAGE_CEILING_LADDER_USD,\n AI_OVERAGE_STAFF_CEILING_MAX_USD,\n AI_OVERAGE_STAFF_CEILING_MIN_USD,\n AI_OVERAGE_THRESHOLD_USD,\n AI_OVERAGE_UNPAID_LIMIT_USD,\n aiOverageCardOnFile,\n aiOverageEffectiveCeilingUsd,\n aiOverageStandingCeilingUsd,\n aiOverageStep,\n readAiOverageStanding,\n} from '../billing/ai-overage-standing'\nimport {\n resetAiOverageStep,\n resumeAiOverage,\n setAiOverageStaffOverride,\n} from '../billing/ai-overage-standing-writes'\nimport { aiOverageBillsByInvoice } from '../billing/ai-overage-cutover'\n\n/**\n * STAFF'S CONTROLS OVER ONE WORKSPACE'S OVERAGE STANDING (AGL-3011).\n *\n * The ladder rises on payment history and a dispute takes it back to the\n * bottom. Both are rules, and a rule that nobody can override is a rule that\n * strands the customer it gets wrong: an enterprise-shaped workspace on its\n * first month, a dispute that turns out to be fraud on the cardholder rather\n * than by them, a failed charge whose cause was ours.\n *\n * So four acts, staff-only, every one of them audited:\n *\n * `get` the standing in full, with the month's charges\n * `setCeiling` a ceiling that outranks the ladder, with a reason and an\n * optional expiry\n * `liftPause` resume accrual, with a reason — the ONLY way a dispute\n * pause comes off\n * `resetStep` put the workspace back at the bottom of the ladder\n *\n * A reason is required on every act that changes something, because the\n * question a month later is never \"what was the ceiling\" — the document says\n * that — but \"why did someone raise it\".\n *\n * The emergency stop is not here and does not change: Lockdown, scoped to\n * the organization, which stops AI along with everything else.\n */\n\n/** How many of the month's charge rows the card lists. */\nconst CHARGES_LISTED = 20\n\n/** The longest a staff reason may be, so a paste cannot fill the document. */\nconst REASON_MAX = 500\n\nfunction badRequest(error: string, code: string): Response {\n return Response.json({ error, code }, { status: 400 })\n}\n\nasync function handler(request: Request): Promise<Response> {\n const { method, body, headers: rawHeaders } = await pluginRequestFromWeb(request)\n const headers = rawHeaders as Partial<Record<string, string>>\n if (method !== 'POST') {\n return Response.json({ error: 'Method not allowed' }, { status: 405 })\n }\n const authorization = headers.authorization ?? ''\n const idToken = authorization.startsWith('Bearer ')\n ? authorization.slice('Bearer '.length)\n : undefined\n if (!idToken) return Response.json({ error: 'Unauthenticated' }, { status: 401 })\n const orgId = String(body?.orgId ?? '')\n const action = String(body?.action ?? '')\n const actions = ['get', 'setCeiling', 'liftPause', 'resetStep']\n if (!orgId || !actions.includes(action)) {\n return Response.json({ error: 'Bad request' }, { status: 400 })\n }\n\n try {\n const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken)\n if (!decoded.email_verified && !isImpersonationSession(decoded)) {\n return emailUnverifiedResponse()\n }\n // The staff claim, the same test `ai/admin/org` makes. Not a permission\n // on the workspace: these controls are Aglyn's side of the relationship,\n // and a workspace admin raising their own ceiling is the thing the\n // ladder exists to prevent.\n if (!decoded['staff']) {\n return Response.json({ error: 'Staff only' }, { status: 403 })\n }\n\n const now = new Date()\n const month = assistUsageMonth(now)\n const db = firebaseAdmin.app().firestore()\n const orgRef = db.collection('orgs').doc(orgId)\n const orgSnapshot = await orgRef.get()\n if (!orgSnapshot.exists) {\n return Response.json({ error: 'No such organization' }, { status: 404 })\n }\n const org = (orgSnapshot.data() ?? {}) as Record<string, unknown>\n const reason = String(body?.reason ?? '').trim().slice(0, REASON_MAX)\n\n if (action === 'setCeiling') {\n const clearing = body?.ceilingUsd === null\n const ceilingUsd = Number(body?.ceilingUsd)\n if (!reason) {\n return badRequest('Say why the ceiling is being changed', 'reason_required')\n }\n if (\n !clearing &&\n (!Number.isFinite(ceilingUsd) ||\n ceilingUsd < AI_OVERAGE_STAFF_CEILING_MIN_USD ||\n ceilingUsd > AI_OVERAGE_STAFF_CEILING_MAX_USD)\n ) {\n return badRequest(\n `Set a ceiling between $${AI_OVERAGE_STAFF_CEILING_MIN_USD} and ` +\n `$${AI_OVERAGE_STAFF_CEILING_MAX_USD.toLocaleString('en-US')}, or clear it.`,\n 'invalid_ceiling',\n )\n }\n // An expiry that does not parse is refused rather than dropped: a\n // ceiling meant to last a week and stored with no end is the failure\n // this field exists to avoid.\n const rawExpiry = body?.expiresAt\n const expiresAt =\n rawExpiry === null || rawExpiry === undefined ? null : String(rawExpiry)\n if (expiresAt !== null && !Number.isFinite(Date.parse(expiresAt))) {\n return badRequest('The expiry is not a date', 'invalid_expiry')\n }\n await setAiOverageStaffOverride(\n db,\n orgId,\n clearing\n ? null\n : { ceilingUsd, reason, setBy: decoded.uid, expiresAt },\n now,\n )\n await recordAdminAudit({\n actorUid: decoded.uid,\n action: clearing\n ? 'ai.overage.clearCeiling'\n : 'ai.overage.setCeiling',\n target: `orgs/${orgId}/${AI_BILLING_SUBCOLLECTION}/${AI_BILLING_STANDING_DOC}`,\n note: clearing\n ? reason\n : `${reason} — ceiling $${ceilingUsd}${expiresAt ? `, until ${expiresAt}` : ''}`,\n })\n }\n\n if (action === 'liftPause') {\n if (!reason) {\n return badRequest('Say why the pause is being lifted', 'reason_required')\n }\n // `force`, because staff lifting a pause is the one path a DISPUTE\n // pause has out. Every other pause lifts on its own when the payment\n // that set it succeeds.\n await resumeAiOverage(db, orgId, { force: true })\n await recordAdminAudit({\n actorUid: decoded.uid,\n action: 'ai.overage.liftPause',\n target: `orgs/${orgId}/${AI_BILLING_SUBCOLLECTION}/${AI_BILLING_STANDING_DOC}`,\n note: reason,\n })\n }\n\n if (action === 'resetStep') {\n if (!reason) {\n return badRequest('Say why the step is being reset', 'reason_required')\n }\n await resetAiOverageStep(db, orgId)\n await recordAdminAudit({\n actorUid: decoded.uid,\n action: 'ai.overage.resetStep',\n target: `orgs/${orgId}/${AI_BILLING_SUBCOLLECTION}/${AI_BILLING_STANDING_DOC}`,\n note: reason,\n })\n }\n\n // Read AFTER any write, so the answer is the state the act produced\n // rather than the state it found — a staff card that showed the old\n // ceiling after raising it would be read as the raise having failed.\n const [standingSnapshot, usageSnapshot, chargesSnapshot] = await Promise.all([\n orgRef.collection(AI_BILLING_SUBCOLLECTION).doc(AI_BILLING_STANDING_DOC).get(),\n orgRef.collection('assistUsage').doc(month).get(),\n orgRef\n .collection(AI_OVERAGE_CHARGES_SUBCOLLECTION)\n .where('month', '==', month)\n .limit(CHARGES_LISTED)\n .get(),\n ])\n const standing = readAiOverageStanding(\n standingSnapshot.exists ? (standingSnapshot.data() ?? null) : null,\n )\n const ledger = readAiOverageMonthLedger(\n usageSnapshot.exists ? (usageSnapshot.data() ?? null) : null,\n )\n return Response.json(\n {\n month,\n // Whether any of this is live yet. Staff looking at a standing that\n // nothing consults should be told so rather than left to infer it\n // from a ceiling that never refuses.\n billsByInvoice: aiOverageBillsByInvoice(month),\n standing: {\n paymentMethodType: standing.paymentMethodType ?? null,\n cardOnFile: aiOverageCardOnFile(standing) ?? null,\n firstPaidMonth: standing.firstPaidMonth,\n qualifyingMonths: standing.qualifyingMonths,\n step: aiOverageStep(standing),\n staffOverride: standing.staffOverride,\n pause: standing.pause,\n lastDisputeAt: standing.lastDisputeAt,\n },\n ceiling: {\n ladderUsd: [...AI_OVERAGE_CEILING_LADDER_USD],\n standingUsd: aiOverageStandingCeilingUsd(standing, now),\n effectiveUsd: aiOverageEffectiveCeilingUsd(org as never, standing, now),\n thresholdUsd: AI_OVERAGE_THRESHOLD_USD,\n unpaidLimitUsd: AI_OVERAGE_UNPAID_LIMIT_USD,\n },\n ledger,\n charges: chargesSnapshot.docs.map((doc) => ({\n chargeId: doc.id,\n kind: doc.get('kind') ?? null,\n amountUsd: Number(doc.get('amountUsd') ?? 0),\n credits: Number(doc.get('credits') ?? 0),\n invoiceId: doc.get('invoiceId') ?? null,\n status: doc.get('status') ?? null,\n })),\n },\n { status: 200 },\n )\n } catch (error) {\n const unauthenticated = invalidIdTokenResponse(error)\n if (unauthenticated) return unauthenticated\n console.error(error)\n return Response.json({ error: 'AI overage standing failed' }, { status: 500 })\n }\n}\n\nexport const dynamic = 'force-dynamic'\nexport { handler as POST }\n"],"names":["pluginRequestFromWeb","emailUnverifiedResponse","firebaseAdmin","isImpersonationSession","recordAdminAudit","invalidIdTokenResponse","assistUsageMonth","AI_BILLING_STANDING_DOC","AI_BILLING_SUBCOLLECTION","AI_OVERAGE_CHARGES_SUBCOLLECTION","readAiOverageMonthLedger","AI_OVERAGE_CEILING_LADDER_USD","AI_OVERAGE_STAFF_CEILING_MAX_USD","AI_OVERAGE_STAFF_CEILING_MIN_USD","AI_OVERAGE_THRESHOLD_USD","AI_OVERAGE_UNPAID_LIMIT_USD","aiOverageCardOnFile","aiOverageEffectiveCeilingUsd","aiOverageStandingCeilingUsd","aiOverageStep","readAiOverageStanding","resetAiOverageStep","resumeAiOverage","setAiOverageStaffOverride","aiOverageBillsByInvoice","CHARGES_LISTED","REASON_MAX","badRequest","error","code","Response","json","status","handler","request","headers","method","body","rawHeaders","authorization","idToken","startsWith","slice","length","undefined","orgId","String","action","actions","includes","orgSnapshot","standingSnapshot","usageSnapshot","standing","decoded","app","auth","verifyIdToken","email_verified","now","Date","month","db","firestore","orgRef","collection","doc","get","exists","org","data","reason","trim","clearing","ceilingUsd","Number","isFinite","toLocaleString","rawExpiry","expiresAt","parse","setBy","uid","actorUid","target","note","force","chargesSnapshot","Promise","all","where","limit","ledger","billsByInvoice","paymentMethodType","cardOnFile","firstPaidMonth","qualifyingMonths","step","staffOverride","pause","lastDisputeAt","ceiling","ladderUsd","standingUsd","effectiveUsd","thresholdUsd","unpaidLimitUsd","charges","docs","map","chargeId","id","kind","amountUsd","credits","invoiceId","unauthenticated","console","dynamic","POST"],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
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 AssistSpendRow } from '../usage/assist-signal-mining';
|
|
18
|
+
export interface AssistSpendLeaderboard {
|
|
19
|
+
month: string;
|
|
20
|
+
rows: AssistSpendRow[];
|
|
21
|
+
/** How many workspaces had a document for the month — the ranked count. */
|
|
22
|
+
ranked: number;
|
|
23
|
+
/** True when the scan hit its ceiling, so the ranking is over a sample. */
|
|
24
|
+
truncated: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* True when the month documents could not be read at all. Reported rather
|
|
27
|
+
* than rendered as an empty table: "no workspace spent anything" and "the
|
|
28
|
+
* read failed" are opposite findings, and the rest of the board — read
|
|
29
|
+
* from a different collection — is still good.
|
|
30
|
+
*/
|
|
31
|
+
failed: boolean;
|
|
32
|
+
}
|
|
33
|
+
declare function handler(request: Request): Promise<Response>;
|
|
34
|
+
export { handler as GET };
|
|
@@ -0,0 +1,330 @@
|
|
|
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 { ORG_BILLING_DOC_ID, ORG_BILLING_SUBCOLLECTION, pluginRequestFromWeb } from "@aglyn/aglyn/server";
|
|
18
|
+
import { emailUnverifiedResponse, firebaseAdmin, isImpersonationSession } from "@aglyn/tenant-data-admin";
|
|
19
|
+
import { ASSIST_PROVIDER_COST_FIELD, assistCreditsFromUsd, assistProviderCostUsd } from "@aglyn/aglyn/app-utils/assist-credits";
|
|
20
|
+
import { hasAiAddon, resolveEffectivePlan } from "@aglyn/aglyn/app-utils/plan-entitlements";
|
|
21
|
+
import { readPlatformFreeSpend } from "../usage/assist-free-taste.js";
|
|
22
|
+
import { assistRefusalCounts } from "../usage/assist-refusals.js";
|
|
23
|
+
import { assistUsageDay, assistUsageMonth } from "../usage/assist-usage.js";
|
|
24
|
+
import { invalidIdTokenResponse } from "@aglyn/tenant-data-admin/server/id-token-refusal";
|
|
25
|
+
import { assistSignalRow, mineAssistSignals, rankAssistSpend } from "../usage/assist-signal-mining.js";
|
|
26
|
+
/**
|
|
27
|
+
* The Assist docs-gap and cost mining view (AGL-1860, AGL-2252), served at
|
|
28
|
+
* `/api/ai/admin/signals` for the plugin's Assist signal staff page.
|
|
29
|
+
* Staff-gated, read-only, and the only reader `assistSignals` has.
|
|
30
|
+
*
|
|
31
|
+
* ## Why a route and not a client query
|
|
32
|
+
*
|
|
33
|
+
* `assistSignals` is absent from `firebase-firestore.rules` deliberately: the
|
|
34
|
+
* org block matches its subcollections BY NAME and carries no wildcard, so an
|
|
35
|
+
* unlisted name is default-deny for every client. That is the property that
|
|
36
|
+
* lets the collection hold cross-tenant analytics at all. Reading it therefore
|
|
37
|
+
* goes through the Admin SDK behind the staff claim, exactly as every staff
|
|
38
|
+
* route does.
|
|
39
|
+
*
|
|
40
|
+
* ## The collection group, and the index it does not need
|
|
41
|
+
*
|
|
42
|
+
* One `collectionGroup('assistSignals')` read gathers every org's signals in a
|
|
43
|
+
* single query; the owning org is `ref.parent.parent.id`, since the document
|
|
44
|
+
* carries no `orgId` field (it carries no identifiers at all — see AGL-1972).
|
|
45
|
+
* The query has no `where` and no `orderBy`, so it needs no composite index,
|
|
46
|
+
* and adding one later would mean declaring a `COLLECTION_GROUP`-scoped
|
|
47
|
+
* override and deploying it by hand. `/api/admin/overview` reads org billing
|
|
48
|
+
* the same way and for the same reason.
|
|
49
|
+
*
|
|
50
|
+
* ## Truncation is reported, never hidden
|
|
51
|
+
*
|
|
52
|
+
* The read is bounded — an unbounded fleet-wide get is how a staff page
|
|
53
|
+
* becomes an outage — but a ranking cut short looks exactly like a complete
|
|
54
|
+
* one, so the ceiling is fetched PLUS ONE and the extra row sets `truncated`.
|
|
55
|
+
* AGL-2220 is the standing example of the alternative: a sweep that stopped at
|
|
56
|
+
* 500 orgs and reported nothing about the rest, for as long as nobody counted.
|
|
57
|
+
*/ /**
|
|
58
|
+
* Rows read in one pass. Each signal is a handful of scalars, so this is a
|
|
59
|
+
* few megabytes at the ceiling — large enough to be worth ranking, small
|
|
60
|
+
* enough that the honest answer to "is it all of them" is usually yes.
|
|
61
|
+
*/ const SCAN_CEILING = 20000;
|
|
62
|
+
/**
|
|
63
|
+
* How much of an answer the prose panel shows.
|
|
64
|
+
*
|
|
65
|
+
* Enough to judge whether the answer was wrong, short enough that twenty-five
|
|
66
|
+
* of them are still a page somebody reads.
|
|
67
|
+
*/ const ANSWER_PREVIEW_CHARS = 600;
|
|
68
|
+
/**
|
|
69
|
+
* Month documents read in one pass for the spend leaderboard (AGL-2930).
|
|
70
|
+
*
|
|
71
|
+
* `assistUsage` holds one document per org per month, so this is orgs times
|
|
72
|
+
* months — a fraction of the signal count, and the same PLUS-ONE truncation
|
|
73
|
+
* probe the signals read uses. Read as a collection group with NO `where`
|
|
74
|
+
* and NO `orderBy`, for the reason the module note gives: a filter on
|
|
75
|
+
* `month` would need a COLLECTION_GROUP-scoped index deployed by hand, and
|
|
76
|
+
* filtering the month in memory costs nothing at this size.
|
|
77
|
+
*/ const SPEND_SCAN_CEILING = 20000;
|
|
78
|
+
/**
|
|
79
|
+
* The month's per-org spend, refusals and plan, dearest first.
|
|
80
|
+
*
|
|
81
|
+
* Plan and add-on come from the org and billing documents of the ranked
|
|
82
|
+
* rows only — bounded by `limit`, never by the fleet — merged org-doc-first
|
|
83
|
+
* exactly as every other staff reader merges them.
|
|
84
|
+
*/ async function readAssistSpendLeaderboard(firestore, limit, month) {
|
|
85
|
+
try {
|
|
86
|
+
return await rankAssistSpendForMonth(firestore, limit, month);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error('[ai/admin/signals] spend leaderboard read failed', error);
|
|
89
|
+
return {
|
|
90
|
+
month,
|
|
91
|
+
rows: [],
|
|
92
|
+
ranked: 0,
|
|
93
|
+
truncated: false,
|
|
94
|
+
failed: true
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async function rankAssistSpendForMonth(firestore, limit, month) {
|
|
99
|
+
const snapshot = await firestore.collectionGroup('assistUsage').limit(SPEND_SCAN_CEILING + 1).get();
|
|
100
|
+
const truncated = snapshot.size > SPEND_SCAN_CEILING;
|
|
101
|
+
const docs = truncated ? snapshot.docs.slice(0, SPEND_SCAN_CEILING) : snapshot.docs;
|
|
102
|
+
const unranked = [];
|
|
103
|
+
for (const doc of docs){
|
|
104
|
+
var _doc_get;
|
|
105
|
+
var _doc_ref_parent_parent;
|
|
106
|
+
// The id IS the month; the field is the same value and is what an
|
|
107
|
+
// older document may lack.
|
|
108
|
+
if (doc.id !== month && doc.get('month') !== month) continue;
|
|
109
|
+
const orgId = (_doc_ref_parent_parent = doc.ref.parent.parent) == null ? void 0 : _doc_ref_parent_parent.id;
|
|
110
|
+
if (!orgId) continue;
|
|
111
|
+
// Two figures off one document (AGL-3015): the credits a workspace drew
|
|
112
|
+
// come from what it was BILLED, and the dollars staff rank workspaces by
|
|
113
|
+
// come from what it COST US. Ranking on the billed figure would sort the
|
|
114
|
+
// fleet by our own markup wherever workspaces differ in model mix.
|
|
115
|
+
const billed = Number((_doc_get = doc.get('estCostUsd')) != null ? _doc_get : 0);
|
|
116
|
+
const billedUsd = Number.isFinite(billed) && billed > 0 ? billed : 0;
|
|
117
|
+
unranked.push({
|
|
118
|
+
orgId,
|
|
119
|
+
plan: 'free',
|
|
120
|
+
aiAddon: false,
|
|
121
|
+
credits: assistCreditsFromUsd(billedUsd),
|
|
122
|
+
providerCostUsd: assistProviderCostUsd(billedUsd, doc.get(ASSIST_PROVIDER_COST_FIELD)),
|
|
123
|
+
refusals: assistRefusalCounts(doc.get('refusals'))
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const { rows, ranked } = rankAssistSpend(unranked, limit);
|
|
127
|
+
if (rows.length) {
|
|
128
|
+
const orgRefs = rows.map((row)=>firestore.collection('orgs').doc(row.orgId));
|
|
129
|
+
const [orgSnaps, billingSnaps] = await Promise.all([
|
|
130
|
+
firestore.getAll(...orgRefs),
|
|
131
|
+
firestore.getAll(...orgRefs.map((ref)=>ref.collection(ORG_BILLING_SUBCOLLECTION).doc(ORG_BILLING_DOC_ID)))
|
|
132
|
+
]);
|
|
133
|
+
rows.forEach((row, index)=>{
|
|
134
|
+
var _orgSnaps_index_data, _ref, _orgData_name;
|
|
135
|
+
var _orgSnaps_index, _billingSnaps_index;
|
|
136
|
+
const orgData = ((_orgSnaps_index = orgSnaps[index]) == null ? void 0 : _orgSnaps_index.exists) ? (_orgSnaps_index_data = orgSnaps[index].data()) != null ? _orgSnaps_index_data : {} : {};
|
|
137
|
+
const org = _extends({}, orgData, ((_billingSnaps_index = billingSnaps[index]) == null ? void 0 : _billingSnaps_index.exists) ? billingSnaps[index].data() : {});
|
|
138
|
+
row.plan = resolveEffectivePlan(org);
|
|
139
|
+
row.aiAddon = hasAiAddon(org);
|
|
140
|
+
const label = (_ref = (_orgData_name = orgData['name']) != null ? _orgData_name : orgData['slug']) != null ? _ref : '';
|
|
141
|
+
row.orgLabel = label || null;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
month,
|
|
146
|
+
rows,
|
|
147
|
+
ranked,
|
|
148
|
+
truncated,
|
|
149
|
+
failed: false
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
async function handler(request) {
|
|
153
|
+
var _headers_authorization;
|
|
154
|
+
const { method, query, headers: rawHeaders } = await pluginRequestFromWeb(request);
|
|
155
|
+
const headers = rawHeaders;
|
|
156
|
+
if (method !== 'GET') {
|
|
157
|
+
return Response.json({
|
|
158
|
+
error: 'Method not allowed'
|
|
159
|
+
}, {
|
|
160
|
+
status: 405
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
const authorization = (_headers_authorization = headers.authorization) != null ? _headers_authorization : '';
|
|
164
|
+
const idToken = authorization.startsWith('Bearer ') ? authorization.slice('Bearer '.length) : undefined;
|
|
165
|
+
if (!idToken) return Response.json({
|
|
166
|
+
error: 'Unauthenticated'
|
|
167
|
+
}, {
|
|
168
|
+
status: 401
|
|
169
|
+
});
|
|
170
|
+
try {
|
|
171
|
+
var _query_limit;
|
|
172
|
+
const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken);
|
|
173
|
+
if (!decoded.email_verified && !isImpersonationSession(decoded)) {
|
|
174
|
+
return emailUnverifiedResponse();
|
|
175
|
+
}
|
|
176
|
+
if (!decoded['staff']) {
|
|
177
|
+
return Response.json({
|
|
178
|
+
error: 'Staff only'
|
|
179
|
+
}, {
|
|
180
|
+
status: 403
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
const requested = Number((_query_limit = query.limit) != null ? _query_limit : 25);
|
|
184
|
+
const limit = Number.isFinite(requested) && requested > 0 ? Math.min(Math.floor(requested), 100) : 25;
|
|
185
|
+
const snapshot = await firebaseAdmin.app().firestore().collectionGroup('assistSignals')// Ceiling PLUS ONE: the extra document is what makes truncation
|
|
186
|
+
// detectable rather than assumed.
|
|
187
|
+
.limit(SCAN_CEILING + 1).get();
|
|
188
|
+
const truncated = snapshot.size > SCAN_CEILING;
|
|
189
|
+
const docs = truncated ? snapshot.docs.slice(0, SCAN_CEILING) : snapshot.docs;
|
|
190
|
+
const rows = docs.map((doc)=>{
|
|
191
|
+
var _ref;
|
|
192
|
+
var _doc_ref_parent_parent;
|
|
193
|
+
return assistSignalRow((_ref = (_doc_ref_parent_parent = doc.ref.parent.parent) == null ? void 0 : _doc_ref_parent_parent.id) != null ? _ref : '(unknown)', // The signal id IS the exchange id (AGL-2314) — one id, two halves,
|
|
194
|
+
// minted together by `recordAssistExchange` precisely so the join is
|
|
195
|
+
// possible. Until now nothing carried it this far.
|
|
196
|
+
doc.id, doc.data());
|
|
197
|
+
});
|
|
198
|
+
const report = mineAssistSignals(rows, {
|
|
199
|
+
truncated,
|
|
200
|
+
limit
|
|
201
|
+
});
|
|
202
|
+
// This month's spend, per workspace (AGL-2930) — the board's only
|
|
203
|
+
// month-scoped panel, read off the month documents rather than mined
|
|
204
|
+
// from the all-time signals above.
|
|
205
|
+
const spend = await readAssistSpendLeaderboard(firebaseAdmin.app().firestore(), limit, assistUsageMonth());
|
|
206
|
+
/*==========================================
|
|
207
|
+
* THE VERBATIM HALF (AGL-2314).
|
|
208
|
+
*
|
|
209
|
+
* `assistExchanges` stores the question a customer typed and the answer
|
|
210
|
+
* we gave, for 180 days, and `assist-usage.ts` calls it "the data loop's
|
|
211
|
+
* corpus". NOTHING read it — one write, no reader, no collection group.
|
|
212
|
+
* So we retained customers' words, and committed publicly in the privacy
|
|
213
|
+
* policy to retaining them, for zero product value.
|
|
214
|
+
*
|
|
215
|
+
* Read here rather than in the miner because the miner is pure: it does
|
|
216
|
+
* the arithmetic, the route does the reading.
|
|
217
|
+
*
|
|
218
|
+
* ## Only the turns that FAILED
|
|
219
|
+
*
|
|
220
|
+
* The shortlist is thumbs-down and ungrounded turns only, capped by the
|
|
221
|
+
* same `limit` as every other panel. That is a privacy decision as much
|
|
222
|
+
* as a cost one: the counts already answer "how often", and the words are
|
|
223
|
+
* fetched only where the counts CANNOT say what went wrong. Pulling every
|
|
224
|
+
* exchange would be surveillance with a dashboard on it.
|
|
225
|
+
*
|
|
226
|
+
* `uid` is deliberately not projected. The corpus question is what people
|
|
227
|
+
* asked, never who asked it — and the exchange is the only document that
|
|
228
|
+
* still carries an identifier at all.
|
|
229
|
+
*
|
|
230
|
+
* ## An expired exchange is an ANSWER
|
|
231
|
+
*
|
|
232
|
+
* The 180-day TTL means a signal can outlive its prose, and it is meant
|
|
233
|
+
* to. A missing document therefore reports `expired: true` rather than
|
|
234
|
+
* being dropped: a shortlist silently shorter than the failure count it
|
|
235
|
+
* came from would read as "these are all the failures", which is the
|
|
236
|
+
* AGL-2220 shape.
|
|
237
|
+
*=========================================*/ const firestore = firebaseAdmin.app().firestore();
|
|
238
|
+
const exchanges = report.proseCandidates.length ? await firestore.getAll(...report.proseCandidates.map((candidate)=>firestore.collection('orgs').doc(candidate.orgId).collection('assistExchanges').doc(candidate.exchangeId))) : [];
|
|
239
|
+
const prose = report.proseCandidates.map((candidate, index)=>{
|
|
240
|
+
var _ref;
|
|
241
|
+
const snapshot = exchanges[index];
|
|
242
|
+
const data = (_ref = (snapshot == null ? void 0 : snapshot.exists) ? snapshot.data() : null) != null ? _ref : {};
|
|
243
|
+
return _extends({}, candidate, {
|
|
244
|
+
expired: !(snapshot == null ? void 0 : snapshot.exists),
|
|
245
|
+
question: typeof data['question'] === 'string' ? data['question'] : null,
|
|
246
|
+
// Trimmed, not omitted: judging whether an answer was wrong needs to
|
|
247
|
+
// see it, and a whole answer per row would make the panel unreadable.
|
|
248
|
+
answer: typeof data['answer'] === 'string' ? data['answer'].slice(0, ANSWER_PREVIEW_CHARS) : null,
|
|
249
|
+
answerTruncated: typeof data['answer'] === 'string' && data['answer'].length > ANSWER_PREVIEW_CHARS
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
/*==========================================
|
|
253
|
+
* THE WORKSPACE, BY NAME.
|
|
254
|
+
*
|
|
255
|
+
* A staff reader recognizes a customer by name, never by document id,
|
|
256
|
+
* and the cost board's own column header says "Workspace" over a column
|
|
257
|
+
* of generated ids. `/api/admin/overview` fixed the same shape by
|
|
258
|
+
* building a label map from a snapshot it already held; there is no such
|
|
259
|
+
* snapshot here — this route reads `assistSignals` and nothing else — so
|
|
260
|
+
* the labels are fetched, with the same `name` → `slug` → id precedence
|
|
261
|
+
* so one workspace cannot appear under two different labels on two
|
|
262
|
+
* screens.
|
|
263
|
+
*
|
|
264
|
+
* Bounded by what is actually RENDERED, not by the fleet. Both lists the
|
|
265
|
+
* ids come from are already sliced to `limit` (25 by default, 100 at the
|
|
266
|
+
* ceiling), so this is one `getAll` over at most a couple of hundred
|
|
267
|
+
* documents — and it reads the orgs the reader can see rather than
|
|
268
|
+
* scanning a collection to name a handful of rows.
|
|
269
|
+
*
|
|
270
|
+
* An org that has been deleted keeps its id rather than going blank: an
|
|
271
|
+
* unfamiliar id is still a lead a staff member can paste into the org
|
|
272
|
+
* search, and an empty cell is not.
|
|
273
|
+
*=========================================*/ const orgIds = [
|
|
274
|
+
...new Set([
|
|
275
|
+
...report.orgs.map((row)=>row.orgId),
|
|
276
|
+
...report.proseCandidates.map((row)=>row.orgId)
|
|
277
|
+
].filter((orgId)=>orgId && orgId !== '(unknown)'))
|
|
278
|
+
];
|
|
279
|
+
const orgLabelById = new Map();
|
|
280
|
+
if (orgIds.length) {
|
|
281
|
+
const orgDocs = await firestore.getAll(...orgIds.map((orgId)=>firestore.collection('orgs').doc(orgId)));
|
|
282
|
+
for (const doc of orgDocs){
|
|
283
|
+
var _doc_data, _ref, _data_name;
|
|
284
|
+
if (!doc.exists) continue;
|
|
285
|
+
const data = (_doc_data = doc.data()) != null ? _doc_data : {};
|
|
286
|
+
const label = (_ref = (_data_name = data['name']) != null ? _data_name : data['slug']) != null ? _ref : '';
|
|
287
|
+
if (label) orgLabelById.set(doc.id, label);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
const orgLabel = (orgId)=>{
|
|
291
|
+
var _orgLabelById_get;
|
|
292
|
+
return (_orgLabelById_get = orgLabelById.get(orgId)) != null ? _orgLabelById_get : orgId;
|
|
293
|
+
};
|
|
294
|
+
// Today's free-tier spend against the platform ceiling (AGL-2925): one
|
|
295
|
+
// document read, and the only place staff can see the taste switching
|
|
296
|
+
// itself off before the email arrives. Best-effort — a readout that
|
|
297
|
+
// cannot be read must not take the rest of the board down with it.
|
|
298
|
+
const freeSpend = await readPlatformFreeSpend(firestore, assistUsageDay()).catch((error)=>{
|
|
299
|
+
console.error('[ai/admin/signals] free spend readout failed', error);
|
|
300
|
+
return undefined;
|
|
301
|
+
});
|
|
302
|
+
return Response.json(_extends({}, report, {
|
|
303
|
+
freeSpend,
|
|
304
|
+
orgs: report.orgs.map((row)=>_extends({}, row, {
|
|
305
|
+
orgLabel: orgLabel(row.orgId)
|
|
306
|
+
})),
|
|
307
|
+
prose: prose.map((row)=>_extends({}, row, {
|
|
308
|
+
orgLabel: orgLabel(row.orgId)
|
|
309
|
+
})),
|
|
310
|
+
spend,
|
|
311
|
+
ceiling: SCAN_CEILING
|
|
312
|
+
}), {
|
|
313
|
+
status: 200
|
|
314
|
+
});
|
|
315
|
+
} catch (error) {
|
|
316
|
+
// An unverifiable credential is a 401, not a fault of ours
|
|
317
|
+
// (AGL-1993). Null for anything else, so a real failure keeps its 500.
|
|
318
|
+
const unauthenticated = invalidIdTokenResponse(error);
|
|
319
|
+
if (unauthenticated) return unauthenticated;
|
|
320
|
+
console.error('[ai/admin/signals]', error);
|
|
321
|
+
return Response.json({
|
|
322
|
+
error: 'Assist signal lookup failed'
|
|
323
|
+
}, {
|
|
324
|
+
status: 500
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
export { handler as GET };
|
|
329
|
+
|
|
330
|
+
//# sourceMappingURL=ai-admin-signals.js.map
|