@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 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/server/assist-view-context.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 { resolveEffectivePlan } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport {\n ASSIST_EDIT_ACTION_ID,\n ASSIST_EDIT_DOCUMENT_KINDS,\n ASSIST_EDIT_TOOL_NAME,\n type AssistEditDocumentKind,\n} from '../model/assist-edit'\n\n/**\n * Aglyn Assist level 2 — the GUIDE capability (AGL-1988, under AGL-1860).\n *\n * Level 1 answers from the docs. Level 2 answers about **the thing in front\n * of the user**: the console screen they are standing on. This module is the\n * whole of that knowledge, and three decisions shape it.\n *\n * ## 1. A curated descriptor, not a state dump\n *\n * The tempting design is to serialise the page — props, records, the loaded\n * list — into the prompt. That buys worse answers at higher cost: the model\n * gets rows when what it needs is *what this screen is for*, and every extra\n * token is billed per turn against a hard margin constraint.\n *\n * So the view block is assembled from a STATIC, in-repo table keyed by route\n * pattern, plus a fixed handful of scalars about the current org. Nothing is\n * read out of the customer's data to build it. That is also why the privacy\n * guard is cheap to state and cheap to prove: there is no path from a\n * Firestore document to this prompt except the two fields `safeOrgFacts`\n * names, and no path from client input except three sanitised strings.\n *\n * ## 2. One answer for both ends of the ICP range\n *\n * the requirement is a single feature that is \"easy for someone who\n * doesn't know code and even easier for someone who does\". Two modes would\n * be the obvious build and the wrong one — it makes the beginner choose a\n * label for themselves before they have a question, and it makes the\n * developer opt in to being taken seriously.\n *\n * Progressive disclosure instead: every view carries a `plain` layer (what\n * you can do here, in words a first-business owner reads) and a `technical`\n * layer (the route template, the ids in the path, the API or field names\n * behind it). The model leads with plain and appends the technical layer\n * under a fixed `Under the hood:` marker, which the panel renders collapsed.\n * Same answer, two depths, one message.\n *\n * ## 3. Actions are PROPOSALS, and a proposal cannot write\n *\n * \"Automate current view\" is level 2's edge and needs a hard boundary — the\n * AGL-1860 ladder puts acting in the besigner at level 3, after launch. The\n * boundary here is structural rather than behavioural, because a rule the\n * model is asked to follow is not a boundary:\n *\n * - An action descriptor has no field that could carry a write. There is no\n * method, no body, no endpoint — only a `route` template and the NAMES of\n * params. `assertInertActions()` proves that over the live table.\n * - The model never supplies a destination. It may name an `id` from the\n * closed set attached to the view it is already on, and supply values for\n * params that view declared. `resolveAssistProposal` builds the href from\n * the registry; an unknown id, a foreign id, or an undeclared param is\n * dropped rather than honoured.\n * - Confirming NAVIGATES. The destination form's own submit button, with\n * its own permission checks, stays the only thing that writes.\n *\n * `prefill` is deliberately `false` across the table today: no console page\n * reads `assist_*` search params yet, and a card that claims \"I filled that\n * in for you\" over a form that came up empty is worse than one that names the\n * values to type. The plumbing is here so switching a page on is a one-line\n * change, and `PREFILL_READY_ROUTES` is the allowlist that has to grow first.\n *\n * ## 4. The one action that edits, and where it opens (AGL-2906)\n *\n * Level 3 makes a single exception, on the besigner only: the `edit` action.\n * The server still writes nothing. The model proposes typed canvas operations\n * through a strict tool, the server validates them against the canvas the\n * request described, and the panel shows the change and applies it in the\n * author's own editor when they press Apply — an unsaved change, undone by\n * the editor's own undo. The rung is closed unless the org carries\n * `aiGenerative`, `release_ai_generative` is on for it and the caller holds\n * `ai.generate`. `offeredActions` hands an edit action only to a request that\n * cleared the rung, and `assertInertActions` fails any edit action offered\n * without it, or one that carries a destination the way a navigation does.\n */\n\n/**\n * One thing the assistant may PROPOSE from a given view, by navigating.\n *\n * Note what this interface cannot express. There is no `method`, no `body`,\n * no `endpoint`, no `submit` — a descriptor is a signpost, and the type is\n * the first line of the write boundary. Adding any of those fields would\n * break `assertInertActions()`, which is the point of writing it down.\n */\nexport interface AssistNavigateAction {\n /** `navigate`, or absent. */\n kind?: 'navigate'\n /** Stable id; the ONLY thing the model gets to choose from. */\n id: string\n /** Beginner-facing label on the confirm card. */\n label: string\n /** What the user will be looking at once they confirm. */\n outcome: string\n /**\n * Server-owned destination template (`/[orgSlug]/…`). Built here, never\n * supplied by the model — so the worst a bad completion can do is send the\n * user to a different page in their own console.\n */\n route: string\n /** Param names the model may supply values for. Anything else is dropped. */\n params: readonly string[]\n /**\n * Whether the destination actually reads `assist_*` search params. False\n * everywhere today — see the module header. When false the values are\n * shown on the card as \"use these\" rather than pushed into the URL.\n */\n prefill: boolean\n}\n\n/**\n * The besigner's edit action (AGL-2906). Its proposal is typed canvas\n * operations the panel applies on confirm — never a destination and never a\n * server write — so it carries none of a navigation's `route`, `params` or\n * `prefill`, and `assertInertActions` fails one that does.\n */\nexport interface AssistEditAction {\n kind: 'edit'\n /** Stable id; the ONLY thing the model gets to choose from. */\n id: string\n /** Beginner-facing label on the confirm button. */\n label: string\n /** What changes once the author confirms. */\n outcome: string\n /** The besigner documents the action opens on. */\n documents: readonly AssistEditDocumentKind[]\n}\n\nexport type AssistViewAction = AssistNavigateAction | AssistEditAction\n\n/** What a request cleared, which decides the actions a view offers it. */\nexport interface AssistActionRung {\n /**\n * The edit rung: `aiGenerative`, `release_ai_generative` and `ai.generate`,\n * on a versioned besigner route, with the canvas described.\n */\n edit: boolean\n}\n\n/** A console screen, described for the assistant rather than for a router. */\nexport interface AssistView {\n /** Registry key; also the analytics/debug handle. */\n key: string\n /** Route matcher. First match wins, so the table is ordered specific-first. */\n match: RegExp\n /** One line: what this screen is. */\n screen: string\n /** The beginner layer — what a person can do here, in plain words. */\n plain: readonly string[]\n /** The developer layer — route template, path ids, API surface. */\n technical: readonly string[]\n /** Proposals available from this view: navigations, and on the besigner the edit action. */\n actions: readonly AssistViewAction[]\n}\n\n/**\n * Destinations verified to read `assist_*` search params. EMPTY on purpose:\n * `assertInertActions()` fails any action with `prefill: true` whose route is\n * not listed, so turning prefill on requires wiring the page first rather\n * than remembering to.\n */\nexport const PREFILL_READY_ROUTES: readonly string[] = []\n\n/** Query-param prefix for proposed values. Namespaced so a page opting in\n * can never confuse an assistant suggestion with its own state. */\nexport const ASSIST_PREFILL_PREFIX = 'assist_'\n\nconst orgAction = (\n id: string,\n label: string,\n outcome: string,\n route: string,\n params: readonly string[] = [],\n): AssistNavigateAction => ({ id, label, outcome, route, params, prefill: false })\n\nconst isNavigateAction = (action: AssistViewAction): action is AssistNavigateAction =>\n action.kind !== 'edit'\n\n/**\n * The registry. Ordered specific-first — `describeView` takes the first\n * match, so a host sub-page must precede the host dashboard, and every\n * host route must precede the bare `/[orgSlug]` home.\n *\n * Content rule: every line here has to be TRUE of the shipped console. These\n * strings are asserted to the model as fact and it will repeat them, so a\n * guessed button label becomes a confidently wrong instruction. Where the\n * exact affordance is uncertain the line names the SCREEN and its purpose\n * and lets docs retrieval supply the steps — a vaguer sentence that is right\n * beats a specific one that is invented.\n */\nexport const ASSIST_VIEWS: readonly AssistView[] = [\n {\n key: 'besigner',\n match: /^\\/[^/]+\\/hosts\\/[^/]+\\/(screens|components|templates|layouts|emails)\\/.*\\/besigner$/,\n screen: 'The Besigner — the visual editor for a screen, component, template, layout or email.',\n plain: [\n 'Edit the page visually: pick an element on the canvas and change its text, styling and layout.',\n 'Work is saved to a draft version; publishing is a separate, deliberate step.',\n 'Preview shows the draft as a visitor would see it, without publishing.',\n ],\n technical: [\n 'Route: /[orgSlug]/hosts/[host]/screens/[screenId]/versions/[versionId]/besigner (and the component, template, layout and email variants).',\n 'Editing writes to the version named in the path — versioning is the undo, so a save never overwrites what is live.',\n 'The preview route is the same path with /preview in place of /besigner.',\n ],\n actions: [\n {\n kind: 'edit',\n id: ASSIST_EDIT_ACTION_ID,\n label: 'Apply as draft',\n outcome: 'the proposed changes on the open canvas, unsaved until the document is saved',\n documents: ASSIST_EDIT_DOCUMENT_KINDS,\n },\n ],\n },\n {\n key: 'host-screens',\n match: /^\\/[^/]+\\/hosts\\/[^/]+\\/screens(\\/|$)/,\n screen: 'Screens — the list of pages on this site.',\n plain: [\n 'Every page a visitor can reach is a screen listed here.',\n 'Open a screen to see its versions, then open the Besigner to edit it.',\n 'Publishing a screen version is what puts a change on the live site.',\n ],\n technical: [\n 'Route: /[orgSlug]/hosts/[host]/screens; detail is .../screens/[screenId]/versions/[versionId]/view.',\n '[host] in the path is the site (host) document id, not the domain name.',\n ],\n actions: [\n orgAction(\n 'open.host.screens',\n 'Open Screens',\n 'the list of pages on this site',\n '/[orgSlug]/hosts/[host]/screens',\n ),\n ],\n },\n {\n key: 'host-theme',\n match: /^\\/[^/]+\\/hosts\\/[^/]+\\/theme(\\/|$)/,\n screen: 'Theme — the site-wide colors, type and spacing every screen inherits.',\n plain: [\n 'Change something here and it changes everywhere on the site at once.',\n 'This is the place to fix a color or a font you keep re-setting on individual elements.',\n ],\n technical: [\n 'Route: /[orgSlug]/hosts/[host]/theme.',\n 'Theme values resolve at render time, so screens pick them up without being republished individually.',\n ],\n actions: [],\n },\n {\n // The key is the analytics/debug handle and stays as it is; the section\n // it names is what was renamed. Both addresses match because the console\n // redirects the older one, so a client can report either.\n key: 'host-workflows',\n match: /^\\/[^/]+\\/hosts\\/[^/]+\\/(automation|workflows)(\\/|$)/,\n screen:\n 'Automation — workflows, actions and webhooks that run when something happens on the site.',\n plain: [\n 'A workflow is a trigger plus the actions that follow it, such as sending an email when a form is submitted.',\n 'Build the trigger first, then add the actions it should run.',\n 'Workflows, Actions and Webhooks are the three tabs of this section.',\n ],\n technical: [\n 'Route: /[orgSlug]/hosts/[host]/automation, with ?tab=workflows, ?tab=actions or ?tab=webhooks.',\n 'Webhook actions let a workflow call an external endpoint; see the automation docs for the payload shape.',\n ],\n actions: [],\n },\n {\n key: 'host-products',\n match: /^\\/[^/]+\\/hosts\\/[^/]+\\/products(\\/|$)/,\n screen: 'Products — the commerce catalog for this site.',\n plain: [\n 'Add and edit the things this site sells, including price and availability.',\n 'A product has to exist here before a screen can put it in front of a buyer.',\n ],\n technical: [\n 'Route: /[orgSlug]/hosts/[host]/products.',\n 'Catalog data is site-scoped: products belong to [host], not to the workspace.',\n ],\n actions: [],\n },\n {\n key: 'host-redirects',\n match: /^\\/[^/]+\\/hosts\\/[^/]+\\/redirects(\\/|$)/,\n screen: 'Redirects — rules that send one path on this site to another.',\n plain: [\n 'Use a redirect when a page has moved, so an old link still lands somewhere useful.',\n 'Each rule is a path to match and a destination to send it to.',\n ],\n technical: [\n 'Route: /[orgSlug]/hosts/[host]/redirects.',\n 'Rules are evaluated by the tenant runtime on the request path, before the screen is resolved.',\n ],\n actions: [\n orgAction(\n 'open.host.redirects',\n 'Open Redirects',\n 'the redirect rules for this site',\n '/[orgSlug]/hosts/[host]/redirects',\n ['source', 'target'],\n ),\n ],\n },\n {\n key: 'host-analytics',\n match: /^\\/[^/]+\\/hosts\\/[^/]+\\/analytics(\\/|$)/,\n screen: 'Analytics — traffic and visitor figures for this site.',\n plain: [\n 'See how many people visited, and which screens they landed on.',\n 'Figures cover the live site only — drafts and previews are not counted.',\n ],\n technical: ['Route: /[orgSlug]/hosts/[host]/analytics.'],\n actions: [],\n },\n {\n key: 'host-setup',\n match: /^\\/[^/]+\\/hosts\\/[^/]+\\/setup(\\/|$)/,\n screen: 'Site setup — the site’s own settings, including its domain.',\n plain: [\n 'Connecting a custom domain starts here.',\n 'A domain change needs DNS records at whoever the domain is registered with; the console shows which ones.',\n ],\n technical: [\n 'Route: /[orgSlug]/hosts/[host]/setup.',\n 'Owner/admin-only controls live on the sibling /admin page rather than here, so collaborators can use Setup safely.',\n ],\n actions: [\n orgAction(\n 'open.host.setup',\n 'Open site setup',\n 'this site’s settings, where a custom domain is connected',\n '/[orgSlug]/hosts/[host]/setup',\n ['domain'],\n ),\n ],\n },\n {\n key: 'host-data',\n match: /^\\/[^/]+\\/hosts\\/[^/]+\\/data(\\/|$)/,\n screen: 'Site data — the datasets this site reads and writes.',\n plain: [\n 'A dataset is a structured list — products, posts, submissions — that screens can display.',\n 'Define the fields first; screens bind to them afterwards.',\n ],\n technical: [\n 'Route: /[orgSlug]/hosts/[host]/data. The workspace-wide view is /[orgSlug]/data.',\n ],\n actions: [],\n },\n {\n key: 'host-dashboard',\n match: /^\\/[^/]+\\/hosts\\/[^/]+(\\/|$)/,\n screen: 'Site dashboard — the home page for one site in this workspace.',\n plain: [\n 'Everything about one site hangs off this page: its screens, theme, data, commerce and settings.',\n 'A workspace can hold several sites; this is one of them.',\n ],\n technical: [\n 'Route: /[orgSlug]/hosts/[host]. The [host] segment is the site document id.',\n ],\n actions: [],\n },\n {\n key: 'org-hosts',\n match: /^\\/[^/]+\\/hosts(\\/|$)/,\n screen: 'Sites — every site in this workspace.',\n plain: [\n 'Each row is a site with its own screens, theme and domain.',\n 'Agencies typically run one site per client from here.',\n ],\n technical: ['Route: /[orgSlug]/hosts.'],\n actions: [\n orgAction(\n 'open.org.hosts',\n 'Open Sites',\n 'every site in this workspace',\n '/[orgSlug]/hosts',\n ),\n ],\n },\n {\n key: 'org-billing',\n match: /^\\/[^/]+\\/billing(\\/|$)/,\n screen: 'Billing & plans — the workspace subscription, plan and invoices.',\n plain: [\n 'The current plan and what it includes, and where to change it.',\n 'Plan limits that stop you elsewhere in the console are set here.',\n ],\n technical: [\n 'Route: /[orgSlug]/billing.',\n 'Entitlements are resolved from the org plan; a limit reached elsewhere reports the entitlement it needs.',\n ],\n actions: [\n orgAction(\n 'open.billing',\n 'Open Billing & plans',\n 'the plan for this workspace and how to change it',\n '/[orgSlug]/billing',\n ),\n ],\n },\n {\n key: 'org-team',\n match: /^\\/[^/]+\\/team(\\/|$)/,\n screen: 'Team — the people in this workspace and what each may do.',\n plain: [\n 'Invite a teammate by email, and choose the role that decides what they can reach.',\n 'Removing someone here removes their access to every site in the workspace.',\n ],\n technical: [\n 'Route: /[orgSlug]/team; one member is /[orgSlug]/team/[uid].',\n 'Seat counts follow the plan, so an invite can be refused by the billing entitlement rather than by permissions.',\n ],\n actions: [\n orgAction(\n 'open.team',\n 'Open Team',\n 'the members of this workspace, where invites are sent',\n '/[orgSlug]/team',\n ['email', 'role'],\n ),\n ],\n },\n {\n key: 'org-data',\n match: /^\\/[^/]+\\/data(\\/|$)/,\n screen: 'Data — datasets shared across the whole workspace.',\n plain: [\n 'Structured lists defined once here can be used by any site in the workspace.',\n 'If a list only belongs to one site, define it on that site’s own Data page instead.',\n 'Define the fields before building the screen that displays them — screens bind to fields that already exist.',\n ],\n technical: [\n 'Route: /[orgSlug]/data. The per-site view is /[orgSlug]/hosts/[host]/data.',\n 'Workspace datasets are visible to every site in the workspace, so a field change here reaches all of them.',\n ],\n actions: [\n orgAction(\n 'open.org.data',\n 'Open Data',\n 'the datasets shared across this workspace',\n '/[orgSlug]/data',\n ),\n ],\n },\n {\n key: 'org-media',\n match: /^\\/[^/]+\\/media(\\/|$)/,\n screen: 'Media — images and files for this workspace.',\n plain: [\n 'Upload once here and use the file on any site in the workspace.',\n 'If the file belongs to one site only, upload it on that site’s own Media page instead.',\n 'Files are referenced by the screens that use them, so replacing a file changes it everywhere it appears.',\n ],\n technical: [\n 'Route: /[orgSlug]/media. The per-site library is /[orgSlug]/hosts/[host]/media.',\n 'Workspace media is shared across every site in the workspace; site media is scoped to that site.',\n ],\n actions: [\n orgAction(\n 'open.org.media',\n 'Open Media',\n 'the images and files shared across this workspace',\n '/[orgSlug]/media',\n ),\n ],\n },\n {\n key: 'org-plugins',\n match: /^\\/[^/]+\\/plugins(\\/|$)/,\n screen: 'Plugins — what is installed in this workspace.',\n plain: [\n 'A plugin adds a feature to the console, to your sites, or to both.',\n 'Open one to see its settings and the permissions it was granted.',\n ],\n technical: [\n 'Route: /[orgSlug]/plugins; one install is /[orgSlug]/plugins/[pluginRef].',\n 'Plugins run inside a sandbox; the permissions listed on the install page are the boundary.',\n ],\n actions: [],\n },\n {\n key: 'org-marketplace',\n match: /^\\/[^/]+\\/marketplace(\\/|$)/,\n screen: 'Marketplace — plugins and items available to install.',\n plain: ['Browse what can be added, and install into this workspace.'],\n technical: [\n 'Route: /[orgSlug]/marketplace; a listing is /[orgSlug]/marketplace/[listingId].',\n 'Publishing your own plugin is /[orgSlug]/marketplace/publish/plugin.',\n ],\n actions: [],\n },\n {\n key: 'org-support',\n match: /^\\/[^/]+\\/support(\\/|$)/,\n screen: 'Support — the channels for getting help.',\n plain: [\n 'Raise a ticket, or ask in the forum.',\n 'Which channels are available depends on the workspace plan.',\n ],\n technical: [\n 'Route: /[orgSlug]/support, which forwards to the channel the plan makes primary.',\n 'Channels are /[orgSlug]/support/tickets and /[orgSlug]/support/forum.',\n ],\n actions: [\n orgAction(\n 'open.support',\n 'Open Support',\n 'the support channels for this workspace',\n '/[orgSlug]/support',\n ),\n ],\n },\n {\n key: 'org-settings',\n match: /^\\/[^/]+\\/settings(\\/|$)/,\n screen: 'Workspace settings — the workspace’s own name, slug and options.',\n plain: ['Settings that apply to the whole workspace rather than to one site.'],\n technical: [\n 'Route: /[orgSlug]/settings.',\n 'The workspace slug is the [orgSlug] segment in every console URL, so changing it changes those links.',\n ],\n actions: [],\n },\n {\n key: 'org-home',\n match: /^\\/[^/]+\\/?$/,\n screen: 'Workspace home — the landing page for one workspace.',\n plain: [\n 'The starting point for a workspace: its sites, and the workspace-wide areas beside them.',\n ],\n technical: ['Route: /[orgSlug].'],\n actions: [],\n },\n]\n\n/** The view the user is standing on, or null where the route is unknown. */\nexport function describeView(route: string): AssistView | null {\n const path = sanitiseRoute(route)\n if (!path) return null\n return ASSIST_VIEWS.find((view) => view.match.test(path)) ?? null\n}\n\n/**\n * The actions a view offers a request: every navigation, and the edit action\n * only to a request that cleared the edit rung.\n */\nexport function offeredActions(\n view: AssistView | null,\n rung: AssistActionRung,\n): readonly AssistViewAction[] {\n if (!view) return []\n return view.actions.filter((action) => action.kind !== 'edit' || rung.edit)\n}\n\n/**\n * Client-supplied strings that end up inside a SYSTEM block have to be\n * treated as hostile, not merely untidy. `route` is whatever the panel says\n * the pathname is, and an attacker who can shape it can otherwise write\n * newlines, backticks and prose into the model's instructions — including a\n * forged action fence, which is the one construct in this feature the model\n * is told to treat as meaningful.\n *\n * So the allowed alphabet is exactly what a console path is made of. Anything\n * else is dropped rather than escaped: there is no legitimate route that\n * needs a backtick, and a sanitiser that tries to preserve intent is a\n * sanitiser with a bypass in it.\n */\nexport function sanitiseRoute(route: string): string {\n const cleaned = String(route ?? '')\n .replace(/[^A-Za-z0-9/_\\-.[\\]]/g, '')\n .slice(0, 200)\n return cleaned.startsWith('/') ? cleaned : ''\n}\n\n/**\n * Same reasoning as `sanitiseRoute`, for a Firestore-shaped document id.\n *\n * Rejects rather than truncates, which is the difference between refusing an\n * id and quietly pointing at a different one: `slice(0, 64)` on an over-long\n * value yields a well-formed id for some OTHER document, and this function's\n * output is substituted straight into a destination path.\n */\nexport function sanitiseId(value: string): string {\n const raw = String(value ?? '')\n return raw.length <= 64 && /^[A-Za-z0-9_-]+$/.test(raw) ? raw : ''\n}\n\n/**\n * The ONLY fields of the org document that may enter a prompt.\n *\n * An allowlist rather than a denylist, and stated as a literal rather than\n * derived, because the failure mode is silent: the org doc grows a field one\n * day — a Stripe customer id, an owner's email, a support note — and a\n * spread would carry it into a third party's API without anything failing.\n * Both fields named here are already on screen for any member who can open\n * the panel, so nothing is disclosed that the asker could not read anyway.\n *\n * The plan is the one the workspace resolves to, as the console's badges name\n * it (AGL-3034): a canceled subscription's stored plan grants nothing, and a\n * staff comp grants a plan the stored field may not name.\n */\nexport function safeOrgFacts(org: Record<string, unknown>): {\n name: string\n plan: string\n} {\n return {\n name: String(org?.['name'] ?? '').slice(0, 120),\n plan: resolveEffectivePlan(org as never).slice(0, 40),\n }\n}\n\n/**\n * The per-VIEW system block — the screen description, and nothing about who\n * is looking at it.\n *\n * The split from `viewFactsBlock` is the whole caching design, and it was\n * not the first shape this took. Folding the workspace name, plan, slug and\n * host id in here reads more natural and quietly destroys the cache: a\n * prefix carrying the tenant's name is unique to that tenant, so on a\n * multi-tenant console every org warms its own copy and the entry is usually\n * cold when it matters. Derived purely from the route, the same block serves\n * every workspace asking anything on that screen — which on a shared console\n * is the difference between a cache that pays and one that mostly writes.\n *\n * So this block is a pure function of the registry and the rung — two\n * variants a route at most, neither carrying a tenant byte — and everything\n * that varies per request lives after the breakpoint.\n */\nexport function viewScreenBlock(\n view: AssistView | null,\n rung: AssistActionRung = { edit: false },\n): string {\n const lines: string[] = []\n if (view) {\n lines.push(`This screen: ${view.screen}`)\n if (view.plain.length) {\n lines.push('What the user can do here:')\n for (const line of view.plain) lines.push(`- ${line}`)\n }\n if (view.technical.length) {\n lines.push('Technical detail for the \"Under the hood\" line:')\n for (const line of view.technical) lines.push(`- ${line}`)\n }\n const offered = offeredActions(view, rung)\n const navigations = offered.filter(isNavigateAction)\n if (navigations.length) {\n lines.push(\n 'Actions you may PROPOSE from this screen (ids are exact; propose at most one, and only when the user asked to get something done):',\n )\n for (const action of navigations) {\n const params = action.params.length\n ? ` params: ${action.params.join(', ')}`\n : ' params: none'\n lines.push(`- id \"${action.id}\" — ${action.label}: opens ${action.outcome}.${params}`)\n }\n } else if (offered.length) {\n lines.push('This screen offers no page to open. Do not emit an action block here.')\n } else {\n lines.push(\n 'This screen offers no proposable actions. Do not emit an action block here.',\n )\n }\n for (const action of offered) {\n if (action.kind !== 'edit') continue\n lines.push(\n `Edits you may PROPOSE on this screen (id \"${action.id}\"): through the ${ASSIST_EDIT_TOOL_NAME} tool described below, never an action block.`,\n )\n }\n } else {\n lines.push(\n 'This exact screen is not in the assistant’s screen index. Answer from the documentation and describe navigation in words rather than asserting what this page contains.',\n 'Do not emit an action block.',\n )\n }\n return lines.join('\\n')\n}\n\n/**\n * The per-REQUEST facts. Everything here varies by workspace or by page, so\n * it sits after the last cache breakpoint where it invalidates nothing.\n *\n * Only `safeOrgFacts`' two allowlisted fields and the three sanitised client\n * strings ever reach this — see the module header.\n */\nexport function viewFactsBlock(facts: {\n route: string\n hostId: string\n orgSlug: string\n name: string\n plan: string\n}): string {\n const lines: string[] = ['Where the user is right now:']\n lines.push(`- Console page path: ${facts.route}`)\n if (facts.orgSlug) lines.push(`- Workspace URL slug: ${facts.orgSlug}`)\n if (facts.hostId) lines.push(`- Selected site (host) id: ${facts.hostId}`)\n if (facts.name) lines.push(`- Workspace name: ${facts.name}`)\n if (facts.plan) lines.push(`- Workspace plan: ${facts.plan}`)\n return lines.join('\\n')\n}\n\n/* ------------------------------------------------------------------ *\n * The proposal channel\n * ------------------------------------------------------------------ */\n\n/** Fence the model wraps a proposal in. Kept out of the visible answer. */\nexport const ASSIST_ACTION_FENCE = '```aglyn:action'\n\n/**\n * How much of `raw` is safe to stream to the user.\n *\n * The proposal fence must never reach the panel as text — a user watching\n * raw JSON appear mid-answer reads it as the assistant breaking. Trimming\n * only at the end is not enough either, because by then the tokens have\n * already been emitted as deltas.\n *\n * So the visible prefix is recomputed on every delta, and the tail is held\n * back only while it could still turn out to be the start of a fence. That\n * matters for latency: holding a fixed window would delay every answer by\n * the fence's length, whereas this holds nothing back unless the text\n * genuinely ends in a backtick run.\n */\nexport function visibleAssistText(raw: string): string {\n const cut = raw.indexOf(ASSIST_ACTION_FENCE)\n if (cut >= 0) return raw.slice(0, cut)\n for (let n = Math.min(ASSIST_ACTION_FENCE.length - 1, raw.length); n > 0; n--) {\n if (ASSIST_ACTION_FENCE.startsWith(raw.slice(raw.length - n))) {\n return raw.slice(0, raw.length - n)\n }\n }\n return raw\n}\n\n/**\n * The visible answer once the stream has ENDED — no holdback.\n *\n * `visibleAssistText` withholds a tail that might still become a fence,\n * which is right mid-stream and wrong at the end: an answer that genuinely\n * closes on a code fence would otherwise lose its last three characters\n * permanently, both on screen and in the stored exchange. Once there are no\n * more deltas the ambiguity is resolved, so the only cut left is a real one.\n */\nexport function finalAssistText(raw: string): string {\n const cut = raw.indexOf(ASSIST_ACTION_FENCE)\n return cut >= 0 ? raw.slice(0, cut) : raw\n}\n\n/** The raw JSON body between the fences, if the model emitted one. */\nexport function extractAssistAction(raw: string): string | null {\n const start = raw.indexOf(ASSIST_ACTION_FENCE)\n if (start < 0) return null\n const bodyStart = start + ASSIST_ACTION_FENCE.length\n const end = raw.indexOf('```', bodyStart)\n const body = (end < 0 ? raw.slice(bodyStart) : raw.slice(bodyStart, end)).trim()\n return body || null\n}\n\n/** A proposal that survived validation — inert, and safe to show. */\nexport interface AssistProposal {\n id: string\n label: string\n outcome: string\n /** Fully-resolved console path. Server-built; the model never sees it. */\n href: string\n /** Values the model suggested, in the order the action declared them. */\n values: ReadonlyArray<{ name: string; value: string }>\n /** Whether `href` carries the values, or the card must ask the user to type them. */\n prefill: boolean\n}\n\nconst MAX_PARAM_VALUE_CHARS = 200\n\n/**\n * Turn a model-emitted action block into a proposal, or nothing.\n *\n * Everything here is a narrowing. The id must be one the CURRENT view\n * offers as a navigation — not merely a real id somewhere in the registry,\n * because \"propose the billing page from the besigner\" is exactly the kind\n * of plausible wandering that makes an assistant feel unsafe, and not the\n * edit action either, which is never a destination. Param names must be ones\n * that action declared. The href is composed from the registry template and\n * the caller's own server-resolved slug and host, so a completion cannot\n * steer the user anywhere the registry does not already point.\n *\n * Anything unexpected returns null. A dropped proposal costs the user a\n * button; an honoured bad one costs them trust.\n */\nexport function resolveAssistProposal(\n rawBlock: string | null,\n view: AssistView | null,\n scope: { orgSlug: string; hostId: string },\n): AssistProposal | null {\n if (!rawBlock || !view) return null\n const navigations = view.actions.filter(isNavigateAction)\n if (!navigations.length) return null\n\n let parsed: Record<string, unknown>\n try {\n parsed = JSON.parse(rawBlock) as Record<string, unknown>\n } catch {\n return null\n }\n if (!parsed || typeof parsed !== 'object') return null\n\n const id = String(parsed['id'] ?? '').trim()\n const action = navigations.find((candidate) => candidate.id === id)\n if (!action) return null\n\n const supplied = (parsed['params'] ?? {}) as Record<string, unknown>\n const values: Array<{ name: string; value: string }> = []\n if (supplied && typeof supplied === 'object' && !Array.isArray(supplied)) {\n for (const name of action.params) {\n const value = String(supplied[name] ?? '')\n .replace(/[\\r\\n]+/g, ' ')\n .trim()\n .slice(0, MAX_PARAM_VALUE_CHARS)\n if (value) values.push({ name, value })\n }\n }\n\n const href = buildActionHref(action, scope, values)\n if (!href) return null\n\n return {\n id: action.id,\n label: action.label,\n outcome: action.outcome,\n href,\n values,\n prefill: action.prefill,\n }\n}\n\n/**\n * Compose the destination from the registry template and the server's own\n * scope values. Returns '' when the template needs a segment this page does\n * not have — a half-substituted path like `/acme/hosts//setup` is a 404 with\n * a confirm button on it, which is worse than no button.\n */\nfunction buildActionHref(\n action: AssistNavigateAction,\n scope: { orgSlug: string; hostId: string },\n values: ReadonlyArray<{ name: string; value: string }>,\n): string {\n const orgSlug = sanitiseId(scope.orgSlug)\n const hostId = sanitiseId(scope.hostId)\n let path = action.route\n if (path.includes('[orgSlug]')) {\n if (!orgSlug) return ''\n path = path.replace('[orgSlug]', orgSlug)\n }\n if (path.includes('[host]')) {\n if (!hostId) return ''\n path = path.replace('[host]', hostId)\n }\n // Nothing above can produce these, which is exactly why they are worth\n // asserting: this is the last line before a path reaches a router.\n if (!path.startsWith('/') || path.includes('..') || path.includes('//')) return ''\n if (/\\[|\\]/.test(path)) return ''\n\n if (!action.prefill || !values.length) return path\n const query = values\n .map(\n ({ name, value }) =>\n `${ASSIST_PREFILL_PREFIX}${encodeURIComponent(name)}=${encodeURIComponent(value)}`,\n )\n .join('&')\n return `${path}?${query}`\n}\n\n/**\n * The write boundary, asserted over the live table rather than described in\n * a comment. Called by the spec; exported so the check travels with the data\n * it checks rather than living in a test file someone can delete.\n *\n * Every action is inert UNLESS it is an edit action and the request cleared\n * the edit rung: a navigation carries no write-capable field and no ops, an\n * edit action carries no destination, and an edit action offered to a\n * request below the rung is a violation. `offer` is the function the doors\n * decide with; a spec passes a broken one to show this check can fail.\n *\n * Returns the list of violations so a failure names the offending action.\n */\nexport function assertInertActions(\n views: readonly AssistView[] = ASSIST_VIEWS,\n rung: AssistActionRung = { edit: false },\n offer: typeof offeredActions = offeredActions,\n): string[] {\n const problems: string[] = []\n const seen = new Set<string>()\n const forbidden = ['method', 'body', 'endpoint', 'submit', 'url', 'api', 'mutation']\n for (const view of views) {\n const offered = offer(view, rung)\n for (const action of view.actions) {\n const where = `${view.key}/${action.id}`\n if (seen.has(action.id)) problems.push(`${where}: duplicate action id`)\n seen.add(action.id)\n for (const key of Object.keys(action)) {\n if (forbidden.includes(key.toLowerCase())) {\n problems.push(`${where}: action carries a write-capable field \"${key}\"`)\n }\n }\n if (action.kind === 'edit') {\n if (!rung.edit && offered.includes(action)) {\n problems.push(\n `${where}: an edit action is offered to a request that did not clear the edit rung`,\n )\n }\n for (const key of ['route', 'params', 'prefill']) {\n if (key in action) {\n problems.push(\n `${where}: an edit action carries \"${key}\" — it applies ops on the open canvas and never navigates`,\n )\n }\n }\n const documents = action.documents ?? []\n if (\n !documents.length ||\n documents.some((kind) => !ASSIST_EDIT_DOCUMENT_KINDS.includes(kind))\n ) {\n problems.push(`${where}: an edit action names a document the edit rung does not open on`)\n }\n continue\n }\n if ('ops' in action) {\n problems.push(`${where}: only an edit action carries ops`)\n }\n if (!action.route.startsWith('/')) {\n problems.push(`${where}: route is not a root-relative console path`)\n }\n if (action.route.includes('/api/')) {\n problems.push(`${where}: route points at an API endpoint`)\n }\n if (action.prefill && !PREFILL_READY_ROUTES.includes(action.route)) {\n problems.push(\n `${where}: prefill:true but ${action.route} is not in PREFILL_READY_ROUTES — wire the page to read ${ASSIST_PREFILL_PREFIX}* params first`,\n )\n }\n }\n }\n return problems\n}\n"],"names":["resolveEffectivePlan","ASSIST_EDIT_ACTION_ID","ASSIST_EDIT_DOCUMENT_KINDS","ASSIST_EDIT_TOOL_NAME","PREFILL_READY_ROUTES","ASSIST_PREFILL_PREFIX","orgAction","id","label","outcome","route","params","prefill","isNavigateAction","action","kind","ASSIST_VIEWS","key","match","screen","plain","technical","actions","documents","describeView","path","sanitiseRoute","find","view","test","offeredActions","rung","filter","edit","cleaned","String","replace","slice","startsWith","sanitiseId","value","raw","length","safeOrgFacts","org","name","plan","viewScreenBlock","lines","push","line","offered","navigations","join","viewFactsBlock","facts","orgSlug","hostId","ASSIST_ACTION_FENCE","visibleAssistText","cut","indexOf","n","Math","min","finalAssistText","extractAssistAction","start","bodyStart","end","body","trim","MAX_PARAM_VALUE_CHARS","resolveAssistProposal","rawBlock","scope","parsed","JSON","parse","candidate","supplied","values","Array","isArray","href","buildActionHref","includes","query","map","encodeURIComponent","assertInertActions","views","offer","problems","seen","Set","forbidden","where","has","add","Object","keys","toLowerCase","some"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,oBAAoB,QAAQ,2CAA0C;AAC/E,SACEC,qBAAqB,EACrBC,0BAA0B,EAC1BC,qBAAqB,QAEhB,0BAAsB;AA0J7B;;;;;CAKC,GACD,OAAO,MAAMC,uBAA0C,EAAE,CAAA;AAEzD;iEACiE,GACjE,OAAO,MAAMC,wBAAwB,UAAS;AAE9C,MAAMC,YAAY,CAChBC,IACAC,OACAC,SACAC,OACAC,SAA4B,EAAE,GACJ,CAAA;QAAEJ;QAAIC;QAAOC;QAASC;QAAOC;QAAQC,SAAS;IAAM,CAAA;AAEhF,MAAMC,mBAAmB,CAACC,SACxBA,OAAOC,IAAI,KAAK;AAElB;;;;;;;;;;;CAWC,GACD,OAAO,MAAMC,eAAsC;IACjD;QACEC,KAAK;QACLC,OAAO;QACPC,QAAQ;QACRC,OAAO;YACL;YACA;YACA;SACD;QACDC,WAAW;YACT;YACA;YACA;SACD;QACDC,SAAS;YACP;gBACEP,MAAM;gBACNR,IAAIN;gBACJO,OAAO;gBACPC,SAAS;gBACTc,WAAWrB;YACb;SACD;IACH;IACA;QACEe,KAAK;QACLC,OAAO;QACPC,QAAQ;QACRC,OAAO;YACL;YACA;YACA;SACD;QACDC,WAAW;YACT;YACA;SACD;QACDC,SAAS;YACPhB,UACE,qBACA,gBACA,kCACA;SAEH;IACH;IACA;QACEW,KAAK;QACLC,OAAO;QACPC,QAAQ;QACRC,OAAO;YACL;YACA;SACD;QACDC,WAAW;YACT;YACA;SACD;QACDC,SAAS,EAAE;IACb;IACA;QACE,wEAAwE;QACxE,yEAAyE;QACzE,0DAA0D;QAC1DL,KAAK;QACLC,OAAO;QACPC,QACE;QACFC,OAAO;YACL;YACA;YACA;SACD;QACDC,WAAW;YACT;YACA;SACD;QACDC,SAAS,EAAE;IACb;IACA;QACEL,KAAK;QACLC,OAAO;QACPC,QAAQ;QACRC,OAAO;YACL;YACA;SACD;QACDC,WAAW;YACT;YACA;SACD;QACDC,SAAS,EAAE;IACb;IACA;QACEL,KAAK;QACLC,OAAO;QACPC,QAAQ;QACRC,OAAO;YACL;YACA;SACD;QACDC,WAAW;YACT;YACA;SACD;QACDC,SAAS;YACPhB,UACE,uBACA,kBACA,oCACA,qCACA;gBAAC;gBAAU;aAAS;SAEvB;IACH;IACA;QACEW,KAAK;QACLC,OAAO;QACPC,QAAQ;QACRC,OAAO;YACL;YACA;SACD;QACDC,WAAW;YAAC;SAA4C;QACxDC,SAAS,EAAE;IACb;IACA;QACEL,KAAK;QACLC,OAAO;QACPC,QAAQ;QACRC,OAAO;YACL;YACA;SACD;QACDC,WAAW;YACT;YACA;SACD;QACDC,SAAS;YACPhB,UACE,mBACA,mBACA,4DACA,iCACA;gBAAC;aAAS;SAEb;IACH;IACA;QACEW,KAAK;QACLC,OAAO;QACPC,QAAQ;QACRC,OAAO;YACL;YACA;SACD;QACDC,WAAW;YACT;SACD;QACDC,SAAS,EAAE;IACb;IACA;QACEL,KAAK;QACLC,OAAO;QACPC,QAAQ;QACRC,OAAO;YACL;YACA;SACD;QACDC,WAAW;YACT;SACD;QACDC,SAAS,EAAE;IACb;IACA;QACEL,KAAK;QACLC,OAAO;QACPC,QAAQ;QACRC,OAAO;YACL;YACA;SACD;QACDC,WAAW;YAAC;SAA2B;QACvCC,SAAS;YACPhB,UACE,kBACA,cACA,gCACA;SAEH;IACH;IACA;QACEW,KAAK;QACLC,OAAO;QACPC,QAAQ;QACRC,OAAO;YACL;YACA;SACD;QACDC,WAAW;YACT;YACA;SACD;QACDC,SAAS;YACPhB,UACE,gBACA,wBACA,oDACA;SAEH;IACH;IACA;QACEW,KAAK;QACLC,OAAO;QACPC,QAAQ;QACRC,OAAO;YACL;YACA;SACD;QACDC,WAAW;YACT;YACA;SACD;QACDC,SAAS;YACPhB,UACE,aACA,aACA,yDACA,mBACA;gBAAC;gBAAS;aAAO;SAEpB;IACH;IACA;QACEW,KAAK;QACLC,OAAO;QACPC,QAAQ;QACRC,OAAO;YACL;YACA;YACA;SACD;QACDC,WAAW;YACT;YACA;SACD;QACDC,SAAS;YACPhB,UACE,iBACA,aACA,6CACA;SAEH;IACH;IACA;QACEW,KAAK;QACLC,OAAO;QACPC,QAAQ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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* This month's Aglyn Assist credit standing for one org — the odometer beside
|
|
19
|
+
* the band on Billing → Usage.
|
|
20
|
+
*
|
|
21
|
+
* ## Why a route at all
|
|
22
|
+
*
|
|
23
|
+
* Every other meter on that page reads its counter straight from Firestore in
|
|
24
|
+
* the browser. This one cannot: `orgs/{id}/assistUsage` is deliberately absent
|
|
25
|
+
* from the rules file and therefore default-deny for every client, because the
|
|
26
|
+
* assist subcollections sit beside the exchange prose and are reached only
|
|
27
|
+
* through the Admin SDK. A client read would fail silently and the meter would
|
|
28
|
+
* sit at "not yet metered" forever — a surface that looks like a readout and
|
|
29
|
+
* is not one, which is worse than no meter at all.
|
|
30
|
+
*
|
|
31
|
+
* ## Why it answers in CREDITS
|
|
32
|
+
*
|
|
33
|
+
* The stored figure is `estCostUsd`: our provider bill for the month at the
|
|
34
|
+
* serving model's list rates. Publishing it would put our model choice and our
|
|
35
|
+
* margin on a billing page, and it would move under the customer every time
|
|
36
|
+
* the model is swapped. `publicAssistCredits` is the one conversion, and no
|
|
37
|
+
* dollar figure crosses this boundary.
|
|
38
|
+
*
|
|
39
|
+
* `credits: null` is the honest answer for an org that has no assist band at
|
|
40
|
+
* all. Since AGL-3203 no plan ROW bands at zero, so what reaches this is a
|
|
41
|
+
* per-org override that writes one. It is not "0 of 0"; there is no band to
|
|
42
|
+
* be a fraction of, and the page renders no meter rather than an empty one.
|
|
43
|
+
*
|
|
44
|
+
* An UNCAPPED staff comp (AGL-3049) has no band either, but it has a meter:
|
|
45
|
+
* the workspace draws credits with no limit to draw them against. It answers
|
|
46
|
+
* `credits: { used, limit: null, remaining: null }` and `unlimited: true`.
|
|
47
|
+
* `null` is the band's absence on the wire — never `Infinity`, which
|
|
48
|
+
* `JSON.stringify` would turn into a `null` nobody chose — and the flag says
|
|
49
|
+
* which absence it is, so a reader that turns `null` into a number cannot
|
|
50
|
+
* mistake an unlimited workspace for one with a band of zero.
|
|
51
|
+
*
|
|
52
|
+
* Membership alone, not `billing.manage`: this is a capacity readout of the
|
|
53
|
+
* kind every other meter on the page shows to anyone who can see the page, and
|
|
54
|
+
* it carries no money. The spend view that DOES carry money is
|
|
55
|
+
* `/api/billing/usage-budget`, which gates on `billing.manage`.
|
|
56
|
+
*/
|
|
57
|
+
declare function handler(request: Request): Promise<Response>;
|
|
58
|
+
export declare const GET: typeof handler;
|
|
59
|
+
export {};
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ import { pluginRequestFromWeb } from "@aglyn/aglyn/server";
|
|
18
|
+
import { publicAssistCredits, resolveAssistBudgetUsd } from "@aglyn/aglyn/app-utils/assist-credits";
|
|
19
|
+
import { isUncappedPlanComp } from "@aglyn/aglyn/app-utils/plan-entitlements";
|
|
20
|
+
import { emailUnverifiedResponse, firebaseAdmin, isImpersonationSession, resolveOrgMembership } from "@aglyn/tenant-data-admin";
|
|
21
|
+
import { invalidIdTokenResponse } from "@aglyn/tenant-data-admin/server/id-token-refusal";
|
|
22
|
+
// lockdown-423: exempt — a READ-ONLY billing surface that writes nothing,
|
|
23
|
+
// same posture as billing/usage-budget beside it. AGL-1501 keeps
|
|
24
|
+
// billing-locked sessions alive so members can reach Billing, and a
|
|
25
|
+
// locked org needs its usage readouts more than an unlocked one does.
|
|
26
|
+
/**
|
|
27
|
+
* This month's Aglyn Assist credit standing for one org — the odometer beside
|
|
28
|
+
* the band on Billing → Usage.
|
|
29
|
+
*
|
|
30
|
+
* ## Why a route at all
|
|
31
|
+
*
|
|
32
|
+
* Every other meter on that page reads its counter straight from Firestore in
|
|
33
|
+
* the browser. This one cannot: `orgs/{id}/assistUsage` is deliberately absent
|
|
34
|
+
* from the rules file and therefore default-deny for every client, because the
|
|
35
|
+
* assist subcollections sit beside the exchange prose and are reached only
|
|
36
|
+
* through the Admin SDK. A client read would fail silently and the meter would
|
|
37
|
+
* sit at "not yet metered" forever — a surface that looks like a readout and
|
|
38
|
+
* is not one, which is worse than no meter at all.
|
|
39
|
+
*
|
|
40
|
+
* ## Why it answers in CREDITS
|
|
41
|
+
*
|
|
42
|
+
* The stored figure is `estCostUsd`: our provider bill for the month at the
|
|
43
|
+
* serving model's list rates. Publishing it would put our model choice and our
|
|
44
|
+
* margin on a billing page, and it would move under the customer every time
|
|
45
|
+
* the model is swapped. `publicAssistCredits` is the one conversion, and no
|
|
46
|
+
* dollar figure crosses this boundary.
|
|
47
|
+
*
|
|
48
|
+
* `credits: null` is the honest answer for an org that has no assist band at
|
|
49
|
+
* all. Since AGL-3203 no plan ROW bands at zero, so what reaches this is a
|
|
50
|
+
* per-org override that writes one. It is not "0 of 0"; there is no band to
|
|
51
|
+
* be a fraction of, and the page renders no meter rather than an empty one.
|
|
52
|
+
*
|
|
53
|
+
* An UNCAPPED staff comp (AGL-3049) has no band either, but it has a meter:
|
|
54
|
+
* the workspace draws credits with no limit to draw them against. It answers
|
|
55
|
+
* `credits: { used, limit: null, remaining: null }` and `unlimited: true`.
|
|
56
|
+
* `null` is the band's absence on the wire — never `Infinity`, which
|
|
57
|
+
* `JSON.stringify` would turn into a `null` nobody chose — and the flag says
|
|
58
|
+
* which absence it is, so a reader that turns `null` into a number cannot
|
|
59
|
+
* mistake an unlimited workspace for one with a band of zero.
|
|
60
|
+
*
|
|
61
|
+
* Membership alone, not `billing.manage`: this is a capacity readout of the
|
|
62
|
+
* kind every other meter on the page shows to anyone who can see the page, and
|
|
63
|
+
* it carries no money. The spend view that DOES carry money is
|
|
64
|
+
* `/api/billing/usage-budget`, which gates on `billing.manage`.
|
|
65
|
+
*/ async function handler(request) {
|
|
66
|
+
var _headers_authorization, _ref;
|
|
67
|
+
const { method, headers: rawHeaders, query } = await pluginRequestFromWeb(request);
|
|
68
|
+
const headers = rawHeaders;
|
|
69
|
+
if (method !== 'GET') {
|
|
70
|
+
return Response.json({
|
|
71
|
+
error: 'Method not allowed'
|
|
72
|
+
}, {
|
|
73
|
+
status: 405
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
const authorization = (_headers_authorization = headers.authorization) != null ? _headers_authorization : '';
|
|
77
|
+
const idToken = authorization.startsWith('Bearer ') ? authorization.slice('Bearer '.length) : undefined;
|
|
78
|
+
if (!idToken) {
|
|
79
|
+
return Response.json({
|
|
80
|
+
error: 'Unauthenticated'
|
|
81
|
+
}, {
|
|
82
|
+
status: 401
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
const orgId = String((_ref = query == null ? void 0 : query.orgId) != null ? _ref : '');
|
|
86
|
+
if (!orgId) return Response.json({
|
|
87
|
+
error: 'Bad request'
|
|
88
|
+
}, {
|
|
89
|
+
status: 400
|
|
90
|
+
});
|
|
91
|
+
try {
|
|
92
|
+
var _usage_get;
|
|
93
|
+
const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken);
|
|
94
|
+
if (!decoded.email_verified && !isImpersonationSession(decoded)) {
|
|
95
|
+
return emailUnverifiedResponse();
|
|
96
|
+
}
|
|
97
|
+
const isStaff = decoded['staff'] === true;
|
|
98
|
+
const actor = await resolveOrgMembership(decoded.uid, orgId);
|
|
99
|
+
if (!isStaff && !(actor == null ? void 0 : actor.member)) {
|
|
100
|
+
return Response.json({
|
|
101
|
+
error: 'Not a member'
|
|
102
|
+
}, {
|
|
103
|
+
status: 403
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
const orgRef = firebaseAdmin.app().firestore().collection('orgs').doc(orgId);
|
|
107
|
+
const orgSnapshot = await orgRef.get();
|
|
108
|
+
if (!orgSnapshot.exists) {
|
|
109
|
+
return Response.json({
|
|
110
|
+
error: 'Unknown organization'
|
|
111
|
+
}, {
|
|
112
|
+
status: 404
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const org = orgSnapshot.data();
|
|
116
|
+
const budgetUsd = resolveAssistBudgetUsd(org);
|
|
117
|
+
const unlimited = budgetUsd === null && isUncappedPlanComp(org);
|
|
118
|
+
if (budgetUsd === null && !unlimited) return Response.json({
|
|
119
|
+
credits: null
|
|
120
|
+
});
|
|
121
|
+
const month = new Date().toISOString().slice(0, 7);
|
|
122
|
+
const usage = await orgRef.collection('assistUsage').doc(month).get();
|
|
123
|
+
const costUsd = Number((_usage_get = usage.get('estCostUsd')) != null ? _usage_get : 0);
|
|
124
|
+
return Response.json(_extends({
|
|
125
|
+
credits: publicAssistCredits(Number.isFinite(costUsd) && costUsd > 0 ? costUsd : 0, budgetUsd)
|
|
126
|
+
}, unlimited ? {
|
|
127
|
+
unlimited: true
|
|
128
|
+
} : {}));
|
|
129
|
+
} catch (error) {
|
|
130
|
+
// A refused credential is a 401, not a fault of ours (AGL-1993). Null
|
|
131
|
+
// for anything else, so a real failure keeps the answer below.
|
|
132
|
+
const unauthenticated = invalidIdTokenResponse(error);
|
|
133
|
+
if (unauthenticated) return unauthenticated;
|
|
134
|
+
console.error('[assist-credits] read failed', orgId, error);
|
|
135
|
+
// The meter's "not yet metered" state, not a zero — a failed read must
|
|
136
|
+
// not render as "you have used none of your credits".
|
|
137
|
+
return Response.json({
|
|
138
|
+
error: 'Assist credits unavailable'
|
|
139
|
+
}, {
|
|
140
|
+
status: 500
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
export const GET = handler;
|
|
145
|
+
|
|
146
|
+
//# sourceMappingURL=billing-credits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/server/billing-credits.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { pluginRequestFromWeb } from '@aglyn/aglyn/server'\nimport {\n publicAssistCredits,\n resolveAssistBudgetUsd,\n} from '@aglyn/aglyn/app-utils/assist-credits'\nimport { isUncappedPlanComp } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport {\n emailUnverifiedResponse,\n firebaseAdmin,\n isImpersonationSession,\n resolveOrgMembership,\n} from '@aglyn/tenant-data-admin'\nimport { invalidIdTokenResponse } from '@aglyn/tenant-data-admin/server/id-token-refusal'\n\n// lockdown-423: exempt — a READ-ONLY billing surface that writes nothing,\n// same posture as billing/usage-budget beside it. AGL-1501 keeps\n// billing-locked sessions alive so members can reach Billing, and a\n// locked org needs its usage readouts more than an unlocked one does.\n\n/**\n * This month's Aglyn Assist credit standing for one org — the odometer beside\n * the band on Billing → Usage.\n *\n * ## Why a route at all\n *\n * Every other meter on that page reads its counter straight from Firestore in\n * the browser. This one cannot: `orgs/{id}/assistUsage` is deliberately absent\n * from the rules file and therefore default-deny for every client, because the\n * assist subcollections sit beside the exchange prose and are reached only\n * through the Admin SDK. A client read would fail silently and the meter would\n * sit at \"not yet metered\" forever — a surface that looks like a readout and\n * is not one, which is worse than no meter at all.\n *\n * ## Why it answers in CREDITS\n *\n * The stored figure is `estCostUsd`: our provider bill for the month at the\n * serving model's list rates. Publishing it would put our model choice and our\n * margin on a billing page, and it would move under the customer every time\n * the model is swapped. `publicAssistCredits` is the one conversion, and no\n * dollar figure crosses this boundary.\n *\n * `credits: null` is the honest answer for an org that has no assist band at\n * all. Since AGL-3203 no plan ROW bands at zero, so what reaches this is a\n * per-org override that writes one. It is not \"0 of 0\"; there is no band to\n * be a fraction of, and the page renders no meter rather than an empty one.\n *\n * An UNCAPPED staff comp (AGL-3049) has no band either, but it has a meter:\n * the workspace draws credits with no limit to draw them against. It answers\n * `credits: { used, limit: null, remaining: null }` and `unlimited: true`.\n * `null` is the band's absence on the wire — never `Infinity`, which\n * `JSON.stringify` would turn into a `null` nobody chose — and the flag says\n * which absence it is, so a reader that turns `null` into a number cannot\n * mistake an unlimited workspace for one with a band of zero.\n *\n * Membership alone, not `billing.manage`: this is a capacity readout of the\n * kind every other meter on the page shows to anyone who can see the page, and\n * it carries no money. The spend view that DOES carry money is\n * `/api/billing/usage-budget`, which gates on `billing.manage`.\n */\nasync function handler(request: Request): Promise<Response> {\n const { method, headers: rawHeaders, query } = await pluginRequestFromWeb(request)\n const headers = rawHeaders as Partial<Record<string, string>>\n if (method !== 'GET') {\n return Response.json({ error: 'Method not allowed' }, { status: 405 })\n }\n const authorization = headers.authorization ?? ''\n const idToken = authorization.startsWith('Bearer ')\n ? authorization.slice('Bearer '.length)\n : undefined\n if (!idToken) {\n return Response.json({ error: 'Unauthenticated' }, { status: 401 })\n }\n const orgId = String((query as Record<string, unknown>)?.orgId ?? '')\n if (!orgId) return Response.json({ error: 'Bad request' }, { status: 400 })\n\n try {\n const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken)\n if (!decoded.email_verified && !isImpersonationSession(decoded)) {\n return emailUnverifiedResponse()\n }\n const isStaff = decoded['staff'] === true\n const actor = await resolveOrgMembership(decoded.uid, orgId)\n if (!isStaff && !actor?.member) {\n return Response.json({ error: 'Not a member' }, { status: 403 })\n }\n const orgRef = firebaseAdmin.app().firestore().collection('orgs').doc(orgId)\n const orgSnapshot = await orgRef.get()\n if (!orgSnapshot.exists) {\n return Response.json({ error: 'Unknown organization' }, { status: 404 })\n }\n const org = orgSnapshot.data() as never\n const budgetUsd = resolveAssistBudgetUsd(org)\n const unlimited = budgetUsd === null && isUncappedPlanComp(org)\n if (budgetUsd === null && !unlimited) return Response.json({ credits: null })\n const month = new Date().toISOString().slice(0, 7)\n const usage = await orgRef.collection('assistUsage').doc(month).get()\n const costUsd = Number(usage.get('estCostUsd') ?? 0)\n return Response.json({\n credits: publicAssistCredits(\n Number.isFinite(costUsd) && costUsd > 0 ? costUsd : 0,\n budgetUsd,\n ),\n ...(unlimited ? { unlimited: true } : {}),\n })\n } catch (error) {\n // A refused credential is a 401, not a fault of ours (AGL-1993). Null\n // for anything else, so a real failure keeps the answer below.\n const unauthenticated = invalidIdTokenResponse(error)\n if (unauthenticated) return unauthenticated\n console.error('[assist-credits] read failed', orgId, error)\n // The meter's \"not yet metered\" state, not a zero — a failed read must\n // not render as \"you have used none of your credits\".\n return Response.json({ error: 'Assist credits unavailable' }, { status: 500 })\n }\n}\n\nexport const GET = handler\n"],"names":["pluginRequestFromWeb","publicAssistCredits","resolveAssistBudgetUsd","isUncappedPlanComp","emailUnverifiedResponse","firebaseAdmin","isImpersonationSession","resolveOrgMembership","invalidIdTokenResponse","handler","request","headers","method","rawHeaders","query","Response","json","error","status","authorization","idToken","startsWith","slice","length","undefined","orgId","String","usage","decoded","app","auth","verifyIdToken","email_verified","isStaff","actor","uid","member","orgRef","firestore","collection","doc","orgSnapshot","get","exists","org","data","budgetUsd","unlimited","credits","month","Date","toISOString","costUsd","Number","isFinite","unauthenticated","console","GET"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
declare function handler(request: Request): Promise<Response>;
|
|
18
|
+
export declare const dynamic = "force-dynamic";
|
|
19
|
+
export { handler as POST };
|