diff options
| author | Frank <[email protected]> | 2026-01-22 16:59:32 -0500 |
|---|---|---|
| committer | Frank <[email protected]> | 2026-01-22 17:02:46 -0500 |
| commit | 5f3ab9395fc8f8543724dcda914d38fba0809049 (patch) | |
| tree | 3be83aa5cc4e4556b62f9ff6b23933f8699eea63 /packages/console/core | |
| parent | fdac21688c9acc4087b83e71cb7e0fd1d2d57f00 (diff) | |
| download | opencode-5f3ab9395fc8f8543724dcda914d38fba0809049.tar.gz opencode-5f3ab9395fc8f8543724dcda914d38fba0809049.zip | |
wip: zen black
Diffstat (limited to 'packages/console/core')
| -rw-r--r-- | packages/console/core/migrations/0055_moaning_karnak.sql | 1 | ||||
| -rw-r--r-- | packages/console/core/migrations/meta/0055_snapshot.json | 1316 | ||||
| -rw-r--r-- | packages/console/core/migrations/meta/_journal.json | 9 | ||||
| -rw-r--r-- | packages/console/core/script/black-gift.ts | 9 | ||||
| -rw-r--r-- | packages/console/core/script/black-onboard.ts | 173 | ||||
| -rw-r--r-- | packages/console/core/script/lookup-user.ts | 2 | ||||
| -rw-r--r-- | packages/console/core/src/billing.ts | 65 | ||||
| -rw-r--r-- | packages/console/core/src/black.ts | 33 | ||||
| -rw-r--r-- | packages/console/core/src/schema/billing.sql.ts | 1 |
9 files changed, 1421 insertions, 188 deletions
diff --git a/packages/console/core/migrations/0055_moaning_karnak.sql b/packages/console/core/migrations/0055_moaning_karnak.sql new file mode 100644 index 000000000..120ae727c --- /dev/null +++ b/packages/console/core/migrations/0055_moaning_karnak.sql @@ -0,0 +1 @@ +ALTER TABLE `billing` ADD `time_subscription_selected` timestamp(3);
\ No newline at end of file diff --git a/packages/console/core/migrations/meta/0055_snapshot.json b/packages/console/core/migrations/meta/0055_snapshot.json new file mode 100644 index 000000000..fadb753b4 --- /dev/null +++ b/packages/console/core/migrations/meta/0055_snapshot.json @@ -0,0 +1,1316 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "e630f63c-04a8-4b59-bf56-03efcdd1b011", + "prevId": "a0ade64b-b735-4a70-8d39-ebd84bc9e924", + "tables": { + "account": { + "name": "account", + "columns": { + "id": { + "name": "id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_created": { + "name": "time_created", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "time_updated": { + "name": "time_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" + }, + "time_deleted": { + "name": "time_deleted", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "account_id_pk": { + "name": "account_id_pk", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "auth": { + "name": "auth", + "columns": { + "id": { + "name": "id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_created": { + "name": "time_created", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "time_updated": { + "name": "time_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" + }, + "time_deleted": { + "name": "time_deleted", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "enum('email','github','google')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject": { + "name": "subject", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "account_id": { + "name": "account_id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "provider": { + "name": "provider", + "columns": [ + "provider", + "subject" + ], + "isUnique": true + }, + "account_id": { + "name": "account_id", + "columns": [ + "account_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "auth_id_pk": { + "name": "auth_id_pk", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "benchmark": { + "name": "benchmark", + "columns": { + "id": { + "name": "id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_created": { + "name": "time_created", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "time_updated": { + "name": "time_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" + }, + "time_deleted": { + "name": "time_deleted", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "model": { + "name": "model", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "agent": { + "name": "agent", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "result": { + "name": "result", + "type": "mediumtext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "time_created": { + "name": "time_created", + "columns": [ + "time_created" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "benchmark_id_pk": { + "name": "benchmark_id_pk", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "billing": { + "name": "billing", + "columns": { + "id": { + "name": "id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_created": { + "name": "time_created", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "time_updated": { + "name": "time_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" + }, + "time_deleted": { + "name": "time_deleted", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "customer_id": { + "name": "customer_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "payment_method_id": { + "name": "payment_method_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "payment_method_type": { + "name": "payment_method_type", + "type": "varchar(32)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "payment_method_last4": { + "name": "payment_method_last4", + "type": "varchar(4)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "balance": { + "name": "balance", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "monthly_limit": { + "name": "monthly_limit", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "monthly_usage": { + "name": "monthly_usage", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_monthly_usage_updated": { + "name": "time_monthly_usage_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reload": { + "name": "reload", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reload_trigger": { + "name": "reload_trigger", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reload_amount": { + "name": "reload_amount", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reload_error": { + "name": "reload_error", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_reload_error": { + "name": "time_reload_error", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_reload_locked_till": { + "name": "time_reload_locked_till", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subscription": { + "name": "subscription", + "type": "json", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subscription_id": { + "name": "subscription_id", + "type": "varchar(28)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subscription_plan": { + "name": "subscription_plan", + "type": "enum('20','100','200')", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_subscription_booked": { + "name": "time_subscription_booked", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_subscription_selected": { + "name": "time_subscription_selected", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "global_customer_id": { + "name": "global_customer_id", + "columns": [ + "customer_id" + ], + "isUnique": true + }, + "global_subscription_id": { + "name": "global_subscription_id", + "columns": [ + "subscription_id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "billing_workspace_id_id_pk": { + "name": "billing_workspace_id_id_pk", + "columns": [ + "workspace_id", + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "payment": { + "name": "payment", + "columns": { + "id": { + "name": "id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_created": { + "name": "time_created", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "time_updated": { + "name": "time_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" + }, + "time_deleted": { + "name": "time_deleted", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "customer_id": { + "name": "customer_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "invoice_id": { + "name": "invoice_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "payment_id": { + "name": "payment_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "amount": { + "name": "amount", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_refunded": { + "name": "time_refunded", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enrichment": { + "name": "enrichment", + "type": "json", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "payment_workspace_id_id_pk": { + "name": "payment_workspace_id_id_pk", + "columns": [ + "workspace_id", + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "subscription": { + "name": "subscription", + "columns": { + "id": { + "name": "id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_created": { + "name": "time_created", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "time_updated": { + "name": "time_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" + }, + "time_deleted": { + "name": "time_deleted", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rolling_usage": { + "name": "rolling_usage", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fixed_usage": { + "name": "fixed_usage", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_rolling_updated": { + "name": "time_rolling_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_fixed_updated": { + "name": "time_fixed_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "workspace_user_id": { + "name": "workspace_user_id", + "columns": [ + "workspace_id", + "user_id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "subscription_workspace_id_id_pk": { + "name": "subscription_workspace_id_id_pk", + "columns": [ + "workspace_id", + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "usage": { + "name": "usage", + "columns": { + "id": { + "name": "id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_created": { + "name": "time_created", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "time_updated": { + "name": "time_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" + }, + "time_deleted": { + "name": "time_deleted", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "model": { + "name": "model", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "input_tokens": { + "name": "input_tokens", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "output_tokens": { + "name": "output_tokens", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reasoning_tokens": { + "name": "reasoning_tokens", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cache_read_tokens": { + "name": "cache_read_tokens", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cache_write_5m_tokens": { + "name": "cache_write_5m_tokens", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cache_write_1h_tokens": { + "name": "cache_write_1h_tokens", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cost": { + "name": "cost", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key_id": { + "name": "key_id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enrichment": { + "name": "enrichment", + "type": "json", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "usage_time_created": { + "name": "usage_time_created", + "columns": [ + "workspace_id", + "time_created" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "usage_workspace_id_id_pk": { + "name": "usage_workspace_id_id_pk", + "columns": [ + "workspace_id", + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "ip_rate_limit": { + "name": "ip_rate_limit", + "columns": { + "ip": { + "name": "ip", + "type": "varchar(45)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "interval": { + "name": "interval", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "count": { + "name": "count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "ip_rate_limit_ip_interval_pk": { + "name": "ip_rate_limit_ip_interval_pk", + "columns": [ + "ip", + "interval" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "ip": { + "name": "ip", + "columns": { + "ip": { + "name": "ip", + "type": "varchar(45)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_created": { + "name": "time_created", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "time_updated": { + "name": "time_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" + }, + "time_deleted": { + "name": "time_deleted", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "usage": { + "name": "usage", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "ip_ip_pk": { + "name": "ip_ip_pk", + "columns": [ + "ip" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "key": { + "name": "key", + "columns": { + "id": { + "name": "id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_created": { + "name": "time_created", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "time_updated": { + "name": "time_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" + }, + "time_deleted": { + "name": "time_deleted", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_used": { + "name": "time_used", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "global_key": { + "name": "global_key", + "columns": [ + "key" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "key_workspace_id_id_pk": { + "name": "key_workspace_id_id_pk", + "columns": [ + "workspace_id", + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "model": { + "name": "model", + "columns": { + "id": { + "name": "id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_created": { + "name": "time_created", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "time_updated": { + "name": "time_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" + }, + "time_deleted": { + "name": "time_deleted", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "model": { + "name": "model", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "model_workspace_model": { + "name": "model_workspace_model", + "columns": [ + "workspace_id", + "model" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "model_workspace_id_id_pk": { + "name": "model_workspace_id_id_pk", + "columns": [ + "workspace_id", + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "provider": { + "name": "provider", + "columns": { + "id": { + "name": "id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_created": { + "name": "time_created", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "time_updated": { + "name": "time_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" + }, + "time_deleted": { + "name": "time_deleted", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credentials": { + "name": "credentials", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "workspace_provider": { + "name": "workspace_provider", + "columns": [ + "workspace_id", + "provider" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "provider_workspace_id_id_pk": { + "name": "provider_workspace_id_id_pk", + "columns": [ + "workspace_id", + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_created": { + "name": "time_created", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "time_updated": { + "name": "time_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" + }, + "time_deleted": { + "name": "time_deleted", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "account_id": { + "name": "account_id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_seen": { + "name": "time_seen", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "enum('admin','member')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "monthly_limit": { + "name": "monthly_limit", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "monthly_usage": { + "name": "monthly_usage", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_monthly_usage_updated": { + "name": "time_monthly_usage_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "user_account_id": { + "name": "user_account_id", + "columns": [ + "workspace_id", + "account_id" + ], + "isUnique": true + }, + "user_email": { + "name": "user_email", + "columns": [ + "workspace_id", + "email" + ], + "isUnique": true + }, + "global_account_id": { + "name": "global_account_id", + "columns": [ + "account_id" + ], + "isUnique": false + }, + "global_email": { + "name": "global_email", + "columns": [ + "email" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "user_workspace_id_id_pk": { + "name": "user_workspace_id_id_pk", + "columns": [ + "workspace_id", + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "workspace": { + "name": "workspace", + "columns": { + "id": { + "name": "id", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "time_created": { + "name": "time_created", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "time_updated": { + "name": "time_updated", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)" + }, + "time_deleted": { + "name": "time_deleted", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "slug": { + "name": "slug", + "columns": [ + "slug" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "workspace_id": { + "name": "workspace_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +}
\ No newline at end of file diff --git a/packages/console/core/migrations/meta/_journal.json b/packages/console/core/migrations/meta/_journal.json index dd0957e51..0314e38c9 100644 --- a/packages/console/core/migrations/meta/_journal.json +++ b/packages/console/core/migrations/meta/_journal.json @@ -386,6 +386,13 @@ "when": 1768603665356, "tag": "0054_numerous_annihilus", "breakpoints": true + }, + { + "idx": 55, + "version": "5", + "when": 1769108945841, + "tag": "0055_moaning_karnak", + "breakpoints": true } ] -} +}
\ No newline at end of file diff --git a/packages/console/core/script/black-gift.ts b/packages/console/core/script/black-gift.ts index ec7db8799..c666a1ab6 100644 --- a/packages/console/core/script/black-gift.ts +++ b/packages/console/core/script/black-gift.ts @@ -5,8 +5,11 @@ import { BillingTable, PaymentTable, SubscriptionTable } from "../src/schema/bil import { Identifier } from "../src/identifier.js" import { centsToMicroCents } from "../src/util/price.js" import { AuthTable } from "../src/schema/auth.sql.js" +import { BlackData } from "../src/black.js" +import { Actor } from "../src/actor.js" const plan = "200" +const couponID = "JAIr0Pe1" const workspaceID = process.argv[2] const seats = parseInt(process.argv[3]) @@ -61,16 +64,18 @@ const customerID = .then((customer) => customer.id))()) console.log(`Customer ID: ${customerID}`) -const couponID = "JAIr0Pe1" const subscription = await Billing.stripe().subscriptions.create({ customer: customerID!, items: [ { - price: `price_1SmfyI2StuRr0lbXovxJNeZn`, + price: BlackData.planToPriceID({ plan }), discounts: [{ coupon: couponID }], quantity: seats, }, ], + metadata: { + workspaceID, + }, }) console.log(`Subscription ID: ${subscription.id}`) diff --git a/packages/console/core/script/black-onboard.ts b/packages/console/core/script/black-onboard.ts deleted file mode 100644 index 77e5b779e..000000000 --- a/packages/console/core/script/black-onboard.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { Billing } from "../src/billing.js" -import { and, Database, eq, isNull, sql } from "../src/drizzle/index.js" -import { UserTable } from "../src/schema/user.sql.js" -import { BillingTable, PaymentTable, SubscriptionTable } from "../src/schema/billing.sql.js" -import { Identifier } from "../src/identifier.js" -import { centsToMicroCents } from "../src/util/price.js" -import { AuthTable } from "../src/schema/auth.sql.js" - -const workspaceID = process.argv[2] -const email = process.argv[3] - -console.log(`Onboarding workspace ${workspaceID} for email ${email}`) - -if (!workspaceID || !email) { - console.error("Usage: bun foo.ts <workspaceID> <email>") - process.exit(1) -} - -// Look up the Stripe customer by email -const customers = await Billing.stripe().customers.list({ email, limit: 10, expand: ["data.subscriptions"] }) -if (!customers.data) { - console.error(`Error: No Stripe customer found for email ${email}`) - process.exit(1) -} -const customer = customers.data.find((c) => c.subscriptions?.data[0]?.items.data[0]?.price.unit_amount === 20000) -if (!customer) { - console.error(`Error: No Stripe customer found for email ${email} with $200 subscription`) - process.exit(1) -} - -const customerID = customer.id -const subscription = customer.subscriptions!.data[0] -const subscriptionID = subscription.id - -// Validate the subscription is $200 -const amountInCents = subscription.items.data[0]?.price.unit_amount ?? 0 -if (amountInCents !== 20000) { - console.error(`Error: Subscription amount is $${amountInCents / 100}, expected $200`) - process.exit(1) -} - -const subscriptionData = await Billing.stripe().subscriptions.retrieve(subscription.id, { expand: ["discounts"] }) -const couponID = - typeof subscriptionData.discounts[0] === "string" - ? subscriptionData.discounts[0] - : subscriptionData.discounts[0]?.coupon?.id - -// Check if subscription is already tied to another workspace -const existingSubscription = await Database.use((tx) => - tx - .select({ workspaceID: BillingTable.workspaceID }) - .from(BillingTable) - .where(sql`JSON_EXTRACT(${BillingTable.subscription}, '$.id') = ${subscriptionID}`) - .then((rows) => rows[0]), -) -if (existingSubscription) { - console.error( - `Error: Subscription ${subscriptionID} is already tied to workspace ${existingSubscription.workspaceID}`, - ) - process.exit(1) -} - -// Look up the workspace billing and check if it already has a customer id or subscription -const billing = await Database.use((tx) => - tx - .select({ customerID: BillingTable.customerID, subscriptionID: BillingTable.subscriptionID }) - .from(BillingTable) - .where(eq(BillingTable.workspaceID, workspaceID)) - .then((rows) => rows[0]), -) -if (billing?.subscriptionID) { - console.error(`Error: Workspace ${workspaceID} already has a subscription: ${billing.subscriptionID}`) - process.exit(1) -} -if (billing?.customerID) { - console.warn( - `Warning: Workspace ${workspaceID} already has a customer id: ${billing.customerID}, replacing with ${customerID}`, - ) -} - -// Get the latest invoice and payment from the subscription -const invoices = await Billing.stripe().invoices.list({ - subscription: subscriptionID, - limit: 1, - expand: ["data.payments"], -}) -const invoice = invoices.data[0] -const invoiceID = invoice?.id -const paymentID = invoice?.payments?.data[0]?.payment.payment_intent as string | undefined - -// Get the default payment method from the customer -const paymentMethodID = (customer.invoice_settings.default_payment_method ?? subscription.default_payment_method) as - | string - | null -const paymentMethod = paymentMethodID ? await Billing.stripe().paymentMethods.retrieve(paymentMethodID) : null -const paymentMethodLast4 = paymentMethod?.card?.last4 ?? null -const paymentMethodType = paymentMethod?.type ?? null - -// Look up the user in the workspace -const users = await Database.use((tx) => - tx - .select({ id: UserTable.id, email: AuthTable.subject }) - .from(UserTable) - .innerJoin(AuthTable, and(eq(AuthTable.accountID, UserTable.accountID), eq(AuthTable.provider, "email"))) - .where(and(eq(UserTable.workspaceID, workspaceID), isNull(UserTable.timeDeleted))), -) -if (users.length === 0) { - console.error(`Error: No users found in workspace ${workspaceID}`) - process.exit(1) -} -const user = users.length === 1 ? users[0] : users.find((u) => u.email === email) -if (!user) { - console.error(`Error: User with email ${email} not found in workspace ${workspaceID}`) - process.exit(1) -} - -// Set workspaceID in Stripe customer metadata -await Billing.stripe().customers.update(customerID, { - metadata: { - workspaceID, - }, -}) - -await Database.transaction(async (tx) => { - // Set customer id, subscription id, and payment method on workspace billing - await tx - .update(BillingTable) - .set({ - customerID, - subscriptionID, - paymentMethodID, - paymentMethodLast4, - paymentMethodType, - subscription: { - status: "subscribed", - coupon: couponID, - seats: 1, - plan: "200", - }, - }) - .where(eq(BillingTable.workspaceID, workspaceID)) - - // Create a row in subscription table - await tx.insert(SubscriptionTable).values({ - workspaceID, - id: Identifier.create("subscription"), - userID: user.id, - }) - - // Create a row in payments table - await tx.insert(PaymentTable).values({ - workspaceID, - id: Identifier.create("payment"), - amount: centsToMicroCents(amountInCents), - customerID, - invoiceID, - paymentID, - enrichment: { - type: "subscription", - couponID, - }, - }) -}) - -console.log(`Successfully onboarded workspace ${workspaceID}`) -console.log(` Customer ID: ${customerID}`) -console.log(` Subscription ID: ${subscriptionID}`) -console.log( - ` Payment Method: ${paymentMethodID ?? "(none)"} (${paymentMethodType ?? "unknown"} ending in ${paymentMethodLast4 ?? "????"})`, -) -console.log(` User ID: ${user.id}`) -console.log(` Invoice ID: ${invoiceID ?? "(none)"}`) -console.log(` Payment ID: ${paymentID ?? "(none)"}`) diff --git a/packages/console/core/script/lookup-user.ts b/packages/console/core/script/lookup-user.ts index 6c76d42c9..0a614bc15 100644 --- a/packages/console/core/script/lookup-user.ts +++ b/packages/console/core/script/lookup-user.ts @@ -244,7 +244,7 @@ function getSubscriptionStatus(row: { return { weekly: null, rolling: null, rateLimited: null, retryIn: null } } - const black = BlackData.get({ plan: row.subscription.plan }) + const black = BlackData.getLimits({ plan: row.subscription.plan }) const now = new Date() const week = getWeekBounds(now) diff --git a/packages/console/core/src/billing.ts b/packages/console/core/src/billing.ts index 36e8a76b7..373f0c595 100644 --- a/packages/console/core/src/billing.ts +++ b/packages/console/core/src/billing.ts @@ -1,6 +1,6 @@ import { Stripe } from "stripe" import { Database, eq, sql } from "./drizzle" -import { BillingTable, PaymentTable, UsageTable } from "./schema/billing.sql" +import { BillingTable, PaymentTable, SubscriptionTable, UsageTable } from "./schema/billing.sql" import { Actor } from "./actor" import { fn } from "./util/fn" import { z } from "zod" @@ -8,6 +8,7 @@ import { Resource } from "@opencode-ai/console-resource" import { Identifier } from "./identifier" import { centsToMicroCents } from "./util/price" import { User } from "./user" +import { BlackData } from "./black" export namespace Billing { export const ITEM_CREDIT_NAME = "opencode credits" @@ -288,4 +289,66 @@ export namespace Billing { return charge.receipt_url }, ) + + export const subscribe = fn(z.object({ + seats: z.number(), + coupon: z.string().optional(), + }), async ({ seats, coupon }) => { + const user = Actor.assert("user") + const billing = await Database.use((tx) => + tx + .select({ + customerID: BillingTable.customerID, + paymentMethodID: BillingTable.paymentMethodID, + subscriptionID: BillingTable.subscriptionID, + subscriptionPlan: BillingTable.subscriptionPlan, + timeSubscriptionSelected: BillingTable.timeSubscriptionSelected, + }) + .from(BillingTable) + .where(eq(BillingTable.workspaceID, Actor.workspace())) + .then((rows) => rows[0]), + ) + + if (!billing) throw new Error("Billing record not found") + if (!billing.timeSubscriptionSelected) throw new Error("Not selected for subscription") + if (billing.subscriptionID) throw new Error("Already subscribed") + if (!billing.customerID) throw new Error("No customer ID") + if (!billing.paymentMethodID) throw new Error("No payment method") + if (!billing.subscriptionPlan) throw new Error("No subscription plan") + + const subscription = await Billing.stripe().subscriptions.create({ + customer: billing.customerID, + default_payment_method: billing.paymentMethodID, + items: [{ price: BlackData.planToPriceID({ plan: billing.subscriptionPlan }) }], + metadata: { + workspaceID: Actor.workspace(), + }, + }) + + await Database.transaction(async (tx) => { + await tx + .update(BillingTable) + .set({ + subscriptionID: subscription.id, + subscription: { + status: "subscribed", + coupon, + seats, + plan: billing.subscriptionPlan!, + }, + subscriptionPlan: null, + timeSubscriptionBooked: null, + timeSubscriptionSelected: null, + }) + .where(eq(BillingTable.workspaceID, Actor.workspace())) + + await tx.insert(SubscriptionTable).values({ + workspaceID: Actor.workspace(), + id: Identifier.create("subscription"), + userID: user.properties.userID, + }) + }) + + return subscription.id + }) } diff --git a/packages/console/core/src/black.ts b/packages/console/core/src/black.ts index 13314a62d..93134de55 100644 --- a/packages/console/core/src/black.ts +++ b/packages/console/core/src/black.ts @@ -28,15 +28,28 @@ export namespace BlackData { return input }) - export const get = fn( - z.object({ + export const getLimits = fn(z.object({ plan: z.enum(SubscriptionPlan), - }), - ({ plan }) => { - const json = JSON.parse(Resource.ZEN_BLACK_LIMITS.value) - return Schema.parse(json)[plan] - }, - ) + }), ({ plan }) => { + const json = JSON.parse(Resource.ZEN_BLACK_LIMITS.value) + return Schema.parse(json)[plan] + }) + + export const planToPriceID = fn(z.object({ + plan: z.enum(SubscriptionPlan), + }), ({ plan }) => { + if (plan === "200") return Resource.ZEN_BLACK_PRICE.plan200 + if (plan === "100") return Resource.ZEN_BLACK_PRICE.plan100 + return Resource.ZEN_BLACK_PRICE.plan20 + }) + + export const priceIDToPlan = fn(z.object({ + priceID: z.string(), + }), ({ priceID }) => { + if (priceID === Resource.ZEN_BLACK_PRICE.plan200) return "200" + if (priceID === Resource.ZEN_BLACK_PRICE.plan100) return "100" + return "20" + }) } export namespace Black { @@ -48,7 +61,7 @@ export namespace Black { }), ({ plan, usage, timeUpdated }) => { const now = new Date() - const black = BlackData.get({ plan }) + const black = BlackData.getLimits({ plan }) const rollingWindowMs = black.rollingWindow * 3600 * 1000 const rollingLimitInMicroCents = centsToMicroCents(black.rollingLimit * 100) const windowStart = new Date(now.getTime() - rollingWindowMs) @@ -83,7 +96,7 @@ export namespace Black { timeUpdated: z.date(), }), ({ plan, usage, timeUpdated }) => { - const black = BlackData.get({ plan }) + const black = BlackData.getLimits({ plan }) const now = new Date() const week = getWeekBounds(now) const fixedLimitInMicroCents = centsToMicroCents(black.fixedLimit * 100) diff --git a/packages/console/core/src/schema/billing.sql.ts b/packages/console/core/src/schema/billing.sql.ts index ae32ed5ce..6f5c55850 100644 --- a/packages/console/core/src/schema/billing.sql.ts +++ b/packages/console/core/src/schema/billing.sql.ts @@ -31,6 +31,7 @@ export const BillingTable = mysqlTable( subscriptionID: varchar("subscription_id", { length: 28 }), subscriptionPlan: mysqlEnum("subscription_plan", SubscriptionPlan), timeSubscriptionBooked: utc("time_subscription_booked"), + timeSubscriptionSelected: utc("time_subscription_selected"), }, (table) => [ ...workspaceIndexes(table), |
