mcpmake 0.1.1 → 0.2.1
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 +88 -635
- package/dist/commands/bundle.d.ts +1 -0
- package/dist/commands/bundle.d.ts.map +1 -0
- package/dist/commands/bundle.js +5 -4
- package/dist/commands/bundle.js.map +1 -0
- package/dist/commands/ci.d.ts +1 -0
- package/dist/commands/ci.d.ts.map +1 -0
- package/dist/commands/ci.js +3 -2
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/deploy.d.ts +1 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +4 -3
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/diff.d.ts +1 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +5 -4
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/from/describe.d.ts +1 -0
- package/dist/commands/from/describe.d.ts.map +1 -0
- package/dist/commands/from/describe.js +11 -10
- package/dist/commands/from/describe.js.map +1 -0
- package/dist/commands/from/har.d.ts +1 -0
- package/dist/commands/from/har.d.ts.map +1 -0
- package/dist/commands/from/har.js +14 -13
- package/dist/commands/from/har.js.map +1 -0
- package/dist/commands/from/openapi.d.ts +1 -0
- package/dist/commands/from/openapi.d.ts.map +1 -0
- package/dist/commands/from/openapi.js +17 -16
- package/dist/commands/from/openapi.js.map +1 -0
- package/dist/commands/from/postman.d.ts +1 -0
- package/dist/commands/from/postman.d.ts.map +1 -0
- package/dist/commands/from/postman.js +13 -12
- package/dist/commands/from/postman.js.map +1 -0
- package/dist/commands/from/stainless.d.ts +110 -0
- package/dist/commands/from/stainless.d.ts.map +1 -0
- package/dist/commands/from/stainless.js +272 -0
- package/dist/commands/from/stainless.js.map +1 -0
- package/dist/commands/from/target-support.d.ts +1 -0
- package/dist/commands/from/target-support.d.ts.map +1 -0
- package/dist/commands/from/target-support.js +2 -1
- package/dist/commands/from/target-support.js.map +1 -0
- package/dist/commands/from/url.d.ts +1 -0
- package/dist/commands/from/url.d.ts.map +1 -0
- package/dist/commands/from/url.js +14 -13
- package/dist/commands/from/url.js.map +1 -0
- package/dist/commands/from/website.d.ts +1 -0
- package/dist/commands/from/website.d.ts.map +1 -0
- package/dist/commands/from/website.js +17 -16
- package/dist/commands/from/website.js.map +1 -0
- package/dist/commands/lint.d.ts +1 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +6 -5
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/merge.d.ts +1 -0
- package/dist/commands/merge.d.ts.map +1 -0
- package/dist/commands/merge.js +3 -2
- package/dist/commands/merge.js.map +1 -0
- package/dist/commands/publish.d.ts +1 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +4 -3
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/rescan.d.ts +1 -0
- package/dist/commands/rescan.d.ts.map +1 -0
- package/dist/commands/rescan.js +12 -11
- package/dist/commands/rescan.js.map +1 -0
- package/dist/commands/update.d.ts +1 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +10 -9
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/verify.d.ts +1 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +7 -6
- package/dist/commands/verify.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -2
- package/dist/index.js.map +1 -0
- package/dist/registry/official-registry.d.ts +1 -0
- package/dist/registry/official-registry.d.ts.map +1 -0
- package/dist/registry/official-registry.js +1 -0
- package/dist/registry/official-registry.js.map +1 -0
- package/package.json +20 -46
- package/dist/analyzer/auth-detector.d.ts +0 -12
- package/dist/analyzer/auth-detector.js +0 -142
- package/dist/analyzer/dom-parser.d.ts +0 -10
- package/dist/analyzer/dom-parser.js +0 -259
- package/dist/analyzer/goal-crawler.d.ts +0 -25
- package/dist/analyzer/goal-crawler.js +0 -177
- package/dist/analyzer/hybrid-detector.d.ts +0 -28
- package/dist/analyzer/hybrid-detector.js +0 -96
- package/dist/analyzer/index.d.ts +0 -12
- package/dist/analyzer/index.js +0 -8
- package/dist/analyzer/screenshot-capture.d.ts +0 -29
- package/dist/analyzer/screenshot-capture.js +0 -42
- package/dist/analyzer/selector-builder.d.ts +0 -19
- package/dist/analyzer/selector-builder.js +0 -199
- package/dist/analyzer/semantic-analyzer.d.ts +0 -13
- package/dist/analyzer/semantic-analyzer.js +0 -145
- package/dist/analyzer/site-crawler.d.ts +0 -38
- package/dist/analyzer/site-crawler.js +0 -235
- package/dist/cloud/billing/billing-engine.d.ts +0 -44
- package/dist/cloud/billing/billing-engine.js +0 -81
- package/dist/cloud/billing/credit-store.d.ts +0 -64
- package/dist/cloud/billing/credit-store.js +0 -168
- package/dist/cloud/billing/index.d.ts +0 -4
- package/dist/cloud/billing/index.js +0 -2
- package/dist/cloud/billing/usage-store.d.ts +0 -42
- package/dist/cloud/billing/usage-store.js +0 -85
- package/dist/cloud/billing/usage-tracker.d.ts +0 -38
- package/dist/cloud/billing/usage-tracker.js +0 -95
- package/dist/cloud/build-pipeline.d.ts +0 -39
- package/dist/cloud/build-pipeline.js +0 -310
- package/dist/cloud/build-queue.d.ts +0 -30
- package/dist/cloud/build-queue.js +0 -70
- package/dist/cloud/caddy-manager.d.ts +0 -18
- package/dist/cloud/caddy-manager.js +0 -97
- package/dist/cloud/container-backend.d.ts +0 -62
- package/dist/cloud/container-backend.js +0 -59
- package/dist/cloud/container-manager.d.ts +0 -64
- package/dist/cloud/container-manager.js +0 -301
- package/dist/cloud/crypto.d.ts +0 -27
- package/dist/cloud/crypto.js +0 -63
- package/dist/cloud/db/index.d.ts +0 -27
- package/dist/cloud/db/index.js +0 -53
- package/dist/cloud/db/migrations.d.ts +0 -12
- package/dist/cloud/db/migrations.js +0 -329
- package/dist/cloud/db/pg-store.d.ts +0 -45
- package/dist/cloud/db/pg-store.js +0 -336
- package/dist/cloud/failure-tracker.d.ts +0 -51
- package/dist/cloud/failure-tracker.js +0 -102
- package/dist/cloud/idle-monitor.d.ts +0 -30
- package/dist/cloud/idle-monitor.js +0 -70
- package/dist/cloud/mailer.d.ts +0 -21
- package/dist/cloud/mailer.js +0 -193
- package/dist/cloud/mcp-proxy.d.ts +0 -58
- package/dist/cloud/mcp-proxy.js +0 -203
- package/dist/cloud/metric-samples.d.ts +0 -43
- package/dist/cloud/metric-samples.js +0 -85
- package/dist/cloud/metrics.d.ts +0 -26
- package/dist/cloud/metrics.js +0 -59
- package/dist/cloud/multipart.d.ts +0 -26
- package/dist/cloud/multipart.js +0 -132
- package/dist/cloud/observability.d.ts +0 -27
- package/dist/cloud/observability.js +0 -98
- package/dist/cloud/rate-limiter.d.ts +0 -31
- package/dist/cloud/rate-limiter.js +0 -58
- package/dist/cloud/request-security.d.ts +0 -5
- package/dist/cloud/request-security.js +0 -74
- package/dist/cloud/resource-monitor.d.ts +0 -69
- package/dist/cloud/resource-monitor.js +0 -130
- package/dist/cloud/secret-store.d.ts +0 -38
- package/dist/cloud/secret-store.js +0 -103
- package/dist/cloud/security.d.ts +0 -26
- package/dist/cloud/security.js +0 -142
- package/dist/cloud/server.d.ts +0 -21
- package/dist/cloud/server.js +0 -1079
- package/dist/cloud/shared-state.d.ts +0 -72
- package/dist/cloud/shared-state.js +0 -159
- package/dist/cloud/ssrf.d.ts +0 -43
- package/dist/cloud/ssrf.js +0 -150
- package/dist/cloud/store.d.ts +0 -41
- package/dist/cloud/store.js +0 -75
- package/dist/cloud/stripe.d.ts +0 -78
- package/dist/cloud/stripe.js +0 -317
- package/dist/cloud/telemetry-store.d.ts +0 -53
- package/dist/cloud/telemetry-store.js +0 -108
- package/dist/cloud/web/auth.d.ts +0 -225
- package/dist/cloud/web/auth.js +0 -555
- package/dist/cloud/web/charts.d.ts +0 -70
- package/dist/cloud/web/charts.js +0 -178
- package/dist/cloud/web/csrf.d.ts +0 -14
- package/dist/cloud/web/csrf.js +0 -22
- package/dist/cloud/web/docs.d.ts +0 -40
- package/dist/cloud/web/docs.js +0 -174
- package/dist/cloud/web/router.d.ts +0 -25
- package/dist/cloud/web/router.js +0 -1921
- package/dist/cloud/web/static/alpine.min.js +0 -5
- package/dist/cloud/web/static/favicon.svg +0 -4
- package/dist/cloud/web/static/htmx-sse.js +0 -290
- package/dist/cloud/web/static/htmx.min.js +0 -1
- package/dist/cloud/web/static/style.css +0 -2683
- package/dist/cloud/web/static-server.d.ts +0 -13
- package/dist/cloud/web/static-server.js +0 -73
- package/dist/cloud/web/template-engine.d.ts +0 -27
- package/dist/cloud/web/template-engine.js +0 -146
- package/dist/cloud/web/templates/layouts/admin.hbs +0 -57
- package/dist/cloud/web/templates/layouts/auth.hbs +0 -138
- package/dist/cloud/web/templates/layouts/base.hbs +0 -16
- package/dist/cloud/web/templates/layouts/dashboard.hbs +0 -39
- package/dist/cloud/web/templates/layouts/landing.hbs +0 -82
- package/dist/cloud/web/templates/pages/admin/overview.hbs +0 -123
- package/dist/cloud/web/templates/pages/admin/servers.hbs +0 -129
- package/dist/cloud/web/templates/pages/admin/telemetry.hbs +0 -39
- package/dist/cloud/web/templates/pages/admin/user-edit.hbs +0 -91
- package/dist/cloud/web/templates/pages/admin/users.hbs +0 -179
- package/dist/cloud/web/templates/pages/auth/forgot-password.hbs +0 -25
- package/dist/cloud/web/templates/pages/auth/login.hbs +0 -33
- package/dist/cloud/web/templates/pages/auth/register.hbs +0 -32
- package/dist/cloud/web/templates/pages/auth/reset-password.hbs +0 -34
- package/dist/cloud/web/templates/pages/dashboard/billing.hbs +0 -140
- package/dist/cloud/web/templates/pages/dashboard/create.hbs +0 -173
- package/dist/cloud/web/templates/pages/dashboard/index.hbs +0 -8
- package/dist/cloud/web/templates/pages/dashboard/server-detail.hbs +0 -280
- package/dist/cloud/web/templates/pages/dashboard/server-logs.hbs +0 -35
- package/dist/cloud/web/templates/pages/dashboard/server-metrics.hbs +0 -63
- package/dist/cloud/web/templates/pages/dashboard/servers-partial.hbs +0 -21
- package/dist/cloud/web/templates/pages/dashboard/servers.hbs +0 -44
- package/dist/cloud/web/templates/pages/docs/show.hbs +0 -16
- package/dist/cloud/web/templates/pages/errors/404.hbs +0 -9
- package/dist/cloud/web/templates/pages/errors/500.hbs +0 -8
- package/dist/cloud/web/templates/pages/landing/index.hbs +0 -223
- package/dist/cloud/web/templates/pages/legal/privacy.hbs +0 -71
- package/dist/cloud/web/templates/pages/legal/terms.hbs +0 -73
- package/dist/cloud/web/templates/partials/admin-stats.hbs +0 -52
- package/dist/cloud/web/templates/partials/flash-message.hbs +0 -6
- package/dist/cloud/web/templates/partials/pricing-table.hbs +0 -103
- package/dist/cloud/web/templates/partials/server-card.hbs +0 -19
- package/dist/cloud/web/templates/partials/status-badge.hbs +0 -1
- package/dist/config/configurable-command.d.ts +0 -13
- package/dist/config/configurable-command.js +0 -70
- package/dist/config/mcpmake-config.d.ts +0 -68
- package/dist/config/mcpmake-config.js +0 -207
- package/dist/docs/cli.md +0 -400
- package/dist/docs/mcp-2026-07-28-migration.md +0 -78
- package/dist/docs/migrate-from-stainless.md +0 -94
- package/dist/docs/quickstart.md +0 -166
- package/dist/docs/show-hn.md +0 -26
- package/dist/docs/website-servers.md +0 -169
- package/dist/emitter/code-writer.d.ts +0 -8
- package/dist/emitter/code-writer.js +0 -25
- package/dist/emitter/index.d.ts +0 -32
- package/dist/emitter/index.js +0 -280
- package/dist/emitter/mcpb-bundler.d.ts +0 -31
- package/dist/emitter/mcpb-bundler.js +0 -172
- package/dist/emitter/project-scaffolder.d.ts +0 -4
- package/dist/emitter/project-scaffolder.js +0 -89
- package/dist/emitter/python-template-loader.d.ts +0 -4
- package/dist/emitter/python-template-loader.js +0 -30
- package/dist/emitter/python-templates/dockerfile.hbs +0 -14
- package/dist/emitter/python-templates/env.example.hbs +0 -6
- package/dist/emitter/python-templates/requirements.txt.hbs +0 -4
- package/dist/emitter/python-templates/server.py.hbs +0 -77
- package/dist/emitter/site-scaffolder.d.ts +0 -13
- package/dist/emitter/site-scaffolder.js +0 -70
- package/dist/emitter/site-template-loader.d.ts +0 -5
- package/dist/emitter/site-template-loader.js +0 -47
- package/dist/emitter/site-templates/browser-manager.ts.hbs +0 -233
- package/dist/emitter/site-templates/config.ts.hbs +0 -28
- package/dist/emitter/site-templates/dockerfile.hbs +0 -31
- package/dist/emitter/site-templates/env.example.hbs +0 -19
- package/dist/emitter/site-templates/package.json.hbs +0 -26
- package/dist/emitter/site-templates/server-main-http.ts.hbs +0 -108
- package/dist/emitter/site-templates/server-main.ts.hbs +0 -23
- package/dist/emitter/site-templates/tool-handler-action.ts.hbs +0 -86
- package/dist/emitter/site-templates/tool-handler-form.ts.hbs +0 -116
- package/dist/emitter/site-templates/tool-handler-lifecycle.ts.hbs +0 -146
- package/dist/emitter/site-templates/tool-index.ts.hbs +0 -11
- package/dist/emitter/template-loader.d.ts +0 -1
- package/dist/emitter/template-loader.js +0 -27
- package/dist/emitter/templates/auth-provider.ts.hbs +0 -57
- package/dist/emitter/templates/config.ts.hbs +0 -63
- package/dist/emitter/templates/discovery.ts.hbs +0 -301
- package/dist/emitter/templates/dockerfile.hbs +0 -34
- package/dist/emitter/templates/env.example.hbs +0 -28
- package/dist/emitter/templates/gitignore.hbs +0 -5
- package/dist/emitter/templates/http-executor.ts.hbs +0 -117
- package/dist/emitter/templates/oauth.ts.hbs +0 -188
- package/dist/emitter/templates/package.json.hbs +0 -25
- package/dist/emitter/templates/prompts.ts.hbs +0 -22
- package/dist/emitter/templates/readme.md.hbs +0 -123
- package/dist/emitter/templates/resources.ts.hbs +0 -63
- package/dist/emitter/templates/server-main-http.ts.hbs +0 -407
- package/dist/emitter/templates/server-main.ts.hbs +0 -40
- package/dist/emitter/templates/task-handlers.ts.hbs +0 -189
- package/dist/emitter/templates/task-manager.ts.hbs +0 -139
- package/dist/emitter/templates/task-sse.ts.hbs +0 -105
- package/dist/emitter/templates/tool-handler.ts.hbs +0 -124
- package/dist/emitter/templates/tool-index.ts.hbs +0 -11
- package/dist/emitter/templates/tool-test.ts.hbs +0 -57
- package/dist/emitter/templates/trace.ts.hbs +0 -79
- package/dist/emitter/templates/tsconfig.json.hbs +0 -16
- package/dist/emitter/templates/types.ts.hbs +0 -5
- package/dist/emitter/worker-template-loader.d.ts +0 -5
- package/dist/emitter/worker-template-loader.js +0 -33
- package/dist/emitter/worker-templates/config.ts.hbs +0 -54
- package/dist/emitter/worker-templates/dev-vars.example.hbs +0 -10
- package/dist/emitter/worker-templates/gitignore.hbs +0 -6
- package/dist/emitter/worker-templates/package.json.hbs +0 -24
- package/dist/emitter/worker-templates/readme.md.hbs +0 -53
- package/dist/emitter/worker-templates/server.test.ts.hbs +0 -20
- package/dist/emitter/worker-templates/tool-handler.ts.hbs +0 -85
- package/dist/emitter/worker-templates/tool-index.ts.hbs +0 -28
- package/dist/emitter/worker-templates/tsconfig.json.hbs +0 -17
- package/dist/emitter/worker-templates/worker.ts.hbs +0 -242
- package/dist/emitter/worker-templates/wrangler.toml.hbs +0 -19
- package/dist/generator/spec-generator.d.ts +0 -6
- package/dist/generator/spec-generator.js +0 -50
- package/dist/parser/har-filter.d.ts +0 -8
- package/dist/parser/har-filter.js +0 -71
- package/dist/parser/har-loader.d.ts +0 -2
- package/dist/parser/har-loader.js +0 -14
- package/dist/parser/har-normalizer.d.ts +0 -20
- package/dist/parser/har-normalizer.js +0 -78
- package/dist/parser/index.d.ts +0 -10
- package/dist/parser/index.js +0 -6
- package/dist/parser/openapi-loader.d.ts +0 -6
- package/dist/parser/openapi-loader.js +0 -308
- package/dist/parser/operation-extractor.d.ts +0 -13
- package/dist/parser/operation-extractor.js +0 -155
- package/dist/parser/overlay-loader.d.ts +0 -10
- package/dist/parser/overlay-loader.js +0 -184
- package/dist/parser/postman-loader.d.ts +0 -9
- package/dist/parser/postman-loader.js +0 -106
- package/dist/parser/schema-converter.d.ts +0 -12
- package/dist/parser/schema-converter.js +0 -117
- package/dist/plugins/adapter.d.ts +0 -40
- package/dist/plugins/adapter.js +0 -15
- package/dist/plugins/loader.d.ts +0 -25
- package/dist/plugins/loader.js +0 -58
- package/dist/pricing.d.ts +0 -55
- package/dist/pricing.js +0 -133
- package/dist/providers/index.d.ts +0 -15
- package/dist/providers/index.js +0 -56
- package/dist/recorder/browser-recorder.d.ts +0 -22
- package/dist/recorder/browser-recorder.js +0 -205
- package/dist/rescan/diff-engine.d.ts +0 -5
- package/dist/rescan/diff-engine.js +0 -312
- package/dist/rescan/index.d.ts +0 -3
- package/dist/rescan/index.js +0 -2
- package/dist/rescan/rescan-runner.d.ts +0 -42
- package/dist/rescan/rescan-runner.js +0 -69
- package/dist/rescan/rescan-scheduler.d.ts +0 -41
- package/dist/rescan/rescan-scheduler.js +0 -179
- package/dist/site-transformer/browser-tools.d.ts +0 -10
- package/dist/site-transformer/browser-tools.js +0 -59
- package/dist/site-transformer/index.d.ts +0 -2
- package/dist/site-transformer/index.js +0 -2
- package/dist/site-transformer/selector-healer.d.ts +0 -8
- package/dist/site-transformer/selector-healer.js +0 -106
- package/dist/site-transformer/tool-generator.d.ts +0 -13
- package/dist/site-transformer/tool-generator.js +0 -245
- package/dist/transformer/auth-detector.d.ts +0 -13
- package/dist/transformer/auth-detector.js +0 -90
- package/dist/transformer/catalog-builder.d.ts +0 -18
- package/dist/transformer/catalog-builder.js +0 -56
- package/dist/transformer/client-compat.d.ts +0 -6
- package/dist/transformer/client-compat.js +0 -44
- package/dist/transformer/har-clusterer.d.ts +0 -9
- package/dist/transformer/har-clusterer.js +0 -27
- package/dist/transformer/har-dedup.d.ts +0 -10
- package/dist/transformer/har-dedup.js +0 -81
- package/dist/transformer/har-schema-inferrer.d.ts +0 -15
- package/dist/transformer/har-schema-inferrer.js +0 -90
- package/dist/transformer/har-to-operations.d.ts +0 -13
- package/dist/transformer/har-to-operations.js +0 -192
- package/dist/transformer/index.d.ts +0 -8
- package/dist/transformer/index.js +0 -6
- package/dist/transformer/llm-namer.d.ts +0 -6
- package/dist/transformer/llm-namer.js +0 -59
- package/dist/transformer/naming.d.ts +0 -4
- package/dist/transformer/naming.js +0 -30
- package/dist/transformer/operation-filter.d.ts +0 -13
- package/dist/transformer/operation-filter.js +0 -52
- package/dist/transformer/resource-builder.d.ts +0 -12
- package/dist/transformer/resource-builder.js +0 -80
- package/dist/transformer/schema-merger.d.ts +0 -14
- package/dist/transformer/schema-merger.js +0 -65
- package/dist/transformer/tool-builder.d.ts +0 -3
- package/dist/transformer/tool-builder.js +0 -114
- package/dist/types/index.d.ts +0 -131
- package/dist/types/index.js +0 -1
- package/dist/types/site.d.ts +0 -284
- package/dist/types/site.js +0 -8
- package/dist/utils/fail.d.ts +0 -48
- package/dist/utils/fail.js +0 -204
- package/dist/utils/fs.d.ts +0 -5
- package/dist/utils/fs.js +0 -28
- package/dist/utils/interactive.d.ts +0 -6
- package/dist/utils/interactive.js +0 -30
- package/dist/utils/logger.d.ts +0 -1
- package/dist/utils/logger.js +0 -2
- package/dist/utils/sanitize.d.ts +0 -28
- package/dist/utils/sanitize.js +0 -44
- package/dist/utils/watcher.d.ts +0 -11
- package/dist/utils/watcher.js +0 -36
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
export type BillingPlan = 'free' | 'hobbyist' | 'pro' | 'team' | 'enterprise';
|
|
2
|
-
export interface PlanLimits {
|
|
3
|
-
/** Maximum allowed usage in minutes per billing period */
|
|
4
|
-
maxMinutes: number;
|
|
5
|
-
plan: BillingPlan;
|
|
6
|
-
}
|
|
7
|
-
export interface QuotaCheckResult {
|
|
8
|
-
allowed: boolean;
|
|
9
|
-
/** Minutes remaining in the current period */
|
|
10
|
-
remaining: number;
|
|
11
|
-
/** Plan limit in minutes */
|
|
12
|
-
limit: number;
|
|
13
|
-
}
|
|
14
|
-
/** Get the minute limits for a given billing plan. */
|
|
15
|
-
export declare function getPlanLimits(plan: BillingPlan): PlanLimits;
|
|
16
|
-
/** Monthly tool-call limit for a plan. */
|
|
17
|
-
export declare function getCallLimit(plan: BillingPlan): number;
|
|
18
|
-
/** Maximum hosted servers for a plan. */
|
|
19
|
-
export declare function getServerLimit(plan: BillingPlan): number;
|
|
20
|
-
/**
|
|
21
|
-
* Check whether a user may create another server given how many they already
|
|
22
|
-
* have. `allowed` is false once the count reaches the plan's server limit.
|
|
23
|
-
*/
|
|
24
|
-
export declare function checkServerLimit(plan: BillingPlan, currentCount: number): {
|
|
25
|
-
allowed: boolean;
|
|
26
|
-
limit: number;
|
|
27
|
-
remaining: number;
|
|
28
|
-
};
|
|
29
|
-
/**
|
|
30
|
-
* Check whether a user has tool-call quota remaining for the billing period.
|
|
31
|
-
*/
|
|
32
|
-
export declare function checkCallQuota(plan: BillingPlan, usedCalls: number): {
|
|
33
|
-
allowed: boolean;
|
|
34
|
-
limit: number;
|
|
35
|
-
remaining: number;
|
|
36
|
-
};
|
|
37
|
-
/**
|
|
38
|
-
* Check whether a user has quota remaining under their plan.
|
|
39
|
-
*
|
|
40
|
-
* @param _userId - The user ID (reserved for future per-user overrides)
|
|
41
|
-
* @param plan - The user's billing plan
|
|
42
|
-
* @param currentUsageMs - Current usage in milliseconds for the billing period
|
|
43
|
-
*/
|
|
44
|
-
export declare function checkQuota(_userId: string, plan: BillingPlan, currentUsageMs: number): QuotaCheckResult;
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
const PLAN_LIMITS = {
|
|
2
|
-
free: 500,
|
|
3
|
-
hobbyist: 5_000,
|
|
4
|
-
pro: 50_000,
|
|
5
|
-
team: 500_000,
|
|
6
|
-
enterprise: Infinity,
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* Monthly tool-call (request) limits per plan. Overage on paid plans is billed
|
|
10
|
-
* separately; the free tier is a hard cap. Tunable business constants.
|
|
11
|
-
*/
|
|
12
|
-
const PLAN_CALL_LIMITS = {
|
|
13
|
-
free: 1_000,
|
|
14
|
-
hobbyist: 10_000,
|
|
15
|
-
pro: 100_000,
|
|
16
|
-
team: 1_000_000,
|
|
17
|
-
enterprise: Infinity,
|
|
18
|
-
};
|
|
19
|
-
/** Maximum number of concurrently hosted servers per plan. */
|
|
20
|
-
const PLAN_SERVER_LIMITS = {
|
|
21
|
-
free: 1,
|
|
22
|
-
hobbyist: 3,
|
|
23
|
-
pro: 5,
|
|
24
|
-
team: 20,
|
|
25
|
-
enterprise: Infinity,
|
|
26
|
-
};
|
|
27
|
-
/** Get the minute limits for a given billing plan. */
|
|
28
|
-
export function getPlanLimits(plan) {
|
|
29
|
-
return {
|
|
30
|
-
maxMinutes: PLAN_LIMITS[plan],
|
|
31
|
-
plan,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
/** Monthly tool-call limit for a plan. */
|
|
35
|
-
export function getCallLimit(plan) {
|
|
36
|
-
return PLAN_CALL_LIMITS[plan] ?? PLAN_CALL_LIMITS.free;
|
|
37
|
-
}
|
|
38
|
-
/** Maximum hosted servers for a plan. */
|
|
39
|
-
export function getServerLimit(plan) {
|
|
40
|
-
return PLAN_SERVER_LIMITS[plan] ?? PLAN_SERVER_LIMITS.free;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Check whether a user may create another server given how many they already
|
|
44
|
-
* have. `allowed` is false once the count reaches the plan's server limit.
|
|
45
|
-
*/
|
|
46
|
-
export function checkServerLimit(plan, currentCount) {
|
|
47
|
-
const limit = getServerLimit(plan);
|
|
48
|
-
return {
|
|
49
|
-
allowed: currentCount < limit,
|
|
50
|
-
limit,
|
|
51
|
-
remaining: Math.max(0, limit - currentCount),
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Check whether a user has tool-call quota remaining for the billing period.
|
|
56
|
-
*/
|
|
57
|
-
export function checkCallQuota(plan, usedCalls) {
|
|
58
|
-
const limit = getCallLimit(plan);
|
|
59
|
-
return {
|
|
60
|
-
allowed: usedCalls < limit,
|
|
61
|
-
limit,
|
|
62
|
-
remaining: Math.max(0, limit - usedCalls),
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Check whether a user has quota remaining under their plan.
|
|
67
|
-
*
|
|
68
|
-
* @param _userId - The user ID (reserved for future per-user overrides)
|
|
69
|
-
* @param plan - The user's billing plan
|
|
70
|
-
* @param currentUsageMs - Current usage in milliseconds for the billing period
|
|
71
|
-
*/
|
|
72
|
-
export function checkQuota(_userId, plan, currentUsageMs) {
|
|
73
|
-
const limit = PLAN_LIMITS[plan];
|
|
74
|
-
const usedMinutes = currentUsageMs / 60_000;
|
|
75
|
-
const remaining = Math.max(0, limit - usedMinutes);
|
|
76
|
-
return {
|
|
77
|
-
allowed: usedMinutes < limit,
|
|
78
|
-
remaining,
|
|
79
|
-
limit,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Promotional tool-call credits.
|
|
3
|
-
*
|
|
4
|
-
* A persistent per-user balance of bonus tool-calls, consumed when a user is
|
|
5
|
-
* over their plan's monthly call quota (before the 429 hard cap). Admins grant
|
|
6
|
-
* and revoke from the dashboard; the serving hot path consumes.
|
|
7
|
-
*
|
|
8
|
-
* Concurrency: `consume` MUST be atomic — two concurrent over-quota requests
|
|
9
|
-
* must not both decrement from the same read value (lost update = leaked free
|
|
10
|
-
* credits). The Pg implementation does the decrement in a single conditional
|
|
11
|
-
* UPDATE; the in-memory one is safe because each call runs to completion within
|
|
12
|
-
* one event-loop turn.
|
|
13
|
-
*
|
|
14
|
-
* The ledger records only admin grants/revokes (low volume, truly auditable).
|
|
15
|
-
* Per-request consumption is intentionally NOT ledgered — that would add a write
|
|
16
|
-
* per over-quota tool call on the hot path; consumption totals are derivable
|
|
17
|
-
* from usage accounting.
|
|
18
|
-
*/
|
|
19
|
-
import type { Database } from '../db/index.js';
|
|
20
|
-
export interface ConsumeResult {
|
|
21
|
-
consumed: boolean;
|
|
22
|
-
/** Remaining balance after the operation (best-effort; 0 when not consumed). */
|
|
23
|
-
balance: number;
|
|
24
|
-
}
|
|
25
|
-
export interface LedgerEntry {
|
|
26
|
-
delta: number;
|
|
27
|
-
reason: string;
|
|
28
|
-
actorId: string | null;
|
|
29
|
-
balanceAfter: number | null;
|
|
30
|
-
createdAt: string;
|
|
31
|
-
}
|
|
32
|
-
export interface CreditStore {
|
|
33
|
-
balance(userId: string): Promise<number>;
|
|
34
|
-
/** Add `amount` credits. Returns the new balance. */
|
|
35
|
-
grant(userId: string, amount: number, actorId: string): Promise<number>;
|
|
36
|
-
/** Remove up to `amount` credits (never below zero). Returns the new balance. */
|
|
37
|
-
revoke(userId: string, amount: number, actorId: string): Promise<number>;
|
|
38
|
-
/** Atomically consume `amount` credits if the balance covers it (all-or-nothing). */
|
|
39
|
-
consume(userId: string, amount: number): Promise<ConsumeResult>;
|
|
40
|
-
recentLedger(userId: string, limit: number): Promise<LedgerEntry[]>;
|
|
41
|
-
}
|
|
42
|
-
export declare class InMemoryCreditStore implements CreditStore {
|
|
43
|
-
private balances;
|
|
44
|
-
private ledger;
|
|
45
|
-
/** Set a balance, bounding the map so a long-lived dev process can't grow it
|
|
46
|
-
* without limit (drops the oldest-inserted half when the cap is exceeded). */
|
|
47
|
-
private setBalance;
|
|
48
|
-
private push;
|
|
49
|
-
balance(userId: string): Promise<number>;
|
|
50
|
-
grant(userId: string, amount: number, actorId: string): Promise<number>;
|
|
51
|
-
revoke(userId: string, amount: number, actorId: string): Promise<number>;
|
|
52
|
-
consume(userId: string, amount: number): Promise<ConsumeResult>;
|
|
53
|
-
recentLedger(userId: string, limit: number): Promise<LedgerEntry[]>;
|
|
54
|
-
}
|
|
55
|
-
export declare class PgCreditStore implements CreditStore {
|
|
56
|
-
private db;
|
|
57
|
-
constructor(db: Database);
|
|
58
|
-
private writeLedger;
|
|
59
|
-
balance(userId: string): Promise<number>;
|
|
60
|
-
grant(userId: string, amount: number, actorId: string): Promise<number>;
|
|
61
|
-
revoke(userId: string, amount: number, actorId: string): Promise<number>;
|
|
62
|
-
consume(userId: string, amount: number): Promise<ConsumeResult>;
|
|
63
|
-
recentLedger(userId: string, limit: number): Promise<LedgerEntry[]>;
|
|
64
|
-
}
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Promotional tool-call credits.
|
|
3
|
-
*
|
|
4
|
-
* A persistent per-user balance of bonus tool-calls, consumed when a user is
|
|
5
|
-
* over their plan's monthly call quota (before the 429 hard cap). Admins grant
|
|
6
|
-
* and revoke from the dashboard; the serving hot path consumes.
|
|
7
|
-
*
|
|
8
|
-
* Concurrency: `consume` MUST be atomic — two concurrent over-quota requests
|
|
9
|
-
* must not both decrement from the same read value (lost update = leaked free
|
|
10
|
-
* credits). The Pg implementation does the decrement in a single conditional
|
|
11
|
-
* UPDATE; the in-memory one is safe because each call runs to completion within
|
|
12
|
-
* one event-loop turn.
|
|
13
|
-
*
|
|
14
|
-
* The ledger records only admin grants/revokes (low volume, truly auditable).
|
|
15
|
-
* Per-request consumption is intentionally NOT ledgered — that would add a write
|
|
16
|
-
* per over-quota tool call on the hot path; consumption totals are derivable
|
|
17
|
-
* from usage accounting.
|
|
18
|
-
*/
|
|
19
|
-
import { randomBytes } from 'node:crypto';
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
// In-memory (dev / no database)
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
const MAX_INMEMORY_LEDGER = 5_000;
|
|
24
|
-
/** Bound the per-user balance map (dev/no-DB only; prod uses the users table). */
|
|
25
|
-
const MAX_INMEMORY_BALANCES = 50_000;
|
|
26
|
-
export class InMemoryCreditStore {
|
|
27
|
-
balances = new Map();
|
|
28
|
-
ledger = [];
|
|
29
|
-
/** Set a balance, bounding the map so a long-lived dev process can't grow it
|
|
30
|
-
* without limit (drops the oldest-inserted half when the cap is exceeded). */
|
|
31
|
-
setBalance(userId, value) {
|
|
32
|
-
if (!this.balances.has(userId) && this.balances.size >= MAX_INMEMORY_BALANCES) {
|
|
33
|
-
const keep = Math.floor(MAX_INMEMORY_BALANCES / 2);
|
|
34
|
-
this.balances = new Map([...this.balances].slice(-keep));
|
|
35
|
-
}
|
|
36
|
-
this.balances.set(userId, value);
|
|
37
|
-
}
|
|
38
|
-
push(entry) {
|
|
39
|
-
this.ledger.push(entry);
|
|
40
|
-
if (this.ledger.length > MAX_INMEMORY_LEDGER) {
|
|
41
|
-
this.ledger.splice(0, this.ledger.length - MAX_INMEMORY_LEDGER);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
async balance(userId) {
|
|
45
|
-
return this.balances.get(userId) ?? 0;
|
|
46
|
-
}
|
|
47
|
-
async grant(userId, amount, actorId) {
|
|
48
|
-
const next = (this.balances.get(userId) ?? 0) + amount;
|
|
49
|
-
this.setBalance(userId, next);
|
|
50
|
-
this.push({
|
|
51
|
-
userId,
|
|
52
|
-
delta: amount,
|
|
53
|
-
reason: 'admin_grant',
|
|
54
|
-
actorId,
|
|
55
|
-
balanceAfter: next,
|
|
56
|
-
createdAt: new Date().toISOString(),
|
|
57
|
-
});
|
|
58
|
-
return next;
|
|
59
|
-
}
|
|
60
|
-
async revoke(userId, amount, actorId) {
|
|
61
|
-
const current = this.balances.get(userId) ?? 0;
|
|
62
|
-
const next = Math.max(0, current - amount);
|
|
63
|
-
this.setBalance(userId, next);
|
|
64
|
-
this.push({
|
|
65
|
-
userId,
|
|
66
|
-
delta: next - current,
|
|
67
|
-
reason: 'admin_revoke',
|
|
68
|
-
actorId,
|
|
69
|
-
balanceAfter: next,
|
|
70
|
-
createdAt: new Date().toISOString(),
|
|
71
|
-
});
|
|
72
|
-
return next;
|
|
73
|
-
}
|
|
74
|
-
async consume(userId, amount) {
|
|
75
|
-
const current = this.balances.get(userId) ?? 0;
|
|
76
|
-
if (amount <= 0 || current < amount)
|
|
77
|
-
return { consumed: false, balance: 0 };
|
|
78
|
-
const next = current - amount;
|
|
79
|
-
this.setBalance(userId, next);
|
|
80
|
-
return { consumed: true, balance: next };
|
|
81
|
-
}
|
|
82
|
-
async recentLedger(userId, limit) {
|
|
83
|
-
return this.ledger
|
|
84
|
-
.filter((e) => e.userId === userId)
|
|
85
|
-
.slice(-limit)
|
|
86
|
-
.reverse()
|
|
87
|
-
.map(({ userId: _u, ...rest }) => rest);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
// ---------------------------------------------------------------------------
|
|
91
|
-
// Postgres
|
|
92
|
-
// ---------------------------------------------------------------------------
|
|
93
|
-
export class PgCreditStore {
|
|
94
|
-
db;
|
|
95
|
-
constructor(db) {
|
|
96
|
-
this.db = db;
|
|
97
|
-
}
|
|
98
|
-
async writeLedger(userId, delta, reason, actorId, balanceAfter) {
|
|
99
|
-
await this.db.query(`INSERT INTO credit_ledger (id, user_id, delta, reason, actor_id, balance_after)
|
|
100
|
-
VALUES ($1, $2, $3, $4, $5, $6)`, [randomBytes(16).toString('hex'), userId, delta, reason, actorId, balanceAfter]);
|
|
101
|
-
}
|
|
102
|
-
async balance(userId) {
|
|
103
|
-
const { rows } = await this.db.query('SELECT credits_calls FROM users WHERE id = $1', [userId]);
|
|
104
|
-
const v = rows[0]?.credits_calls ?? 0;
|
|
105
|
-
return typeof v === 'number' ? v : Number(v) || 0;
|
|
106
|
-
}
|
|
107
|
-
async grant(userId, amount, actorId) {
|
|
108
|
-
const { rows } = await this.db.query('UPDATE users SET credits_calls = credits_calls + $2 WHERE id = $1 RETURNING credits_calls', [userId, amount]);
|
|
109
|
-
if (rows.length === 0)
|
|
110
|
-
throw new Error(`User "${userId}" not found`);
|
|
111
|
-
const next = typeof rows[0].credits_calls === 'number'
|
|
112
|
-
? rows[0].credits_calls
|
|
113
|
-
: Number(rows[0].credits_calls);
|
|
114
|
-
await this.writeLedger(userId, amount, 'admin_grant', actorId, next);
|
|
115
|
-
return next;
|
|
116
|
-
}
|
|
117
|
-
async revoke(userId, amount, actorId) {
|
|
118
|
-
// Single atomic statement: lock the row (FOR UPDATE), clamp at zero, and
|
|
119
|
-
// return both the old and new balance so the ledger delta is exact even
|
|
120
|
-
// under concurrent admin revokes (no read-modify-write window).
|
|
121
|
-
const { rows } = await this.db.query(`WITH prev AS (
|
|
122
|
-
SELECT credits_calls AS old_balance FROM users WHERE id = $1 FOR UPDATE
|
|
123
|
-
)
|
|
124
|
-
UPDATE users
|
|
125
|
-
SET credits_calls = GREATEST(0, users.credits_calls - $2)
|
|
126
|
-
FROM prev
|
|
127
|
-
WHERE users.id = $1
|
|
128
|
-
RETURNING users.credits_calls AS new_balance, prev.old_balance`, [userId, amount]);
|
|
129
|
-
if (rows.length === 0)
|
|
130
|
-
throw new Error(`User "${userId}" not found`);
|
|
131
|
-
const toNum = (v) => (typeof v === 'number' ? v : Number(v));
|
|
132
|
-
const next = toNum(rows[0].new_balance);
|
|
133
|
-
const before = toNum(rows[0].old_balance);
|
|
134
|
-
// Record the actual delta applied (clamped at zero), not the requested amount.
|
|
135
|
-
await this.writeLedger(userId, next - before, 'admin_revoke', actorId, next);
|
|
136
|
-
return next;
|
|
137
|
-
}
|
|
138
|
-
async consume(userId, amount) {
|
|
139
|
-
if (amount <= 0)
|
|
140
|
-
return { consumed: false, balance: 0 };
|
|
141
|
-
// Single atomic statement: decrement only if the balance covers it.
|
|
142
|
-
const { rows } = await this.db.query('UPDATE users SET credits_calls = credits_calls - $2 WHERE id = $1 AND credits_calls >= $2 RETURNING credits_calls', [userId, amount]);
|
|
143
|
-
if (rows.length === 0)
|
|
144
|
-
return { consumed: false, balance: 0 };
|
|
145
|
-
const balance = typeof rows[0].credits_calls === 'number'
|
|
146
|
-
? rows[0].credits_calls
|
|
147
|
-
: Number(rows[0].credits_calls);
|
|
148
|
-
return { consumed: true, balance };
|
|
149
|
-
}
|
|
150
|
-
async recentLedger(userId, limit) {
|
|
151
|
-
const { rows } = await this.db.query(`SELECT delta, reason, actor_id, balance_after, created_at
|
|
152
|
-
FROM credit_ledger WHERE user_id = $1 ORDER BY created_at DESC LIMIT $2`, [userId, limit]);
|
|
153
|
-
return rows.map((row) => {
|
|
154
|
-
const createdAt = row.created_at;
|
|
155
|
-
return {
|
|
156
|
-
delta: typeof row.delta === 'number' ? row.delta : Number(row.delta ?? 0),
|
|
157
|
-
reason: String(row.reason ?? ''),
|
|
158
|
-
actorId: row.actor_id != null ? String(row.actor_id) : null,
|
|
159
|
-
balanceAfter: row.balance_after != null
|
|
160
|
-
? typeof row.balance_after === 'number'
|
|
161
|
-
? row.balance_after
|
|
162
|
-
: Number(row.balance_after)
|
|
163
|
-
: null,
|
|
164
|
-
createdAt: typeof createdAt === 'string' ? createdAt : new Date(createdAt).toISOString(),
|
|
165
|
-
};
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export { UsageTracker } from './usage-tracker.js';
|
|
2
|
-
export type { UsageEvent, UsageEventType, UsageSummary } from './usage-tracker.js';
|
|
3
|
-
export { checkQuota, getPlanLimits } from './billing-engine.js';
|
|
4
|
-
export type { BillingPlan, PlanLimits, QuotaCheckResult } from './billing-engine.js';
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Durable per-user usage accounting tied to a billing period.
|
|
3
|
-
*
|
|
4
|
-
* Records tool calls (and total requests) for the served MCP traffic so that
|
|
5
|
-
* quota can be enforced and usage survives process restarts. Backed by the
|
|
6
|
-
* `usage_summaries` Postgres table when a database is configured; otherwise an
|
|
7
|
-
* in-memory fallback is used (dev / single-process).
|
|
8
|
-
*/
|
|
9
|
-
import type { Database } from '../db/index.js';
|
|
10
|
-
export interface BillingPeriod {
|
|
11
|
-
/** ISO timestamp of the period start (inclusive). */
|
|
12
|
-
start: string;
|
|
13
|
-
/** ISO timestamp of the period end (exclusive). */
|
|
14
|
-
end: string;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Compute the billing period containing `now`.
|
|
18
|
-
*
|
|
19
|
-
* When `anchorEndMs` (a Stripe subscription's current_period_end) is provided
|
|
20
|
-
* and in the future, the period is the month ending at that anchor; otherwise
|
|
21
|
-
* it falls back to the calendar month (UTC). Calendar-month alignment is a safe
|
|
22
|
-
* default for the free tier and approximates monthly subscriptions closely.
|
|
23
|
-
*/
|
|
24
|
-
export declare function getBillingPeriod(now?: Date, anchorEndMs?: number): BillingPeriod;
|
|
25
|
-
export interface UsageStore {
|
|
26
|
-
/** Add tool-call and request counts for a user in the given period. */
|
|
27
|
-
record(userId: string, period: BillingPeriod, toolCalls: number, requests: number): Promise<void>;
|
|
28
|
-
/** Total tool calls a user has made in the given period. */
|
|
29
|
-
getToolCalls(userId: string, period: BillingPeriod): Promise<number>;
|
|
30
|
-
}
|
|
31
|
-
export declare class InMemoryUsageStore implements UsageStore {
|
|
32
|
-
private counts;
|
|
33
|
-
private key;
|
|
34
|
-
record(userId: string, period: BillingPeriod, toolCalls: number, requests: number): Promise<void>;
|
|
35
|
-
getToolCalls(userId: string, period: BillingPeriod): Promise<number>;
|
|
36
|
-
}
|
|
37
|
-
export declare class PgUsageStore implements UsageStore {
|
|
38
|
-
private db;
|
|
39
|
-
constructor(db: Database);
|
|
40
|
-
record(userId: string, period: BillingPeriod, toolCalls: number, requests: number): Promise<void>;
|
|
41
|
-
getToolCalls(userId: string, period: BillingPeriod): Promise<number>;
|
|
42
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Durable per-user usage accounting tied to a billing period.
|
|
3
|
-
*
|
|
4
|
-
* Records tool calls (and total requests) for the served MCP traffic so that
|
|
5
|
-
* quota can be enforced and usage survives process restarts. Backed by the
|
|
6
|
-
* `usage_summaries` Postgres table when a database is configured; otherwise an
|
|
7
|
-
* in-memory fallback is used (dev / single-process).
|
|
8
|
-
*/
|
|
9
|
-
import { randomBytes } from 'node:crypto';
|
|
10
|
-
/**
|
|
11
|
-
* Compute the billing period containing `now`.
|
|
12
|
-
*
|
|
13
|
-
* When `anchorEndMs` (a Stripe subscription's current_period_end) is provided
|
|
14
|
-
* and in the future, the period is the month ending at that anchor; otherwise
|
|
15
|
-
* it falls back to the calendar month (UTC). Calendar-month alignment is a safe
|
|
16
|
-
* default for the free tier and approximates monthly subscriptions closely.
|
|
17
|
-
*/
|
|
18
|
-
export function getBillingPeriod(now = new Date(), anchorEndMs) {
|
|
19
|
-
if (anchorEndMs && anchorEndMs > now.getTime()) {
|
|
20
|
-
const end = new Date(anchorEndMs);
|
|
21
|
-
// Compute "one month before end" without JS month-overflow. Using
|
|
22
|
-
// setUTCMonth(-1) on e.g. Mar 31 yields Mar 3 (Feb has no 31st), which would
|
|
23
|
-
// leave a 2–3 day gap where usage is keyed to a different period and quota
|
|
24
|
-
// appears to reset. Clamp the day to the target month's length instead.
|
|
25
|
-
const targetMonthIndex = end.getUTCMonth() - 1;
|
|
26
|
-
const year = targetMonthIndex < 0 ? end.getUTCFullYear() - 1 : end.getUTCFullYear();
|
|
27
|
-
const month = ((targetMonthIndex % 12) + 12) % 12;
|
|
28
|
-
const daysInTarget = new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
|
|
29
|
-
const day = Math.min(end.getUTCDate(), daysInTarget);
|
|
30
|
-
const start = new Date(Date.UTC(year, month, day, end.getUTCHours(), end.getUTCMinutes(), end.getUTCSeconds(), end.getUTCMilliseconds()));
|
|
31
|
-
if (start.getTime() <= now.getTime()) {
|
|
32
|
-
return { start: start.toISOString(), end: end.toISOString() };
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
const start = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
|
|
36
|
-
const end = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1));
|
|
37
|
-
return { start: start.toISOString(), end: end.toISOString() };
|
|
38
|
-
}
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
|
-
// In-memory implementation (dev / no database)
|
|
41
|
-
// ---------------------------------------------------------------------------
|
|
42
|
-
const MAX_INMEMORY_KEYS = 50_000;
|
|
43
|
-
export class InMemoryUsageStore {
|
|
44
|
-
counts = new Map();
|
|
45
|
-
key(userId, period) {
|
|
46
|
-
return `${userId}::${period.start}`;
|
|
47
|
-
}
|
|
48
|
-
async record(userId, period, toolCalls, requests) {
|
|
49
|
-
if (this.counts.size > MAX_INMEMORY_KEYS) {
|
|
50
|
-
// Drop the oldest-inserted half to bound memory.
|
|
51
|
-
const keep = Math.floor(MAX_INMEMORY_KEYS / 2);
|
|
52
|
-
this.counts = new Map([...this.counts].slice(-keep));
|
|
53
|
-
}
|
|
54
|
-
const k = this.key(userId, period);
|
|
55
|
-
const entry = this.counts.get(k) ?? { toolCalls: 0, requests: 0 };
|
|
56
|
-
entry.toolCalls += toolCalls;
|
|
57
|
-
entry.requests += requests;
|
|
58
|
-
this.counts.set(k, entry);
|
|
59
|
-
}
|
|
60
|
-
async getToolCalls(userId, period) {
|
|
61
|
-
return this.counts.get(this.key(userId, period))?.toolCalls ?? 0;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
// Postgres implementation
|
|
66
|
-
// ---------------------------------------------------------------------------
|
|
67
|
-
export class PgUsageStore {
|
|
68
|
-
db;
|
|
69
|
-
constructor(db) {
|
|
70
|
-
this.db = db;
|
|
71
|
-
}
|
|
72
|
-
async record(userId, period, toolCalls, requests) {
|
|
73
|
-
await this.db.query(`INSERT INTO usage_summaries (id, user_id, period_start, period_end, request_count, tool_calls)
|
|
74
|
-
VALUES ($1, $2, $3, $4, $5, $6)
|
|
75
|
-
ON CONFLICT (user_id, period_start)
|
|
76
|
-
DO UPDATE SET request_count = usage_summaries.request_count + EXCLUDED.request_count,
|
|
77
|
-
tool_calls = usage_summaries.tool_calls + EXCLUDED.tool_calls`, [randomBytes(16).toString('hex'), userId, period.start, period.end, requests, toolCalls]);
|
|
78
|
-
}
|
|
79
|
-
async getToolCalls(userId, period) {
|
|
80
|
-
const { rows } = await this.db.query(`SELECT COALESCE(SUM(tool_calls), 0) AS calls
|
|
81
|
-
FROM usage_summaries WHERE user_id = $1 AND period_start = $2`, [userId, period.start]);
|
|
82
|
-
const value = rows[0]?.calls ?? 0;
|
|
83
|
-
return typeof value === 'number' ? value : parseInt(value, 10) || 0;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export type UsageEventType = 'session-start' | 'session-end' | 'tool-call' | 'screenshot';
|
|
2
|
-
export interface UsageEvent {
|
|
3
|
-
userId: string;
|
|
4
|
-
slug: string;
|
|
5
|
-
eventType: UsageEventType;
|
|
6
|
-
timestamp: Date;
|
|
7
|
-
/** Duration in milliseconds (for session-end events) */
|
|
8
|
-
durationMs?: number;
|
|
9
|
-
/** Extra metadata */
|
|
10
|
-
metadata?: Record<string, unknown>;
|
|
11
|
-
}
|
|
12
|
-
export interface UsageSummary {
|
|
13
|
-
userId: string;
|
|
14
|
-
totalSessionsMs: number;
|
|
15
|
-
totalToolCalls: number;
|
|
16
|
-
totalScreenshots: number;
|
|
17
|
-
/** Usage broken down by site slug */
|
|
18
|
-
bySlug: Map<string, {
|
|
19
|
-
sessionsMs: number;
|
|
20
|
-
toolCalls: number;
|
|
21
|
-
screenshots: number;
|
|
22
|
-
}>;
|
|
23
|
-
}
|
|
24
|
-
export declare class UsageTracker {
|
|
25
|
-
private events;
|
|
26
|
-
private activeSessions;
|
|
27
|
-
private appendEvent;
|
|
28
|
-
/** Start a new session for a user + site slug. Returns a session key. */
|
|
29
|
-
startSession(userId: string, slug: string): string;
|
|
30
|
-
/** End an active session. Records the duration. */
|
|
31
|
-
endSession(sessionKey: string): void;
|
|
32
|
-
/** Record a tool call event. */
|
|
33
|
-
recordToolCall(userId: string, slug: string, metadata?: Record<string, unknown>): void;
|
|
34
|
-
/** Record a screenshot capture event. */
|
|
35
|
-
recordScreenshot(userId: string, slug: string, metadata?: Record<string, unknown>): void;
|
|
36
|
-
/** Get a usage summary for a specific user. */
|
|
37
|
-
getUsageSummary(userId: string): UsageSummary;
|
|
38
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* In-memory usage tracker for billing purposes.
|
|
3
|
-
* Tracks sessions, tool calls, and screenshots per user/slug.
|
|
4
|
-
*/
|
|
5
|
-
const MAX_EVENTS = 50_000;
|
|
6
|
-
export class UsageTracker {
|
|
7
|
-
events = [];
|
|
8
|
-
activeSessions = new Map();
|
|
9
|
-
appendEvent(event) {
|
|
10
|
-
this.events.push(event);
|
|
11
|
-
if (this.events.length > MAX_EVENTS) {
|
|
12
|
-
// Keep the newest half to avoid unbounded memory growth
|
|
13
|
-
this.events = this.events.slice(-Math.floor(MAX_EVENTS / 2));
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
/** Start a new session for a user + site slug. Returns a session key. */
|
|
17
|
-
startSession(userId, slug) {
|
|
18
|
-
const key = `${userId}:${slug}:${Date.now()}`;
|
|
19
|
-
this.activeSessions.set(key, { userId, slug, startedAt: new Date() });
|
|
20
|
-
this.appendEvent({
|
|
21
|
-
userId,
|
|
22
|
-
slug,
|
|
23
|
-
eventType: 'session-start',
|
|
24
|
-
timestamp: new Date(),
|
|
25
|
-
});
|
|
26
|
-
return key;
|
|
27
|
-
}
|
|
28
|
-
/** End an active session. Records the duration. */
|
|
29
|
-
endSession(sessionKey) {
|
|
30
|
-
const session = this.activeSessions.get(sessionKey);
|
|
31
|
-
if (!session)
|
|
32
|
-
return;
|
|
33
|
-
const durationMs = Date.now() - session.startedAt.getTime();
|
|
34
|
-
this.appendEvent({
|
|
35
|
-
userId: session.userId,
|
|
36
|
-
slug: session.slug,
|
|
37
|
-
eventType: 'session-end',
|
|
38
|
-
timestamp: new Date(),
|
|
39
|
-
durationMs,
|
|
40
|
-
});
|
|
41
|
-
this.activeSessions.delete(sessionKey);
|
|
42
|
-
}
|
|
43
|
-
/** Record a tool call event. */
|
|
44
|
-
recordToolCall(userId, slug, metadata) {
|
|
45
|
-
this.appendEvent({
|
|
46
|
-
userId,
|
|
47
|
-
slug,
|
|
48
|
-
eventType: 'tool-call',
|
|
49
|
-
timestamp: new Date(),
|
|
50
|
-
metadata,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
/** Record a screenshot capture event. */
|
|
54
|
-
recordScreenshot(userId, slug, metadata) {
|
|
55
|
-
this.appendEvent({
|
|
56
|
-
userId,
|
|
57
|
-
slug,
|
|
58
|
-
eventType: 'screenshot',
|
|
59
|
-
timestamp: new Date(),
|
|
60
|
-
metadata,
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
/** Get a usage summary for a specific user. */
|
|
64
|
-
getUsageSummary(userId) {
|
|
65
|
-
const userEvents = this.events.filter((e) => e.userId === userId);
|
|
66
|
-
const bySlug = new Map();
|
|
67
|
-
let totalSessionsMs = 0;
|
|
68
|
-
let totalToolCalls = 0;
|
|
69
|
-
let totalScreenshots = 0;
|
|
70
|
-
for (const event of userEvents) {
|
|
71
|
-
let slugEntry = bySlug.get(event.slug);
|
|
72
|
-
if (!slugEntry) {
|
|
73
|
-
slugEntry = { sessionsMs: 0, toolCalls: 0, screenshots: 0 };
|
|
74
|
-
bySlug.set(event.slug, slugEntry);
|
|
75
|
-
}
|
|
76
|
-
switch (event.eventType) {
|
|
77
|
-
case 'session-end':
|
|
78
|
-
if (event.durationMs != null) {
|
|
79
|
-
totalSessionsMs += event.durationMs;
|
|
80
|
-
slugEntry.sessionsMs += event.durationMs;
|
|
81
|
-
}
|
|
82
|
-
break;
|
|
83
|
-
case 'tool-call':
|
|
84
|
-
totalToolCalls++;
|
|
85
|
-
slugEntry.toolCalls++;
|
|
86
|
-
break;
|
|
87
|
-
case 'screenshot':
|
|
88
|
-
totalScreenshots++;
|
|
89
|
-
slugEntry.screenshots++;
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return { userId, totalSessionsMs, totalToolCalls, totalScreenshots, bySlug };
|
|
94
|
-
}
|
|
95
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Spec -> Generated project pipeline.
|
|
3
|
-
*
|
|
4
|
-
* Takes an uploaded spec file (OpenAPI or HAR), runs it through the existing
|
|
5
|
-
* parser/transformer/emitter pipeline, audits the output, and returns a
|
|
6
|
-
* BuildResult with the slug and image metadata.
|
|
7
|
-
*/
|
|
8
|
-
export interface BuildResult {
|
|
9
|
-
slug: string;
|
|
10
|
-
imageName: string;
|
|
11
|
-
imageTag: string;
|
|
12
|
-
buildDir: string;
|
|
13
|
-
toolCount: number;
|
|
14
|
-
/** Detected server type based on project dependencies. */
|
|
15
|
-
serverType: 'http' | 'playwright';
|
|
16
|
-
}
|
|
17
|
-
export interface BuildOptions {
|
|
18
|
-
name?: string;
|
|
19
|
-
format: 'openapi' | 'har';
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Build a project from an uploaded spec file.
|
|
23
|
-
*
|
|
24
|
-
* Steps:
|
|
25
|
-
* 1. Generate slug and create temp build dir
|
|
26
|
-
* 2. Run the appropriate pipeline (OpenAPI or HAR) to generate the project
|
|
27
|
-
* 3. Audit the generated code for dangerous patterns
|
|
28
|
-
* 4. Return build result
|
|
29
|
-
*/
|
|
30
|
-
export declare function buildFromSpec(specPath: string, opts: BuildOptions): Promise<BuildResult>;
|
|
31
|
-
/**
|
|
32
|
-
* Detect the spec format from a file path.
|
|
33
|
-
*/
|
|
34
|
-
export declare function detectFormat(filePath: string, contentType?: string): 'openapi' | 'har';
|
|
35
|
-
/**
|
|
36
|
-
* Detect format by inspecting file content.
|
|
37
|
-
* Useful when the file extension is ambiguous (e.g., .json).
|
|
38
|
-
*/
|
|
39
|
-
export declare function detectFormatFromContent(filePath: string): Promise<'openapi' | 'har'>;
|