@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,161 @@
|
|
|
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 AiUsageByUserMonth, type AiUsageKind } from '../model/ai-usage-by-user';
|
|
18
|
+
import type { AiUsage } from '../providers/contract';
|
|
19
|
+
/**
|
|
20
|
+
* PER-USER AI USAGE (AGL-2928): the writer and the readers.
|
|
21
|
+
*
|
|
22
|
+
* One document per person per month, under the org they spent in:
|
|
23
|
+
*
|
|
24
|
+
* orgs/{orgId}/aiUsageByUser/{uid}/months/{YYYY-MM}
|
|
25
|
+
* { uid, month, credits, estCostUsd, requests, refusals,
|
|
26
|
+
* tokens: { input, cached, cacheWrite, output },
|
|
27
|
+
* byKind: { kind: credits }, byHost: { hostId: credits },
|
|
28
|
+
* updatedAt, expiresAt }
|
|
29
|
+
*
|
|
30
|
+
* ## Written in the org rollup's own batch
|
|
31
|
+
*
|
|
32
|
+
* `recordUserAiUsage` takes the BATCH the org rollup is being written into
|
|
33
|
+
* and adds this document to it, so the two cannot disagree: a batch commits
|
|
34
|
+
* whole or not at all, and there is no path on which the workspace's month
|
|
35
|
+
* moves and the person's does not. Both assist entrypoints hand it the batch
|
|
36
|
+
* from inside `recordAssistCost` / `recordAssistExchange`, and the job
|
|
37
|
+
* runner meters through the first of those, so a generation step lands here
|
|
38
|
+
* with the job's kind and creator.
|
|
39
|
+
*
|
|
40
|
+
* ## No prose, no PII past the uid
|
|
41
|
+
*
|
|
42
|
+
* The exchange's verbatim half already expires at 180 days for the reason
|
|
43
|
+
* `assist-usage.ts` gives; this rollup is integers keyed by an id, and it
|
|
44
|
+
* is kept longer (`AI_USAGE_BY_USER_RETENTION_MONTHS`) because a workspace
|
|
45
|
+
* admin's question is month-over-month. It is still a document ABOUT a
|
|
46
|
+
* person, so it is readable only by the person and by members holding
|
|
47
|
+
* `billing.view` or `org.auditLog` (the rules, and every route that serves
|
|
48
|
+
* it), and an account erasure sweeps it (`eraseUserAiUsage`).
|
|
49
|
+
*/
|
|
50
|
+
/** What one metered request attributes to a person. */
|
|
51
|
+
export interface RecordUserAiUsageInput {
|
|
52
|
+
/** The person who asked. No uid, no attribution — the write is skipped. */
|
|
53
|
+
uid: string | null | undefined;
|
|
54
|
+
/** The billing month the org rollup is being written into. */
|
|
55
|
+
month: string;
|
|
56
|
+
/** The request's measured provider spend, as the org rollup counts it. */
|
|
57
|
+
estCostUsd: number;
|
|
58
|
+
hostId: string | null | undefined;
|
|
59
|
+
kind: AiUsageKind;
|
|
60
|
+
/** The request's four token counts (AGL-2937), added to the month's `tokens`. */
|
|
61
|
+
usage?: AiUsage;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A request's four token counts as increments, under the names every rollup
|
|
65
|
+
* keeps them by (`model/ai-tokens.ts`).
|
|
66
|
+
*/
|
|
67
|
+
export declare function aiTokenIncrements(usage: AiUsage): Record<string, FirebaseFirestore.FieldValue>;
|
|
68
|
+
export declare function userAiUsageMonthRef(orgRef: FirebaseFirestore.DocumentReference, uid: string, month: string): FirebaseFirestore.DocumentReference;
|
|
69
|
+
/**
|
|
70
|
+
* Fold one request into a person's month, on the caller's batch.
|
|
71
|
+
*
|
|
72
|
+
* Returns whether anything was queued: a request with no uid (a meter that
|
|
73
|
+
* could not say who asked) attributes to nobody rather than to a placeholder
|
|
74
|
+
* id that would rank on every table. `set(…, { merge: true })`, never
|
|
75
|
+
* `update()`: the document does not exist before a person's first request
|
|
76
|
+
* of the month, and a merge into a map field adds the key rather than
|
|
77
|
+
* replacing the map.
|
|
78
|
+
*/
|
|
79
|
+
export declare function recordUserAiUsage(batch: FirebaseFirestore.WriteBatch, orgRef: FirebaseFirestore.DocumentReference, input: RecordUserAiUsageInput): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* The slice of a reservation a refusal is counted from: whether the gate
|
|
82
|
+
* admitted the request, and the billing month it decided in. Structural, so
|
|
83
|
+
* every door can hand over the reservation it already holds.
|
|
84
|
+
*/
|
|
85
|
+
export interface UserAiRefusalSource {
|
|
86
|
+
allowed: boolean;
|
|
87
|
+
monthKey: string;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Count a refused reservation against the person who asked — the per-person
|
|
91
|
+
* twin of `recordAssistRefusal`, and shaped the same way: fire-and-forget,
|
|
92
|
+
* off the refusal's await path, swallowing every error, because a refusal
|
|
93
|
+
* is the gate's cheap exit and a counter must not make it dearer than the
|
|
94
|
+
* thing it counts.
|
|
95
|
+
*
|
|
96
|
+
* Takes the whole reservation rather than a month so every door calls it
|
|
97
|
+
* the same way, once, right after reserving: an admitted reservation records
|
|
98
|
+
* nothing, so the call needs no branch of its own and cannot drift from the
|
|
99
|
+
* door's refusal branch. The month is the reservation's, not the clock's,
|
|
100
|
+
* because that is the month the org's own refusal was counted in.
|
|
101
|
+
*/
|
|
102
|
+
export declare function recordUserAiRefusal(firestore: FirebaseFirestore.Firestore, orgId: string, uid: string | null | undefined, reservation: UserAiRefusalSource): void;
|
|
103
|
+
/** One roster row's month, with the person the roster names. */
|
|
104
|
+
export interface OrgAiUsageByUserRow extends AiUsageByUserMonth {
|
|
105
|
+
/** The display name, else the email, else the uid — never blank. */
|
|
106
|
+
name: string;
|
|
107
|
+
email: string | null;
|
|
108
|
+
role: string | null;
|
|
109
|
+
/** This person's share of the org's measured spend, in `[0, 1]`. */
|
|
110
|
+
share: number;
|
|
111
|
+
}
|
|
112
|
+
export interface OrgAiUsageByUserMonth {
|
|
113
|
+
month: string;
|
|
114
|
+
/** The org rollup's spend for the month — the denominator of every share. */
|
|
115
|
+
orgEstCostUsd: number;
|
|
116
|
+
orgCredits: number;
|
|
117
|
+
/** Every current member with a document for the month, dearest first. */
|
|
118
|
+
rows: OrgAiUsageByUserRow[];
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The month for every current member of the org, dearest first.
|
|
122
|
+
*
|
|
123
|
+
* Reads the ROSTER and then each member's month document by path, rather
|
|
124
|
+
* than a collection-group query over `months`: the roster is the join the
|
|
125
|
+
* table needs anyway (a uid is not a name), it is bounded by the seats the
|
|
126
|
+
* plan sells, and a path read rides no index that has to be deployed before
|
|
127
|
+
* a workspace can open its Usage page. A person who has left the org is not
|
|
128
|
+
* listed — the roster is the set of people the reader may see — and their
|
|
129
|
+
* documents expire on the retention window.
|
|
130
|
+
*/
|
|
131
|
+
export declare function readOrgAiUsageByUser(firestore: FirebaseFirestore.Firestore, orgId: string, month: string): Promise<OrgAiUsageByUserMonth>;
|
|
132
|
+
/**
|
|
133
|
+
* One person's months in one org, newest first — the member card and the
|
|
134
|
+
* staff page. Ordered on the document id, which IS the month key and so
|
|
135
|
+
* needs no field every writer must remember.
|
|
136
|
+
*/
|
|
137
|
+
export declare function readUserAiUsageMonths(firestore: FirebaseFirestore.Firestore, orgId: string, uid: string, limit?: number): Promise<AiUsageByUserMonth[]>;
|
|
138
|
+
export interface EraseUserAiUsageResult {
|
|
139
|
+
/** Orgs whose `aiUsageByUser/{uid}` subtree was deleted by path. */
|
|
140
|
+
orgs: number;
|
|
141
|
+
/**
|
|
142
|
+
* Month documents found by the collection-group sweep and deleted — the
|
|
143
|
+
* ones in orgs the person had already left. `null` when the sweep could
|
|
144
|
+
* not run (its index is not deployed), which is not zero.
|
|
145
|
+
*/
|
|
146
|
+
sweptMonths: number | null;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Remove a person's usage documents on account erasure.
|
|
150
|
+
*
|
|
151
|
+
* Two passes, because the documents live under the ORG and are keyed by the
|
|
152
|
+
* uid: `recursiveDelete(users/{uid})` cannot see them, and neither can a
|
|
153
|
+
* walk of current memberships find the months left behind in an org the
|
|
154
|
+
* person was removed from. So every org the erasure knows of is deleted by
|
|
155
|
+
* path first — no index, cannot fail for want of one — and then a
|
|
156
|
+
* collection-group query on `uid` catches the rest. The second pass is
|
|
157
|
+
* reported as `null` rather than thrown when it cannot run: the erasure has
|
|
158
|
+
* a legal clock, and the by-path pass has already removed everything a
|
|
159
|
+
* current membership could reach.
|
|
160
|
+
*/
|
|
161
|
+
export declare function eraseUserAiUsage(firestore: FirebaseFirestore.Firestore, uid: string, orgIds: readonly string[]): Promise<EraseUserAiUsageResult>;
|
|
@@ -0,0 +1,211 @@
|
|
|
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
|
+
*/ // Straight from the SDK, not the admin lib, for the reason `assist-usage.ts`
|
|
18
|
+
// gives at its head: the statics need no app, and the admin lib would drag the
|
|
19
|
+
// default-app initialization into every unit test that touches a counter.
|
|
20
|
+
import { FieldPath, FieldValue } from "firebase-admin/firestore";
|
|
21
|
+
import { AI_USAGE_BY_USER_COLLECTION, AI_USAGE_BY_USER_MONTHS_COLLECTION, AI_USAGE_BY_USER_RETENTION_MONTHS, aiUsageByUserExpiry, aiUsageByUserMonthFrom, aiUsageShare } from "../model/ai-usage-by-user.js";
|
|
22
|
+
import { AI_USAGE_TOKENS_FIELD } from "../model/ai-tokens.js";
|
|
23
|
+
import { assistCreditsFromUsd } from "@aglyn/aglyn/app-utils/assist-credits";
|
|
24
|
+
/**
|
|
25
|
+
* A request's four token counts as increments, under the names every rollup
|
|
26
|
+
* keeps them by (`model/ai-tokens.ts`).
|
|
27
|
+
*/ export function aiTokenIncrements(usage) {
|
|
28
|
+
const increment = FieldValue.increment;
|
|
29
|
+
return {
|
|
30
|
+
input: increment(usage.inputTokens),
|
|
31
|
+
cached: increment(usage.cacheReadTokens),
|
|
32
|
+
cacheWrite: increment(usage.cacheWriteTokens),
|
|
33
|
+
output: increment(usage.outputTokens)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function userAiUsageMonthRef(orgRef, uid, month) {
|
|
37
|
+
return orgRef.collection(AI_USAGE_BY_USER_COLLECTION).doc(uid).collection(AI_USAGE_BY_USER_MONTHS_COLLECTION).doc(month);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Fold one request into a person's month, on the caller's batch.
|
|
41
|
+
*
|
|
42
|
+
* Returns whether anything was queued: a request with no uid (a meter that
|
|
43
|
+
* could not say who asked) attributes to nobody rather than to a placeholder
|
|
44
|
+
* id that would rank on every table. `set(…, { merge: true })`, never
|
|
45
|
+
* `update()`: the document does not exist before a person's first request
|
|
46
|
+
* of the month, and a merge into a map field adds the key rather than
|
|
47
|
+
* replacing the map.
|
|
48
|
+
*/ export function recordUserAiUsage(batch, orgRef, input) {
|
|
49
|
+
var _input_uid, _input_hostId;
|
|
50
|
+
const uid = String((_input_uid = input.uid) != null ? _input_uid : '').trim();
|
|
51
|
+
if (!uid) return false;
|
|
52
|
+
const estCostUsd = Number.isFinite(input.estCostUsd) && input.estCostUsd > 0 ? input.estCostUsd : 0;
|
|
53
|
+
const credits = assistCreditsFromUsd(estCostUsd);
|
|
54
|
+
const increment = FieldValue.increment;
|
|
55
|
+
const hostId = String((_input_hostId = input.hostId) != null ? _input_hostId : '').trim();
|
|
56
|
+
batch.set(userAiUsageMonthRef(orgRef, uid, input.month), _extends({
|
|
57
|
+
uid,
|
|
58
|
+
month: input.month,
|
|
59
|
+
credits: increment(credits),
|
|
60
|
+
estCostUsd: increment(estCostUsd),
|
|
61
|
+
requests: increment(1)
|
|
62
|
+
}, input.usage ? {
|
|
63
|
+
[AI_USAGE_TOKENS_FIELD]: aiTokenIncrements(input.usage)
|
|
64
|
+
} : {}, {
|
|
65
|
+
byKind: {
|
|
66
|
+
[input.kind]: increment(credits)
|
|
67
|
+
}
|
|
68
|
+
}, hostId ? {
|
|
69
|
+
byHost: {
|
|
70
|
+
[hostId]: increment(credits)
|
|
71
|
+
}
|
|
72
|
+
} : {}, {
|
|
73
|
+
updatedAt: FieldValue.serverTimestamp(),
|
|
74
|
+
// The retention window, as a Timestamp the TTL policy can act on.
|
|
75
|
+
expiresAt: aiUsageByUserExpiry(input.month)
|
|
76
|
+
}), {
|
|
77
|
+
merge: true
|
|
78
|
+
});
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Count a refused reservation against the person who asked — the per-person
|
|
83
|
+
* twin of `recordAssistRefusal`, and shaped the same way: fire-and-forget,
|
|
84
|
+
* off the refusal's await path, swallowing every error, because a refusal
|
|
85
|
+
* is the gate's cheap exit and a counter must not make it dearer than the
|
|
86
|
+
* thing it counts.
|
|
87
|
+
*
|
|
88
|
+
* Takes the whole reservation rather than a month so every door calls it
|
|
89
|
+
* the same way, once, right after reserving: an admitted reservation records
|
|
90
|
+
* nothing, so the call needs no branch of its own and cannot drift from the
|
|
91
|
+
* door's refusal branch. The month is the reservation's, not the clock's,
|
|
92
|
+
* because that is the month the org's own refusal was counted in.
|
|
93
|
+
*/ export function recordUserAiRefusal(firestore, orgId, uid, reservation) {
|
|
94
|
+
if (reservation.allowed) return;
|
|
95
|
+
const subject = String(uid != null ? uid : '').trim();
|
|
96
|
+
if (!subject) return;
|
|
97
|
+
try {
|
|
98
|
+
const ref = userAiUsageMonthRef(firestore.collection('orgs').doc(orgId), subject, reservation.monthKey);
|
|
99
|
+
void Promise.resolve(ref.set({
|
|
100
|
+
uid: subject,
|
|
101
|
+
month: reservation.monthKey,
|
|
102
|
+
refusals: FieldValue.increment(1),
|
|
103
|
+
updatedAt: FieldValue.serverTimestamp(),
|
|
104
|
+
expiresAt: aiUsageByUserExpiry(reservation.monthKey)
|
|
105
|
+
}, {
|
|
106
|
+
merge: true
|
|
107
|
+
})).catch(()=>undefined);
|
|
108
|
+
} catch (unused) {
|
|
109
|
+
// A double without `set`, a ref that could not be built — the refusal
|
|
110
|
+
// has already been decided and this must not change that.
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** How many references one `getAll` carries. */ const GET_ALL_CHUNK = 100;
|
|
114
|
+
/**
|
|
115
|
+
* The month for every current member of the org, dearest first.
|
|
116
|
+
*
|
|
117
|
+
* Reads the ROSTER and then each member's month document by path, rather
|
|
118
|
+
* than a collection-group query over `months`: the roster is the join the
|
|
119
|
+
* table needs anyway (a uid is not a name), it is bounded by the seats the
|
|
120
|
+
* plan sells, and a path read rides no index that has to be deployed before
|
|
121
|
+
* a workspace can open its Usage page. A person who has left the org is not
|
|
122
|
+
* listed — the roster is the set of people the reader may see — and their
|
|
123
|
+
* documents expire on the retention window.
|
|
124
|
+
*/ export async function readOrgAiUsageByUser(firestore, orgId, month) {
|
|
125
|
+
var _rollup_get;
|
|
126
|
+
const orgRef = firestore.collection('orgs').doc(orgId);
|
|
127
|
+
const [roster, rollup] = await Promise.all([
|
|
128
|
+
orgRef.collection('members').get(),
|
|
129
|
+
orgRef.collection('assistUsage').doc(month).get()
|
|
130
|
+
]);
|
|
131
|
+
const orgEstCostUsd = Number((_rollup_get = rollup.get('estCostUsd')) != null ? _rollup_get : 0);
|
|
132
|
+
const denominator = Number.isFinite(orgEstCostUsd) && orgEstCostUsd > 0 ? orgEstCostUsd : 0;
|
|
133
|
+
const members = roster.docs.map((doc)=>({
|
|
134
|
+
uid: doc.id,
|
|
135
|
+
email: typeof doc.get('email') === 'string' ? String(doc.get('email')) : null,
|
|
136
|
+
displayName: typeof doc.get('displayName') === 'string' && String(doc.get('displayName')).trim() ? String(doc.get('displayName')).trim() : null,
|
|
137
|
+
role: typeof doc.get('role') === 'string' ? String(doc.get('role')) : null
|
|
138
|
+
}));
|
|
139
|
+
const rows = [];
|
|
140
|
+
for(let start = 0; start < members.length; start += GET_ALL_CHUNK){
|
|
141
|
+
const chunk = members.slice(start, start + GET_ALL_CHUNK);
|
|
142
|
+
const snapshots = await firestore.getAll(...chunk.map((member)=>userAiUsageMonthRef(orgRef, member.uid, month)));
|
|
143
|
+
snapshots.forEach((snapshot, index)=>{
|
|
144
|
+
var _ref, _member_displayName;
|
|
145
|
+
if (!snapshot.exists) return;
|
|
146
|
+
const member = chunk[index];
|
|
147
|
+
const usage = aiUsageByUserMonthFrom(snapshot.data(), member.uid, month);
|
|
148
|
+
rows.push(_extends({}, usage, {
|
|
149
|
+
name: (_ref = (_member_displayName = member.displayName) != null ? _member_displayName : member.email) != null ? _ref : member.uid,
|
|
150
|
+
email: member.email,
|
|
151
|
+
role: member.role,
|
|
152
|
+
share: aiUsageShare(usage.estCostUsd, denominator)
|
|
153
|
+
}));
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
rows.sort((a, b)=>b.credits - a.credits || b.requests - a.requests || a.name.localeCompare(b.name));
|
|
157
|
+
return {
|
|
158
|
+
month,
|
|
159
|
+
orgEstCostUsd: denominator,
|
|
160
|
+
orgCredits: assistCreditsFromUsd(denominator),
|
|
161
|
+
rows
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* One person's months in one org, newest first — the member card and the
|
|
166
|
+
* staff page. Ordered on the document id, which IS the month key and so
|
|
167
|
+
* needs no field every writer must remember.
|
|
168
|
+
*/ export async function readUserAiUsageMonths(firestore, orgId, uid, limit = AI_USAGE_BY_USER_RETENTION_MONTHS) {
|
|
169
|
+
const snapshot = await firestore.collection('orgs').doc(orgId).collection(AI_USAGE_BY_USER_COLLECTION).doc(uid).collection(AI_USAGE_BY_USER_MONTHS_COLLECTION).orderBy(FieldPath.documentId(), 'desc').limit(limit).get();
|
|
170
|
+
return snapshot.docs.map((doc)=>aiUsageByUserMonthFrom(doc.data(), uid, doc.id));
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Remove a person's usage documents on account erasure.
|
|
174
|
+
*
|
|
175
|
+
* Two passes, because the documents live under the ORG and are keyed by the
|
|
176
|
+
* uid: `recursiveDelete(users/{uid})` cannot see them, and neither can a
|
|
177
|
+
* walk of current memberships find the months left behind in an org the
|
|
178
|
+
* person was removed from. So every org the erasure knows of is deleted by
|
|
179
|
+
* path first — no index, cannot fail for want of one — and then a
|
|
180
|
+
* collection-group query on `uid` catches the rest. The second pass is
|
|
181
|
+
* reported as `null` rather than thrown when it cannot run: the erasure has
|
|
182
|
+
* a legal clock, and the by-path pass has already removed everything a
|
|
183
|
+
* current membership could reach.
|
|
184
|
+
*/ export async function eraseUserAiUsage(firestore, uid, orgIds) {
|
|
185
|
+
let orgs = 0;
|
|
186
|
+
for (const orgId of orgIds){
|
|
187
|
+
await firestore.recursiveDelete(firestore.collection('orgs').doc(orgId).collection(AI_USAGE_BY_USER_COLLECTION).doc(uid));
|
|
188
|
+
orgs += 1;
|
|
189
|
+
}
|
|
190
|
+
let sweptMonths = null;
|
|
191
|
+
try {
|
|
192
|
+
const stray = await firestore.collectionGroup(AI_USAGE_BY_USER_MONTHS_COLLECTION).where('uid', '==', uid).get();
|
|
193
|
+
sweptMonths = 0;
|
|
194
|
+
for(let start = 0; start < stray.docs.length; start += GET_ALL_CHUNK){
|
|
195
|
+
const batch = firestore.batch();
|
|
196
|
+
for (const doc of stray.docs.slice(start, start + GET_ALL_CHUNK)){
|
|
197
|
+
batch.delete(doc.ref);
|
|
198
|
+
sweptMonths += 1;
|
|
199
|
+
}
|
|
200
|
+
await batch.commit();
|
|
201
|
+
}
|
|
202
|
+
} catch (error) {
|
|
203
|
+
console.error(`eraseUserAiUsage: collection-group sweep failed for ${uid}`, error);
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
orgs,
|
|
207
|
+
sweptMonths
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
//# sourceMappingURL=ai-usage-by-user.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/usage/ai-usage-by-user.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// Straight from the SDK, not the admin lib, for the reason `assist-usage.ts`\n// gives at its head: the statics need no app, and the admin lib would drag the\n// default-app initialization into every unit test that touches a counter.\nimport { FieldPath, FieldValue } from 'firebase-admin/firestore'\nimport {\n AI_USAGE_BY_USER_COLLECTION,\n AI_USAGE_BY_USER_MONTHS_COLLECTION,\n AI_USAGE_BY_USER_RETENTION_MONTHS,\n aiUsageByUserExpiry,\n aiUsageByUserMonthFrom,\n aiUsageShare,\n type AiUsageByUserMonth,\n type AiUsageKind,\n} from '../model/ai-usage-by-user'\nimport { AI_USAGE_TOKENS_FIELD } from '../model/ai-tokens'\nimport type { AiUsage } from '../providers/contract'\nimport { assistCreditsFromUsd } from '@aglyn/aglyn/app-utils/assist-credits'\n\n/**\n * PER-USER AI USAGE (AGL-2928): the writer and the readers.\n *\n * One document per person per month, under the org they spent in:\n *\n * orgs/{orgId}/aiUsageByUser/{uid}/months/{YYYY-MM}\n * { uid, month, credits, estCostUsd, requests, refusals,\n * tokens: { input, cached, cacheWrite, output },\n * byKind: { kind: credits }, byHost: { hostId: credits },\n * updatedAt, expiresAt }\n *\n * ## Written in the org rollup's own batch\n *\n * `recordUserAiUsage` takes the BATCH the org rollup is being written into\n * and adds this document to it, so the two cannot disagree: a batch commits\n * whole or not at all, and there is no path on which the workspace's month\n * moves and the person's does not. Both assist entrypoints hand it the batch\n * from inside `recordAssistCost` / `recordAssistExchange`, and the job\n * runner meters through the first of those, so a generation step lands here\n * with the job's kind and creator.\n *\n * ## No prose, no PII past the uid\n *\n * The exchange's verbatim half already expires at 180 days for the reason\n * `assist-usage.ts` gives; this rollup is integers keyed by an id, and it\n * is kept longer (`AI_USAGE_BY_USER_RETENTION_MONTHS`) because a workspace\n * admin's question is month-over-month. It is still a document ABOUT a\n * person, so it is readable only by the person and by members holding\n * `billing.view` or `org.auditLog` (the rules, and every route that serves\n * it), and an account erasure sweeps it (`eraseUserAiUsage`).\n */\n\n/** What one metered request attributes to a person. */\nexport interface RecordUserAiUsageInput {\n /** The person who asked. No uid, no attribution — the write is skipped. */\n uid: string | null | undefined\n /** The billing month the org rollup is being written into. */\n month: string\n /** The request's measured provider spend, as the org rollup counts it. */\n estCostUsd: number\n hostId: string | null | undefined\n kind: AiUsageKind\n /** The request's four token counts (AGL-2937), added to the month's `tokens`. */\n usage?: AiUsage\n}\n\n/**\n * A request's four token counts as increments, under the names every rollup\n * keeps them by (`model/ai-tokens.ts`).\n */\nexport function aiTokenIncrements(usage: AiUsage): Record<string, FirebaseFirestore.FieldValue> {\n const increment = FieldValue.increment\n return {\n input: increment(usage.inputTokens),\n cached: increment(usage.cacheReadTokens),\n cacheWrite: increment(usage.cacheWriteTokens),\n output: increment(usage.outputTokens),\n }\n}\n\nexport function userAiUsageMonthRef(\n orgRef: FirebaseFirestore.DocumentReference,\n uid: string,\n month: string,\n): FirebaseFirestore.DocumentReference {\n return orgRef\n .collection(AI_USAGE_BY_USER_COLLECTION)\n .doc(uid)\n .collection(AI_USAGE_BY_USER_MONTHS_COLLECTION)\n .doc(month)\n}\n\n/**\n * Fold one request into a person's month, on the caller's batch.\n *\n * Returns whether anything was queued: a request with no uid (a meter that\n * could not say who asked) attributes to nobody rather than to a placeholder\n * id that would rank on every table. `set(…, { merge: true })`, never\n * `update()`: the document does not exist before a person's first request\n * of the month, and a merge into a map field adds the key rather than\n * replacing the map.\n */\nexport function recordUserAiUsage(\n batch: FirebaseFirestore.WriteBatch,\n orgRef: FirebaseFirestore.DocumentReference,\n input: RecordUserAiUsageInput,\n): boolean {\n const uid = String(input.uid ?? '').trim()\n if (!uid) return false\n const estCostUsd =\n Number.isFinite(input.estCostUsd) && input.estCostUsd > 0\n ? input.estCostUsd\n : 0\n const credits = assistCreditsFromUsd(estCostUsd)\n const increment = FieldValue.increment\n const hostId = String(input.hostId ?? '').trim()\n batch.set(\n userAiUsageMonthRef(orgRef, uid, input.month),\n {\n uid,\n month: input.month,\n credits: increment(credits),\n estCostUsd: increment(estCostUsd),\n requests: increment(1),\n ...(input.usage ? { [AI_USAGE_TOKENS_FIELD]: aiTokenIncrements(input.usage) } : {}),\n byKind: { [input.kind]: increment(credits) },\n ...(hostId ? { byHost: { [hostId]: increment(credits) } } : {}),\n updatedAt: FieldValue.serverTimestamp(),\n // The retention window, as a Timestamp the TTL policy can act on.\n expiresAt: aiUsageByUserExpiry(input.month),\n },\n { merge: true },\n )\n return true\n}\n\n/**\n * The slice of a reservation a refusal is counted from: whether the gate\n * admitted the request, and the billing month it decided in. Structural, so\n * every door can hand over the reservation it already holds.\n */\nexport interface UserAiRefusalSource {\n allowed: boolean\n monthKey: string\n}\n\n/**\n * Count a refused reservation against the person who asked — the per-person\n * twin of `recordAssistRefusal`, and shaped the same way: fire-and-forget,\n * off the refusal's await path, swallowing every error, because a refusal\n * is the gate's cheap exit and a counter must not make it dearer than the\n * thing it counts.\n *\n * Takes the whole reservation rather than a month so every door calls it\n * the same way, once, right after reserving: an admitted reservation records\n * nothing, so the call needs no branch of its own and cannot drift from the\n * door's refusal branch. The month is the reservation's, not the clock's,\n * because that is the month the org's own refusal was counted in.\n */\nexport function recordUserAiRefusal(\n firestore: FirebaseFirestore.Firestore,\n orgId: string,\n uid: string | null | undefined,\n reservation: UserAiRefusalSource,\n): void {\n if (reservation.allowed) return\n const subject = String(uid ?? '').trim()\n if (!subject) return\n try {\n const ref = userAiUsageMonthRef(\n firestore.collection('orgs').doc(orgId),\n subject,\n reservation.monthKey,\n )\n void Promise.resolve(\n ref.set(\n {\n uid: subject,\n month: reservation.monthKey,\n refusals: FieldValue.increment(1),\n updatedAt: FieldValue.serverTimestamp(),\n expiresAt: aiUsageByUserExpiry(reservation.monthKey),\n },\n { merge: true },\n ),\n ).catch(() => undefined)\n } catch {\n // A double without `set`, a ref that could not be built — the refusal\n // has already been decided and this must not change that.\n }\n}\n\n/** One roster row's month, with the person the roster names. */\nexport interface OrgAiUsageByUserRow extends AiUsageByUserMonth {\n /** The display name, else the email, else the uid — never blank. */\n name: string\n email: string | null\n role: string | null\n /** This person's share of the org's measured spend, in `[0, 1]`. */\n share: number\n}\n\nexport interface OrgAiUsageByUserMonth {\n month: string\n /** The org rollup's spend for the month — the denominator of every share. */\n orgEstCostUsd: number\n orgCredits: number\n /** Every current member with a document for the month, dearest first. */\n rows: OrgAiUsageByUserRow[]\n}\n\n/** How many references one `getAll` carries. */\nconst GET_ALL_CHUNK = 100\n\n/**\n * The month for every current member of the org, dearest first.\n *\n * Reads the ROSTER and then each member's month document by path, rather\n * than a collection-group query over `months`: the roster is the join the\n * table needs anyway (a uid is not a name), it is bounded by the seats the\n * plan sells, and a path read rides no index that has to be deployed before\n * a workspace can open its Usage page. A person who has left the org is not\n * listed — the roster is the set of people the reader may see — and their\n * documents expire on the retention window.\n */\nexport async function readOrgAiUsageByUser(\n firestore: FirebaseFirestore.Firestore,\n orgId: string,\n month: string,\n): Promise<OrgAiUsageByUserMonth> {\n const orgRef = firestore.collection('orgs').doc(orgId)\n const [roster, rollup] = await Promise.all([\n orgRef.collection('members').get(),\n orgRef.collection('assistUsage').doc(month).get(),\n ])\n const orgEstCostUsd = Number(rollup.get('estCostUsd') ?? 0)\n const denominator =\n Number.isFinite(orgEstCostUsd) && orgEstCostUsd > 0 ? orgEstCostUsd : 0\n\n const members = roster.docs.map((doc) => ({\n uid: doc.id,\n email: typeof doc.get('email') === 'string' ? String(doc.get('email')) : null,\n displayName:\n typeof doc.get('displayName') === 'string' && String(doc.get('displayName')).trim()\n ? String(doc.get('displayName')).trim()\n : null,\n role: typeof doc.get('role') === 'string' ? String(doc.get('role')) : null,\n }))\n\n const rows: OrgAiUsageByUserRow[] = []\n for (let start = 0; start < members.length; start += GET_ALL_CHUNK) {\n const chunk = members.slice(start, start + GET_ALL_CHUNK)\n const snapshots = await firestore.getAll(\n ...chunk.map((member) => userAiUsageMonthRef(orgRef, member.uid, month)),\n )\n snapshots.forEach((snapshot, index) => {\n if (!snapshot.exists) return\n const member = chunk[index]\n const usage = aiUsageByUserMonthFrom(snapshot.data(), member.uid, month)\n rows.push({\n ...usage,\n name: member.displayName ?? member.email ?? member.uid,\n email: member.email,\n role: member.role,\n share: aiUsageShare(usage.estCostUsd, denominator),\n })\n })\n }\n rows.sort(\n (a, b) =>\n b.credits - a.credits ||\n b.requests - a.requests ||\n a.name.localeCompare(b.name),\n )\n return {\n month,\n orgEstCostUsd: denominator,\n orgCredits: assistCreditsFromUsd(denominator),\n rows,\n }\n}\n\n/**\n * One person's months in one org, newest first — the member card and the\n * staff page. Ordered on the document id, which IS the month key and so\n * needs no field every writer must remember.\n */\nexport async function readUserAiUsageMonths(\n firestore: FirebaseFirestore.Firestore,\n orgId: string,\n uid: string,\n limit: number = AI_USAGE_BY_USER_RETENTION_MONTHS,\n): Promise<AiUsageByUserMonth[]> {\n const snapshot = await firestore\n .collection('orgs')\n .doc(orgId)\n .collection(AI_USAGE_BY_USER_COLLECTION)\n .doc(uid)\n .collection(AI_USAGE_BY_USER_MONTHS_COLLECTION)\n .orderBy(FieldPath.documentId(), 'desc')\n .limit(limit)\n .get()\n return snapshot.docs.map((doc) => aiUsageByUserMonthFrom(doc.data(), uid, doc.id))\n}\n\nexport interface EraseUserAiUsageResult {\n /** Orgs whose `aiUsageByUser/{uid}` subtree was deleted by path. */\n orgs: number\n /**\n * Month documents found by the collection-group sweep and deleted — the\n * ones in orgs the person had already left. `null` when the sweep could\n * not run (its index is not deployed), which is not zero.\n */\n sweptMonths: number | null\n}\n\n/**\n * Remove a person's usage documents on account erasure.\n *\n * Two passes, because the documents live under the ORG and are keyed by the\n * uid: `recursiveDelete(users/{uid})` cannot see them, and neither can a\n * walk of current memberships find the months left behind in an org the\n * person was removed from. So every org the erasure knows of is deleted by\n * path first — no index, cannot fail for want of one — and then a\n * collection-group query on `uid` catches the rest. The second pass is\n * reported as `null` rather than thrown when it cannot run: the erasure has\n * a legal clock, and the by-path pass has already removed everything a\n * current membership could reach.\n */\nexport async function eraseUserAiUsage(\n firestore: FirebaseFirestore.Firestore,\n uid: string,\n orgIds: readonly string[],\n): Promise<EraseUserAiUsageResult> {\n let orgs = 0\n for (const orgId of orgIds) {\n await firestore.recursiveDelete(\n firestore\n .collection('orgs')\n .doc(orgId)\n .collection(AI_USAGE_BY_USER_COLLECTION)\n .doc(uid),\n )\n orgs += 1\n }\n let sweptMonths: number | null = null\n try {\n const stray = await firestore\n .collectionGroup(AI_USAGE_BY_USER_MONTHS_COLLECTION)\n .where('uid', '==', uid)\n .get()\n sweptMonths = 0\n for (let start = 0; start < stray.docs.length; start += GET_ALL_CHUNK) {\n const batch = firestore.batch()\n for (const doc of stray.docs.slice(start, start + GET_ALL_CHUNK)) {\n batch.delete(doc.ref)\n sweptMonths += 1\n }\n await batch.commit()\n }\n } catch (error) {\n console.error(`eraseUserAiUsage: collection-group sweep failed for ${uid}`, error)\n }\n return { orgs, sweptMonths }\n}\n"],"names":["FieldPath","FieldValue","AI_USAGE_BY_USER_COLLECTION","AI_USAGE_BY_USER_MONTHS_COLLECTION","AI_USAGE_BY_USER_RETENTION_MONTHS","aiUsageByUserExpiry","aiUsageByUserMonthFrom","aiUsageShare","AI_USAGE_TOKENS_FIELD","assistCreditsFromUsd","aiTokenIncrements","usage","increment","input","inputTokens","cached","cacheReadTokens","cacheWrite","cacheWriteTokens","output","outputTokens","userAiUsageMonthRef","orgRef","uid","month","collection","doc","recordUserAiUsage","batch","String","trim","estCostUsd","Number","isFinite","credits","hostId","set","requests","byKind","kind","byHost","updatedAt","serverTimestamp","expiresAt","merge","recordUserAiRefusal","firestore","orgId","reservation","allowed","subject","ref","monthKey","Promise","resolve","refusals","catch","undefined","GET_ALL_CHUNK","readOrgAiUsageByUser","rollup","roster","all","get","orgEstCostUsd","denominator","members","docs","map","id","email","displayName","role","rows","start","length","chunk","slice","snapshots","getAll","member","forEach","snapshot","index","exists","data","push","name","share","sort","a","b","localeCompare","orgCredits","readUserAiUsageMonths","limit","orderBy","documentId","eraseUserAiUsage","orgIds","orgs","recursiveDelete","sweptMonths","stray","collectionGroup","where","delete","commit","error","console"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
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 { PluginUserErasureReport, PluginUserErasureRequest } from '@aglyn/aglyn/plugin-manager/plugin-user-erasure';
|
|
18
|
+
/**
|
|
19
|
+
* The AI plugin's share of an account erasure (AGL-2939): the person's
|
|
20
|
+
* monthly usage documents, deleted from every org they belonged to and
|
|
21
|
+
* swept from the ones they had left, and the AI allotments set on them
|
|
22
|
+
* (AGL-2942) in the orgs the erasure names. The report is the meter's own —
|
|
23
|
+
* orgs deleted by path, months found by the cross-org sweep (`null` when
|
|
24
|
+
* that sweep could not run), and allotments removed.
|
|
25
|
+
*
|
|
26
|
+
* Its own module, imported by the server declarations when an erasure
|
|
27
|
+
* runs, so the boot registers the eraser without loading the meter.
|
|
28
|
+
*/
|
|
29
|
+
export declare function eraseAiUsageForUser({ uid, orgIds, }: PluginUserErasureRequest): Promise<PluginUserErasureReport>;
|
|
@@ -0,0 +1,40 @@
|
|
|
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 { eraseAiAllotmentsForUser } from "./ai-allotments.js";
|
|
17
|
+
import { eraseUserAiUsage } from "./ai-usage-by-user.js";
|
|
18
|
+
import { firebaseAdmin } from "@aglyn/tenant-data-admin/server/firebase-admin";
|
|
19
|
+
/**
|
|
20
|
+
* The AI plugin's share of an account erasure (AGL-2939): the person's
|
|
21
|
+
* monthly usage documents, deleted from every org they belonged to and
|
|
22
|
+
* swept from the ones they had left, and the AI allotments set on them
|
|
23
|
+
* (AGL-2942) in the orgs the erasure names. The report is the meter's own —
|
|
24
|
+
* orgs deleted by path, months found by the cross-org sweep (`null` when
|
|
25
|
+
* that sweep could not run), and allotments removed.
|
|
26
|
+
*
|
|
27
|
+
* Its own module, imported by the server declarations when an erasure
|
|
28
|
+
* runs, so the boot registers the eraser without loading the meter.
|
|
29
|
+
*/ export async function eraseAiUsageForUser({ uid, orgIds }) {
|
|
30
|
+
const firestore = firebaseAdmin.app().firestore();
|
|
31
|
+
const { orgs, sweptMonths } = await eraseUserAiUsage(firestore, uid, orgIds);
|
|
32
|
+
const allotments = await eraseAiAllotmentsForUser(firestore, uid, orgIds);
|
|
33
|
+
return {
|
|
34
|
+
orgs,
|
|
35
|
+
sweptMonths,
|
|
36
|
+
allotments
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=ai-usage-eraser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/usage/ai-usage-eraser.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 type {\n PluginUserErasureReport,\n PluginUserErasureRequest,\n} from '@aglyn/aglyn/plugin-manager/plugin-user-erasure'\nimport { eraseAiAllotmentsForUser } from './ai-allotments'\nimport { eraseUserAiUsage } from './ai-usage-by-user'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin/server/firebase-admin'\n\n/**\n * The AI plugin's share of an account erasure (AGL-2939): the person's\n * monthly usage documents, deleted from every org they belonged to and\n * swept from the ones they had left, and the AI allotments set on them\n * (AGL-2942) in the orgs the erasure names. The report is the meter's own —\n * orgs deleted by path, months found by the cross-org sweep (`null` when\n * that sweep could not run), and allotments removed.\n *\n * Its own module, imported by the server declarations when an erasure\n * runs, so the boot registers the eraser without loading the meter.\n */\nexport async function eraseAiUsageForUser({\n uid,\n orgIds,\n}: PluginUserErasureRequest): Promise<PluginUserErasureReport> {\n const firestore = firebaseAdmin.app().firestore()\n const { orgs, sweptMonths } = await eraseUserAiUsage(firestore, uid, orgIds)\n const allotments = await eraseAiAllotmentsForUser(firestore, uid, orgIds)\n return { orgs, sweptMonths, allotments }\n}\n"],"names":["eraseAiAllotmentsForUser","eraseUserAiUsage","firebaseAdmin","eraseAiUsageForUser","uid","orgIds","firestore","app","orgs","sweptMonths","allotments"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAMD,SAASA,wBAAwB,QAAQ,qBAAiB;AAC1D,SAASC,gBAAgB,QAAQ,wBAAoB;AACrD,SAASC,aAAa,QAAQ,iDAAgD;AAE9E;;;;;;;;;;CAUC,GACD,OAAO,eAAeC,oBAAoB,EACxCC,GAAG,EACHC,MAAM,EACmB;IACzB,MAAMC,YAAYJ,cAAcK,GAAG,GAAGD,SAAS;IAC/C,MAAM,EAAEE,IAAI,EAAEC,WAAW,EAAE,GAAG,MAAMR,iBAAiBK,WAAWF,KAAKC;IACrE,MAAMK,aAAa,MAAMV,yBAAyBM,WAAWF,KAAKC;IAClE,OAAO;QAAEG;QAAMC;QAAaC;IAAW;AACzC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
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 AssistReservation } from './assist-usage';
|
|
18
|
+
import { type AiUsageMeterWire } from './ai-usage-wire';
|
|
19
|
+
/**
|
|
20
|
+
* The usage strip's envelope from what a door already holds (AGL-2942): the
|
|
21
|
+
* reservation it took and, once the provider answered, what the exchange
|
|
22
|
+
* cost. No read — the reservation measured the pool and the caller's month
|
|
23
|
+
* inside the transaction it already runs.
|
|
24
|
+
*
|
|
25
|
+
* Every figure is credits. The pool comes through `publicAssistQuota`, the
|
|
26
|
+
* one projection allowed to turn our provider bill into a customer figure;
|
|
27
|
+
* the caller's month comes off the allotment gate, which the meter wrote in
|
|
28
|
+
* credits in the first place.
|
|
29
|
+
*
|
|
30
|
+
* `last` is added to both months, because the reservation measured them
|
|
31
|
+
* BEFORE this exchange and the strip is read after it.
|
|
32
|
+
*/
|
|
33
|
+
export declare function aiUsageMeter(reservation: Pick<AssistReservation, 'monthKey' | 'allowed'> & Partial<AssistReservation>, extra?: {
|
|
34
|
+
lastCredits?: number | null;
|
|
35
|
+
model?: {
|
|
36
|
+
id: string;
|
|
37
|
+
auto: boolean;
|
|
38
|
+
} | null;
|
|
39
|
+
}): AiUsageMeterWire;
|
|
@@ -0,0 +1,85 @@
|
|
|
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 { aiCatalogEntry } from "../providers/catalog.js";
|
|
17
|
+
import { publicAssistQuota } from "./assist-usage.js";
|
|
18
|
+
import { aiUsageMeterState } from "./ai-usage-wire.js";
|
|
19
|
+
/**
|
|
20
|
+
* The usage strip's envelope from what a door already holds (AGL-2942): the
|
|
21
|
+
* reservation it took and, once the provider answered, what the exchange
|
|
22
|
+
* cost. No read — the reservation measured the pool and the caller's month
|
|
23
|
+
* inside the transaction it already runs.
|
|
24
|
+
*
|
|
25
|
+
* Every figure is credits. The pool comes through `publicAssistQuota`, the
|
|
26
|
+
* one projection allowed to turn our provider bill into a customer figure;
|
|
27
|
+
* the caller's month comes off the allotment gate, which the meter wrote in
|
|
28
|
+
* credits in the first place.
|
|
29
|
+
*
|
|
30
|
+
* `last` is added to both months, because the reservation measured them
|
|
31
|
+
* BEFORE this exchange and the strip is read after it.
|
|
32
|
+
*/ export function aiUsageMeter(reservation, extra = {}) {
|
|
33
|
+
var _reservation_allotment, _ref, _ref1;
|
|
34
|
+
const last = typeof extra.lastCredits === 'number' && Number.isFinite(extra.lastCredits) ? Math.max(0, Math.ceil(extra.lastCredits)) : null;
|
|
35
|
+
const spent = last != null ? last : 0;
|
|
36
|
+
let pool = {
|
|
37
|
+
used: spent,
|
|
38
|
+
limit: null
|
|
39
|
+
};
|
|
40
|
+
try {
|
|
41
|
+
var _publicAssistQuota;
|
|
42
|
+
const credits = (_publicAssistQuota = publicAssistQuota(reservation)) == null ? void 0 : _publicAssistQuota.credits;
|
|
43
|
+
if (credits) pool = {
|
|
44
|
+
used: credits.used + spent,
|
|
45
|
+
limit: credits.limit
|
|
46
|
+
};
|
|
47
|
+
} catch (unused) {
|
|
48
|
+
// A reservation without its dollar figures (a double, a refusal taken
|
|
49
|
+
// before the month was read) reports the exchange alone.
|
|
50
|
+
}
|
|
51
|
+
const gate = (_reservation_allotment = reservation.allotment) != null ? _reservation_allotment : null;
|
|
52
|
+
const binding = (_ref = gate == null ? void 0 : gate.binding) != null ? _ref : null;
|
|
53
|
+
const mine = binding ? {
|
|
54
|
+
used: binding.used + spent,
|
|
55
|
+
limit: binding.credits,
|
|
56
|
+
mode: binding.mode,
|
|
57
|
+
scope: binding.scope
|
|
58
|
+
} : {
|
|
59
|
+
used: ((_ref1 = gate == null ? void 0 : gate.personalCredits) != null ? _ref1 : 0) + spent,
|
|
60
|
+
limit: null,
|
|
61
|
+
mode: null,
|
|
62
|
+
scope: null
|
|
63
|
+
};
|
|
64
|
+
const refused = !reservation.allowed;
|
|
65
|
+
const entry = extra.model ? aiCatalogEntry(extra.model.id) : undefined;
|
|
66
|
+
return {
|
|
67
|
+
month: reservation.monthKey,
|
|
68
|
+
pool,
|
|
69
|
+
mine,
|
|
70
|
+
last,
|
|
71
|
+
refused,
|
|
72
|
+
state: aiUsageMeterState({
|
|
73
|
+
pool,
|
|
74
|
+
mine,
|
|
75
|
+
refused
|
|
76
|
+
}),
|
|
77
|
+
model: extra.model && entry ? {
|
|
78
|
+
id: entry.id,
|
|
79
|
+
label: entry.label,
|
|
80
|
+
auto: extra.model.auto
|
|
81
|
+
} : null
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//# sourceMappingURL=ai-usage-meter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/usage/ai-usage-meter.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 { aiCatalogEntry } from '../providers/catalog'\nimport { publicAssistQuota, type AssistReservation } from './assist-usage'\nimport { aiUsageMeterState, type AiUsageMeterWire } from './ai-usage-wire'\n\n/**\n * The usage strip's envelope from what a door already holds (AGL-2942): the\n * reservation it took and, once the provider answered, what the exchange\n * cost. No read — the reservation measured the pool and the caller's month\n * inside the transaction it already runs.\n *\n * Every figure is credits. The pool comes through `publicAssistQuota`, the\n * one projection allowed to turn our provider bill into a customer figure;\n * the caller's month comes off the allotment gate, which the meter wrote in\n * credits in the first place.\n *\n * `last` is added to both months, because the reservation measured them\n * BEFORE this exchange and the strip is read after it.\n */\nexport function aiUsageMeter(\n reservation: Pick<AssistReservation, 'monthKey' | 'allowed'> &\n Partial<AssistReservation>,\n extra: {\n lastCredits?: number | null\n model?: { id: string; auto: boolean } | null\n } = {},\n): AiUsageMeterWire {\n const last =\n typeof extra.lastCredits === 'number' && Number.isFinite(extra.lastCredits)\n ? Math.max(0, Math.ceil(extra.lastCredits))\n : null\n const spent = last ?? 0\n let pool: AiUsageMeterWire['pool'] = { used: spent, limit: null }\n try {\n const credits = publicAssistQuota(reservation as AssistReservation)?.credits\n if (credits) pool = { used: credits.used + spent, limit: credits.limit }\n } catch {\n // A reservation without its dollar figures (a double, a refusal taken\n // before the month was read) reports the exchange alone.\n }\n const gate = reservation.allotment ?? null\n const binding = gate?.binding ?? null\n const mine: AiUsageMeterWire['mine'] = binding\n ? {\n used: binding.used + spent,\n limit: binding.credits,\n mode: binding.mode,\n scope: binding.scope,\n }\n : {\n used: (gate?.personalCredits ?? 0) + spent,\n limit: null,\n mode: null,\n scope: null,\n }\n const refused = !reservation.allowed\n const entry = extra.model ? aiCatalogEntry(extra.model.id) : undefined\n return {\n month: reservation.monthKey,\n pool,\n mine,\n last,\n refused,\n state: aiUsageMeterState({ pool, mine, refused }),\n model:\n extra.model && entry\n ? { id: entry.id, label: entry.label, auto: extra.model.auto }\n : null,\n }\n}\n"],"names":["aiCatalogEntry","publicAssistQuota","aiUsageMeterState","aiUsageMeter","reservation","extra","last","lastCredits","Number","isFinite","Math","max","ceil","spent","pool","used","limit","credits","gate","allotment","binding","mine","mode","scope","personalCredits","refused","allowed","entry","model","id","undefined","month","monthKey","state","label","auto"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,cAAc,QAAQ,0BAAsB;AACrD,SAASC,iBAAiB,QAAgC,oBAAgB;AAC1E,SAASC,iBAAiB,QAA+B,qBAAiB;AAE1E;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASC,aACdC,WAC4B,EAC5BC,QAGI,CAAC,CAAC;QAeOD;IAbb,MAAME,OACJ,OAAOD,MAAME,WAAW,KAAK,YAAYC,OAAOC,QAAQ,CAACJ,MAAME,WAAW,IACtEG,KAAKC,GAAG,CAAC,GAAGD,KAAKE,IAAI,CAACP,MAAME,WAAW,KACvC;IACN,MAAMM,QAAQP,eAAAA,OAAQ;IACtB,IAAIQ,OAAiC;QAAEC,MAAMF;QAAOG,OAAO;IAAK;IAChE,IAAI;YACcf;QAAhB,MAAMgB,WAAUhB,qBAAAA,kBAAkBG,iCAAlBH,mBAAqDgB,OAAO;QAC5E,IAAIA,SAASH,OAAO;YAAEC,MAAME,QAAQF,IAAI,GAAGF;YAAOG,OAAOC,QAAQD,KAAK;QAAC;IACzE,EAAE,eAAM;IACN,sEAAsE;IACtE,yDAAyD;IAC3D;IACA,MAAME,QAAOd,yBAAAA,YAAYe,SAAS,YAArBf,yBAAyB;IACtC,MAAMgB,kBAAUF,wBAAAA,KAAME,OAAO,mBAAI;IACjC,MAAMC,OAAiCD,UACnC;QACEL,MAAMK,QAAQL,IAAI,GAAGF;QACrBG,OAAOI,QAAQH,OAAO;QACtBK,MAAMF,QAAQE,IAAI;QAClBC,OAAOH,QAAQG,KAAK;IACtB,IACA;QACER,MAAM,UAACG,wBAAAA,KAAMM,eAAe,oBAAI,KAAKX;QACrCG,OAAO;QACPM,MAAM;QACNC,OAAO;IACT;IACJ,MAAME,UAAU,CAACrB,YAAYsB,OAAO;IACpC,MAAMC,QAAQtB,MAAMuB,KAAK,GAAG5B,eAAeK,MAAMuB,KAAK,CAACC,EAAE,IAAIC;IAC7D,OAAO;QACLC,OAAO3B,YAAY4B,QAAQ;QAC3BlB;QACAO;QACAf;QACAmB;QACAQ,OAAO/B,kBAAkB;YAAEY;YAAMO;YAAMI;QAAQ;QAC/CG,OACEvB,MAAMuB,KAAK,IAAID,QACX;YAAEE,IAAIF,MAAME,EAAE;YAAEK,OAAOP,MAAMO,KAAK;YAAEC,MAAM9B,MAAMuB,KAAK,CAACO,IAAI;QAAC,IAC3D;IACR;AACF"}
|