@wizeworks/lens-cloud 0.3.0-alpha.3 → 0.3.0-alpha.5
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/README.md +3 -0
- package/dist/alerts/evaluate.d.ts +6 -5
- package/dist/alerts/evaluate.d.ts.map +1 -1
- package/dist/alerts/evaluate.js +59 -26
- package/dist/alerts/evaluate.js.map +1 -1
- package/dist/alerts/problem-link.d.ts +12 -0
- package/dist/alerts/problem-link.d.ts.map +1 -0
- package/dist/alerts/problem-link.js +31 -0
- package/dist/alerts/problem-link.js.map +1 -0
- package/dist/app.d.ts +9 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/auth/auth.d.ts +8 -2
- package/dist/auth/auth.d.ts.map +1 -1
- package/dist/auth/auth.js +25 -2
- package/dist/auth/auth.js.map +1 -1
- package/dist/auth/billing-hooks.d.ts +9 -0
- package/dist/auth/billing-hooks.d.ts.map +1 -0
- package/dist/auth/billing-hooks.js +49 -0
- package/dist/auth/billing-hooks.js.map +1 -0
- package/dist/auth/bridge.js +2 -2
- package/dist/auth/bridge.js.map +1 -1
- package/dist/auth/crypto.d.ts +2 -0
- package/dist/auth/crypto.d.ts.map +1 -1
- package/dist/auth/crypto.js +2 -2
- package/dist/auth/crypto.js.map +1 -1
- package/dist/auth/deps.d.ts +7 -0
- package/dist/auth/deps.d.ts.map +1 -1
- package/dist/auth/deps.js.map +1 -1
- package/dist/auth/hooks.d.ts.map +1 -1
- package/dist/auth/hooks.js +8 -1
- package/dist/auth/hooks.js.map +1 -1
- package/dist/auth/join-scope.d.ts +1 -1
- package/dist/auth/join-scope.d.ts.map +1 -1
- package/dist/auth/join-scope.js +8 -4
- package/dist/auth/join-scope.js.map +1 -1
- package/dist/auth/oauth-access.d.ts +8 -0
- package/dist/auth/oauth-access.d.ts.map +1 -0
- package/dist/auth/oauth-access.js +31 -0
- package/dist/auth/oauth-access.js.map +1 -0
- package/dist/auth/oauth-grant.d.ts +5 -0
- package/dist/auth/oauth-grant.d.ts.map +1 -0
- package/dist/auth/oauth-grant.js +79 -0
- package/dist/auth/oauth-grant.js.map +1 -0
- package/dist/auth/oauth-names.d.ts +104 -0
- package/dist/auth/oauth-names.d.ts.map +1 -0
- package/dist/auth/oauth-names.js +72 -0
- package/dist/auth/oauth-names.js.map +1 -0
- package/dist/auth/oauth.d.ts +17 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +47 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/options.d.ts.map +1 -1
- package/dist/auth/options.js +2 -0
- package/dist/auth/options.js.map +1 -1
- package/dist/auth/plugins.d.ts.map +1 -1
- package/dist/auth/plugins.js +15 -1
- package/dist/auth/plugins.js.map +1 -1
- package/dist/auth/principal.d.ts +10 -1
- package/dist/auth/principal.d.ts.map +1 -1
- package/dist/auth/principal.js +8 -7
- package/dist/auth/principal.js.map +1 -1
- package/dist/auth/roles.d.ts +5 -2
- package/dist/auth/roles.d.ts.map +1 -1
- package/dist/auth/roles.js +1 -0
- package/dist/auth/roles.js.map +1 -1
- package/dist/auth/schema-names.d.ts +33 -0
- package/dist/auth/schema-names.d.ts.map +1 -1
- package/dist/auth/schema-names.js +23 -0
- package/dist/auth/schema-names.js.map +1 -1
- package/dist/auth/scim.d.ts +6 -0
- package/dist/auth/scim.d.ts.map +1 -0
- package/dist/auth/scim.js +56 -0
- package/dist/auth/scim.js.map +1 -0
- package/dist/auth/signup.d.ts.map +1 -1
- package/dist/auth/signup.js +5 -2
- package/dist/auth/signup.js.map +1 -1
- package/dist/auth/wire.d.ts +2 -1
- package/dist/auth/wire.d.ts.map +1 -1
- package/dist/auth/wire.js +4 -1
- package/dist/auth/wire.js.map +1 -1
- package/dist/billing/cli.d.ts +6 -0
- package/dist/billing/cli.d.ts.map +1 -0
- package/dist/billing/cli.js +54 -0
- package/dist/billing/cli.js.map +1 -0
- package/dist/billing/gate.d.ts +13 -0
- package/dist/billing/gate.d.ts.map +1 -0
- package/dist/billing/gate.js +27 -0
- package/dist/billing/gate.js.map +1 -0
- package/dist/billing/limits.d.ts +29 -0
- package/dist/billing/limits.d.ts.map +1 -0
- package/dist/billing/limits.js +69 -0
- package/dist/billing/limits.js.map +1 -0
- package/dist/billing/notices.d.ts +4 -0
- package/dist/billing/notices.d.ts.map +1 -0
- package/dist/billing/notices.js +40 -0
- package/dist/billing/notices.js.map +1 -0
- package/dist/billing/options.d.ts +37 -0
- package/dist/billing/options.d.ts.map +1 -0
- package/dist/billing/options.js +33 -0
- package/dist/billing/options.js.map +1 -0
- package/dist/billing/plans.d.ts +50 -0
- package/dist/billing/plans.d.ts.map +1 -0
- package/dist/billing/plans.js +47 -0
- package/dist/billing/plans.js.map +1 -0
- package/dist/billing/report.d.ts +26 -0
- package/dist/billing/report.d.ts.map +1 -0
- package/dist/billing/report.js +53 -0
- package/dist/billing/report.js.map +1 -0
- package/dist/billing/service.d.ts +20 -0
- package/dist/billing/service.d.ts.map +1 -0
- package/dist/billing/service.js +29 -0
- package/dist/billing/service.js.map +1 -0
- package/dist/billing/stripe-plugin.d.ts +14 -0
- package/dist/billing/stripe-plugin.d.ts.map +1 -0
- package/dist/billing/stripe-plugin.js +39 -0
- package/dist/billing/stripe-plugin.js.map +1 -0
- package/dist/billing/stripe-setup.d.ts +15 -0
- package/dist/billing/stripe-setup.d.ts.map +1 -0
- package/dist/billing/stripe-setup.js +73 -0
- package/dist/billing/stripe-setup.js.map +1 -0
- package/dist/billing/summary.d.ts +59 -0
- package/dist/billing/summary.d.ts.map +1 -0
- package/dist/billing/summary.js +50 -0
- package/dist/billing/summary.js.map +1 -0
- package/dist/billing/sync.d.ts +5 -0
- package/dist/billing/sync.d.ts.map +1 -0
- package/dist/billing/sync.js +35 -0
- package/dist/billing/sync.js.map +1 -0
- package/dist/billing/usage-sub.d.ts +17 -0
- package/dist/billing/usage-sub.d.ts.map +1 -0
- package/dist/billing/usage-sub.js +47 -0
- package/dist/billing/usage-sub.js.map +1 -0
- package/dist/billing/usage.d.ts +28 -0
- package/dist/billing/usage.d.ts.map +1 -0
- package/dist/billing/usage.js +80 -0
- package/dist/billing/usage.js.map +1 -0
- package/dist/billing/webhook.d.ts +6 -0
- package/dist/billing/webhook.d.ts.map +1 -0
- package/dist/billing/webhook.js +41 -0
- package/dist/billing/webhook.js.map +1 -0
- package/dist/cli-args.d.ts +1 -1
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +33 -2
- package/dist/cli-args.js.map +1 -1
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +15 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +19 -1
- package/dist/config.js.map +1 -1
- package/dist/db/schema-alerts.d.ts +2 -0
- package/dist/db/schema-alerts.d.ts.map +1 -0
- package/dist/db/schema-alerts.js +15 -0
- package/dist/db/schema-alerts.js.map +1 -0
- package/dist/db/schema-billing.d.ts +2 -0
- package/dist/db/schema-billing.d.ts.map +1 -0
- package/dist/db/schema-billing.js +38 -0
- package/dist/db/schema-billing.js.map +1 -0
- package/dist/db/schema-issues.d.ts +2 -0
- package/dist/db/schema-issues.d.ts.map +1 -0
- package/dist/db/schema-issues.js +9 -0
- package/dist/db/schema-issues.js.map +1 -0
- package/dist/db/schema-logs.d.ts +2 -0
- package/dist/db/schema-logs.d.ts.map +1 -0
- package/dist/db/schema-logs.js +13 -0
- package/dist/db/schema-logs.js.map +1 -0
- package/dist/db/schema-oauth.d.ts +2 -0
- package/dist/db/schema-oauth.d.ts.map +1 -0
- package/dist/db/schema-oauth.js +69 -0
- package/dist/db/schema-oauth.js.map +1 -0
- package/dist/db/schema-saved-move.d.ts +2 -0
- package/dist/db/schema-saved-move.d.ts.map +1 -0
- package/dist/db/schema-saved-move.js +13 -0
- package/dist/db/schema-saved-move.js.map +1 -0
- package/dist/db/schema-saved.d.ts +2 -0
- package/dist/db/schema-saved.d.ts.map +1 -0
- package/dist/db/schema-saved.js +13 -0
- package/dist/db/schema-saved.js.map +1 -0
- package/dist/db/schema-scim.d.ts +2 -0
- package/dist/db/schema-scim.d.ts.map +1 -0
- package/dist/db/schema-scim.js +28 -0
- package/dist/db/schema-scim.js.map +1 -0
- package/dist/db/schema-slos.d.ts +2 -0
- package/dist/db/schema-slos.d.ts.map +1 -0
- package/dist/db/schema-slos.js +12 -0
- package/dist/db/schema-slos.js.map +1 -0
- package/dist/db/schema-sourcemaps.d.ts +2 -0
- package/dist/db/schema-sourcemaps.d.ts.map +1 -0
- package/dist/db/schema-sourcemaps.js +9 -0
- package/dist/db/schema-sourcemaps.js.map +1 -0
- package/dist/db/schema-tags.d.ts +2 -0
- package/dist/db/schema-tags.d.ts.map +1 -0
- package/dist/db/schema-tags.js +12 -0
- package/dist/db/schema-tags.js.map +1 -0
- package/dist/db/schema-team.d.ts +2 -0
- package/dist/db/schema-team.d.ts.map +1 -0
- package/dist/db/schema-team.js +15 -0
- package/dist/db/schema-team.js.map +1 -0
- package/dist/db/schema-uptime.d.ts +2 -0
- package/dist/db/schema-uptime.d.ts.map +1 -0
- package/dist/db/schema-uptime.js +22 -0
- package/dist/db/schema-uptime.js.map +1 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +30 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/http/http.d.ts +5 -1
- package/dist/http/http.d.ts.map +1 -1
- package/dist/http/http.js +5 -1
- package/dist/http/http.js.map +1 -1
- package/dist/jobs.d.ts +1 -1
- package/dist/jobs.d.ts.map +1 -1
- package/dist/jobs.js +15 -2
- package/dist/jobs.js.map +1 -1
- package/dist/mail/emails-billing.d.ts +17 -0
- package/dist/mail/emails-billing.d.ts.map +1 -0
- package/dist/mail/emails-billing.js +36 -0
- package/dist/mail/emails-billing.js.map +1 -0
- package/dist/mail/emails.d.ts +1 -1
- package/dist/mail/emails.d.ts.map +1 -1
- package/dist/mail/emails.js +7 -4
- package/dist/mail/emails.js.map +1 -1
- package/dist/mail/mailer.d.ts +1 -1
- package/dist/mail/mailer.d.ts.map +1 -1
- package/dist/mail/samples.d.ts.map +1 -1
- package/dist/mail/samples.js +17 -0
- package/dist/mail/samples.js.map +1 -1
- package/dist/mail/templates.d.ts +1 -1
- package/dist/mail/templates.d.ts.map +1 -1
- package/dist/notify/digest-data.d.ts.map +1 -1
- package/dist/notify/digest-data.js +2 -2
- package/dist/notify/digest-data.js.map +1 -1
- package/dist/notify/digest.d.ts.map +1 -1
- package/dist/notify/digest.js +4 -1
- package/dist/notify/digest.js.map +1 -1
- package/dist/notify/team-describe.d.ts.map +1 -1
- package/dist/notify/team-describe.js +14 -0
- package/dist/notify/team-describe.js.map +1 -1
- package/dist/repo/alert-events.d.ts +38 -0
- package/dist/repo/alert-events.d.ts.map +1 -0
- package/dist/repo/alert-events.js +29 -0
- package/dist/repo/alert-events.js.map +1 -0
- package/dist/repo/alerts.d.ts +14 -44
- package/dist/repo/alerts.d.ts.map +1 -1
- package/dist/repo/alerts.js +35 -13
- package/dist/repo/alerts.js.map +1 -1
- package/dist/repo/audit.d.ts +19 -1
- package/dist/repo/audit.d.ts.map +1 -1
- package/dist/repo/audit.js +24 -2
- package/dist/repo/audit.js.map +1 -1
- package/dist/repo/auth-prune.d.ts +1 -1
- package/dist/repo/auth-prune.d.ts.map +1 -1
- package/dist/repo/auth-prune.js +13 -1
- package/dist/repo/auth-prune.js.map +1 -1
- package/dist/repo/billing.d.ts +30 -0
- package/dist/repo/billing.d.ts.map +1 -0
- package/dist/repo/billing.js +47 -0
- package/dist/repo/billing.js.map +1 -0
- package/dist/repo/grants.d.ts +30 -0
- package/dist/repo/grants.d.ts.map +1 -0
- package/dist/repo/grants.js +57 -0
- package/dist/repo/grants.js.map +1 -0
- package/dist/repo/issues.d.ts +15 -0
- package/dist/repo/issues.d.ts.map +1 -0
- package/dist/repo/issues.js +31 -0
- package/dist/repo/issues.js.map +1 -0
- package/dist/repo/keys.d.ts +51 -0
- package/dist/repo/keys.d.ts.map +1 -0
- package/dist/repo/keys.js +58 -0
- package/dist/repo/keys.js.map +1 -0
- package/dist/repo/log-retention.d.ts +8 -0
- package/dist/repo/log-retention.d.ts.map +1 -0
- package/dist/repo/log-retention.js +20 -0
- package/dist/repo/log-retention.js.map +1 -0
- package/dist/repo/metric-read.d.ts +2 -0
- package/dist/repo/metric-read.d.ts.map +1 -1
- package/dist/repo/metric-read.js +5 -1
- package/dist/repo/metric-read.js.map +1 -1
- package/dist/repo/metric-write.d.ts.map +1 -1
- package/dist/repo/metric-write.js +3 -2
- package/dist/repo/metric-write.js.map +1 -1
- package/dist/repo/orgs.d.ts +2 -0
- package/dist/repo/orgs.d.ts.map +1 -1
- package/dist/repo/orgs.js +5 -1
- package/dist/repo/orgs.js.map +1 -1
- package/dist/repo/project-roles.d.ts +28 -0
- package/dist/repo/project-roles.d.ts.map +1 -0
- package/dist/repo/project-roles.js +39 -0
- package/dist/repo/project-roles.js.map +1 -0
- package/dist/repo/projects.d.ts +3 -22
- package/dist/repo/projects.d.ts.map +1 -1
- package/dist/repo/projects.js +4 -29
- package/dist/repo/projects.js.map +1 -1
- package/dist/repo/saved.d.ts +9 -0
- package/dist/repo/saved.d.ts.map +1 -0
- package/dist/repo/saved.js +29 -0
- package/dist/repo/saved.js.map +1 -0
- package/dist/repo/scim-tokens.d.ts +20 -0
- package/dist/repo/scim-tokens.d.ts.map +1 -0
- package/dist/repo/scim-tokens.js +32 -0
- package/dist/repo/scim-tokens.js.map +1 -0
- package/dist/repo/services.d.ts.map +1 -1
- package/dist/repo/services.js +2 -1
- package/dist/repo/services.js.map +1 -1
- package/dist/repo/settings.d.ts +30 -0
- package/dist/repo/settings.d.ts.map +1 -0
- package/dist/repo/settings.js +55 -0
- package/dist/repo/settings.js.map +1 -0
- package/dist/repo/slos.d.ts +10 -0
- package/dist/repo/slos.d.ts.map +1 -0
- package/dist/repo/slos.js +27 -0
- package/dist/repo/slos.js.map +1 -0
- package/dist/repo/sourcemaps.d.ts +9 -0
- package/dist/repo/sourcemaps.d.ts.map +1 -0
- package/dist/repo/sourcemaps.js +34 -0
- package/dist/repo/sourcemaps.js.map +1 -0
- package/dist/repo/tags.d.ts +11 -0
- package/dist/repo/tags.d.ts.map +1 -0
- package/dist/repo/tags.js +33 -0
- package/dist/repo/tags.js.map +1 -0
- package/dist/repo/trace-read.d.ts.map +1 -1
- package/dist/repo/trace-read.js +3 -1
- package/dist/repo/trace-read.js.map +1 -1
- package/dist/repo/trace-write.d.ts +1 -1
- package/dist/repo/trace-write.d.ts.map +1 -1
- package/dist/repo/trace-write.js +11 -5
- package/dist/repo/trace-write.js.map +1 -1
- package/dist/repo/uptime.d.ts +21 -0
- package/dist/repo/uptime.d.ts.map +1 -0
- package/dist/repo/uptime.js +53 -0
- package/dist/repo/uptime.js.map +1 -0
- package/dist/routes/alerts.d.ts.map +1 -1
- package/dist/routes/alerts.js +65 -66
- package/dist/routes/alerts.js.map +1 -1
- package/dist/routes/apps.d.ts +20 -0
- package/dist/routes/apps.d.ts.map +1 -0
- package/dist/routes/apps.js +53 -0
- package/dist/routes/apps.js.map +1 -0
- package/dist/routes/billing.d.ts +4 -0
- package/dist/routes/billing.d.ts.map +1 -0
- package/dist/routes/billing.js +51 -0
- package/dist/routes/billing.js.map +1 -0
- package/dist/routes/data.d.ts.map +1 -1
- package/dist/routes/data.js +16 -7
- package/dist/routes/data.js.map +1 -1
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +24 -0
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/ingest.d.ts +3 -1
- package/dist/routes/ingest.d.ts.map +1 -1
- package/dist/routes/ingest.js +55 -14
- package/dist/routes/ingest.js.map +1 -1
- package/dist/routes/issues.d.ts +4 -0
- package/dist/routes/issues.d.ts.map +1 -0
- package/dist/routes/issues.js +34 -0
- package/dist/routes/issues.js.map +1 -0
- package/dist/routes/keys.d.ts +4 -0
- package/dist/routes/keys.d.ts.map +1 -0
- package/dist/routes/keys.js +70 -0
- package/dist/routes/keys.js.map +1 -0
- package/dist/routes/mcp.d.ts.map +1 -1
- package/dist/routes/mcp.js +60 -23
- package/dist/routes/mcp.js.map +1 -1
- package/dist/routes/me.d.ts.map +1 -1
- package/dist/routes/me.js +15 -5
- package/dist/routes/me.js.map +1 -1
- package/dist/routes/metrics.js +1 -1
- package/dist/routes/metrics.js.map +1 -1
- package/dist/routes/models.d.ts +7 -1
- package/dist/routes/models.d.ts.map +1 -1
- package/dist/routes/models.js +55 -19
- package/dist/routes/models.js.map +1 -1
- package/dist/routes/notify.d.ts.map +1 -1
- package/dist/routes/notify.js +3 -1
- package/dist/routes/notify.js.map +1 -1
- package/dist/routes/oauth-meta.d.ts +7 -0
- package/dist/routes/oauth-meta.d.ts.map +1 -0
- package/dist/routes/oauth-meta.js +52 -0
- package/dist/routes/oauth-meta.js.map +1 -0
- package/dist/routes/orgs.d.ts.map +1 -1
- package/dist/routes/orgs.js +23 -7
- package/dist/routes/orgs.js.map +1 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +31 -22
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/saved.d.ts +4 -0
- package/dist/routes/saved.d.ts.map +1 -0
- package/dist/routes/saved.js +56 -0
- package/dist/routes/saved.js.map +1 -0
- package/dist/routes/scim.d.ts +4 -0
- package/dist/routes/scim.d.ts.map +1 -0
- package/dist/routes/scim.js +37 -0
- package/dist/routes/scim.js.map +1 -0
- package/dist/routes/search.d.ts.map +1 -1
- package/dist/routes/search.js +8 -5
- package/dist/routes/search.js.map +1 -1
- package/dist/routes/settings.d.ts +4 -0
- package/dist/routes/settings.d.ts.map +1 -0
- package/dist/routes/settings.js +39 -0
- package/dist/routes/settings.js.map +1 -0
- package/dist/routes/shares.d.ts +3 -0
- package/dist/routes/shares.d.ts.map +1 -1
- package/dist/routes/shares.js +28 -15
- package/dist/routes/shares.js.map +1 -1
- package/dist/routes/slos.d.ts +4 -0
- package/dist/routes/slos.d.ts.map +1 -0
- package/dist/routes/slos.js +76 -0
- package/dist/routes/slos.js.map +1 -0
- package/dist/routes/sourcemaps.d.ts +9 -0
- package/dist/routes/sourcemaps.d.ts.map +1 -0
- package/dist/routes/sourcemaps.js +54 -0
- package/dist/routes/sourcemaps.js.map +1 -0
- package/dist/routes/status.d.ts +4 -0
- package/dist/routes/status.d.ts.map +1 -0
- package/dist/routes/status.js +60 -0
- package/dist/routes/status.js.map +1 -0
- package/dist/routes/tags.d.ts +4 -0
- package/dist/routes/tags.d.ts.map +1 -0
- package/dist/routes/tags.js +81 -0
- package/dist/routes/tags.js.map +1 -0
- package/dist/routes/uptime.d.ts +4 -0
- package/dist/routes/uptime.d.ts.map +1 -0
- package/dist/routes/uptime.js +71 -0
- package/dist/routes/uptime.js.map +1 -0
- package/dist/scale-exec.d.ts +3 -2
- package/dist/scale-exec.d.ts.map +1 -1
- package/dist/scale-exec.js +5 -4
- package/dist/scale-exec.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +30 -7
- package/dist/server.js.map +1 -1
- package/dist/settle.d.ts +6 -3
- package/dist/settle.d.ts.map +1 -1
- package/dist/settle.js +11 -8
- package/dist/settle.js.map +1 -1
- package/dist/telemetry/ch/admin.d.ts +8 -4
- package/dist/telemetry/ch/admin.d.ts.map +1 -1
- package/dist/telemetry/ch/admin.js +33 -16
- package/dist/telemetry/ch/admin.js.map +1 -1
- package/dist/telemetry/ch/queue.d.ts +6 -4
- package/dist/telemetry/ch/queue.d.ts.map +1 -1
- package/dist/telemetry/ch/queue.js +13 -9
- package/dist/telemetry/ch/queue.js.map +1 -1
- package/dist/telemetry/ch/read.d.ts.map +1 -1
- package/dist/telemetry/ch/read.js +3 -1
- package/dist/telemetry/ch/read.js.map +1 -1
- package/dist/telemetry/ch/rebuild.d.ts +23 -0
- package/dist/telemetry/ch/rebuild.d.ts.map +1 -0
- package/dist/telemetry/ch/rebuild.js +65 -0
- package/dist/telemetry/ch/rebuild.js.map +1 -0
- package/dist/telemetry/ch/schema-facts.d.ts +1 -1
- package/dist/telemetry/ch/schema-facts.d.ts.map +1 -1
- package/dist/telemetry/ch/schema-facts.js +8 -2
- package/dist/telemetry/ch/schema-facts.js.map +1 -1
- package/dist/telemetry/ch/schema-raw.d.ts +2 -0
- package/dist/telemetry/ch/schema-raw.d.ts.map +1 -1
- package/dist/telemetry/ch/schema-raw.js +2 -0
- package/dist/telemetry/ch/schema-raw.js.map +1 -1
- package/dist/telemetry/ch/schema.d.ts.map +1 -1
- package/dist/telemetry/ch/schema.js +2 -2
- package/dist/telemetry/ch/schema.js.map +1 -1
- package/dist/telemetry/ch/settle-pool.d.ts +24 -0
- package/dist/telemetry/ch/settle-pool.d.ts.map +1 -0
- package/dist/telemetry/ch/settle-pool.js +58 -0
- package/dist/telemetry/ch/settle-pool.js.map +1 -0
- package/dist/telemetry/ch/settle-rows.d.ts +7 -4
- package/dist/telemetry/ch/settle-rows.d.ts.map +1 -1
- package/dist/telemetry/ch/settle-rows.js +15 -8
- package/dist/telemetry/ch/settle-rows.js.map +1 -1
- package/dist/telemetry/ch/settle-work.d.ts +21 -0
- package/dist/telemetry/ch/settle-work.d.ts.map +1 -0
- package/dist/telemetry/ch/settle-work.js +52 -0
- package/dist/telemetry/ch/settle-work.js.map +1 -0
- package/dist/telemetry/ch/settle-worker.d.ts +2 -0
- package/dist/telemetry/ch/settle-worker.d.ts.map +1 -0
- package/dist/telemetry/ch/settle-worker.js +10 -0
- package/dist/telemetry/ch/settle-worker.js.map +1 -0
- package/dist/telemetry/ch/settle.d.ts +17 -3
- package/dist/telemetry/ch/settle.d.ts.map +1 -1
- package/dist/telemetry/ch/settle.js +15 -56
- package/dist/telemetry/ch/settle.js.map +1 -1
- package/dist/telemetry/ch/store.d.ts +12 -1
- package/dist/telemetry/ch/store.d.ts.map +1 -1
- package/dist/telemetry/ch/store.js +37 -8
- package/dist/telemetry/ch/store.js.map +1 -1
- package/dist/telemetry/ch/util.d.ts +7 -0
- package/dist/telemetry/ch/util.d.ts.map +1 -1
- package/dist/telemetry/ch/util.js +4 -0
- package/dist/telemetry/ch/util.js.map +1 -1
- package/dist/telemetry/ch/write.d.ts +2 -1
- package/dist/telemetry/ch/write.d.ts.map +1 -1
- package/dist/telemetry/ch/write.js +10 -10
- package/dist/telemetry/ch/write.js.map +1 -1
- package/dist/telemetry/index.d.ts +4 -1
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/index.js +8 -3
- package/dist/telemetry/index.js.map +1 -1
- package/dist/telemetry/pg-store.d.ts.map +1 -1
- package/dist/telemetry/pg-store.js +13 -8
- package/dist/telemetry/pg-store.js.map +1 -1
- package/dist/telemetry/store.d.ts +13 -2
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/uptime/headers.d.ts +6 -0
- package/dist/uptime/headers.d.ts.map +1 -0
- package/dist/uptime/headers.js +25 -0
- package/dist/uptime/headers.js.map +1 -0
- package/dist/uptime/run.d.ts +9 -0
- package/dist/uptime/run.d.ts.map +1 -0
- package/dist/uptime/run.js +40 -0
- package/dist/uptime/run.js.map +1 -0
- package/package.json +9 -5
- package/dist/alerts/notify.d.ts +0 -28
- package/dist/alerts/notify.d.ts.map +0 -1
- package/dist/alerts/notify.js +0 -52
- package/dist/alerts/notify.js.map +0 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { HttpError } from "../http/http.js";
|
|
2
|
+
import { orgHas, orgLimits } from "../repo/billing.js";
|
|
3
|
+
import { PLANS, planFor } from "./plans.js";
|
|
4
|
+
export const FEATURE_NAME = { sso: "Single sign-on", scim: "SCIM provisioning", auditExport: "Audit log export" };
|
|
5
|
+
/** What a 402 says: the feature, and the plan it needs. */
|
|
6
|
+
export function planRequired(feature) {
|
|
7
|
+
const plan = planFor(feature);
|
|
8
|
+
return { message: `${FEATURE_NAME[feature]} needs the ${PLANS[plan].name} plan. Upgrade on the Billing page.`, plan };
|
|
9
|
+
}
|
|
10
|
+
/** 402 with the plan it needs, unless the organization's plan has the feature (always, with billing off). */
|
|
11
|
+
export async function requireFeature(app, orgId, feature) {
|
|
12
|
+
if (await orgHas(app.db, orgId, app.billing.on, feature))
|
|
13
|
+
return;
|
|
14
|
+
const { message, plan } = planRequired(feature);
|
|
15
|
+
throw new HttpError(402, message, { plan, feature });
|
|
16
|
+
}
|
|
17
|
+
/** The cheapest plan that keeps data `days` long. */
|
|
18
|
+
const planForDays = (days) => ["team", "business", "enterprise"].find((p) => PLANS[p].maxRetentionDays >= days) ?? "enterprise";
|
|
19
|
+
/** 402 when the retention is longer than the plan allows. */
|
|
20
|
+
export async function requireRetention(app, orgId, days) {
|
|
21
|
+
const limits = await orgLimits(app.db, orgId, app.billing.on);
|
|
22
|
+
if (days <= limits.maxRetentionDays)
|
|
23
|
+
return;
|
|
24
|
+
const plan = planForDays(days);
|
|
25
|
+
throw new HttpError(402, `The ${limits.plan.name} plan keeps data up to ${limits.maxRetentionDays} days. ${days} days needs the ${PLANS[plan].name} plan.`, { plan, maxRetentionDays: limits.maxRetentionDays });
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/billing/gate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAgB,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1D,MAAM,CAAC,MAAM,YAAY,GAA4B,EAAE,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,mBAAmB,EAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC;AAE3I,2DAA2D;AAC3D,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,cAAc,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,qCAAqC,EAAE,IAAI,EAAE,CAAC;AACxH,CAAC;AAED,6GAA6G;AAC7G,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAa,EAAE,KAAa,EAAE,OAAgB;IACjF,IAAI,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC;QAAE,OAAO;IACjE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,qDAAqD;AACrD,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE,CAAE,CAAC,MAAM,EAAE,UAAU,EAAE,YAAY,CAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,gBAAgB,IAAI,IAAI,CAAC,IAAI,YAAY,CAAC;AAEnJ,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAa,EAAE,KAAa,EAAE,IAAY;IAC/E,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9D,IAAI,IAAI,IAAI,MAAM,CAAC,gBAAgB;QAAE,OAAO;IAC5C,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,0BAA0B,MAAM,CAAC,gBAAgB,UAAU,IAAI,mBAAmB,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,QAAQ,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;AACnN,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Queryable } from "../db/db.js";
|
|
2
|
+
import { type OrgBilling } from "../repo/billing.js";
|
|
3
|
+
import { type Limits } from "./plans.js";
|
|
4
|
+
import { type UsageMeter } from "./usage.js";
|
|
5
|
+
export interface UsageState {
|
|
6
|
+
billing: OrgBilling;
|
|
7
|
+
limits: Limits;
|
|
8
|
+
monthGb: number;
|
|
9
|
+
/** Why ingest is stopped, or null. */
|
|
10
|
+
blocked: string | null;
|
|
11
|
+
/** "free" or "cap" when blocked. */
|
|
12
|
+
reason: "free" | "cap" | null;
|
|
13
|
+
}
|
|
14
|
+
/** The block, if any, for a plan and this month's GB. */
|
|
15
|
+
export declare function blockOf(b: OrgBilling, limits: Limits, monthGb: number): Pick<UsageState, "blocked" | "reason">;
|
|
16
|
+
/** Plans cached for a minute per instance, so ingest does not read orgs on every call. */
|
|
17
|
+
export declare class Limiter {
|
|
18
|
+
#private;
|
|
19
|
+
private readonly db;
|
|
20
|
+
private readonly usage;
|
|
21
|
+
private readonly on;
|
|
22
|
+
private readonly now;
|
|
23
|
+
constructor(db: Queryable, usage: UsageMeter, on: boolean, now: () => number);
|
|
24
|
+
forget(orgId: string): void;
|
|
25
|
+
state(orgId: string): Promise<UsageState | null>;
|
|
26
|
+
/** The message for a 429 when ingest is stopped, else null. The first block of a month goes to the audit log. */
|
|
27
|
+
blocked(orgId: string): Promise<string | null>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/billing/limits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAE,KAAK,UAAU,EAAc,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAgB,KAAK,MAAM,EAA0B,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAW,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAMtD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,oCAAoC;IACpC,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAAC;CAC/B;AAID,yDAAyD;AACzD,wBAAgB,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,GAAG,QAAQ,CAAC,CAS9G;AAED,0FAA0F;AAC1F,qBAAa,OAAO;;IAMhB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAJtB,YACmB,EAAE,EAAE,SAAS,EACb,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,OAAO,EACX,GAAG,EAAE,MAAM,MAAM,EAChC;IAEJ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE1B;IAEK,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAQrD;IAED,iHAAiH;IAC3G,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMnD;CAUF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { audit } from "../repo/audit.js";
|
|
2
|
+
import { orgBilling } from "../repo/billing.js";
|
|
3
|
+
import { BYTES_PER_GB, limitsOf, overageCents } from "./plans.js";
|
|
4
|
+
import { monthOf } from "./usage.js";
|
|
5
|
+
// Whether an organization may send more data this month: the Free cap and the optional spend cap on Team and Business.
|
|
6
|
+
const PLAN_TTL_MS = 60_000;
|
|
7
|
+
const usd = (cents) => `$${(cents / 100).toFixed(cents % 100 ? 2 : 0)}`;
|
|
8
|
+
/** The block, if any, for a plan and this month's GB. */
|
|
9
|
+
export function blockOf(b, limits, monthGb) {
|
|
10
|
+
const included = limits.includedGb;
|
|
11
|
+
if (limits.plan.id === "free" && included !== null && monthGb >= included) {
|
|
12
|
+
return { reason: "free", blocked: `This organization reached the Free plan's ${included} GB for this month. Data is accepted again on the 1st (UTC), or upgrade on the Billing page.` };
|
|
13
|
+
}
|
|
14
|
+
if (limits.plan.overage && included !== null && b.spendCapCents !== null && overageCents(monthGb - included) >= b.spendCapCents) {
|
|
15
|
+
return { reason: "cap", blocked: `This organization reached its monthly spend cap of ${usd(b.spendCapCents)}. Raise the cap on the Billing page, or data is accepted again on the 1st (UTC).` };
|
|
16
|
+
}
|
|
17
|
+
return { reason: null, blocked: null };
|
|
18
|
+
}
|
|
19
|
+
/** Plans cached for a minute per instance, so ingest does not read orgs on every call. */
|
|
20
|
+
export class Limiter {
|
|
21
|
+
db;
|
|
22
|
+
usage;
|
|
23
|
+
on;
|
|
24
|
+
now;
|
|
25
|
+
#plans = new Map();
|
|
26
|
+
/** Blocks already written to the audit log, by "orgId|month|reason". */
|
|
27
|
+
#logged = new Set();
|
|
28
|
+
constructor(db, usage, on, now) {
|
|
29
|
+
this.db = db;
|
|
30
|
+
this.usage = usage;
|
|
31
|
+
this.on = on;
|
|
32
|
+
this.now = now;
|
|
33
|
+
}
|
|
34
|
+
forget(orgId) {
|
|
35
|
+
this.#plans.delete(orgId);
|
|
36
|
+
}
|
|
37
|
+
async state(orgId) {
|
|
38
|
+
const hit = this.#plans.get(orgId);
|
|
39
|
+
const b = hit && this.now() - hit.at < PLAN_TTL_MS ? hit.b : await orgBilling(this.db, orgId);
|
|
40
|
+
if (!b)
|
|
41
|
+
return null;
|
|
42
|
+
if (!hit || hit.b !== b)
|
|
43
|
+
this.#plans.set(orgId, { b, at: this.now() });
|
|
44
|
+
const limits = limitsOf(b, this.on);
|
|
45
|
+
const monthGb = (await this.usage.monthBytes(orgId)) / BYTES_PER_GB;
|
|
46
|
+
return { billing: b, limits, monthGb, ...(this.on ? blockOf(b, limits, monthGb) : { blocked: null, reason: null }) };
|
|
47
|
+
}
|
|
48
|
+
/** The message for a 429 when ingest is stopped, else null. The first block of a month goes to the audit log. */
|
|
49
|
+
async blocked(orgId) {
|
|
50
|
+
if (!this.on)
|
|
51
|
+
return null;
|
|
52
|
+
const s = await this.state(orgId);
|
|
53
|
+
if (!s?.blocked)
|
|
54
|
+
return null;
|
|
55
|
+
await this.#logOnce(orgId, s);
|
|
56
|
+
return s.blocked;
|
|
57
|
+
}
|
|
58
|
+
async #logOnce(orgId, s) {
|
|
59
|
+
const month = monthOf(this.now());
|
|
60
|
+
const key = `${orgId}|${month}|${s.reason}`;
|
|
61
|
+
if (this.#logged.has(key))
|
|
62
|
+
return;
|
|
63
|
+
this.#logged.add(key);
|
|
64
|
+
const fresh = await this.db.query("INSERT INTO usage_notices (org_id, month, kind, sent_ms) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING RETURNING org_id", [orgId, month, `blocked-${s.reason}`, this.now()]);
|
|
65
|
+
if (fresh.length)
|
|
66
|
+
await audit(this.db, orgId, "system", "ingest.blocked", { reason: s.reason, month, gb: Math.round(s.monthGb * 100) / 100 }, this.now());
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.js","sourceRoot":"","sources":["../../src/billing/limits.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notices.d.ts","sourceRoot":"","sources":["../../src/billing/notices.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAmC1C,iFAAiF;AACjF,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CASnE"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { spendCapReached, usageNotice } from "../mail/emails-billing.js";
|
|
2
|
+
import { renderMail } from "../mail/templates.js";
|
|
3
|
+
import { monthOf } from "./usage.js";
|
|
4
|
+
// Mail to owners and admins at 80% and 100% of the included GB, and when the spend cap stops ingest: once a month each.
|
|
5
|
+
/** True the first time this organization reaches `kind` this month, on any instance. */
|
|
6
|
+
async function claim(app, orgId, month, kind) {
|
|
7
|
+
const rows = await app.db.query("INSERT INTO usage_notices (org_id, month, kind, sent_ms) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING RETURNING org_id", [orgId, month, kind, app.config.now()]);
|
|
8
|
+
return rows.length > 0;
|
|
9
|
+
}
|
|
10
|
+
async function tell(app, orgId, content) {
|
|
11
|
+
const people = await app.db.query("SELECT u.email FROM members m JOIN users u ON u.id = m.user_id WHERE m.org_id = $1 AND m.role IN ('owner', 'admin') AND (u.email_verified OR NOT $2) ORDER BY u.email", [orgId, app.mailer.live]);
|
|
12
|
+
for (const p of people)
|
|
13
|
+
app.mailer.send(renderMail(p.email, content));
|
|
14
|
+
}
|
|
15
|
+
async function checkOrg(app, org, month, url) {
|
|
16
|
+
const s = await app.billing.limits.state(org.id);
|
|
17
|
+
const included = s?.limits.includedGb;
|
|
18
|
+
if (!s || !included)
|
|
19
|
+
return;
|
|
20
|
+
const percent = (s.monthGb / included) * 100;
|
|
21
|
+
const notice = (level) => usageNotice({ org: org.name, plan: s.limits.plan.name, usedGb: s.monthGb, includedGb: included, percent: level, overage: s.limits.plan.overage, url });
|
|
22
|
+
// At 100%, the 80% notice counts as sent, so a fast month never sends both.
|
|
23
|
+
if (percent >= 100 && (await claim(app, org.id, month, "mail100")))
|
|
24
|
+
await claim(app, org.id, month, "mail80").then(() => tell(app, org.id, notice(100)));
|
|
25
|
+
else if (percent >= 80 && (await claim(app, org.id, month, "mail80")))
|
|
26
|
+
await tell(app, org.id, notice(80));
|
|
27
|
+
if (s.reason === "cap" && (await claim(app, org.id, month, "mail-cap")))
|
|
28
|
+
await tell(app, org.id, spendCapReached(org.name, (s.billing.spendCapCents ?? 0) / 100, url));
|
|
29
|
+
}
|
|
30
|
+
/** Every organization that sent data this month. Runs after each usage flush. */
|
|
31
|
+
export async function sendUsageNotices(app) {
|
|
32
|
+
if (!app.billing.on)
|
|
33
|
+
return;
|
|
34
|
+
const month = monthOf(app.config.now());
|
|
35
|
+
const orgs = await app.db.query("SELECT o.id, o.name FROM orgs o WHERE o.plan IN ('free', 'team', 'business', 'enterprise') AND EXISTS (SELECT 1 FROM usage_daily u WHERE u.org_id = o.id AND u.day LIKE $1)", [`${month}-%`]);
|
|
36
|
+
const url = `${app.baseUrl()}/_wizelens/#/team/billing`;
|
|
37
|
+
for (const org of orgs)
|
|
38
|
+
await checkOrg(app, org, month, url);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=notices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notices.js","sourceRoot":"","sources":["../../src/billing/notices.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Stripe } from "stripe";
|
|
2
|
+
/** The Stripe ids `wizelens-cloud stripe-setup` prints, passed back as `--stripe-prices` JSON. */
|
|
3
|
+
export interface StripePrices {
|
|
4
|
+
teamMonthly: string;
|
|
5
|
+
teamAnnual: string;
|
|
6
|
+
businessMonthly: string;
|
|
7
|
+
businessAnnual: string;
|
|
8
|
+
/** The graduated metered price on the GB meter, billed monthly. */
|
|
9
|
+
overage: string;
|
|
10
|
+
/** The meter's event name, `wizelens_gb`. */
|
|
11
|
+
meter: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const PRICE_KEYS: readonly (keyof StripePrices)[];
|
|
14
|
+
/** The Stripe calls the cloud makes. Tests pass a fake with the same shape. */
|
|
15
|
+
export type StripeClient = Stripe;
|
|
16
|
+
export interface BillingOptions {
|
|
17
|
+
/** Stripe's secret key (sk_ or rk_). Without it billing is off: every organization is unlimited. */
|
|
18
|
+
stripeSecretKey?: string;
|
|
19
|
+
/** The Stripe webhook's whsec_ signing secret. */
|
|
20
|
+
stripeWebhookSecret?: string;
|
|
21
|
+
/** Price and meter ids, as JSON text or an object. */
|
|
22
|
+
stripePrices?: string | StripePrices;
|
|
23
|
+
/** For tests: a Stripe client in place of the real one. */
|
|
24
|
+
stripeClient?: StripeClient;
|
|
25
|
+
}
|
|
26
|
+
export interface BillingConfig {
|
|
27
|
+
on: boolean;
|
|
28
|
+
stripeSecretKey?: string;
|
|
29
|
+
stripeWebhookSecret?: string;
|
|
30
|
+
prices?: StripePrices;
|
|
31
|
+
stripeClient?: StripeClient;
|
|
32
|
+
}
|
|
33
|
+
/** Billing is on only with a Stripe key; then the webhook secret, the prices, and a public URL must come too. */
|
|
34
|
+
export declare function resolveBilling(o: BillingOptions & {
|
|
35
|
+
publicUrl?: string;
|
|
36
|
+
}): BillingConfig;
|
|
37
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/billing/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,kGAAkG;AAClG,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,UAAU,EAAE,SAAS,CAAC,MAAM,YAAY,CAAC,EAA2F,CAAC;AAElJ,+EAA+E;AAC/E,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC,MAAM,WAAW,cAAc;IAC7B,oGAAoG;IACpG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kDAAkD;IAClD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;IACrC,2DAA2D;IAC3D,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAiBD,iHAAiH;AACjH,wBAAgB,cAAc,CAAC,CAAC,EAAE,cAAc,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CASxF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export const PRICE_KEYS = ["teamMonthly", "teamAnnual", "businessMonthly", "businessAnnual", "overage", "meter"];
|
|
2
|
+
function pricesOf(raw) {
|
|
3
|
+
let v = raw;
|
|
4
|
+
if (typeof raw === "string") {
|
|
5
|
+
try {
|
|
6
|
+
v = JSON.parse(raw);
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
throw new Error("--stripe-prices must be JSON, as `wizelens-cloud stripe-setup` prints it.");
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const o = (v ?? {});
|
|
13
|
+
const missing = PRICE_KEYS.filter((k) => typeof o[k] !== "string" || !o[k]);
|
|
14
|
+
if (missing.length)
|
|
15
|
+
throw new Error(`--stripe-prices is missing ${missing.join(", ")}. Run wizelens-cloud stripe-setup to make them.`);
|
|
16
|
+
return Object.fromEntries(PRICE_KEYS.map((k) => [k, o[k]]));
|
|
17
|
+
}
|
|
18
|
+
/** Billing is on only with a Stripe key; then the webhook secret, the prices, and a public URL must come too. */
|
|
19
|
+
export function resolveBilling(o) {
|
|
20
|
+
if (!o.stripeSecretKey) {
|
|
21
|
+
if (o.stripeWebhookSecret || o.stripePrices)
|
|
22
|
+
throw new Error("--stripe-webhook-secret and --stripe-prices need --stripe-secret-key.");
|
|
23
|
+
return { on: false };
|
|
24
|
+
}
|
|
25
|
+
if (!/^(sk|rk)_/.test(o.stripeSecretKey))
|
|
26
|
+
throw new Error("--stripe-secret-key must be a Stripe secret key (it starts with sk_ or rk_).");
|
|
27
|
+
if (!o.stripeWebhookSecret?.startsWith("whsec_"))
|
|
28
|
+
throw new Error("Billing needs --stripe-webhook-secret (it starts with whsec_).");
|
|
29
|
+
if (!o.publicUrl)
|
|
30
|
+
throw new Error("Billing needs --public-url, so Stripe sends people back to this cloud.");
|
|
31
|
+
return { on: true, stripeSecretKey: o.stripeSecretKey, stripeWebhookSecret: o.stripeWebhookSecret, prices: pricesOf(o.stripePrices), stripeClient: o.stripeClient };
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/billing/options.ts"],"names":[],"mappings":"AAcA,MAAM,CAAC,MAAM,UAAU,GAAoC,CAAC,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAwBlJ,SAAS,QAAQ,CAAC,GAAsC;IACtD,IAAI,CAAC,GAAY,GAAG,CAAC;IACrB,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,2EAA2E,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAA4B,CAAC;IAC/C,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,IAAI,OAAO,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;IACvI,OAAO,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAA4B,CAAC;AACzF,CAAC;AAED,iHAAiH;AACjH,MAAM,UAAU,cAAc,CAAC,CAA0C;IACvE,IAAI,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,CAAC,mBAAmB,IAAI,CAAC,CAAC,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;QACtI,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;IACvB,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAC;IAC1I,IAAI,CAAC,CAAC,CAAC,mBAAmB,EAAE,UAAU,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACpI,IAAI,CAAC,CAAC,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;IAC5G,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC,eAAe,EAAE,mBAAmB,EAAE,CAAC,CAAC,mBAAmB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC;AACtK,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export type PlanId = "unlimited" | "free" | "team" | "business" | "enterprise";
|
|
2
|
+
export type Feature = "sso" | "scim" | "auditExport";
|
|
3
|
+
/** The plans people buy through Stripe. */
|
|
4
|
+
export type PaidPlanId = "team" | "business";
|
|
5
|
+
export interface Plan {
|
|
6
|
+
id: PlanId;
|
|
7
|
+
name: string;
|
|
8
|
+
/** Dollars per month; null when the price is set by hand (Enterprise) or there is none. */
|
|
9
|
+
monthlyUsd: number | null;
|
|
10
|
+
/** Dollars per year: 10 months' price for 12. */
|
|
11
|
+
annualUsd: number | null;
|
|
12
|
+
/** GB a month included; null means no limit. */
|
|
13
|
+
includedGb: number | null;
|
|
14
|
+
/** The longest retention the plan allows, in days. */
|
|
15
|
+
maxRetentionDays: number;
|
|
16
|
+
/** Past the included GB, data keeps coming and costs extra (Team and Business). False: ingest stops at the cap. */
|
|
17
|
+
overage: boolean;
|
|
18
|
+
features: Record<Feature, boolean>;
|
|
19
|
+
}
|
|
20
|
+
export declare const PLANS: Record<PlanId, Plan>;
|
|
21
|
+
export declare const PLAN_IDS: PlanId[];
|
|
22
|
+
export declare const PAID_PLANS: readonly PaidPlanId[];
|
|
23
|
+
export declare const isPlanId: (v: unknown) => v is PlanId;
|
|
24
|
+
export declare const isPaidPlan: (v: unknown) => v is PaidPlanId;
|
|
25
|
+
/** Extra data, graduated, counted on the GB above the plan's included GB each month: first 500 at $0.30, next 1,500 at $0.20, then $0.10. */
|
|
26
|
+
export declare const OVERAGE_TIERS: readonly {
|
|
27
|
+
upToGb: number | null;
|
|
28
|
+
centsPerGb: number;
|
|
29
|
+
}[];
|
|
30
|
+
/** A GB is 10^9 bytes of request body as sent, before compression is undone. */
|
|
31
|
+
export declare const BYTES_PER_GB = 1000000000;
|
|
32
|
+
/** What `extraGb` above the included GB costs, in cents, with the graduated tiers. */
|
|
33
|
+
export declare function overageCents(extraGb: number): number;
|
|
34
|
+
/** One organization's billing columns. */
|
|
35
|
+
export interface OrgPlanRow {
|
|
36
|
+
plan: PlanId;
|
|
37
|
+
/** Enterprise only: the GB a month and the retention set by hand. */
|
|
38
|
+
planGb: number | null;
|
|
39
|
+
planRetentionDays: number | null;
|
|
40
|
+
}
|
|
41
|
+
/** The limits that apply now: everything is unlimited while billing is off. */
|
|
42
|
+
export interface Limits {
|
|
43
|
+
plan: Plan;
|
|
44
|
+
includedGb: number | null;
|
|
45
|
+
maxRetentionDays: number;
|
|
46
|
+
}
|
|
47
|
+
export declare function limitsOf(row: OrgPlanRow, billingOn: boolean): Limits;
|
|
48
|
+
/** The cheapest plan with a feature, for a 402 answer and the upgrade prompt. */
|
|
49
|
+
export declare const planFor: (feature: Feature) => PaidPlanId | "enterprise";
|
|
50
|
+
//# sourceMappingURL=plans.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plans.d.ts","sourceRoot":"","sources":["../../src/billing/plans.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,MAAM,GAAG,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,CAAC;AAC/E,MAAM,MAAM,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,aAAa,CAAC;AACrD,2CAA2C;AAC3C,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC;AAE7C,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,2FAA2F;IAC3F,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,iDAAiD;IACjD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gDAAgD;IAChD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,sDAAsD;IACtD,gBAAgB,EAAE,MAAM,CAAC;IACzB,mHAAmH;IACnH,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;CACpC;AAKD,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAMtC,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAyB,MAAM,EAAE,CAAC;AACvD,eAAO,MAAM,UAAU,EAAE,SAAS,UAAU,EAAyB,CAAC;AACtE,eAAO,MAAM,QAAQ,MAAO,OAAO,KAAG,CAAC,IAAI,MAA6C,CAAC;AACzF,eAAO,MAAM,UAAU,MAAO,OAAO,KAAG,CAAC,IAAI,UAA8C,CAAC;AAE5F,6IAA6I;AAC7I,eAAO,MAAM,aAAa,EAAE,SAAS;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EAIjF,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,YAAY,aAAM,CAAC;AAEhC,sFAAsF;AACtF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAYpD;AAED,0CAA0C;AAC1C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,+EAA+E;AAC/E,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,IAAI,CAAC;IACX,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAIpE;AAED,iFAAiF;AACjF,eAAO,MAAM,OAAO,YAAa,OAAO,KAAG,UAAU,GAAG,YAAsH,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Cloud plans, prices, and limits in one place (docs/BILLING-PLAN.md). A first version: change them here only.
|
|
2
|
+
const none = { sso: false, scim: false, auditExport: false };
|
|
3
|
+
const all = { sso: true, scim: true, auditExport: true };
|
|
4
|
+
export const PLANS = {
|
|
5
|
+
unlimited: { id: "unlimited", name: "Unlimited", monthlyUsd: null, annualUsd: null, includedGb: null, maxRetentionDays: 400, overage: false, features: all },
|
|
6
|
+
free: { id: "free", name: "Free", monthlyUsd: 0, annualUsd: 0, includedGb: 10, maxRetentionDays: 14, overage: false, features: none },
|
|
7
|
+
team: { id: "team", name: "Team", monthlyUsd: 29, annualUsd: 290, includedGb: 50, maxRetentionDays: 30, overage: true, features: none },
|
|
8
|
+
business: { id: "business", name: "Business", monthlyUsd: 99, annualUsd: 990, includedGb: 150, maxRetentionDays: 90, overage: true, features: all },
|
|
9
|
+
enterprise: { id: "enterprise", name: "Enterprise", monthlyUsd: null, annualUsd: null, includedGb: null, maxRetentionDays: 400, overage: false, features: all },
|
|
10
|
+
};
|
|
11
|
+
export const PLAN_IDS = Object.keys(PLANS);
|
|
12
|
+
export const PAID_PLANS = ["team", "business"];
|
|
13
|
+
export const isPlanId = (v) => typeof v === "string" && v in PLANS;
|
|
14
|
+
export const isPaidPlan = (v) => v === "team" || v === "business";
|
|
15
|
+
/** Extra data, graduated, counted on the GB above the plan's included GB each month: first 500 at $0.30, next 1,500 at $0.20, then $0.10. */
|
|
16
|
+
export const OVERAGE_TIERS = [
|
|
17
|
+
{ upToGb: 500, centsPerGb: 30 },
|
|
18
|
+
{ upToGb: 2000, centsPerGb: 20 },
|
|
19
|
+
{ upToGb: null, centsPerGb: 10 },
|
|
20
|
+
];
|
|
21
|
+
/** A GB is 10^9 bytes of request body as sent, before compression is undone. */
|
|
22
|
+
export const BYTES_PER_GB = 1e9;
|
|
23
|
+
/** What `extraGb` above the included GB costs, in cents, with the graduated tiers. */
|
|
24
|
+
export function overageCents(extraGb) {
|
|
25
|
+
let left = Math.max(0, extraGb);
|
|
26
|
+
let from = 0;
|
|
27
|
+
let cents = 0;
|
|
28
|
+
for (const t of OVERAGE_TIERS) {
|
|
29
|
+
const size = t.upToGb === null ? left : Math.min(left, t.upToGb - from);
|
|
30
|
+
cents += size * t.centsPerGb;
|
|
31
|
+
left -= size;
|
|
32
|
+
if (t.upToGb !== null)
|
|
33
|
+
from = t.upToGb;
|
|
34
|
+
if (left <= 0)
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
return Math.round(cents * 100) / 100;
|
|
38
|
+
}
|
|
39
|
+
export function limitsOf(row, billingOn) {
|
|
40
|
+
const plan = PLANS[billingOn ? row.plan : "unlimited"] ?? PLANS.free;
|
|
41
|
+
if (plan.id !== "enterprise")
|
|
42
|
+
return { plan, includedGb: plan.includedGb, maxRetentionDays: plan.maxRetentionDays };
|
|
43
|
+
return { plan, includedGb: row.planGb, maxRetentionDays: Math.min(400, row.planRetentionDays ?? 400) };
|
|
44
|
+
}
|
|
45
|
+
/** The cheapest plan with a feature, for a 402 answer and the upgrade prompt. */
|
|
46
|
+
export const planFor = (feature) => (PLANS.team.features[feature] ? "team" : PLANS.business.features[feature] ? "business" : "enterprise");
|
|
47
|
+
//# sourceMappingURL=plans.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plans.js","sourceRoot":"","sources":["../../src/billing/plans.ts"],"names":[],"mappings":"AAAA,+GAA+G;AAuB/G,MAAM,IAAI,GAA6B,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;AACvF,MAAM,GAAG,GAA6B,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AAEnF,MAAM,CAAC,MAAM,KAAK,GAAyB;IACzC,SAAS,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE;IAC5J,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE;IACrI,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACvI,QAAQ,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,gBAAgB,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE;IACnJ,UAAU,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE;CAChK,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAa,CAAC;AACvD,MAAM,CAAC,MAAM,UAAU,GAA0B,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AACtE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAU,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,IAAI,KAAK,CAAC;AACzF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAU,EAAmB,EAAE,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,UAAU,CAAC;AAE5F,6IAA6I;AAC7I,MAAM,CAAC,MAAM,aAAa,GAA6D;IACrF,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE;IAC/B,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;IAChC,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;CACjC,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAC;AAEhC,sFAAsF;AACtF,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAChC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QACxE,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC;QAC7B,IAAI,IAAI,IAAI,CAAC;QACb,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI;YAAE,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC;QACvC,IAAI,IAAI,IAAI,CAAC;YAAE,MAAM;IACvB,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACvC,CAAC;AAiBD,MAAM,UAAU,QAAQ,CAAC,GAAe,EAAE,SAAkB;IAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC;IACrE,IAAI,IAAI,CAAC,EAAE,KAAK,YAAY;QAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC;IACpH,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,iBAAiB,IAAI,GAAG,CAAC,EAAE,CAAC;AACzG,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,OAAgB,EAA6B,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Queryable } from "../db/db.js";
|
|
2
|
+
import { type PlanId } from "./plans.js";
|
|
3
|
+
import type { StripeClient, StripePrices } from "./options.js";
|
|
4
|
+
export interface ReportDeps {
|
|
5
|
+
db: Queryable;
|
|
6
|
+
client: StripeClient;
|
|
7
|
+
prices: StripePrices;
|
|
8
|
+
now: () => number;
|
|
9
|
+
}
|
|
10
|
+
interface PaidOrg {
|
|
11
|
+
id: string;
|
|
12
|
+
plan: PlanId;
|
|
13
|
+
plan_gb: number | null;
|
|
14
|
+
plan_retention_days: number | null;
|
|
15
|
+
stripe_customer_id: string;
|
|
16
|
+
}
|
|
17
|
+
/** Completed days from a week back to yesterday, oldest first. */
|
|
18
|
+
export declare function daysToReport(nowMs: number): string[];
|
|
19
|
+
/** Report one organization's unreported days. */
|
|
20
|
+
export declare function reportOrg(d: ReportDeps, org: PaidOrg): Promise<void>;
|
|
21
|
+
/** Every paid organization with a usage subscription. Returns how many it checked. */
|
|
22
|
+
export declare function reportUsage(d: ReportDeps): Promise<number>;
|
|
23
|
+
/** One organization by id, when it is paid, for the last report before its usage subscription ends. */
|
|
24
|
+
export declare function reportBeforeEnd(d: ReportDeps, orgId: string, plan: PlanId): Promise<void>;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/billing/report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAA0B,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAW/D,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,SAAS,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,GAAG,EAAE,MAAM,MAAM,CAAC;CACnB;AAED,UAAU,OAAO;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAGpD;AAqBD,iDAAiD;AACjD,wBAAsB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAI1E;AAED,sFAAsF;AACtF,wBAAsB,WAAW,CAAC,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAOhE;AAED,uGAAuG;AACvG,wBAAsB,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG/F"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { BYTES_PER_GB, limitsOf } from "./plans.js";
|
|
2
|
+
import { dayOf } from "./usage.js";
|
|
3
|
+
// Each finished UTC day, a paid organization's GB above its included GB goes to the Stripe meter once (wl-<org>-<day>, usage_reports).
|
|
4
|
+
const DAY_MS = 86_400_000;
|
|
5
|
+
/** A day is reported this long after it ends, once every instance flushed it, and well inside the hour Stripe keeps the invoice open. */
|
|
6
|
+
const SETTLE_MS = 5 * 60_000;
|
|
7
|
+
/** Days a rerun still catches up on (Stripe takes events up to 35 days old). */
|
|
8
|
+
const CATCH_UP_DAYS = 7;
|
|
9
|
+
/** Completed days from a week back to yesterday, oldest first. */
|
|
10
|
+
export function daysToReport(nowMs) {
|
|
11
|
+
const last = Math.floor((nowMs - SETTLE_MS) / DAY_MS) * DAY_MS - DAY_MS;
|
|
12
|
+
return Array.from({ length: CATCH_UP_DAYS }, (_, i) => dayOf(last - (CATCH_UP_DAYS - 1 - i) * DAY_MS));
|
|
13
|
+
}
|
|
14
|
+
/** Whole GB above the included GB from the 1st through `day`, less what was reported earlier that month. */
|
|
15
|
+
async function gbFor(q, org, day) {
|
|
16
|
+
const month = `${day.slice(0, 7)}-%`;
|
|
17
|
+
const [used] = await q.query("SELECT COALESCE(SUM(bytes), 0)::double precision AS b FROM usage_daily WHERE org_id = $1 AND day LIKE $2 AND day <= $3", [org.id, month, day]);
|
|
18
|
+
const [sent] = await q.query("SELECT COALESCE(SUM(gb), 0)::double precision AS gb FROM usage_reports WHERE org_id = $1 AND day LIKE $2", [org.id, month]);
|
|
19
|
+
const included = limitsOf({ plan: org.plan, planGb: org.plan_gb, planRetentionDays: org.plan_retention_days }, true).includedGb ?? Infinity;
|
|
20
|
+
const extra = Math.floor(Math.max(0, Number(used?.b ?? 0) / BYTES_PER_GB - included));
|
|
21
|
+
return Math.max(0, extra - Number(sent?.gb ?? 0));
|
|
22
|
+
}
|
|
23
|
+
async function reportDay(d, org, day) {
|
|
24
|
+
const gb = await gbFor(d.db, org, day);
|
|
25
|
+
if (gb > 0) {
|
|
26
|
+
const timestamp = Math.floor(Date.parse(`${day}T12:00:00Z`) / 1000);
|
|
27
|
+
await d.client.billing.meterEvents.create({ event_name: d.prices.meter, identifier: `wl-${org.id}-${day}`, timestamp, payload: { stripe_customer_id: org.stripe_customer_id, value: String(gb) } });
|
|
28
|
+
}
|
|
29
|
+
await d.db.query("INSERT INTO usage_reports (org_id, day, gb, reported_ms) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING", [org.id, day, gb, d.now()]);
|
|
30
|
+
}
|
|
31
|
+
/** Report one organization's unreported days. */
|
|
32
|
+
export async function reportOrg(d, org) {
|
|
33
|
+
const days = daysToReport(d.now());
|
|
34
|
+
const done = new Set((await d.db.query("SELECT day FROM usage_reports WHERE org_id = $1 AND day >= $2", [org.id, days[0]])).map((r) => r.day));
|
|
35
|
+
for (const day of days)
|
|
36
|
+
if (!done.has(day))
|
|
37
|
+
await reportDay(d, org, day);
|
|
38
|
+
}
|
|
39
|
+
/** Every paid organization with a usage subscription. Returns how many it checked. */
|
|
40
|
+
export async function reportUsage(d) {
|
|
41
|
+
const orgs = await d.db.query(`SELECT id, plan, plan_gb, plan_retention_days, stripe_customer_id FROM orgs
|
|
42
|
+
WHERE plan IN ('team', 'business') AND stripe_customer_id IS NOT NULL AND overage_subscription_id IS NOT NULL`);
|
|
43
|
+
for (const org of orgs)
|
|
44
|
+
await reportOrg(d, org);
|
|
45
|
+
return orgs.length;
|
|
46
|
+
}
|
|
47
|
+
/** One organization by id, when it is paid, for the last report before its usage subscription ends. */
|
|
48
|
+
export async function reportBeforeEnd(d, orgId, plan) {
|
|
49
|
+
const [row] = await d.db.query("SELECT id, plan_gb, plan_retention_days, stripe_customer_id FROM orgs WHERE id = $1 AND stripe_customer_id IS NOT NULL", [orgId]);
|
|
50
|
+
if (row && (plan === "team" || plan === "business"))
|
|
51
|
+
await reportOrg(d, { ...row, plan });
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/billing/report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { StripeDeps } from "./stripe-plugin.js";
|
|
2
|
+
import type { CloudConfig } from "../config.js";
|
|
3
|
+
import type { Db } from "../db/db.js";
|
|
4
|
+
import { Limiter } from "./limits.js";
|
|
5
|
+
import { UsageMeter } from "./usage.js";
|
|
6
|
+
/** Plans, usage, limits, and (with billing on) Stripe, for routes and jobs. */
|
|
7
|
+
export interface Billing {
|
|
8
|
+
/** False without a Stripe key: every organization is unlimited and no plan shows anywhere. */
|
|
9
|
+
readonly on: boolean;
|
|
10
|
+
readonly usage: UsageMeter;
|
|
11
|
+
readonly limits: Limiter;
|
|
12
|
+
/** The Stripe plugin's needs, with billing on. */
|
|
13
|
+
readonly stripe?: StripeDeps;
|
|
14
|
+
/** Forget a cached plan after a change, so limits apply at once on this instance. */
|
|
15
|
+
forget(orgId: string): void;
|
|
16
|
+
/** With billing on: mend missing usage subscriptions, then send unreported days to the Stripe meter (billing/report.ts). */
|
|
17
|
+
report?: () => Promise<number>;
|
|
18
|
+
}
|
|
19
|
+
export declare function createBilling(config: CloudConfig, db: Db): Promise<Billing>;
|
|
20
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/billing/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAItC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,+EAA+E;AAC/E,MAAM,WAAW,OAAO;IACtB,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,kDAAkD;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B,qFAAqF;IACrF,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,4HAA4H;IAC5H,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAChC;AAcD,wBAAsB,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAUjF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Limiter } from "./limits.js";
|
|
2
|
+
import { reportUsage } from "./report.js";
|
|
3
|
+
import { syncOrgPlan } from "./sync.js";
|
|
4
|
+
import { UsageMeter } from "./usage.js";
|
|
5
|
+
/** Paid organizations without a usage subscription (it failed to start, or someone canceled it in the portal) get it again. */
|
|
6
|
+
async function mend(db, sync) {
|
|
7
|
+
const rows = await db.query("SELECT id FROM orgs WHERE plan IN ('team', 'business') AND stripe_customer_id IS NOT NULL AND overage_subscription_id IS NULL");
|
|
8
|
+
for (const r of rows)
|
|
9
|
+
await sync(r.id).catch((err) => console.error(`[wizelens-cloud] usage subscription for ${r.id} failed:`, err));
|
|
10
|
+
}
|
|
11
|
+
async function stripeClientOf(config) {
|
|
12
|
+
if (config.billing.stripeClient)
|
|
13
|
+
return config.billing.stripeClient;
|
|
14
|
+
const { default: Stripe } = await import("stripe");
|
|
15
|
+
return new Stripe(config.billing.stripeSecretKey, { appInfo: { name: "WizeLens Cloud", url: "https://wizelens.com" }, maxNetworkRetries: 2 });
|
|
16
|
+
}
|
|
17
|
+
export async function createBilling(config, db) {
|
|
18
|
+
const usage = new UsageMeter(db, config.now);
|
|
19
|
+
const limits = new Limiter(db, usage, config.billing.on, config.now);
|
|
20
|
+
const forget = (orgId) => limits.forget(orgId);
|
|
21
|
+
if (!config.billing.on)
|
|
22
|
+
return { on: false, usage, limits, forget };
|
|
23
|
+
const client = await stripeClientOf(config);
|
|
24
|
+
const d = { db, client, prices: config.billing.prices, now: config.now };
|
|
25
|
+
const stripe = { client, webhookSecret: config.billing.stripeWebhookSecret, prices: d.prices, sync: async (orgId) => void (await syncOrgPlan(d, orgId, forget)) };
|
|
26
|
+
const report = async () => (await mend(db, stripe.sync), reportUsage(d));
|
|
27
|
+
return { on: true, usage, limits, stripe, forget, report };
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/billing/service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAgBxC,+HAA+H;AAC/H,KAAK,UAAU,IAAI,CAAC,EAAM,EAAE,IAAsC;IAChE,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,KAAK,CAAiB,+HAA+H,CAAC,CAAC;IAC7K,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,MAAM,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC;AAChJ,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,MAAmB;IAC/C,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY;QAAE,OAAO,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;IACpE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnD,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,eAAgB,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE,sBAAsB,EAAE,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC,CAAC;AACjJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAmB,EAAE,EAAM;IAC7D,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IACrE,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvD,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACpE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,CAAC,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,MAAO,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;IAC1E,MAAM,MAAM,GAAe,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,mBAAoB,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;IAC/K,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { BetterAuthPlugin } from "better-auth";
|
|
2
|
+
import type { AuthDeps } from "../auth/deps.js";
|
|
3
|
+
import type { StripeClient, StripePrices } from "./options.js";
|
|
4
|
+
/** What the Stripe plugin needs: the client, the webhook secret, the prices, and the plan sync that runs on every subscription change. */
|
|
5
|
+
export interface StripeDeps {
|
|
6
|
+
client: StripeClient;
|
|
7
|
+
webhookSecret: string;
|
|
8
|
+
prices: StripePrices;
|
|
9
|
+
/** Set orgs.plan from the organization's subscriptions (billing/sync.ts). */
|
|
10
|
+
sync(orgId: string): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
/** Better Auth's Stripe plugin: the organization is the customer, Checkout starts a plan, the portal changes or cancels it. */
|
|
13
|
+
export declare function stripePlugin(deps: AuthDeps, s: StripeDeps): BetterAuthPlugin;
|
|
14
|
+
//# sourceMappingURL=stripe-plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe-plugin.d.ts","sourceRoot":"","sources":["../../src/billing/stripe-plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE/D,0IAA0I;AAC1I,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,YAAY,CAAC;IACrB,6EAA6E;IAC7E,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAaD,+HAA+H;AAC/H,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,UAAU,GAAG,gBAAgB,CAuB5E"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { stripe } from "@better-auth/stripe";
|
|
2
|
+
import { can, isRole } from "../auth/roles.js";
|
|
3
|
+
import { stripeSchema } from "../auth/schema-names.js";
|
|
4
|
+
import { membership } from "../repo/orgs.js";
|
|
5
|
+
/** Only owners and admins of the organization buy, change, or cancel its plan. */
|
|
6
|
+
async function mayBill(deps, userId, orgId) {
|
|
7
|
+
const m = await membership(deps.db, userId, orgId);
|
|
8
|
+
return !!m && isRole(m.role) && can(m.role, "manage");
|
|
9
|
+
}
|
|
10
|
+
const plansOf = (p) => [
|
|
11
|
+
{ name: "team", priceId: p.teamMonthly, annualDiscountPriceId: p.teamAnnual },
|
|
12
|
+
{ name: "business", priceId: p.businessMonthly, annualDiscountPriceId: p.businessAnnual },
|
|
13
|
+
];
|
|
14
|
+
/** Better Auth's Stripe plugin: the organization is the customer, Checkout starts a plan, the portal changes or cancels it. */
|
|
15
|
+
export function stripePlugin(deps, s) {
|
|
16
|
+
const sync = async ({ subscription }) => s.sync(subscription.referenceId);
|
|
17
|
+
return stripe({
|
|
18
|
+
stripeClient: s.client,
|
|
19
|
+
stripeWebhookSecret: s.webhookSecret,
|
|
20
|
+
createCustomerOnSignUp: false,
|
|
21
|
+
schema: stripeSchema,
|
|
22
|
+
organization: {
|
|
23
|
+
enabled: true,
|
|
24
|
+
getCustomerCreateParams: async (org, ctx) => ({ email: ctx.context.session?.user.email, metadata: { wizelensOrgId: org.id } }),
|
|
25
|
+
},
|
|
26
|
+
subscription: {
|
|
27
|
+
enabled: true,
|
|
28
|
+
plans: plansOf(s.prices),
|
|
29
|
+
requireEmailVerification: deps.mailer.live,
|
|
30
|
+
authorizeReference: async ({ user, referenceId }) => mayBill(deps, user.id, referenceId),
|
|
31
|
+
getCheckoutSessionParams: () => ({ params: { allow_promotion_codes: true, billing_address_collection: "auto" } }),
|
|
32
|
+
onSubscriptionComplete: sync,
|
|
33
|
+
onSubscriptionCreated: sync,
|
|
34
|
+
onSubscriptionUpdate: sync,
|
|
35
|
+
onSubscriptionDeleted: sync,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=stripe-plugin.js.map
|