diff --git a/.dev.vars.example b/.dev.vars.example index 41a3e7b2..35b8bcf6 100644 --- a/.dev.vars.example +++ b/.dev.vars.example @@ -7,6 +7,9 @@ BETTER_AUTH_SECRET= # Local ZPan URL. BETTER_AUTH_URL=http://localhost:5185 TRUSTED_ORIGINS=http://localhost:5185 +# Optional comma-separated hosts accepted by the Vite development server. +# Cloudflare Quick Tunnel (*.trycloudflare.com) is already allowed in development. +ZPAN_DEV_ALLOWED_HOSTS= # Local ZPan Cloud URL. ZPAN_CLOUD_URL=http://localhost:5186 diff --git a/cmd/internal/openapi/client.gen.go b/cmd/internal/openapi/client.gen.go index 38114b79..4591d78a 100644 --- a/cmd/internal/openapi/client.gen.go +++ b/cmd/internal/openapi/client.gen.go @@ -1126,6 +1126,21 @@ func (e BrandingThemePreset) Valid() bool { } } +// Defines values for CapacityRequiredError. +const ( + CAPACITYREQUIRED CapacityRequiredError = "CAPACITY_REQUIRED" +) + +// Valid indicates whether the value is a known member of the CapacityRequiredError enum. +func (e CapacityRequiredError) Valid() bool { + switch e { + case CAPACITYREQUIRED: + return true + default: + return false + } +} + // Defines values for CaptchaProvider. const ( Captchafox CaptchaProvider = "captchafox" @@ -2035,6 +2050,7 @@ const ( GetAgentOAuthConsentContext200JSONResponseBodyScopesObjectsDelete GetAgentOAuthConsentContext200JSONResponseBodyScopes = "objects:delete" GetAgentOAuthConsentContext200JSONResponseBodyScopesObjectsRead GetAgentOAuthConsentContext200JSONResponseBodyScopes = "objects:read" GetAgentOAuthConsentContext200JSONResponseBodyScopesObjectsUpdate GetAgentOAuthConsentContext200JSONResponseBodyScopes = "objects:update" + GetAgentOAuthConsentContext200JSONResponseBodyScopesQuotaPurchase GetAgentOAuthConsentContext200JSONResponseBodyScopes = "quota:purchase" GetAgentOAuthConsentContext200JSONResponseBodyScopesQuotaRead GetAgentOAuthConsentContext200JSONResponseBodyScopes = "quota:read" GetAgentOAuthConsentContext200JSONResponseBodyScopesSharesCreate GetAgentOAuthConsentContext200JSONResponseBodyScopes = "shares:create" GetAgentOAuthConsentContext200JSONResponseBodyScopesSharesDelete GetAgentOAuthConsentContext200JSONResponseBodyScopes = "shares:delete" @@ -2053,6 +2069,8 @@ func (e GetAgentOAuthConsentContext200JSONResponseBodyScopes) Valid() bool { return true case GetAgentOAuthConsentContext200JSONResponseBodyScopesObjectsUpdate: return true + case GetAgentOAuthConsentContext200JSONResponseBodyScopesQuotaPurchase: + return true case GetAgentOAuthConsentContext200JSONResponseBodyScopesQuotaRead: return true case GetAgentOAuthConsentContext200JSONResponseBodyScopesSharesCreate: @@ -2074,6 +2092,7 @@ const ( ListAgentOAuthGrants200JSONResponseBodyItemsScopesObjectsDelete ListAgentOAuthGrants200JSONResponseBodyItemsScopes = "objects:delete" ListAgentOAuthGrants200JSONResponseBodyItemsScopesObjectsRead ListAgentOAuthGrants200JSONResponseBodyItemsScopes = "objects:read" ListAgentOAuthGrants200JSONResponseBodyItemsScopesObjectsUpdate ListAgentOAuthGrants200JSONResponseBodyItemsScopes = "objects:update" + ListAgentOAuthGrants200JSONResponseBodyItemsScopesQuotaPurchase ListAgentOAuthGrants200JSONResponseBodyItemsScopes = "quota:purchase" ListAgentOAuthGrants200JSONResponseBodyItemsScopesQuotaRead ListAgentOAuthGrants200JSONResponseBodyItemsScopes = "quota:read" ListAgentOAuthGrants200JSONResponseBodyItemsScopesSharesCreate ListAgentOAuthGrants200JSONResponseBodyItemsScopes = "shares:create" ListAgentOAuthGrants200JSONResponseBodyItemsScopesSharesDelete ListAgentOAuthGrants200JSONResponseBodyItemsScopes = "shares:delete" @@ -2092,6 +2111,8 @@ func (e ListAgentOAuthGrants200JSONResponseBodyItemsScopes) Valid() bool { return true case ListAgentOAuthGrants200JSONResponseBodyItemsScopesObjectsUpdate: return true + case ListAgentOAuthGrants200JSONResponseBodyItemsScopesQuotaPurchase: + return true case ListAgentOAuthGrants200JSONResponseBodyItemsScopesQuotaRead: return true case ListAgentOAuthGrants200JSONResponseBodyItemsScopesSharesCreate: @@ -5006,6 +5027,31 @@ type BrandingThemeValues struct { SidebarAccentColor string `json:"sidebarAccentColor"` } +// CapacityRequired defines model for CapacityRequired. +type CapacityRequired struct { + Error CapacityRequiredError `json:"error"` + Offers []struct { + Amount int `json:"amount"` + Currency string `json:"currency"` + Description *string `json:"description"` + Interval *string `json:"interval"` + IntervalCount *int `json:"intervalCount"` + Name string `json:"name"` + PriceId string `json:"priceId"` + ProductId string `json:"productId"` + PurchaseUrl string `json:"purchaseUrl"` + ResourceId string `json:"resourceId"` + StorageBytes int `json:"storageBytes"` + } `json:"offers"` + QuotaBytes int `json:"quotaBytes"` + RequestHash string `json:"requestHash"` + RequestedBytes int `json:"requestedBytes"` + UsedBytes int `json:"usedBytes"` +} + +// CapacityRequiredError defines model for CapacityRequired.Error. +type CapacityRequiredError string + // CaptchaProvider defines model for CaptchaProvider. type CaptchaProvider string @@ -8322,6 +8368,17 @@ type ListStorageUsageItemsParamsSortDir string // ListStorageUsageItems200JSONResponseBodyItemsSource defines parameters for ListStorageUsageItems. type ListStorageUsageItems200JSONResponseBodyItemsSource string +// PurchaseStorageCapacityJSONBody defines parameters for PurchaseStorageCapacity. +type PurchaseStorageCapacityJSONBody struct { + IdempotencyKey string `json:"idempotencyKey"` + RequestHash string `json:"requestHash"` +} + +// PurchaseStorageCapacityParams defines parameters for PurchaseStorageCapacity. +type PurchaseStorageCapacityParams struct { + PaymentSignature *string `json:"payment-signature,omitempty"` +} + // CreateCheckoutJSONBody defines parameters for CreateCheckout. type CreateCheckoutJSONBody struct { PackageId string `json:"packageId"` @@ -8764,6 +8821,9 @@ type ReplaceStorageJSONRequestBody ReplaceStorageJSONBody // UpdateStorageEgressBillingJSONRequestBody defines body for UpdateStorageEgressBilling for application/json ContentType. type UpdateStorageEgressBillingJSONRequestBody UpdateStorageEgressBillingJSONBody +// PurchaseStorageCapacityJSONRequestBody defines body for PurchaseStorageCapacity for application/json ContentType. +type PurchaseStorageCapacityJSONRequestBody PurchaseStorageCapacityJSONBody + // CreateCheckoutJSONRequestBody defines body for CreateCheckout for application/json ContentType. type CreateCheckoutJSONRequestBody CreateCheckoutJSONBody @@ -11357,6 +11417,11 @@ type ClientInterface interface { // CreateBillingPortalSession request CreateBillingPortalSession(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + // PurchaseStorageCapacityWithBody request with any body + PurchaseStorageCapacityWithBody(ctx context.Context, resourceId string, params *PurchaseStorageCapacityParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + PurchaseStorageCapacity(ctx context.Context, resourceId string, params *PurchaseStorageCapacityParams, body PurchaseStorageCapacityJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // CreateCheckoutWithBody request with any body CreateCheckoutWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -15532,6 +15597,30 @@ func (c *Client) CreateBillingPortalSession(ctx context.Context, reqEditors ...R return c.Client.Do(req) } +func (c *Client) PurchaseStorageCapacityWithBody(ctx context.Context, resourceId string, params *PurchaseStorageCapacityParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPurchaseStorageCapacityRequestWithBody(c.Server, resourceId, params, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) PurchaseStorageCapacity(ctx context.Context, resourceId string, params *PurchaseStorageCapacityParams, body PurchaseStorageCapacityJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPurchaseStorageCapacityRequest(c.Server, resourceId, params, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) CreateCheckoutWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewCreateCheckoutRequestWithBody(c.Server, contentType, body) if err != nil { @@ -26112,6 +26201,68 @@ func NewCreateBillingPortalSessionRequest(server string) (*http.Request, error) return req, nil } +// NewPurchaseStorageCapacityRequest calls the generic PurchaseStorageCapacity builder with application/json body +func NewPurchaseStorageCapacityRequest(server string, resourceId string, params *PurchaseStorageCapacityParams, body PurchaseStorageCapacityJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewPurchaseStorageCapacityRequestWithBody(server, resourceId, params, "application/json", bodyReader) +} + +// NewPurchaseStorageCapacityRequestWithBody generates requests for PurchaseStorageCapacity with any type of body +func NewPurchaseStorageCapacityRequestWithBody(server string, resourceId string, params *PurchaseStorageCapacityParams, contentType string, body io.Reader) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithOptions("simple", false, "resourceId", resourceId, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""}) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/api/store/capacity-purchases/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest(http.MethodPost, queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + if params != nil { + + if params.PaymentSignature != nil { + var headerParam0 string + + headerParam0, err = runtime.StyleParamWithOptions("simple", false, "payment-signature", *params.PaymentSignature, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "string", Format: ""}) + if err != nil { + return nil, err + } + + req.Header.Set("payment-signature", headerParam0) + } + + } + + return req, nil +} + // NewCreateCheckoutRequest calls the generic CreateCheckout builder with application/json body func NewCreateCheckoutRequest(server string, body CreateCheckoutJSONRequestBody) (*http.Request, error) { var bodyReader io.Reader @@ -28475,6 +28626,11 @@ type ClientWithResponsesInterface interface { // CreateBillingPortalSessionWithResponse request CreateBillingPortalSessionWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*CreateBillingPortalSessionResponse, error) + // PurchaseStorageCapacityWithBodyWithResponse request with any body + PurchaseStorageCapacityWithBodyWithResponse(ctx context.Context, resourceId string, params *PurchaseStorageCapacityParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PurchaseStorageCapacityResponse, error) + + PurchaseStorageCapacityWithResponse(ctx context.Context, resourceId string, params *PurchaseStorageCapacityParams, body PurchaseStorageCapacityJSONRequestBody, reqEditors ...RequestEditorFn) (*PurchaseStorageCapacityResponse, error) + // CreateCheckoutWithBodyWithResponse request with any body CreateCheckoutWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateCheckoutResponse, error) @@ -35947,6 +36103,7 @@ type CreateObjectResponse struct { } `json:"upload,omitempty"` } JSON400 *Error + JSON402 *CapacityRequired JSON403 *Error JSON409 *Error JSON503 *Error @@ -38444,6 +38601,43 @@ func (r CreateBillingPortalSessionResponse) ContentType() string { return "" } +type PurchaseStorageCapacityResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *CloudStoreValue + JSON202 *CloudStoreValue + JSON400 *Error + JSON402 *CloudStoreValue + JSON403 *Error + JSON409 *Error + JSON429 *Error + JSON502 *Error +} + +// Status returns HTTPResponse.Status +func (r PurchaseStorageCapacityResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r PurchaseStorageCapacityResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers +func (r PurchaseStorageCapacityResponse) ContentType() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Header.Get("Content-Type") + } + return "" +} + type CreateCheckoutResponse struct { Body []byte HTTPResponse *http.Response @@ -42521,6 +42715,23 @@ func (c *ClientWithResponses) CreateBillingPortalSessionWithResponse(ctx context return ParseCreateBillingPortalSessionResponse(rsp) } +// PurchaseStorageCapacityWithBodyWithResponse request with arbitrary body returning *PurchaseStorageCapacityResponse +func (c *ClientWithResponses) PurchaseStorageCapacityWithBodyWithResponse(ctx context.Context, resourceId string, params *PurchaseStorageCapacityParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PurchaseStorageCapacityResponse, error) { + rsp, err := c.PurchaseStorageCapacityWithBody(ctx, resourceId, params, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePurchaseStorageCapacityResponse(rsp) +} + +func (c *ClientWithResponses) PurchaseStorageCapacityWithResponse(ctx context.Context, resourceId string, params *PurchaseStorageCapacityParams, body PurchaseStorageCapacityJSONRequestBody, reqEditors ...RequestEditorFn) (*PurchaseStorageCapacityResponse, error) { + rsp, err := c.PurchaseStorageCapacity(ctx, resourceId, params, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePurchaseStorageCapacityResponse(rsp) +} + // CreateCheckoutWithBodyWithResponse request with arbitrary body returning *CreateCheckoutResponse func (c *ClientWithResponses) CreateCheckoutWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateCheckoutResponse, error) { rsp, err := c.CreateCheckoutWithBody(ctx, contentType, body, reqEditors...) @@ -53825,6 +54036,13 @@ func ParseCreateObjectResponse(rsp *http.Response) (*CreateObjectResponse, error } response.JSON400 = &dest + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 402: + var dest CapacityRequired + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON402 = &dest + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: var dest Error if err := json.Unmarshal(bodyBytes, &dest); err != nil { @@ -56569,6 +56787,81 @@ func ParseCreateBillingPortalSessionResponse(rsp *http.Response) (*CreateBilling return response, nil } +// ParsePurchaseStorageCapacityResponse parses an HTTP response from a PurchaseStorageCapacityWithResponse call +func ParsePurchaseStorageCapacityResponse(rsp *http.Response) (*PurchaseStorageCapacityResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &PurchaseStorageCapacityResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest CloudStoreValue + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 202: + var dest CloudStoreValue + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON202 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest Error + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 402: + var dest CloudStoreValue + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON402 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest Error + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409: + var dest Error + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON409 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 429: + var dest Error + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON429 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 502: + var dest Error + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON502 = &dest + + } + + return response, nil +} + // ParseCreateCheckoutResponse parses an HTTP response from a CreateCheckoutWithResponse call func ParseCreateCheckoutResponse(rsp *http.Response) (*CreateCheckoutResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) diff --git a/docs/design/agent-authentication.md b/docs/design/agent-authentication.md index 4eb4f08c..625b2b3e 100644 --- a/docs/design/agent-authentication.md +++ b/docs/design/agent-authentication.md @@ -138,16 +138,31 @@ catalog includes: | `shares:create` | Create public shares | | `shares:delete` | Revoke shares | | `quota:read` | Inspect workspace quota | +| `quota:purchase` | Purchase storage capacity for the bound workspace through x402 | | `storage-usage:read` | Inspect workspace storage usage | | `tasks:read` | Inspect task state | -Administrative, billing, credential-management, WebDAV, downloader bootstrap, -and purge authority are not grantable through this catalog. +Administrative, general billing management, credential-management, WebDAV, +downloader bootstrap, and purge authority are not grantable through this +catalog. `quota:purchase` is the narrow exception for autonomous x402 capacity +purchases and cannot manage subscriptions or other billing resources. OAuth is a credential adapter, not a business-logic fork. Middleware resolves a protocol-neutral principal, bound workspace, scope set, and audit actor before calling the same file use cases used by other authenticated clients. +Upgrades that add Agent scopes do not mutate OAuth tables during authentication +startup. Before deploying such an upgrade, operators run the idempotent scope +backfill in dry-run mode and then apply it: + +```sh +pnpm agent-oauth-scopes:backfill -- --d1 zpan-db --remote +pnpm agent-oauth-scopes:backfill -- --d1 zpan-db --remote --apply +``` + +For Node/SQLite deployments, replace the D1 arguments with +`--sqlite `. + ## Self-Describing Direct Upload File bytes continue to bypass ZPan and go directly to S3-compatible storage. diff --git a/migrations/0087_x402_capacity_purchases.sql b/migrations/0087_x402_capacity_purchases.sql new file mode 100644 index 00000000..f6e78ba1 --- /dev/null +++ b/migrations/0087_x402_capacity_purchases.sql @@ -0,0 +1,18 @@ +CREATE TABLE `x402_capacity_purchase_intents` ( + `id` text PRIMARY KEY NOT NULL, + `org_id` text NOT NULL, + `resource_id` text NOT NULL, + `request_hash` text NOT NULL, + `idempotency_key` text NOT NULL, + `cloud_order_id` text, + `cloud_attempt_id` text, + `status` text DEFAULT 'created' NOT NULL, + `expires_at` integer, + `created_at` integer NOT NULL, + `updated_at` integer NOT NULL +); +--> statement-breakpoint +CREATE UNIQUE INDEX `x402_capacity_purchase_intents_org_request_uniq` ON `x402_capacity_purchase_intents` (`org_id`,`resource_id`,`request_hash`);--> statement-breakpoint +CREATE UNIQUE INDEX `x402_capacity_purchase_intents_idempotency_uniq` ON `x402_capacity_purchase_intents` (`idempotency_key`);--> statement-breakpoint +CREATE INDEX `x402_capacity_purchase_intents_attempt_idx` ON `x402_capacity_purchase_intents` (`cloud_attempt_id`);--> statement-breakpoint +DROP INDEX `org_quota_entitlements_active_plan_uniq`; \ No newline at end of file diff --git a/migrations/0088_x402_tenant_idempotency.sql b/migrations/0088_x402_tenant_idempotency.sql new file mode 100644 index 00000000..0c4148ca --- /dev/null +++ b/migrations/0088_x402_tenant_idempotency.sql @@ -0,0 +1,2 @@ +DROP INDEX `x402_capacity_purchase_intents_idempotency_uniq`;--> statement-breakpoint +CREATE UNIQUE INDEX `x402_capacity_purchase_intents_org_idempotency_uniq` ON `x402_capacity_purchase_intents` (`org_id`,`idempotency_key`); \ No newline at end of file diff --git a/migrations/0089_better-auth-account-issuer-backfill.sql b/migrations/0089_better-auth-account-issuer-backfill.sql new file mode 100644 index 00000000..5fda0a39 --- /dev/null +++ b/migrations/0089_better-auth-account-issuer-backfill.sql @@ -0,0 +1,18 @@ +-- Better Auth providers can define trusted issuer semantics. Abort on unknown +-- legacy providers instead of assigning an issuer that could join the wrong identity. +SELECT CASE + WHEN EXISTS ( + SELECT 1 + FROM `account` + WHERE `issuer` = '' + AND `provider_id` NOT IN ('credential', 'github', 'google') + ) THEN json_extract('unsupported legacy account provider', '$') + ELSE NULL +END;--> statement-breakpoint +UPDATE `account` +SET `issuer` = CASE + WHEN `provider_id` = 'credential' THEN 'local:credential' + WHEN `provider_id` = 'github' THEN 'local:oauth:github' + WHEN `provider_id` = 'google' THEN 'https://accounts.google.com' +END +WHERE `issuer` = ''; diff --git a/migrations/meta/0087_snapshot.json b/migrations/meta/0087_snapshot.json new file mode 100644 index 00000000..19151939 --- /dev/null +++ b/migrations/meta/0087_snapshot.json @@ -0,0 +1,6218 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "64b4d2c4-9851-49e5-94a8-481e1d79ef70", + "prevId": "6c131458-27c9-48c1-9cca-81032a1725bd", + "tables": { + "announcements": { + "name": "announcements", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "published_at": { + "name": "published_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "announcements_status_priority_idx": { + "name": "announcements_status_priority_idx", + "columns": [ + "status", + "priority" + ], + "isUnique": false + }, + "announcements_published_idx": { + "name": "announcements_published_idx", + "columns": [ + "published_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "audit_events": { + "name": "audit_events", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_type": { + "name": "target_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_id": { + "name": "target_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_name": { + "name": "target_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actor_type": { + "name": "actor_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actor_ref": { + "name": "actor_ref", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actor_issuer": { + "name": "actor_issuer", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "audit_events_org_created_idx": { + "name": "audit_events_org_created_idx", + "columns": [ + "org_id", + "created_at" + ], + "isUnique": false + }, + "audit_events_user_created_idx": { + "name": "audit_events_user_created_idx", + "columns": [ + "user_id", + "created_at" + ], + "isUnique": false + }, + "audit_events_action_created_idx": { + "name": "audit_events_action_created_idx", + "columns": [ + "action", + "created_at" + ], + "isUnique": false + }, + "audit_events_target_created_idx": { + "name": "audit_events_target_created_idx", + "columns": [ + "target_type", + "target_id", + "created_at" + ], + "isUnique": false + }, + "audit_events_created_idx": { + "name": "audit_events_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "background_jobs": { + "name": "background_jobs", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_folder": { + "name": "target_folder", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_path": { + "name": "target_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "input_bytes": { + "name": "input_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "output_bytes": { + "name": "output_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "processed_bytes": { + "name": "processed_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "file_count": { + "name": "file_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "current_filename": { + "name": "current_filename", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "result_metadata": { + "name": "result_metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "retryable": { + "name": "retryable", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "cancelable": { + "name": "cancelable", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "retried_from_job_id": { + "name": "retried_from_job_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "finished_at": { + "name": "finished_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "background_jobs_org_created_idx": { + "name": "background_jobs_org_created_idx", + "columns": [ + "org_id", + "created_at" + ], + "isUnique": false + }, + "background_jobs_org_status_idx": { + "name": "background_jobs_org_status_idx", + "columns": [ + "org_id", + "status" + ], + "isUnique": false + }, + "background_jobs_org_type_idx": { + "name": "background_jobs_org_type_idx", + "columns": [ + "org_id", + "type" + ], + "isUnique": false + }, + "background_jobs_created_idx": { + "name": "background_jobs_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + }, + "background_jobs_org_page_idx": { + "name": "background_jobs_org_page_idx", + "columns": [ + "org_id", + "created_at", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "cloud_traffic_reports": { + "name": "cloud_traffic_reports", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "period": { + "name": "period", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "bytes": { + "name": "bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "unit_bytes": { + "name": "unit_bytes", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "credits_per_unit": { + "name": "credits_per_unit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "attempt_count": { + "name": "attempt_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "next_retry_at": { + "name": "next_retry_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "issued_at": { + "name": "issued_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "cloud_traffic_reports_event_uniq": { + "name": "cloud_traffic_reports_event_uniq", + "columns": [ + "event_id" + ], + "isUnique": true + }, + "cloud_traffic_reports_org_period_idx": { + "name": "cloud_traffic_reports_org_period_idx", + "columns": [ + "org_id", + "period" + ], + "isUnique": false + }, + "cloud_traffic_reports_status_idx": { + "name": "cloud_traffic_reports_status_idx", + "columns": [ + "status" + ], + "isUnique": false + }, + "cloud_traffic_reports_retry_idx": { + "name": "cloud_traffic_reports_retry_idx", + "columns": [ + "status", + "next_retry_at", + "created_at" + ], + "isUnique": false + }, + "cloud_traffic_reports_issued_idx": { + "name": "cloud_traffic_reports_issued_idx", + "columns": [ + "issued_at" + ], + "isUnique": false + }, + "cloud_traffic_reports_updated_idx": { + "name": "cloud_traffic_reports_updated_idx", + "columns": [ + "updated_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "download_tasks": { + "name": "download_tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_uri": { + "name": "source_uri", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_folder": { + "name": "target_folder", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tags": { + "name": "tags", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "assigned_downloader_id": { + "name": "assigned_downloader_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "attempt": { + "name": "attempt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "billing_authorized_bytes": { + "name": "billing_authorized_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "billing_charged_bytes": { + "name": "billing_charged_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "billing_charged_credits": { + "name": "billing_charged_credits", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "billing_status": { + "name": "billing_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'none'" + }, + "error_code": { + "name": "error_code", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "result_object_id": { + "name": "result_object_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "runtime": { + "name": "runtime", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "events": { + "name": "events", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "resolve_started_at": { + "name": "resolve_started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resolve_completed_at": { + "name": "resolve_completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "download_completed_at": { + "name": "download_completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ingest_started_at": { + "name": "ingest_started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ingest_completed_at": { + "name": "ingest_completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "seeding_started_at": { + "name": "seeding_started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "seeding_stopped_at": { + "name": "seeding_stopped_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "assigned_at": { + "name": "assigned_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "finished_at": { + "name": "finished_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "download_tasks_org_created_idx": { + "name": "download_tasks_org_created_idx", + "columns": [ + "org_id", + "created_at" + ], + "isUnique": false + }, + "download_tasks_org_status_idx": { + "name": "download_tasks_org_status_idx", + "columns": [ + "org_id", + "status" + ], + "isUnique": false + }, + "download_tasks_org_category_idx": { + "name": "download_tasks_org_category_idx", + "columns": [ + "org_id", + "category" + ], + "isUnique": false + }, + "download_tasks_org_tags_idx": { + "name": "download_tasks_org_tags_idx", + "columns": [ + "org_id", + "tags" + ], + "isUnique": false + }, + "download_tasks_downloader_idx": { + "name": "download_tasks_downloader_idx", + "columns": [ + "assigned_downloader_id", + "status" + ], + "isUnique": false + }, + "download_tasks_created_idx": { + "name": "download_tasks_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + }, + "download_tasks_finished_idx": { + "name": "download_tasks_finished_idx", + "columns": [ + "finished_at" + ], + "isUnique": false + }, + "download_tasks_org_deleted_created_idx": { + "name": "download_tasks_org_deleted_created_idx", + "columns": [ + "org_id", + "deleted_at", + "created_at" + ], + "isUnique": false + }, + "download_tasks_org_page_idx": { + "name": "download_tasks_org_page_idx", + "columns": [ + "org_id", + "deleted_at", + "created_at", + "id" + ], + "isUnique": false + }, + "download_tasks_downloader_page_idx": { + "name": "download_tasks_downloader_page_idx", + "columns": [ + "assigned_downloader_id", + "deleted_at", + "created_at", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "downloaders": { + "name": "downloaders", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token_jti": { + "name": "token_jti", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'offline'" + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "hostname": { + "name": "hostname", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "platform": { + "name": "platform", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "arch": { + "name": "arch", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "engine": { + "name": "engine", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'http'" + }, + "capabilities": { + "name": "capabilities", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "max_concurrent_tasks": { + "name": "max_concurrent_tasks", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "current_tasks": { + "name": "current_tasks", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "download_bps": { + "name": "download_bps", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "upload_bps": { + "name": "upload_bps", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "free_disk_bytes": { + "name": "free_disk_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "remote_download_credit_billing_enabled": { + "name": "remote_download_credit_billing_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "remote_download_credit_unit_bytes": { + "name": "remote_download_credit_unit_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 104857600 + }, + "remote_download_credit_per_unit": { + "name": "remote_download_credit_per_unit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "last_heartbeat_at": { + "name": "last_heartbeat_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "downloaders_token_jti_unique": { + "name": "downloaders_token_jti_unique", + "columns": [ + "token_jti" + ], + "isUnique": true + }, + "downloaders_status_idx": { + "name": "downloaders_status_idx", + "columns": [ + "status" + ], + "isUnique": false + }, + "downloaders_enabled_idx": { + "name": "downloaders_enabled_idx", + "columns": [ + "enabled" + ], + "isUnique": false + }, + "downloaders_created_idx": { + "name": "downloaders_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "image_hosting_configs": { + "name": "image_hosting_configs", + "columns": { + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "custom_domain": { + "name": "custom_domain", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_provider": { + "name": "domain_provider", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider_hostname_id": { + "name": "provider_hostname_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_status": { + "name": "domain_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_error": { + "name": "domain_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "verification_token": { + "name": "verification_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_last_checked_at": { + "name": "domain_last_checked_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_verified_at": { + "name": "domain_verified_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "referer_allowlist": { + "name": "referer_allowlist", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "image_hosting_configs_custom_domain_unique": { + "name": "image_hosting_configs_custom_domain_unique", + "columns": [ + "custom_domain" + ], + "isUnique": true + } + }, + "foreignKeys": { + "image_hosting_configs_org_id_organization_id_fk": { + "name": "image_hosting_configs_org_id_organization_id_fk", + "tableFrom": "image_hosting_configs", + "tableTo": "organization", + "columnsFrom": [ + "org_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "image_hostings": { + "name": "image_hostings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_key": { + "name": "storage_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mime": { + "name": "mime", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "purged_at": { + "name": "purged_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_count": { + "name": "access_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "last_accessed_at": { + "name": "last_accessed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "image_hostings_token_unique": { + "name": "image_hostings_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "image_hostings_org_path_uniq": { + "name": "image_hostings_org_path_uniq", + "columns": [ + "org_id", + "path" + ], + "isUnique": true, + "where": "\"image_hostings\".\"purged_at\" IS NULL" + }, + "image_hostings_org_created_idx": { + "name": "image_hostings_org_created_idx", + "columns": [ + "org_id", + "created_at" + ], + "isUnique": false + }, + "image_hostings_page_idx": { + "name": "image_hostings_page_idx", + "columns": [ + "org_id", + "status", + "purged_at", + "created_at", + "id" + ], + "isUnique": false + }, + "image_hostings_token_idx": { + "name": "image_hostings_token_idx", + "columns": [ + "token" + ], + "isUnique": false + } + }, + "foreignKeys": { + "image_hostings_org_id_organization_id_fk": { + "name": "image_hostings_org_id_organization_id_fk", + "tableFrom": "image_hostings", + "tableTo": "organization", + "columnsFrom": [ + "org_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "image_hostings_storage_id_storages_id_fk": { + "name": "image_hostings_storage_id_storages_id_fk", + "tableFrom": "image_hostings", + "tableTo": "storages", + "columnsFrom": [ + "storage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invite_codes": { + "name": "invite_codes", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "used_by": { + "name": "used_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "used_at": { + "name": "used_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invite_codes_code_unique": { + "name": "invite_codes_code_unique", + "columns": [ + "code" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "license_bindings": { + "name": "license_bindings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "cloud_binding_id": { + "name": "cloud_binding_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cloud_store_id": { + "name": "cloud_store_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "instance_id": { + "name": "instance_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cloud_account_id": { + "name": "cloud_account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cloud_account_email": { + "name": "cloud_account_email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cached_certificate": { + "name": "cached_certificate", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cached_certificate_expires_at": { + "name": "cached_certificate_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bound_at": { + "name": "bound_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "disconnected_at": { + "name": "disconnected_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_refresh_at": { + "name": "last_refresh_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_refresh_error": { + "name": "last_refresh_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "license_bindings_active_uniq": { + "name": "license_bindings_active_uniq", + "columns": [ + "status" + ], + "isUnique": true, + "where": "status = 'active'" + }, + "license_bindings_cloud_binding_idx": { + "name": "license_bindings_cloud_binding_idx", + "columns": [ + "cloud_binding_id" + ], + "isUnique": false + }, + "license_bindings_instance_idx": { + "name": "license_bindings_instance_idx", + "columns": [ + "instance_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "matters": { + "name": "matters", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "alias": { + "name": "alias", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "dirtype": { + "name": "dirtype", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "parent": { + "name": "parent", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "object": { + "name": "object", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "trashed_at": { + "name": "trashed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "purged_at": { + "name": "purged_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "matters_alias_unique": { + "name": "matters_alias_unique", + "columns": [ + "alias" + ], + "isUnique": true + }, + "matters_status_dir_created_idx": { + "name": "matters_status_dir_created_idx", + "columns": [ + "status", + "dirtype", + "created_at" + ], + "isUnique": false + }, + "matters_webdav_path_idx": { + "name": "matters_webdav_path_idx", + "columns": [ + "org_id", + "parent", + "name", + "status", + "trashed_at", + "purged_at" + ], + "isUnique": false + }, + "matters_webdav_children_idx": { + "name": "matters_webdav_children_idx", + "columns": [ + "org_id", + "parent", + "status", + "trashed_at", + "purged_at", + "\"dirtype\" desc", + "name" + ], + "isUnique": false + }, + "matters_list_page_idx": { + "name": "matters_list_page_idx", + "columns": [ + "org_id", + "parent", + "status", + "trashed_at", + "purged_at", + "\"dirtype\" desc", + "created_at", + "id" + ], + "isUnique": false + }, + "matters_trash_page_idx": { + "name": "matters_trash_page_idx", + "columns": [ + "org_id", + "status", + "purged_at", + "trashed_at", + "created_at", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "notifications": { + "name": "notifications", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "ref_type": { + "name": "ref_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ref_id": { + "name": "ref_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "read_at": { + "name": "read_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "notifications_user_created_idx": { + "name": "notifications_user_created_idx", + "columns": [ + "user_id", + "created_at" + ], + "isUnique": false + }, + "notifications_user_read_idx": { + "name": "notifications_user_read_idx", + "columns": [ + "user_id", + "read_at" + ], + "isUnique": false + }, + "notifications_user_page_idx": { + "name": "notifications_user_page_idx", + "columns": [ + "user_id", + "read_at", + "created_at", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "object_upload_sessions": { + "name": "object_upload_sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "object_id": { + "name": "object_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_key": { + "name": "storage_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "upload_id": { + "name": "upload_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "part_size": { + "name": "part_size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "on_conflict": { + "name": "on_conflict", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'fail'" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "object_upload_sessions_object_idx": { + "name": "object_upload_sessions_object_idx", + "columns": [ + "org_id", + "object_id" + ], + "isUnique": false + }, + "object_upload_sessions_expires_idx": { + "name": "object_upload_sessions_expires_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "org_quota_entitlements": { + "name": "org_quota_entitlements", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "entitlement_type": { + "name": "entitlement_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'grant'" + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "bytes": { + "name": "bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "starts_at": { + "name": "starts_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "org_quota_entitlements_org_resource_idx": { + "name": "org_quota_entitlements_org_resource_idx", + "columns": [ + "org_id", + "resource_type", + "status" + ], + "isUnique": false + }, + "org_quota_entitlements_org_type_idx": { + "name": "org_quota_entitlements_org_type_idx", + "columns": [ + "org_id", + "resource_type", + "entitlement_type", + "status" + ], + "isUnique": false + }, + "org_quota_entitlements_source_resource_uniq": { + "name": "org_quota_entitlements_source_resource_uniq", + "columns": [ + "source", + "source_id", + "resource_type" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "org_quotas": { + "name": "org_quotas", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "quota": { + "name": "quota", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "used": { + "name": "used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "traffic_quota": { + "name": "traffic_quota", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "traffic_used": { + "name": "traffic_used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "traffic_period": { + "name": "traffic_period", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'1970-01'" + } + }, + "indexes": { + "org_quotas_org_uniq": { + "name": "org_quotas_org_uniq", + "columns": [ + "org_id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "remote_download_usage_reports": { + "name": "remote_download_usage_reports", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "downloader_id": { + "name": "downloader_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "unit_index": { + "name": "unit_index", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "unit_bytes": { + "name": "unit_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credits_per_unit": { + "name": "credits_per_unit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "remote_download_usage_reports_event_id_unique": { + "name": "remote_download_usage_reports_event_id_unique", + "columns": [ + "event_id" + ], + "isUnique": true + }, + "remote_download_usage_task_unit_uniq": { + "name": "remote_download_usage_task_unit_uniq", + "columns": [ + "task_id", + "unit_index" + ], + "isUnique": true + }, + "remote_download_usage_org_idx": { + "name": "remote_download_usage_org_idx", + "columns": [ + "org_id" + ], + "isUnique": false + }, + "remote_download_usage_status_idx": { + "name": "remote_download_usage_status_idx", + "columns": [ + "status" + ], + "isUnique": false + }, + "remote_download_usage_created_idx": { + "name": "remote_download_usage_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "resource_changes": { + "name": "resource_changes", + "columns": { + "sequence": { + "name": "sequence", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "scope_type": { + "name": "scope_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scope_id": { + "name": "scope_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "change_type": { + "name": "change_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "occurred_at": { + "name": "occurred_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "resource_changes_scope_sequence_idx": { + "name": "resource_changes_scope_sequence_idx", + "columns": [ + "scope_type", + "scope_id", + "sequence" + ], + "isUnique": false + }, + "resource_changes_resource_sequence_idx": { + "name": "resource_changes_resource_sequence_idx", + "columns": [ + "resource_type", + "resource_id", + "sequence" + ], + "isUnique": false + }, + "resource_changes_occurred_idx": { + "name": "resource_changes_occurred_idx", + "columns": [ + "occurred_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "share_recipients": { + "name": "share_recipients", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "share_id": { + "name": "share_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "recipient_user_id": { + "name": "recipient_user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "recipient_email": { + "name": "recipient_email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "share_recipients_share_id_idx": { + "name": "share_recipients_share_id_idx", + "columns": [ + "share_id" + ], + "isUnique": false + }, + "share_recipients_user_id_idx": { + "name": "share_recipients_user_id_idx", + "columns": [ + "recipient_user_id" + ], + "isUnique": false + }, + "share_recipients_email_idx": { + "name": "share_recipients_email_idx", + "columns": [ + "recipient_email" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "shares": { + "name": "shares", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "matter_id": { + "name": "matter_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "download_limit": { + "name": "download_limit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "views": { + "name": "views", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "downloads": { + "name": "downloads", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'active'" + }, + "private": { + "name": "private", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "shares_token_unique": { + "name": "shares_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "shares_creator_status_created_idx": { + "name": "shares_creator_status_created_idx", + "columns": [ + "creator_id", + "status", + "created_at", + "id" + ], + "isUnique": false + }, + "shares_creator_private_created_idx": { + "name": "shares_creator_private_created_idx", + "columns": [ + "creator_id", + "private", + "created_at" + ], + "isUnique": false + }, + "shares_created_idx": { + "name": "shares_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "site_invitations": { + "name": "site_invitations", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "invited_by": { + "name": "invited_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "accepted_by": { + "name": "accepted_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "accepted_at": { + "name": "accepted_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "revoked_by": { + "name": "revoked_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "site_invitations_token_unique": { + "name": "site_invitations_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "site_invitations_email_idx": { + "name": "site_invitations_email_idx", + "columns": [ + "email" + ], + "isUnique": false + }, + "site_invitations_created_idx": { + "name": "site_invitations_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + }, + "site_invitations_expires_idx": { + "name": "site_invitations_expires_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "stats_rollups_hourly": { + "name": "stats_rollups_hourly", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "bucket_start": { + "name": "bucket_start", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "metric_key": { + "name": "metric_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dimension_key": { + "name": "dimension_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "dimension_value": { + "name": "dimension_value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "bytes": { + "name": "bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "unique_count": { + "name": "unique_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "stats_rollups_hourly_bucket_metric_dim_uniq": { + "name": "stats_rollups_hourly_bucket_metric_dim_uniq", + "columns": [ + "bucket_start", + "org_id", + "metric_key", + "dimension_key", + "dimension_value" + ], + "isUnique": true + }, + "stats_rollups_hourly_metric_bucket_idx": { + "name": "stats_rollups_hourly_metric_bucket_idx", + "columns": [ + "metric_key", + "bucket_start" + ], + "isUnique": false + }, + "stats_rollups_hourly_dimension_bucket_idx": { + "name": "stats_rollups_hourly_dimension_bucket_idx", + "columns": [ + "metric_key", + "dimension_key", + "bucket_start" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "storage_usage_breakdowns": { + "name": "storage_usage_breakdowns", + "columns": { + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "bytes": { + "name": "bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "file_count": { + "name": "file_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "storage_usage_breakdowns_org_category_uniq": { + "name": "storage_usage_breakdowns_org_category_uniq", + "columns": [ + "org_id", + "category" + ], + "isUnique": true + }, + "storage_usage_breakdowns_org_idx": { + "name": "storage_usage_breakdowns_org_idx", + "columns": [ + "org_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "storage_usage_ledger": { + "name": "storage_usage_ledger", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "event_key": { + "name": "event_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "delta_bytes": { + "name": "delta_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "occurred_at": { + "name": "occurred_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "storage_usage_ledger_event_key_unique": { + "name": "storage_usage_ledger_event_key_unique", + "columns": [ + "event_key" + ], + "isUnique": true + }, + "storage_usage_ledger_occurred_idx": { + "name": "storage_usage_ledger_occurred_idx", + "columns": [ + "occurred_at" + ], + "isUnique": false + }, + "storage_usage_ledger_org_occurred_idx": { + "name": "storage_usage_ledger_org_occurred_idx", + "columns": [ + "org_id", + "occurred_at" + ], + "isUnique": false + }, + "storage_usage_ledger_storage_occurred_idx": { + "name": "storage_usage_ledger_storage_occurred_idx", + "columns": [ + "storage_id", + "occurred_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "storages": { + "name": "storages", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'auto'" + }, + "access_key": { + "name": "access_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "secret_key": { + "name": "secret_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "custom_host": { + "name": "custom_host", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "''" + }, + "capacity": { + "name": "capacity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "egress_credit_billing_enabled": { + "name": "egress_credit_billing_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "egress_credit_unit_bytes": { + "name": "egress_credit_unit_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 104857600 + }, + "egress_credit_per_unit": { + "name": "egress_credit_per_unit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "force_path_style": { + "name": "force_path_style", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "used": { + "name": "used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "status_reason": { + "name": "status_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status_checked_at": { + "name": "status_checked_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "system_options": { + "name": "system_options", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "team_invite_links": { + "name": "team_invite_links", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'member'" + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "team_invite_links_token_unique": { + "name": "team_invite_links_token_unique", + "columns": [ + "token" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "webdav_dead_properties": { + "name": "webdav_dead_properties", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_path": { + "name": "resource_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "namespace": { + "name": "namespace", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "webdav_dead_properties_resource_prop_uniq": { + "name": "webdav_dead_properties_resource_prop_uniq", + "columns": [ + "org_id", + "resource_path", + "namespace", + "name" + ], + "isUnique": true + }, + "webdav_dead_properties_resource_idx": { + "name": "webdav_dead_properties_resource_idx", + "columns": [ + "org_id", + "resource_path" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "webdav_locks": { + "name": "webdav_locks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_path": { + "name": "resource_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "depth": { + "name": "depth", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'infinity'" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "webdav_locks_token_unique": { + "name": "webdav_locks_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "webdav_locks_resource_idx": { + "name": "webdav_locks_resource_idx", + "columns": [ + "org_id", + "resource_path" + ], + "isUnique": false + }, + "webdav_locks_expires_idx": { + "name": "webdav_locks_expires_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "webhook_events": { + "name": "webhook_events", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'cloud'" + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'order.quota_changed'" + }, + "payload_hash": { + "name": "payload_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "raw_payload": { + "name": "raw_payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "processed_at": { + "name": "processed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "webhook_events_source_event_uniq": { + "name": "webhook_events_source_event_uniq", + "columns": [ + "source", + "event_id" + ], + "isUnique": true + }, + "webhook_events_source_created_idx": { + "name": "webhook_events_source_created_idx", + "columns": [ + "source", + "created_at" + ], + "isUnique": false + }, + "webhook_events_status_idx": { + "name": "webhook_events_status_idx", + "columns": [ + "status" + ], + "isUnique": false + }, + "webhook_events_processed_idx": { + "name": "webhook_events_processed_idx", + "columns": [ + "processed_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "x402_capacity_purchase_intents": { + "name": "x402_capacity_purchase_intents", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "request_hash": { + "name": "request_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "idempotency_key": { + "name": "idempotency_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cloud_order_id": { + "name": "cloud_order_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cloud_attempt_id": { + "name": "cloud_attempt_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'created'" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "x402_capacity_purchase_intents_org_request_uniq": { + "name": "x402_capacity_purchase_intents_org_request_uniq", + "columns": [ + "org_id", + "resource_id", + "request_hash" + ], + "isUnique": true + }, + "x402_capacity_purchase_intents_idempotency_uniq": { + "name": "x402_capacity_purchase_intents_idempotency_uniq", + "columns": [ + "idempotency_key" + ], + "isUnique": true + }, + "x402_capacity_purchase_intents_attempt_idx": { + "name": "x402_capacity_purchase_intents_attempt_idx", + "columns": [ + "cloud_attempt_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "account": { + "name": "account", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "issuer": { + "name": "issuer", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "account_issuer_providerAccountId_unique": { + "name": "account_issuer_providerAccountId_unique", + "columns": [ + "issuer", + "account_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "apikey": { + "name": "apikey", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "config_id": { + "name": "config_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'default'" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "start": { + "name": "start", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refill_interval": { + "name": "refill_interval", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refill_amount": { + "name": "refill_amount", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "rate_limit_enabled": { + "name": "rate_limit_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "rate_limit_time_window": { + "name": "rate_limit_time_window", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rate_limit_max": { + "name": "rate_limit_max", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "request_count": { + "name": "request_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "remaining": { + "name": "remaining", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_request": { + "name": "last_request", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permissions": { + "name": "permissions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "apikey_config_id_idx": { + "name": "apikey_config_id_idx", + "columns": [ + "config_id" + ], + "isUnique": false + }, + "apikey_reference_id_idx": { + "name": "apikey_reference_id_idx", + "columns": [ + "reference_id" + ], + "isUnique": false + }, + "apikey_key_idx": { + "name": "apikey_key_idx", + "columns": [ + "key" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "deviceCode": { + "name": "deviceCode", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "device_code": { + "name": "device_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_code": { + "name": "user_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_polled_at": { + "name": "last_polled_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "polling_interval": { + "name": "polling_interval", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "deviceCode_device_code_idx": { + "name": "deviceCode_device_code_idx", + "columns": [ + "device_code" + ], + "isUnique": false + }, + "deviceCode_user_code_idx": { + "name": "deviceCode_user_code_idx", + "columns": [ + "user_code" + ], + "isUnique": false + }, + "deviceCode_status_idx": { + "name": "deviceCode_status_idx", + "columns": [ + "status" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "downloader_bootstrap_credentials": { + "name": "downloader_bootstrap_credentials", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_code": { + "name": "device_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "consumed_at": { + "name": "consumed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "downloader_bootstrap_credentials_token_hash_unique": { + "name": "downloader_bootstrap_credentials_token_hash_unique", + "columns": [ + "token_hash" + ], + "isUnique": true + }, + "downloader_bootstrap_token_hash_idx": { + "name": "downloader_bootstrap_token_hash_idx", + "columns": [ + "token_hash" + ], + "isUnique": false + }, + "downloader_bootstrap_user_idx": { + "name": "downloader_bootstrap_user_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "downloader_bootstrap_consumed_idx": { + "name": "downloader_bootstrap_consumed_idx", + "columns": [ + "consumed_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "downloader_bootstrap_credentials_user_id_user_id_fk": { + "name": "downloader_bootstrap_credentials_user_id_user_id_fk", + "tableFrom": "downloader_bootstrap_credentials", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invitation": { + "name": "invitation", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invitation_organizationId_idx": { + "name": "invitation_organizationId_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "invitation_email_idx": { + "name": "invitation_email_idx", + "columns": [ + "email" + ], + "isUnique": false + } + }, + "foreignKeys": { + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_inviter_id_user_id_fk": { + "name": "invitation_inviter_id_user_id_fk", + "tableFrom": "invitation", + "tableTo": "user", + "columnsFrom": [ + "inviter_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "jwks": { + "name": "jwks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "private_key": { + "name": "private_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "alg": { + "name": "alg", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "crv": { + "name": "crv", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "member": { + "name": "member", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'member'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "member_organizationId_idx": { + "name": "member_organizationId_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "member_userId_idx": { + "name": "member_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "member_user_id_user_id_fk": { + "name": "member_user_id_user_id_fk", + "tableFrom": "member", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthAccessToken": { + "name": "oauthAccessToken", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "authorization_code_id": { + "name": "authorization_code_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resources": { + "name": "resources", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "requested_user_info_claims": { + "name": "requested_user_info_claims", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_id": { + "name": "refresh_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "revoked": { + "name": "revoked", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "confirmation": { + "name": "confirmation", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "oauthAccessToken_token_unique": { + "name": "oauthAccessToken_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "oauthAccessToken_client_id_idx": { + "name": "oauthAccessToken_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthAccessToken_session_id_idx": { + "name": "oauthAccessToken_session_id_idx", + "columns": [ + "session_id" + ], + "isUnique": false + }, + "oauthAccessToken_user_id_idx": { + "name": "oauthAccessToken_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "oauthAccessToken_refresh_id_idx": { + "name": "oauthAccessToken_refresh_id_idx", + "columns": [ + "refresh_id" + ], + "isUnique": false + }, + "oauthAccessToken_token_idx": { + "name": "oauthAccessToken_token_idx", + "columns": [ + "token" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthAccessToken_client_id_oauthClient_client_id_fk": { + "name": "oauthAccessToken_client_id_oauthClient_client_id_fk", + "tableFrom": "oauthAccessToken", + "tableTo": "oauthClient", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "client_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauthAccessToken_session_id_session_id_fk": { + "name": "oauthAccessToken_session_id_session_id_fk", + "tableFrom": "oauthAccessToken", + "tableTo": "session", + "columnsFrom": [ + "session_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "oauthAccessToken_user_id_user_id_fk": { + "name": "oauthAccessToken_user_id_user_id_fk", + "tableFrom": "oauthAccessToken", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauthAccessToken_refresh_id_oauthRefreshToken_id_fk": { + "name": "oauthAccessToken_refresh_id_oauthRefreshToken_id_fk", + "tableFrom": "oauthAccessToken", + "tableTo": "oauthRefreshToken", + "columnsFrom": [ + "refresh_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthClient": { + "name": "oauthClient", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_secret": { + "name": "client_secret", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "disabled": { + "name": "disabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "skip_consent": { + "name": "skip_consent", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enable_end_session": { + "name": "enable_end_session", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_type": { + "name": "subject_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "uri": { + "name": "uri", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "contacts": { + "name": "contacts", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tos": { + "name": "tos", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "policy": { + "name": "policy", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "software_id": { + "name": "software_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "software_version": { + "name": "software_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "software_statement": { + "name": "software_statement", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "redirect_uris": { + "name": "redirect_uris", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_logout_redirect_uris": { + "name": "post_logout_redirect_uris", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "backchannel_logout_uri": { + "name": "backchannel_logout_uri", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "backchannel_logout_session_required": { + "name": "backchannel_logout_session_required", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_endpoint_auth_method": { + "name": "token_endpoint_auth_method", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "jwks": { + "name": "jwks", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "jwks_uri": { + "name": "jwks_uri", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "grant_types": { + "name": "grant_types", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "response_types": { + "name": "response_types", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "public": { + "name": "public", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "require_pkce": { + "name": "require_pkce", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dpop_bound_access_tokens": { + "name": "dpop_bound_access_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "oauthClient_client_id_unique": { + "name": "oauthClient_client_id_unique", + "columns": [ + "client_id" + ], + "isUnique": true + }, + "oauthClient_client_id_idx": { + "name": "oauthClient_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthClient_user_id_idx": { + "name": "oauthClient_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthClient_user_id_user_id_fk": { + "name": "oauthClient_user_id_user_id_fk", + "tableFrom": "oauthClient", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthClientAssertion": { + "name": "oauthClientAssertion", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthClientResource": { + "name": "oauthClientResource", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "oauthClientResource_client_id_idx": { + "name": "oauthClientResource_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthClientResource_resource_id_idx": { + "name": "oauthClientResource_resource_id_idx", + "columns": [ + "resource_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthClientResource_client_id_oauthClient_client_id_fk": { + "name": "oauthClientResource_client_id_oauthClient_client_id_fk", + "tableFrom": "oauthClientResource", + "tableTo": "oauthClient", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "client_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauthClientResource_resource_id_oauthResource_identifier_fk": { + "name": "oauthClientResource_resource_id_oauthResource_identifier_fk", + "tableFrom": "oauthClientResource", + "tableTo": "oauthResource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "identifier" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthConsent": { + "name": "oauthConsent", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resources": { + "name": "resources", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "requested_user_info_claims": { + "name": "requested_user_info_claims", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "last_used_at": { + "name": "last_used_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "oauthConsent_client_id_idx": { + "name": "oauthConsent_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthConsent_user_id_idx": { + "name": "oauthConsent_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthConsent_client_id_oauthClient_client_id_fk": { + "name": "oauthConsent_client_id_oauthClient_client_id_fk", + "tableFrom": "oauthConsent", + "tableTo": "oauthClient", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "client_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauthConsent_user_id_user_id_fk": { + "name": "oauthConsent_user_id_user_id_fk", + "tableFrom": "oauthConsent", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthJwtRevocation": { + "name": "oauthJwtRevocation", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "oauthJwtRevocation_expires_at_idx": { + "name": "oauthJwtRevocation_expires_at_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthRefreshToken": { + "name": "oauthRefreshToken", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "authorization_code_id": { + "name": "authorization_code_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resources": { + "name": "resources", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "requested_user_info_claims": { + "name": "requested_user_info_claims", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "revoked": { + "name": "revoked", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rotated_at": { + "name": "rotated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rotation_replay_response": { + "name": "rotation_replay_response", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rotation_replay_expires_at": { + "name": "rotation_replay_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "auth_time": { + "name": "auth_time", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "confirmation": { + "name": "confirmation", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "oauthRefreshToken_token_unique": { + "name": "oauthRefreshToken_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "oauthRefreshToken_client_id_idx": { + "name": "oauthRefreshToken_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthRefreshToken_session_id_idx": { + "name": "oauthRefreshToken_session_id_idx", + "columns": [ + "session_id" + ], + "isUnique": false + }, + "oauthRefreshToken_user_id_idx": { + "name": "oauthRefreshToken_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "oauthRefreshToken_token_idx": { + "name": "oauthRefreshToken_token_idx", + "columns": [ + "token" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthRefreshToken_client_id_oauthClient_client_id_fk": { + "name": "oauthRefreshToken_client_id_oauthClient_client_id_fk", + "tableFrom": "oauthRefreshToken", + "tableTo": "oauthClient", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "client_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauthRefreshToken_session_id_session_id_fk": { + "name": "oauthRefreshToken_session_id_session_id_fk", + "tableFrom": "oauthRefreshToken", + "tableTo": "session", + "columnsFrom": [ + "session_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "oauthRefreshToken_user_id_user_id_fk": { + "name": "oauthRefreshToken_user_id_user_id_fk", + "tableFrom": "oauthRefreshToken", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthResource": { + "name": "oauthResource", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token_ttl": { + "name": "access_token_ttl", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_ttl": { + "name": "refresh_token_ttl", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "signing_algorithm": { + "name": "signing_algorithm", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "signing_key_id": { + "name": "signing_key_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "allowed_scopes": { + "name": "allowed_scopes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "custom_claims": { + "name": "custom_claims", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dpop_bound_access_tokens_required": { + "name": "dpop_bound_access_tokens_required", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "disabled": { + "name": "disabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "policy_version": { + "name": "policy_version", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 1 + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "oauthResource_identifier_unique": { + "name": "oauthResource_identifier_unique", + "columns": [ + "identifier" + ], + "isUnique": true + }, + "oauthResource_identifier_idx": { + "name": "oauthResource_identifier_idx", + "columns": [ + "identifier" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "organization": { + "name": "organization", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "columns": [ + "slug" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "session_token_unique": { + "name": "session_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "session_created_idx": { + "name": "session_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "banned": { + "name": "banned", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_username": { + "name": "display_username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_active_at": { + "name": "last_active_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ], + "isUnique": true + }, + "user_username_unique": { + "name": "user_username_unique", + "columns": [ + "username" + ], + "isUnique": true + }, + "user_created_idx": { + "name": "user_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + }, + "user_lastActiveAt_idx": { + "name": "user_lastActiveAt_idx", + "columns": [ + "last_active_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verification": { + "name": "verification", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + "identifier" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": { + "matters_webdav_children_idx": { + "columns": { + "\"dirtype\" desc": { + "isExpression": true + } + } + }, + "matters_list_page_idx": { + "columns": { + "\"dirtype\" desc": { + "isExpression": true + } + } + } + } + } +} \ No newline at end of file diff --git a/migrations/meta/0088_snapshot.json b/migrations/meta/0088_snapshot.json new file mode 100644 index 00000000..72bbb4fa --- /dev/null +++ b/migrations/meta/0088_snapshot.json @@ -0,0 +1,6219 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "2af1cfb2-4d7a-4f68-bdef-dcdd2e18decf", + "prevId": "64b4d2c4-9851-49e5-94a8-481e1d79ef70", + "tables": { + "announcements": { + "name": "announcements", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "published_at": { + "name": "published_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "announcements_status_priority_idx": { + "name": "announcements_status_priority_idx", + "columns": [ + "status", + "priority" + ], + "isUnique": false + }, + "announcements_published_idx": { + "name": "announcements_published_idx", + "columns": [ + "published_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "audit_events": { + "name": "audit_events", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_type": { + "name": "target_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_id": { + "name": "target_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_name": { + "name": "target_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actor_type": { + "name": "actor_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actor_ref": { + "name": "actor_ref", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actor_issuer": { + "name": "actor_issuer", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "audit_events_org_created_idx": { + "name": "audit_events_org_created_idx", + "columns": [ + "org_id", + "created_at" + ], + "isUnique": false + }, + "audit_events_user_created_idx": { + "name": "audit_events_user_created_idx", + "columns": [ + "user_id", + "created_at" + ], + "isUnique": false + }, + "audit_events_action_created_idx": { + "name": "audit_events_action_created_idx", + "columns": [ + "action", + "created_at" + ], + "isUnique": false + }, + "audit_events_target_created_idx": { + "name": "audit_events_target_created_idx", + "columns": [ + "target_type", + "target_id", + "created_at" + ], + "isUnique": false + }, + "audit_events_created_idx": { + "name": "audit_events_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "background_jobs": { + "name": "background_jobs", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_folder": { + "name": "target_folder", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_path": { + "name": "target_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "input_bytes": { + "name": "input_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "output_bytes": { + "name": "output_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "processed_bytes": { + "name": "processed_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "file_count": { + "name": "file_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "current_filename": { + "name": "current_filename", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "result_metadata": { + "name": "result_metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "retryable": { + "name": "retryable", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "cancelable": { + "name": "cancelable", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "retried_from_job_id": { + "name": "retried_from_job_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "finished_at": { + "name": "finished_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "background_jobs_org_created_idx": { + "name": "background_jobs_org_created_idx", + "columns": [ + "org_id", + "created_at" + ], + "isUnique": false + }, + "background_jobs_org_status_idx": { + "name": "background_jobs_org_status_idx", + "columns": [ + "org_id", + "status" + ], + "isUnique": false + }, + "background_jobs_org_type_idx": { + "name": "background_jobs_org_type_idx", + "columns": [ + "org_id", + "type" + ], + "isUnique": false + }, + "background_jobs_created_idx": { + "name": "background_jobs_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + }, + "background_jobs_org_page_idx": { + "name": "background_jobs_org_page_idx", + "columns": [ + "org_id", + "created_at", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "cloud_traffic_reports": { + "name": "cloud_traffic_reports", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "period": { + "name": "period", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "bytes": { + "name": "bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "unit_bytes": { + "name": "unit_bytes", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "credits_per_unit": { + "name": "credits_per_unit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "attempt_count": { + "name": "attempt_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "next_retry_at": { + "name": "next_retry_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "issued_at": { + "name": "issued_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "cloud_traffic_reports_event_uniq": { + "name": "cloud_traffic_reports_event_uniq", + "columns": [ + "event_id" + ], + "isUnique": true + }, + "cloud_traffic_reports_org_period_idx": { + "name": "cloud_traffic_reports_org_period_idx", + "columns": [ + "org_id", + "period" + ], + "isUnique": false + }, + "cloud_traffic_reports_status_idx": { + "name": "cloud_traffic_reports_status_idx", + "columns": [ + "status" + ], + "isUnique": false + }, + "cloud_traffic_reports_retry_idx": { + "name": "cloud_traffic_reports_retry_idx", + "columns": [ + "status", + "next_retry_at", + "created_at" + ], + "isUnique": false + }, + "cloud_traffic_reports_issued_idx": { + "name": "cloud_traffic_reports_issued_idx", + "columns": [ + "issued_at" + ], + "isUnique": false + }, + "cloud_traffic_reports_updated_idx": { + "name": "cloud_traffic_reports_updated_idx", + "columns": [ + "updated_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "download_tasks": { + "name": "download_tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_uri": { + "name": "source_uri", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_folder": { + "name": "target_folder", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tags": { + "name": "tags", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "assigned_downloader_id": { + "name": "assigned_downloader_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "attempt": { + "name": "attempt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "billing_authorized_bytes": { + "name": "billing_authorized_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "billing_charged_bytes": { + "name": "billing_charged_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "billing_charged_credits": { + "name": "billing_charged_credits", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "billing_status": { + "name": "billing_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'none'" + }, + "error_code": { + "name": "error_code", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "result_object_id": { + "name": "result_object_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "runtime": { + "name": "runtime", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "events": { + "name": "events", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "resolve_started_at": { + "name": "resolve_started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resolve_completed_at": { + "name": "resolve_completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "download_completed_at": { + "name": "download_completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ingest_started_at": { + "name": "ingest_started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ingest_completed_at": { + "name": "ingest_completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "seeding_started_at": { + "name": "seeding_started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "seeding_stopped_at": { + "name": "seeding_stopped_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "assigned_at": { + "name": "assigned_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "finished_at": { + "name": "finished_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "download_tasks_org_created_idx": { + "name": "download_tasks_org_created_idx", + "columns": [ + "org_id", + "created_at" + ], + "isUnique": false + }, + "download_tasks_org_status_idx": { + "name": "download_tasks_org_status_idx", + "columns": [ + "org_id", + "status" + ], + "isUnique": false + }, + "download_tasks_org_category_idx": { + "name": "download_tasks_org_category_idx", + "columns": [ + "org_id", + "category" + ], + "isUnique": false + }, + "download_tasks_org_tags_idx": { + "name": "download_tasks_org_tags_idx", + "columns": [ + "org_id", + "tags" + ], + "isUnique": false + }, + "download_tasks_downloader_idx": { + "name": "download_tasks_downloader_idx", + "columns": [ + "assigned_downloader_id", + "status" + ], + "isUnique": false + }, + "download_tasks_created_idx": { + "name": "download_tasks_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + }, + "download_tasks_finished_idx": { + "name": "download_tasks_finished_idx", + "columns": [ + "finished_at" + ], + "isUnique": false + }, + "download_tasks_org_deleted_created_idx": { + "name": "download_tasks_org_deleted_created_idx", + "columns": [ + "org_id", + "deleted_at", + "created_at" + ], + "isUnique": false + }, + "download_tasks_org_page_idx": { + "name": "download_tasks_org_page_idx", + "columns": [ + "org_id", + "deleted_at", + "created_at", + "id" + ], + "isUnique": false + }, + "download_tasks_downloader_page_idx": { + "name": "download_tasks_downloader_page_idx", + "columns": [ + "assigned_downloader_id", + "deleted_at", + "created_at", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "downloaders": { + "name": "downloaders", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token_jti": { + "name": "token_jti", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'offline'" + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "hostname": { + "name": "hostname", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "platform": { + "name": "platform", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "arch": { + "name": "arch", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "engine": { + "name": "engine", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'http'" + }, + "capabilities": { + "name": "capabilities", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "max_concurrent_tasks": { + "name": "max_concurrent_tasks", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "current_tasks": { + "name": "current_tasks", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "download_bps": { + "name": "download_bps", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "upload_bps": { + "name": "upload_bps", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "free_disk_bytes": { + "name": "free_disk_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "remote_download_credit_billing_enabled": { + "name": "remote_download_credit_billing_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "remote_download_credit_unit_bytes": { + "name": "remote_download_credit_unit_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 104857600 + }, + "remote_download_credit_per_unit": { + "name": "remote_download_credit_per_unit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "last_heartbeat_at": { + "name": "last_heartbeat_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "downloaders_token_jti_unique": { + "name": "downloaders_token_jti_unique", + "columns": [ + "token_jti" + ], + "isUnique": true + }, + "downloaders_status_idx": { + "name": "downloaders_status_idx", + "columns": [ + "status" + ], + "isUnique": false + }, + "downloaders_enabled_idx": { + "name": "downloaders_enabled_idx", + "columns": [ + "enabled" + ], + "isUnique": false + }, + "downloaders_created_idx": { + "name": "downloaders_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "image_hosting_configs": { + "name": "image_hosting_configs", + "columns": { + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "custom_domain": { + "name": "custom_domain", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_provider": { + "name": "domain_provider", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider_hostname_id": { + "name": "provider_hostname_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_status": { + "name": "domain_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_error": { + "name": "domain_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "verification_token": { + "name": "verification_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_last_checked_at": { + "name": "domain_last_checked_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_verified_at": { + "name": "domain_verified_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "referer_allowlist": { + "name": "referer_allowlist", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "image_hosting_configs_custom_domain_unique": { + "name": "image_hosting_configs_custom_domain_unique", + "columns": [ + "custom_domain" + ], + "isUnique": true + } + }, + "foreignKeys": { + "image_hosting_configs_org_id_organization_id_fk": { + "name": "image_hosting_configs_org_id_organization_id_fk", + "tableFrom": "image_hosting_configs", + "tableTo": "organization", + "columnsFrom": [ + "org_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "image_hostings": { + "name": "image_hostings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_key": { + "name": "storage_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mime": { + "name": "mime", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "purged_at": { + "name": "purged_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_count": { + "name": "access_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "last_accessed_at": { + "name": "last_accessed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "image_hostings_token_unique": { + "name": "image_hostings_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "image_hostings_org_path_uniq": { + "name": "image_hostings_org_path_uniq", + "columns": [ + "org_id", + "path" + ], + "isUnique": true, + "where": "\"image_hostings\".\"purged_at\" IS NULL" + }, + "image_hostings_org_created_idx": { + "name": "image_hostings_org_created_idx", + "columns": [ + "org_id", + "created_at" + ], + "isUnique": false + }, + "image_hostings_page_idx": { + "name": "image_hostings_page_idx", + "columns": [ + "org_id", + "status", + "purged_at", + "created_at", + "id" + ], + "isUnique": false + }, + "image_hostings_token_idx": { + "name": "image_hostings_token_idx", + "columns": [ + "token" + ], + "isUnique": false + } + }, + "foreignKeys": { + "image_hostings_org_id_organization_id_fk": { + "name": "image_hostings_org_id_organization_id_fk", + "tableFrom": "image_hostings", + "tableTo": "organization", + "columnsFrom": [ + "org_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "image_hostings_storage_id_storages_id_fk": { + "name": "image_hostings_storage_id_storages_id_fk", + "tableFrom": "image_hostings", + "tableTo": "storages", + "columnsFrom": [ + "storage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invite_codes": { + "name": "invite_codes", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "used_by": { + "name": "used_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "used_at": { + "name": "used_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invite_codes_code_unique": { + "name": "invite_codes_code_unique", + "columns": [ + "code" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "license_bindings": { + "name": "license_bindings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "cloud_binding_id": { + "name": "cloud_binding_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cloud_store_id": { + "name": "cloud_store_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "instance_id": { + "name": "instance_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cloud_account_id": { + "name": "cloud_account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cloud_account_email": { + "name": "cloud_account_email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cached_certificate": { + "name": "cached_certificate", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cached_certificate_expires_at": { + "name": "cached_certificate_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bound_at": { + "name": "bound_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "disconnected_at": { + "name": "disconnected_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_refresh_at": { + "name": "last_refresh_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_refresh_error": { + "name": "last_refresh_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "license_bindings_active_uniq": { + "name": "license_bindings_active_uniq", + "columns": [ + "status" + ], + "isUnique": true, + "where": "status = 'active'" + }, + "license_bindings_cloud_binding_idx": { + "name": "license_bindings_cloud_binding_idx", + "columns": [ + "cloud_binding_id" + ], + "isUnique": false + }, + "license_bindings_instance_idx": { + "name": "license_bindings_instance_idx", + "columns": [ + "instance_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "matters": { + "name": "matters", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "alias": { + "name": "alias", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "dirtype": { + "name": "dirtype", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "parent": { + "name": "parent", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "object": { + "name": "object", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "trashed_at": { + "name": "trashed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "purged_at": { + "name": "purged_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "matters_alias_unique": { + "name": "matters_alias_unique", + "columns": [ + "alias" + ], + "isUnique": true + }, + "matters_status_dir_created_idx": { + "name": "matters_status_dir_created_idx", + "columns": [ + "status", + "dirtype", + "created_at" + ], + "isUnique": false + }, + "matters_webdav_path_idx": { + "name": "matters_webdav_path_idx", + "columns": [ + "org_id", + "parent", + "name", + "status", + "trashed_at", + "purged_at" + ], + "isUnique": false + }, + "matters_webdav_children_idx": { + "name": "matters_webdav_children_idx", + "columns": [ + "org_id", + "parent", + "status", + "trashed_at", + "purged_at", + "\"dirtype\" desc", + "name" + ], + "isUnique": false + }, + "matters_list_page_idx": { + "name": "matters_list_page_idx", + "columns": [ + "org_id", + "parent", + "status", + "trashed_at", + "purged_at", + "\"dirtype\" desc", + "created_at", + "id" + ], + "isUnique": false + }, + "matters_trash_page_idx": { + "name": "matters_trash_page_idx", + "columns": [ + "org_id", + "status", + "purged_at", + "trashed_at", + "created_at", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "notifications": { + "name": "notifications", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "ref_type": { + "name": "ref_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ref_id": { + "name": "ref_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "read_at": { + "name": "read_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "notifications_user_created_idx": { + "name": "notifications_user_created_idx", + "columns": [ + "user_id", + "created_at" + ], + "isUnique": false + }, + "notifications_user_read_idx": { + "name": "notifications_user_read_idx", + "columns": [ + "user_id", + "read_at" + ], + "isUnique": false + }, + "notifications_user_page_idx": { + "name": "notifications_user_page_idx", + "columns": [ + "user_id", + "read_at", + "created_at", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "object_upload_sessions": { + "name": "object_upload_sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "object_id": { + "name": "object_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_key": { + "name": "storage_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "upload_id": { + "name": "upload_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "part_size": { + "name": "part_size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "on_conflict": { + "name": "on_conflict", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'fail'" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "object_upload_sessions_object_idx": { + "name": "object_upload_sessions_object_idx", + "columns": [ + "org_id", + "object_id" + ], + "isUnique": false + }, + "object_upload_sessions_expires_idx": { + "name": "object_upload_sessions_expires_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "org_quota_entitlements": { + "name": "org_quota_entitlements", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "entitlement_type": { + "name": "entitlement_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'grant'" + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "bytes": { + "name": "bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "starts_at": { + "name": "starts_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "org_quota_entitlements_org_resource_idx": { + "name": "org_quota_entitlements_org_resource_idx", + "columns": [ + "org_id", + "resource_type", + "status" + ], + "isUnique": false + }, + "org_quota_entitlements_org_type_idx": { + "name": "org_quota_entitlements_org_type_idx", + "columns": [ + "org_id", + "resource_type", + "entitlement_type", + "status" + ], + "isUnique": false + }, + "org_quota_entitlements_source_resource_uniq": { + "name": "org_quota_entitlements_source_resource_uniq", + "columns": [ + "source", + "source_id", + "resource_type" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "org_quotas": { + "name": "org_quotas", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "quota": { + "name": "quota", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "used": { + "name": "used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "traffic_quota": { + "name": "traffic_quota", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "traffic_used": { + "name": "traffic_used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "traffic_period": { + "name": "traffic_period", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'1970-01'" + } + }, + "indexes": { + "org_quotas_org_uniq": { + "name": "org_quotas_org_uniq", + "columns": [ + "org_id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "remote_download_usage_reports": { + "name": "remote_download_usage_reports", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "downloader_id": { + "name": "downloader_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "unit_index": { + "name": "unit_index", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "unit_bytes": { + "name": "unit_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credits_per_unit": { + "name": "credits_per_unit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "remote_download_usage_reports_event_id_unique": { + "name": "remote_download_usage_reports_event_id_unique", + "columns": [ + "event_id" + ], + "isUnique": true + }, + "remote_download_usage_task_unit_uniq": { + "name": "remote_download_usage_task_unit_uniq", + "columns": [ + "task_id", + "unit_index" + ], + "isUnique": true + }, + "remote_download_usage_org_idx": { + "name": "remote_download_usage_org_idx", + "columns": [ + "org_id" + ], + "isUnique": false + }, + "remote_download_usage_status_idx": { + "name": "remote_download_usage_status_idx", + "columns": [ + "status" + ], + "isUnique": false + }, + "remote_download_usage_created_idx": { + "name": "remote_download_usage_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "resource_changes": { + "name": "resource_changes", + "columns": { + "sequence": { + "name": "sequence", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "scope_type": { + "name": "scope_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scope_id": { + "name": "scope_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "change_type": { + "name": "change_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "occurred_at": { + "name": "occurred_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "resource_changes_scope_sequence_idx": { + "name": "resource_changes_scope_sequence_idx", + "columns": [ + "scope_type", + "scope_id", + "sequence" + ], + "isUnique": false + }, + "resource_changes_resource_sequence_idx": { + "name": "resource_changes_resource_sequence_idx", + "columns": [ + "resource_type", + "resource_id", + "sequence" + ], + "isUnique": false + }, + "resource_changes_occurred_idx": { + "name": "resource_changes_occurred_idx", + "columns": [ + "occurred_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "share_recipients": { + "name": "share_recipients", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "share_id": { + "name": "share_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "recipient_user_id": { + "name": "recipient_user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "recipient_email": { + "name": "recipient_email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "share_recipients_share_id_idx": { + "name": "share_recipients_share_id_idx", + "columns": [ + "share_id" + ], + "isUnique": false + }, + "share_recipients_user_id_idx": { + "name": "share_recipients_user_id_idx", + "columns": [ + "recipient_user_id" + ], + "isUnique": false + }, + "share_recipients_email_idx": { + "name": "share_recipients_email_idx", + "columns": [ + "recipient_email" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "shares": { + "name": "shares", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "matter_id": { + "name": "matter_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "download_limit": { + "name": "download_limit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "views": { + "name": "views", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "downloads": { + "name": "downloads", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'active'" + }, + "private": { + "name": "private", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "shares_token_unique": { + "name": "shares_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "shares_creator_status_created_idx": { + "name": "shares_creator_status_created_idx", + "columns": [ + "creator_id", + "status", + "created_at", + "id" + ], + "isUnique": false + }, + "shares_creator_private_created_idx": { + "name": "shares_creator_private_created_idx", + "columns": [ + "creator_id", + "private", + "created_at" + ], + "isUnique": false + }, + "shares_created_idx": { + "name": "shares_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "site_invitations": { + "name": "site_invitations", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "invited_by": { + "name": "invited_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "accepted_by": { + "name": "accepted_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "accepted_at": { + "name": "accepted_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "revoked_by": { + "name": "revoked_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "site_invitations_token_unique": { + "name": "site_invitations_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "site_invitations_email_idx": { + "name": "site_invitations_email_idx", + "columns": [ + "email" + ], + "isUnique": false + }, + "site_invitations_created_idx": { + "name": "site_invitations_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + }, + "site_invitations_expires_idx": { + "name": "site_invitations_expires_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "stats_rollups_hourly": { + "name": "stats_rollups_hourly", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "bucket_start": { + "name": "bucket_start", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "metric_key": { + "name": "metric_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dimension_key": { + "name": "dimension_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "dimension_value": { + "name": "dimension_value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "bytes": { + "name": "bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "unique_count": { + "name": "unique_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "stats_rollups_hourly_bucket_metric_dim_uniq": { + "name": "stats_rollups_hourly_bucket_metric_dim_uniq", + "columns": [ + "bucket_start", + "org_id", + "metric_key", + "dimension_key", + "dimension_value" + ], + "isUnique": true + }, + "stats_rollups_hourly_metric_bucket_idx": { + "name": "stats_rollups_hourly_metric_bucket_idx", + "columns": [ + "metric_key", + "bucket_start" + ], + "isUnique": false + }, + "stats_rollups_hourly_dimension_bucket_idx": { + "name": "stats_rollups_hourly_dimension_bucket_idx", + "columns": [ + "metric_key", + "dimension_key", + "bucket_start" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "storage_usage_breakdowns": { + "name": "storage_usage_breakdowns", + "columns": { + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "bytes": { + "name": "bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "file_count": { + "name": "file_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "storage_usage_breakdowns_org_category_uniq": { + "name": "storage_usage_breakdowns_org_category_uniq", + "columns": [ + "org_id", + "category" + ], + "isUnique": true + }, + "storage_usage_breakdowns_org_idx": { + "name": "storage_usage_breakdowns_org_idx", + "columns": [ + "org_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "storage_usage_ledger": { + "name": "storage_usage_ledger", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "event_key": { + "name": "event_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "delta_bytes": { + "name": "delta_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "occurred_at": { + "name": "occurred_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "storage_usage_ledger_event_key_unique": { + "name": "storage_usage_ledger_event_key_unique", + "columns": [ + "event_key" + ], + "isUnique": true + }, + "storage_usage_ledger_occurred_idx": { + "name": "storage_usage_ledger_occurred_idx", + "columns": [ + "occurred_at" + ], + "isUnique": false + }, + "storage_usage_ledger_org_occurred_idx": { + "name": "storage_usage_ledger_org_occurred_idx", + "columns": [ + "org_id", + "occurred_at" + ], + "isUnique": false + }, + "storage_usage_ledger_storage_occurred_idx": { + "name": "storage_usage_ledger_storage_occurred_idx", + "columns": [ + "storage_id", + "occurred_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "storages": { + "name": "storages", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'auto'" + }, + "access_key": { + "name": "access_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "secret_key": { + "name": "secret_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "custom_host": { + "name": "custom_host", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "''" + }, + "capacity": { + "name": "capacity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "egress_credit_billing_enabled": { + "name": "egress_credit_billing_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "egress_credit_unit_bytes": { + "name": "egress_credit_unit_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 104857600 + }, + "egress_credit_per_unit": { + "name": "egress_credit_per_unit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "force_path_style": { + "name": "force_path_style", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "used": { + "name": "used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "status_reason": { + "name": "status_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status_checked_at": { + "name": "status_checked_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "system_options": { + "name": "system_options", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "team_invite_links": { + "name": "team_invite_links", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'member'" + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "team_invite_links_token_unique": { + "name": "team_invite_links_token_unique", + "columns": [ + "token" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "webdav_dead_properties": { + "name": "webdav_dead_properties", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_path": { + "name": "resource_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "namespace": { + "name": "namespace", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "webdav_dead_properties_resource_prop_uniq": { + "name": "webdav_dead_properties_resource_prop_uniq", + "columns": [ + "org_id", + "resource_path", + "namespace", + "name" + ], + "isUnique": true + }, + "webdav_dead_properties_resource_idx": { + "name": "webdav_dead_properties_resource_idx", + "columns": [ + "org_id", + "resource_path" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "webdav_locks": { + "name": "webdav_locks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_path": { + "name": "resource_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "depth": { + "name": "depth", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'infinity'" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "webdav_locks_token_unique": { + "name": "webdav_locks_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "webdav_locks_resource_idx": { + "name": "webdav_locks_resource_idx", + "columns": [ + "org_id", + "resource_path" + ], + "isUnique": false + }, + "webdav_locks_expires_idx": { + "name": "webdav_locks_expires_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "webhook_events": { + "name": "webhook_events", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'cloud'" + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'order.quota_changed'" + }, + "payload_hash": { + "name": "payload_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "raw_payload": { + "name": "raw_payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "processed_at": { + "name": "processed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "webhook_events_source_event_uniq": { + "name": "webhook_events_source_event_uniq", + "columns": [ + "source", + "event_id" + ], + "isUnique": true + }, + "webhook_events_source_created_idx": { + "name": "webhook_events_source_created_idx", + "columns": [ + "source", + "created_at" + ], + "isUnique": false + }, + "webhook_events_status_idx": { + "name": "webhook_events_status_idx", + "columns": [ + "status" + ], + "isUnique": false + }, + "webhook_events_processed_idx": { + "name": "webhook_events_processed_idx", + "columns": [ + "processed_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "x402_capacity_purchase_intents": { + "name": "x402_capacity_purchase_intents", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "request_hash": { + "name": "request_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "idempotency_key": { + "name": "idempotency_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cloud_order_id": { + "name": "cloud_order_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cloud_attempt_id": { + "name": "cloud_attempt_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'created'" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "x402_capacity_purchase_intents_org_request_uniq": { + "name": "x402_capacity_purchase_intents_org_request_uniq", + "columns": [ + "org_id", + "resource_id", + "request_hash" + ], + "isUnique": true + }, + "x402_capacity_purchase_intents_org_idempotency_uniq": { + "name": "x402_capacity_purchase_intents_org_idempotency_uniq", + "columns": [ + "org_id", + "idempotency_key" + ], + "isUnique": true + }, + "x402_capacity_purchase_intents_attempt_idx": { + "name": "x402_capacity_purchase_intents_attempt_idx", + "columns": [ + "cloud_attempt_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "account": { + "name": "account", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "issuer": { + "name": "issuer", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "account_issuer_providerAccountId_unique": { + "name": "account_issuer_providerAccountId_unique", + "columns": [ + "issuer", + "account_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "apikey": { + "name": "apikey", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "config_id": { + "name": "config_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'default'" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "start": { + "name": "start", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refill_interval": { + "name": "refill_interval", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refill_amount": { + "name": "refill_amount", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "rate_limit_enabled": { + "name": "rate_limit_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "rate_limit_time_window": { + "name": "rate_limit_time_window", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rate_limit_max": { + "name": "rate_limit_max", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "request_count": { + "name": "request_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "remaining": { + "name": "remaining", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_request": { + "name": "last_request", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permissions": { + "name": "permissions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "apikey_config_id_idx": { + "name": "apikey_config_id_idx", + "columns": [ + "config_id" + ], + "isUnique": false + }, + "apikey_reference_id_idx": { + "name": "apikey_reference_id_idx", + "columns": [ + "reference_id" + ], + "isUnique": false + }, + "apikey_key_idx": { + "name": "apikey_key_idx", + "columns": [ + "key" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "deviceCode": { + "name": "deviceCode", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "device_code": { + "name": "device_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_code": { + "name": "user_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_polled_at": { + "name": "last_polled_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "polling_interval": { + "name": "polling_interval", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "deviceCode_device_code_idx": { + "name": "deviceCode_device_code_idx", + "columns": [ + "device_code" + ], + "isUnique": false + }, + "deviceCode_user_code_idx": { + "name": "deviceCode_user_code_idx", + "columns": [ + "user_code" + ], + "isUnique": false + }, + "deviceCode_status_idx": { + "name": "deviceCode_status_idx", + "columns": [ + "status" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "downloader_bootstrap_credentials": { + "name": "downloader_bootstrap_credentials", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_code": { + "name": "device_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "consumed_at": { + "name": "consumed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "downloader_bootstrap_credentials_token_hash_unique": { + "name": "downloader_bootstrap_credentials_token_hash_unique", + "columns": [ + "token_hash" + ], + "isUnique": true + }, + "downloader_bootstrap_token_hash_idx": { + "name": "downloader_bootstrap_token_hash_idx", + "columns": [ + "token_hash" + ], + "isUnique": false + }, + "downloader_bootstrap_user_idx": { + "name": "downloader_bootstrap_user_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "downloader_bootstrap_consumed_idx": { + "name": "downloader_bootstrap_consumed_idx", + "columns": [ + "consumed_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "downloader_bootstrap_credentials_user_id_user_id_fk": { + "name": "downloader_bootstrap_credentials_user_id_user_id_fk", + "tableFrom": "downloader_bootstrap_credentials", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invitation": { + "name": "invitation", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invitation_organizationId_idx": { + "name": "invitation_organizationId_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "invitation_email_idx": { + "name": "invitation_email_idx", + "columns": [ + "email" + ], + "isUnique": false + } + }, + "foreignKeys": { + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_inviter_id_user_id_fk": { + "name": "invitation_inviter_id_user_id_fk", + "tableFrom": "invitation", + "tableTo": "user", + "columnsFrom": [ + "inviter_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "jwks": { + "name": "jwks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "private_key": { + "name": "private_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "alg": { + "name": "alg", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "crv": { + "name": "crv", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "member": { + "name": "member", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'member'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "member_organizationId_idx": { + "name": "member_organizationId_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "member_userId_idx": { + "name": "member_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "member_user_id_user_id_fk": { + "name": "member_user_id_user_id_fk", + "tableFrom": "member", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthAccessToken": { + "name": "oauthAccessToken", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "authorization_code_id": { + "name": "authorization_code_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resources": { + "name": "resources", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "requested_user_info_claims": { + "name": "requested_user_info_claims", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_id": { + "name": "refresh_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "revoked": { + "name": "revoked", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "confirmation": { + "name": "confirmation", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "oauthAccessToken_token_unique": { + "name": "oauthAccessToken_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "oauthAccessToken_client_id_idx": { + "name": "oauthAccessToken_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthAccessToken_session_id_idx": { + "name": "oauthAccessToken_session_id_idx", + "columns": [ + "session_id" + ], + "isUnique": false + }, + "oauthAccessToken_user_id_idx": { + "name": "oauthAccessToken_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "oauthAccessToken_refresh_id_idx": { + "name": "oauthAccessToken_refresh_id_idx", + "columns": [ + "refresh_id" + ], + "isUnique": false + }, + "oauthAccessToken_token_idx": { + "name": "oauthAccessToken_token_idx", + "columns": [ + "token" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthAccessToken_client_id_oauthClient_client_id_fk": { + "name": "oauthAccessToken_client_id_oauthClient_client_id_fk", + "tableFrom": "oauthAccessToken", + "tableTo": "oauthClient", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "client_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauthAccessToken_session_id_session_id_fk": { + "name": "oauthAccessToken_session_id_session_id_fk", + "tableFrom": "oauthAccessToken", + "tableTo": "session", + "columnsFrom": [ + "session_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "oauthAccessToken_user_id_user_id_fk": { + "name": "oauthAccessToken_user_id_user_id_fk", + "tableFrom": "oauthAccessToken", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauthAccessToken_refresh_id_oauthRefreshToken_id_fk": { + "name": "oauthAccessToken_refresh_id_oauthRefreshToken_id_fk", + "tableFrom": "oauthAccessToken", + "tableTo": "oauthRefreshToken", + "columnsFrom": [ + "refresh_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthClient": { + "name": "oauthClient", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_secret": { + "name": "client_secret", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "disabled": { + "name": "disabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "skip_consent": { + "name": "skip_consent", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enable_end_session": { + "name": "enable_end_session", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_type": { + "name": "subject_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "uri": { + "name": "uri", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "contacts": { + "name": "contacts", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tos": { + "name": "tos", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "policy": { + "name": "policy", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "software_id": { + "name": "software_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "software_version": { + "name": "software_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "software_statement": { + "name": "software_statement", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "redirect_uris": { + "name": "redirect_uris", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_logout_redirect_uris": { + "name": "post_logout_redirect_uris", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "backchannel_logout_uri": { + "name": "backchannel_logout_uri", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "backchannel_logout_session_required": { + "name": "backchannel_logout_session_required", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_endpoint_auth_method": { + "name": "token_endpoint_auth_method", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "jwks": { + "name": "jwks", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "jwks_uri": { + "name": "jwks_uri", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "grant_types": { + "name": "grant_types", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "response_types": { + "name": "response_types", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "public": { + "name": "public", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "require_pkce": { + "name": "require_pkce", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dpop_bound_access_tokens": { + "name": "dpop_bound_access_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "oauthClient_client_id_unique": { + "name": "oauthClient_client_id_unique", + "columns": [ + "client_id" + ], + "isUnique": true + }, + "oauthClient_client_id_idx": { + "name": "oauthClient_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthClient_user_id_idx": { + "name": "oauthClient_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthClient_user_id_user_id_fk": { + "name": "oauthClient_user_id_user_id_fk", + "tableFrom": "oauthClient", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthClientAssertion": { + "name": "oauthClientAssertion", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthClientResource": { + "name": "oauthClientResource", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "oauthClientResource_client_id_idx": { + "name": "oauthClientResource_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthClientResource_resource_id_idx": { + "name": "oauthClientResource_resource_id_idx", + "columns": [ + "resource_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthClientResource_client_id_oauthClient_client_id_fk": { + "name": "oauthClientResource_client_id_oauthClient_client_id_fk", + "tableFrom": "oauthClientResource", + "tableTo": "oauthClient", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "client_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauthClientResource_resource_id_oauthResource_identifier_fk": { + "name": "oauthClientResource_resource_id_oauthResource_identifier_fk", + "tableFrom": "oauthClientResource", + "tableTo": "oauthResource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "identifier" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthConsent": { + "name": "oauthConsent", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resources": { + "name": "resources", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "requested_user_info_claims": { + "name": "requested_user_info_claims", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "last_used_at": { + "name": "last_used_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "oauthConsent_client_id_idx": { + "name": "oauthConsent_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthConsent_user_id_idx": { + "name": "oauthConsent_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthConsent_client_id_oauthClient_client_id_fk": { + "name": "oauthConsent_client_id_oauthClient_client_id_fk", + "tableFrom": "oauthConsent", + "tableTo": "oauthClient", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "client_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauthConsent_user_id_user_id_fk": { + "name": "oauthConsent_user_id_user_id_fk", + "tableFrom": "oauthConsent", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthJwtRevocation": { + "name": "oauthJwtRevocation", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "oauthJwtRevocation_expires_at_idx": { + "name": "oauthJwtRevocation_expires_at_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthRefreshToken": { + "name": "oauthRefreshToken", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "authorization_code_id": { + "name": "authorization_code_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resources": { + "name": "resources", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "requested_user_info_claims": { + "name": "requested_user_info_claims", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "revoked": { + "name": "revoked", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rotated_at": { + "name": "rotated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rotation_replay_response": { + "name": "rotation_replay_response", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rotation_replay_expires_at": { + "name": "rotation_replay_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "auth_time": { + "name": "auth_time", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "confirmation": { + "name": "confirmation", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "oauthRefreshToken_token_unique": { + "name": "oauthRefreshToken_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "oauthRefreshToken_client_id_idx": { + "name": "oauthRefreshToken_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthRefreshToken_session_id_idx": { + "name": "oauthRefreshToken_session_id_idx", + "columns": [ + "session_id" + ], + "isUnique": false + }, + "oauthRefreshToken_user_id_idx": { + "name": "oauthRefreshToken_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "oauthRefreshToken_token_idx": { + "name": "oauthRefreshToken_token_idx", + "columns": [ + "token" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthRefreshToken_client_id_oauthClient_client_id_fk": { + "name": "oauthRefreshToken_client_id_oauthClient_client_id_fk", + "tableFrom": "oauthRefreshToken", + "tableTo": "oauthClient", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "client_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauthRefreshToken_session_id_session_id_fk": { + "name": "oauthRefreshToken_session_id_session_id_fk", + "tableFrom": "oauthRefreshToken", + "tableTo": "session", + "columnsFrom": [ + "session_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "oauthRefreshToken_user_id_user_id_fk": { + "name": "oauthRefreshToken_user_id_user_id_fk", + "tableFrom": "oauthRefreshToken", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthResource": { + "name": "oauthResource", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token_ttl": { + "name": "access_token_ttl", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_ttl": { + "name": "refresh_token_ttl", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "signing_algorithm": { + "name": "signing_algorithm", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "signing_key_id": { + "name": "signing_key_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "allowed_scopes": { + "name": "allowed_scopes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "custom_claims": { + "name": "custom_claims", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dpop_bound_access_tokens_required": { + "name": "dpop_bound_access_tokens_required", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "disabled": { + "name": "disabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "policy_version": { + "name": "policy_version", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 1 + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "oauthResource_identifier_unique": { + "name": "oauthResource_identifier_unique", + "columns": [ + "identifier" + ], + "isUnique": true + }, + "oauthResource_identifier_idx": { + "name": "oauthResource_identifier_idx", + "columns": [ + "identifier" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "organization": { + "name": "organization", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "columns": [ + "slug" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "session_token_unique": { + "name": "session_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "session_created_idx": { + "name": "session_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "banned": { + "name": "banned", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_username": { + "name": "display_username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_active_at": { + "name": "last_active_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ], + "isUnique": true + }, + "user_username_unique": { + "name": "user_username_unique", + "columns": [ + "username" + ], + "isUnique": true + }, + "user_created_idx": { + "name": "user_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + }, + "user_lastActiveAt_idx": { + "name": "user_lastActiveAt_idx", + "columns": [ + "last_active_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verification": { + "name": "verification", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + "identifier" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": { + "matters_webdav_children_idx": { + "columns": { + "\"dirtype\" desc": { + "isExpression": true + } + } + }, + "matters_list_page_idx": { + "columns": { + "\"dirtype\" desc": { + "isExpression": true + } + } + } + } + } +} \ No newline at end of file diff --git a/migrations/meta/0089_snapshot.json b/migrations/meta/0089_snapshot.json new file mode 100644 index 00000000..286ba169 --- /dev/null +++ b/migrations/meta/0089_snapshot.json @@ -0,0 +1,6219 @@ +{ + "id": "21fae6dd-0684-4962-8599-f1e940277fdf", + "prevId": "2af1cfb2-4d7a-4f68-bdef-dcdd2e18decf", + "version": "6", + "dialect": "sqlite", + "tables": { + "announcements": { + "name": "announcements", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "published_at": { + "name": "published_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "announcements_status_priority_idx": { + "name": "announcements_status_priority_idx", + "columns": [ + "status", + "priority" + ], + "isUnique": false + }, + "announcements_published_idx": { + "name": "announcements_published_idx", + "columns": [ + "published_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "audit_events": { + "name": "audit_events", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_type": { + "name": "target_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_id": { + "name": "target_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_name": { + "name": "target_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actor_type": { + "name": "actor_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actor_ref": { + "name": "actor_ref", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actor_issuer": { + "name": "actor_issuer", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "audit_events_org_created_idx": { + "name": "audit_events_org_created_idx", + "columns": [ + "org_id", + "created_at" + ], + "isUnique": false + }, + "audit_events_user_created_idx": { + "name": "audit_events_user_created_idx", + "columns": [ + "user_id", + "created_at" + ], + "isUnique": false + }, + "audit_events_action_created_idx": { + "name": "audit_events_action_created_idx", + "columns": [ + "action", + "created_at" + ], + "isUnique": false + }, + "audit_events_target_created_idx": { + "name": "audit_events_target_created_idx", + "columns": [ + "target_type", + "target_id", + "created_at" + ], + "isUnique": false + }, + "audit_events_created_idx": { + "name": "audit_events_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "background_jobs": { + "name": "background_jobs", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_folder": { + "name": "target_folder", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_path": { + "name": "target_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "input_bytes": { + "name": "input_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "output_bytes": { + "name": "output_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "processed_bytes": { + "name": "processed_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "file_count": { + "name": "file_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "current_filename": { + "name": "current_filename", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "result_metadata": { + "name": "result_metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "retryable": { + "name": "retryable", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "cancelable": { + "name": "cancelable", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "retried_from_job_id": { + "name": "retried_from_job_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "finished_at": { + "name": "finished_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "background_jobs_org_created_idx": { + "name": "background_jobs_org_created_idx", + "columns": [ + "org_id", + "created_at" + ], + "isUnique": false + }, + "background_jobs_org_status_idx": { + "name": "background_jobs_org_status_idx", + "columns": [ + "org_id", + "status" + ], + "isUnique": false + }, + "background_jobs_org_type_idx": { + "name": "background_jobs_org_type_idx", + "columns": [ + "org_id", + "type" + ], + "isUnique": false + }, + "background_jobs_created_idx": { + "name": "background_jobs_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + }, + "background_jobs_org_page_idx": { + "name": "background_jobs_org_page_idx", + "columns": [ + "org_id", + "created_at", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "cloud_traffic_reports": { + "name": "cloud_traffic_reports", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "period": { + "name": "period", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "bytes": { + "name": "bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "unit_bytes": { + "name": "unit_bytes", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "credits_per_unit": { + "name": "credits_per_unit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "attempt_count": { + "name": "attempt_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "next_retry_at": { + "name": "next_retry_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "issued_at": { + "name": "issued_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "cloud_traffic_reports_event_uniq": { + "name": "cloud_traffic_reports_event_uniq", + "columns": [ + "event_id" + ], + "isUnique": true + }, + "cloud_traffic_reports_org_period_idx": { + "name": "cloud_traffic_reports_org_period_idx", + "columns": [ + "org_id", + "period" + ], + "isUnique": false + }, + "cloud_traffic_reports_status_idx": { + "name": "cloud_traffic_reports_status_idx", + "columns": [ + "status" + ], + "isUnique": false + }, + "cloud_traffic_reports_retry_idx": { + "name": "cloud_traffic_reports_retry_idx", + "columns": [ + "status", + "next_retry_at", + "created_at" + ], + "isUnique": false + }, + "cloud_traffic_reports_issued_idx": { + "name": "cloud_traffic_reports_issued_idx", + "columns": [ + "issued_at" + ], + "isUnique": false + }, + "cloud_traffic_reports_updated_idx": { + "name": "cloud_traffic_reports_updated_idx", + "columns": [ + "updated_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "download_tasks": { + "name": "download_tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_uri": { + "name": "source_uri", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_folder": { + "name": "target_folder", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tags": { + "name": "tags", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "assigned_downloader_id": { + "name": "assigned_downloader_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "attempt": { + "name": "attempt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "billing_authorized_bytes": { + "name": "billing_authorized_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "billing_charged_bytes": { + "name": "billing_charged_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "billing_charged_credits": { + "name": "billing_charged_credits", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "billing_status": { + "name": "billing_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'none'" + }, + "error_code": { + "name": "error_code", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "result_object_id": { + "name": "result_object_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "runtime": { + "name": "runtime", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "events": { + "name": "events", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "resolve_started_at": { + "name": "resolve_started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resolve_completed_at": { + "name": "resolve_completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "download_completed_at": { + "name": "download_completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ingest_started_at": { + "name": "ingest_started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ingest_completed_at": { + "name": "ingest_completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "seeding_started_at": { + "name": "seeding_started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "seeding_stopped_at": { + "name": "seeding_stopped_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "assigned_at": { + "name": "assigned_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "finished_at": { + "name": "finished_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "download_tasks_org_created_idx": { + "name": "download_tasks_org_created_idx", + "columns": [ + "org_id", + "created_at" + ], + "isUnique": false + }, + "download_tasks_org_status_idx": { + "name": "download_tasks_org_status_idx", + "columns": [ + "org_id", + "status" + ], + "isUnique": false + }, + "download_tasks_org_category_idx": { + "name": "download_tasks_org_category_idx", + "columns": [ + "org_id", + "category" + ], + "isUnique": false + }, + "download_tasks_org_tags_idx": { + "name": "download_tasks_org_tags_idx", + "columns": [ + "org_id", + "tags" + ], + "isUnique": false + }, + "download_tasks_downloader_idx": { + "name": "download_tasks_downloader_idx", + "columns": [ + "assigned_downloader_id", + "status" + ], + "isUnique": false + }, + "download_tasks_created_idx": { + "name": "download_tasks_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + }, + "download_tasks_finished_idx": { + "name": "download_tasks_finished_idx", + "columns": [ + "finished_at" + ], + "isUnique": false + }, + "download_tasks_org_deleted_created_idx": { + "name": "download_tasks_org_deleted_created_idx", + "columns": [ + "org_id", + "deleted_at", + "created_at" + ], + "isUnique": false + }, + "download_tasks_org_page_idx": { + "name": "download_tasks_org_page_idx", + "columns": [ + "org_id", + "deleted_at", + "created_at", + "id" + ], + "isUnique": false + }, + "download_tasks_downloader_page_idx": { + "name": "download_tasks_downloader_page_idx", + "columns": [ + "assigned_downloader_id", + "deleted_at", + "created_at", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "downloaders": { + "name": "downloaders", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token_jti": { + "name": "token_jti", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'offline'" + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "hostname": { + "name": "hostname", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "platform": { + "name": "platform", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "arch": { + "name": "arch", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "engine": { + "name": "engine", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'http'" + }, + "capabilities": { + "name": "capabilities", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "max_concurrent_tasks": { + "name": "max_concurrent_tasks", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "current_tasks": { + "name": "current_tasks", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "download_bps": { + "name": "download_bps", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "upload_bps": { + "name": "upload_bps", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "free_disk_bytes": { + "name": "free_disk_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "remote_download_credit_billing_enabled": { + "name": "remote_download_credit_billing_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "remote_download_credit_unit_bytes": { + "name": "remote_download_credit_unit_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 104857600 + }, + "remote_download_credit_per_unit": { + "name": "remote_download_credit_per_unit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "last_heartbeat_at": { + "name": "last_heartbeat_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "downloaders_token_jti_unique": { + "name": "downloaders_token_jti_unique", + "columns": [ + "token_jti" + ], + "isUnique": true + }, + "downloaders_status_idx": { + "name": "downloaders_status_idx", + "columns": [ + "status" + ], + "isUnique": false + }, + "downloaders_enabled_idx": { + "name": "downloaders_enabled_idx", + "columns": [ + "enabled" + ], + "isUnique": false + }, + "downloaders_created_idx": { + "name": "downloaders_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "image_hosting_configs": { + "name": "image_hosting_configs", + "columns": { + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "custom_domain": { + "name": "custom_domain", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_provider": { + "name": "domain_provider", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider_hostname_id": { + "name": "provider_hostname_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_status": { + "name": "domain_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_error": { + "name": "domain_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "verification_token": { + "name": "verification_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_last_checked_at": { + "name": "domain_last_checked_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "domain_verified_at": { + "name": "domain_verified_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "referer_allowlist": { + "name": "referer_allowlist", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "image_hosting_configs_custom_domain_unique": { + "name": "image_hosting_configs_custom_domain_unique", + "columns": [ + "custom_domain" + ], + "isUnique": true + } + }, + "foreignKeys": { + "image_hosting_configs_org_id_organization_id_fk": { + "name": "image_hosting_configs_org_id_organization_id_fk", + "tableFrom": "image_hosting_configs", + "columnsFrom": [ + "org_id" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "image_hostings": { + "name": "image_hostings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_key": { + "name": "storage_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mime": { + "name": "mime", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "purged_at": { + "name": "purged_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_count": { + "name": "access_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "last_accessed_at": { + "name": "last_accessed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "image_hostings_token_unique": { + "name": "image_hostings_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "image_hostings_org_path_uniq": { + "name": "image_hostings_org_path_uniq", + "columns": [ + "org_id", + "path" + ], + "where": "\"image_hostings\".\"purged_at\" IS NULL", + "isUnique": true + }, + "image_hostings_org_created_idx": { + "name": "image_hostings_org_created_idx", + "columns": [ + "org_id", + "created_at" + ], + "isUnique": false + }, + "image_hostings_page_idx": { + "name": "image_hostings_page_idx", + "columns": [ + "org_id", + "status", + "purged_at", + "created_at", + "id" + ], + "isUnique": false + }, + "image_hostings_token_idx": { + "name": "image_hostings_token_idx", + "columns": [ + "token" + ], + "isUnique": false + } + }, + "foreignKeys": { + "image_hostings_org_id_organization_id_fk": { + "name": "image_hostings_org_id_organization_id_fk", + "tableFrom": "image_hostings", + "columnsFrom": [ + "org_id" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "image_hostings_storage_id_storages_id_fk": { + "name": "image_hostings_storage_id_storages_id_fk", + "tableFrom": "image_hostings", + "columnsFrom": [ + "storage_id" + ], + "tableTo": "storages", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invite_codes": { + "name": "invite_codes", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "used_by": { + "name": "used_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "used_at": { + "name": "used_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invite_codes_code_unique": { + "name": "invite_codes_code_unique", + "columns": [ + "code" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "license_bindings": { + "name": "license_bindings", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "cloud_binding_id": { + "name": "cloud_binding_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cloud_store_id": { + "name": "cloud_store_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "instance_id": { + "name": "instance_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cloud_account_id": { + "name": "cloud_account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cloud_account_email": { + "name": "cloud_account_email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cached_certificate": { + "name": "cached_certificate", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cached_certificate_expires_at": { + "name": "cached_certificate_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bound_at": { + "name": "bound_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "disconnected_at": { + "name": "disconnected_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_refresh_at": { + "name": "last_refresh_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_refresh_error": { + "name": "last_refresh_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "license_bindings_active_uniq": { + "name": "license_bindings_active_uniq", + "columns": [ + "status" + ], + "where": "status = 'active'", + "isUnique": true + }, + "license_bindings_cloud_binding_idx": { + "name": "license_bindings_cloud_binding_idx", + "columns": [ + "cloud_binding_id" + ], + "isUnique": false + }, + "license_bindings_instance_idx": { + "name": "license_bindings_instance_idx", + "columns": [ + "instance_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "matters": { + "name": "matters", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "alias": { + "name": "alias", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "dirtype": { + "name": "dirtype", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "parent": { + "name": "parent", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "object": { + "name": "object", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "trashed_at": { + "name": "trashed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "purged_at": { + "name": "purged_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "matters_alias_unique": { + "name": "matters_alias_unique", + "columns": [ + "alias" + ], + "isUnique": true + }, + "matters_status_dir_created_idx": { + "name": "matters_status_dir_created_idx", + "columns": [ + "status", + "dirtype", + "created_at" + ], + "isUnique": false + }, + "matters_webdav_path_idx": { + "name": "matters_webdav_path_idx", + "columns": [ + "org_id", + "parent", + "name", + "status", + "trashed_at", + "purged_at" + ], + "isUnique": false + }, + "matters_webdav_children_idx": { + "name": "matters_webdav_children_idx", + "columns": [ + "org_id", + "parent", + "status", + "trashed_at", + "purged_at", + "\"dirtype\" desc", + "name" + ], + "isUnique": false + }, + "matters_list_page_idx": { + "name": "matters_list_page_idx", + "columns": [ + "org_id", + "parent", + "status", + "trashed_at", + "purged_at", + "\"dirtype\" desc", + "created_at", + "id" + ], + "isUnique": false + }, + "matters_trash_page_idx": { + "name": "matters_trash_page_idx", + "columns": [ + "org_id", + "status", + "purged_at", + "trashed_at", + "created_at", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "notifications": { + "name": "notifications", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "ref_type": { + "name": "ref_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ref_id": { + "name": "ref_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "read_at": { + "name": "read_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "notifications_user_created_idx": { + "name": "notifications_user_created_idx", + "columns": [ + "user_id", + "created_at" + ], + "isUnique": false + }, + "notifications_user_read_idx": { + "name": "notifications_user_read_idx", + "columns": [ + "user_id", + "read_at" + ], + "isUnique": false + }, + "notifications_user_page_idx": { + "name": "notifications_user_page_idx", + "columns": [ + "user_id", + "read_at", + "created_at", + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "object_upload_sessions": { + "name": "object_upload_sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "object_id": { + "name": "object_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_key": { + "name": "storage_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "upload_id": { + "name": "upload_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "part_size": { + "name": "part_size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "on_conflict": { + "name": "on_conflict", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'fail'" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "object_upload_sessions_object_idx": { + "name": "object_upload_sessions_object_idx", + "columns": [ + "org_id", + "object_id" + ], + "isUnique": false + }, + "object_upload_sessions_expires_idx": { + "name": "object_upload_sessions_expires_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "org_quota_entitlements": { + "name": "org_quota_entitlements", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "entitlement_type": { + "name": "entitlement_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'grant'" + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "bytes": { + "name": "bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "starts_at": { + "name": "starts_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "org_quota_entitlements_org_resource_idx": { + "name": "org_quota_entitlements_org_resource_idx", + "columns": [ + "org_id", + "resource_type", + "status" + ], + "isUnique": false + }, + "org_quota_entitlements_org_type_idx": { + "name": "org_quota_entitlements_org_type_idx", + "columns": [ + "org_id", + "resource_type", + "entitlement_type", + "status" + ], + "isUnique": false + }, + "org_quota_entitlements_source_resource_uniq": { + "name": "org_quota_entitlements_source_resource_uniq", + "columns": [ + "source", + "source_id", + "resource_type" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "org_quotas": { + "name": "org_quotas", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "quota": { + "name": "quota", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "used": { + "name": "used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "traffic_quota": { + "name": "traffic_quota", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "traffic_used": { + "name": "traffic_used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "traffic_period": { + "name": "traffic_period", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'1970-01'" + } + }, + "indexes": { + "org_quotas_org_uniq": { + "name": "org_quotas_org_uniq", + "columns": [ + "org_id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "remote_download_usage_reports": { + "name": "remote_download_usage_reports", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "downloader_id": { + "name": "downloader_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "unit_index": { + "name": "unit_index", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "unit_bytes": { + "name": "unit_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credits_per_unit": { + "name": "credits_per_unit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "remote_download_usage_reports_event_id_unique": { + "name": "remote_download_usage_reports_event_id_unique", + "columns": [ + "event_id" + ], + "isUnique": true + }, + "remote_download_usage_task_unit_uniq": { + "name": "remote_download_usage_task_unit_uniq", + "columns": [ + "task_id", + "unit_index" + ], + "isUnique": true + }, + "remote_download_usage_org_idx": { + "name": "remote_download_usage_org_idx", + "columns": [ + "org_id" + ], + "isUnique": false + }, + "remote_download_usage_status_idx": { + "name": "remote_download_usage_status_idx", + "columns": [ + "status" + ], + "isUnique": false + }, + "remote_download_usage_created_idx": { + "name": "remote_download_usage_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "resource_changes": { + "name": "resource_changes", + "columns": { + "sequence": { + "name": "sequence", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "scope_type": { + "name": "scope_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scope_id": { + "name": "scope_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "change_type": { + "name": "change_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "occurred_at": { + "name": "occurred_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "resource_changes_scope_sequence_idx": { + "name": "resource_changes_scope_sequence_idx", + "columns": [ + "scope_type", + "scope_id", + "sequence" + ], + "isUnique": false + }, + "resource_changes_resource_sequence_idx": { + "name": "resource_changes_resource_sequence_idx", + "columns": [ + "resource_type", + "resource_id", + "sequence" + ], + "isUnique": false + }, + "resource_changes_occurred_idx": { + "name": "resource_changes_occurred_idx", + "columns": [ + "occurred_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "share_recipients": { + "name": "share_recipients", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "share_id": { + "name": "share_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "recipient_user_id": { + "name": "recipient_user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "recipient_email": { + "name": "recipient_email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "share_recipients_share_id_idx": { + "name": "share_recipients_share_id_idx", + "columns": [ + "share_id" + ], + "isUnique": false + }, + "share_recipients_user_id_idx": { + "name": "share_recipients_user_id_idx", + "columns": [ + "recipient_user_id" + ], + "isUnique": false + }, + "share_recipients_email_idx": { + "name": "share_recipients_email_idx", + "columns": [ + "recipient_email" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "shares": { + "name": "shares", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "matter_id": { + "name": "matter_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "download_limit": { + "name": "download_limit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "views": { + "name": "views", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "downloads": { + "name": "downloads", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'active'" + }, + "private": { + "name": "private", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "shares_token_unique": { + "name": "shares_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "shares_creator_status_created_idx": { + "name": "shares_creator_status_created_idx", + "columns": [ + "creator_id", + "status", + "created_at", + "id" + ], + "isUnique": false + }, + "shares_creator_private_created_idx": { + "name": "shares_creator_private_created_idx", + "columns": [ + "creator_id", + "private", + "created_at" + ], + "isUnique": false + }, + "shares_created_idx": { + "name": "shares_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "site_invitations": { + "name": "site_invitations", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "invited_by": { + "name": "invited_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "accepted_by": { + "name": "accepted_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "accepted_at": { + "name": "accepted_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "revoked_by": { + "name": "revoked_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "site_invitations_token_unique": { + "name": "site_invitations_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "site_invitations_email_idx": { + "name": "site_invitations_email_idx", + "columns": [ + "email" + ], + "isUnique": false + }, + "site_invitations_created_idx": { + "name": "site_invitations_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + }, + "site_invitations_expires_idx": { + "name": "site_invitations_expires_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "stats_rollups_hourly": { + "name": "stats_rollups_hourly", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "bucket_start": { + "name": "bucket_start", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "metric_key": { + "name": "metric_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dimension_key": { + "name": "dimension_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "dimension_value": { + "name": "dimension_value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "bytes": { + "name": "bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "unique_count": { + "name": "unique_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "stats_rollups_hourly_bucket_metric_dim_uniq": { + "name": "stats_rollups_hourly_bucket_metric_dim_uniq", + "columns": [ + "bucket_start", + "org_id", + "metric_key", + "dimension_key", + "dimension_value" + ], + "isUnique": true + }, + "stats_rollups_hourly_metric_bucket_idx": { + "name": "stats_rollups_hourly_metric_bucket_idx", + "columns": [ + "metric_key", + "bucket_start" + ], + "isUnique": false + }, + "stats_rollups_hourly_dimension_bucket_idx": { + "name": "stats_rollups_hourly_dimension_bucket_idx", + "columns": [ + "metric_key", + "dimension_key", + "bucket_start" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "storage_usage_breakdowns": { + "name": "storage_usage_breakdowns", + "columns": { + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "bytes": { + "name": "bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "file_count": { + "name": "file_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "storage_usage_breakdowns_org_category_uniq": { + "name": "storage_usage_breakdowns_org_category_uniq", + "columns": [ + "org_id", + "category" + ], + "isUnique": true + }, + "storage_usage_breakdowns_org_idx": { + "name": "storage_usage_breakdowns_org_idx", + "columns": [ + "org_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "storage_usage_ledger": { + "name": "storage_usage_ledger", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "event_key": { + "name": "event_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "storage_id": { + "name": "storage_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "delta_bytes": { + "name": "delta_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "occurred_at": { + "name": "occurred_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "storage_usage_ledger_event_key_unique": { + "name": "storage_usage_ledger_event_key_unique", + "columns": [ + "event_key" + ], + "isUnique": true + }, + "storage_usage_ledger_occurred_idx": { + "name": "storage_usage_ledger_occurred_idx", + "columns": [ + "occurred_at" + ], + "isUnique": false + }, + "storage_usage_ledger_org_occurred_idx": { + "name": "storage_usage_ledger_org_occurred_idx", + "columns": [ + "org_id", + "occurred_at" + ], + "isUnique": false + }, + "storage_usage_ledger_storage_occurred_idx": { + "name": "storage_usage_ledger_storage_occurred_idx", + "columns": [ + "storage_id", + "occurred_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "storages": { + "name": "storages", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'auto'" + }, + "access_key": { + "name": "access_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "secret_key": { + "name": "secret_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "custom_host": { + "name": "custom_host", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "''" + }, + "capacity": { + "name": "capacity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "egress_credit_billing_enabled": { + "name": "egress_credit_billing_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "egress_credit_unit_bytes": { + "name": "egress_credit_unit_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 104857600 + }, + "egress_credit_per_unit": { + "name": "egress_credit_per_unit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "force_path_style": { + "name": "force_path_style", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "used": { + "name": "used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'unknown'" + }, + "status_reason": { + "name": "status_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status_checked_at": { + "name": "status_checked_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "system_options": { + "name": "system_options", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "team_invite_links": { + "name": "team_invite_links", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'member'" + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "team_invite_links_token_unique": { + "name": "team_invite_links_token_unique", + "columns": [ + "token" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "webdav_dead_properties": { + "name": "webdav_dead_properties", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_path": { + "name": "resource_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "namespace": { + "name": "namespace", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "webdav_dead_properties_resource_prop_uniq": { + "name": "webdav_dead_properties_resource_prop_uniq", + "columns": [ + "org_id", + "resource_path", + "namespace", + "name" + ], + "isUnique": true + }, + "webdav_dead_properties_resource_idx": { + "name": "webdav_dead_properties_resource_idx", + "columns": [ + "org_id", + "resource_path" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "webdav_locks": { + "name": "webdav_locks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_path": { + "name": "resource_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "depth": { + "name": "depth", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'infinity'" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "webdav_locks_token_unique": { + "name": "webdav_locks_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "webdav_locks_resource_idx": { + "name": "webdav_locks_resource_idx", + "columns": [ + "org_id", + "resource_path" + ], + "isUnique": false + }, + "webdav_locks_expires_idx": { + "name": "webdav_locks_expires_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "webhook_events": { + "name": "webhook_events", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'cloud'" + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'order.quota_changed'" + }, + "payload_hash": { + "name": "payload_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "raw_payload": { + "name": "raw_payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "processed_at": { + "name": "processed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "webhook_events_source_event_uniq": { + "name": "webhook_events_source_event_uniq", + "columns": [ + "source", + "event_id" + ], + "isUnique": true + }, + "webhook_events_source_created_idx": { + "name": "webhook_events_source_created_idx", + "columns": [ + "source", + "created_at" + ], + "isUnique": false + }, + "webhook_events_status_idx": { + "name": "webhook_events_status_idx", + "columns": [ + "status" + ], + "isUnique": false + }, + "webhook_events_processed_idx": { + "name": "webhook_events_processed_idx", + "columns": [ + "processed_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "x402_capacity_purchase_intents": { + "name": "x402_capacity_purchase_intents", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "request_hash": { + "name": "request_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "idempotency_key": { + "name": "idempotency_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cloud_order_id": { + "name": "cloud_order_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cloud_attempt_id": { + "name": "cloud_attempt_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'created'" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "x402_capacity_purchase_intents_org_request_uniq": { + "name": "x402_capacity_purchase_intents_org_request_uniq", + "columns": [ + "org_id", + "resource_id", + "request_hash" + ], + "isUnique": true + }, + "x402_capacity_purchase_intents_org_idempotency_uniq": { + "name": "x402_capacity_purchase_intents_org_idempotency_uniq", + "columns": [ + "org_id", + "idempotency_key" + ], + "isUnique": true + }, + "x402_capacity_purchase_intents_attempt_idx": { + "name": "x402_capacity_purchase_intents_attempt_idx", + "columns": [ + "cloud_attempt_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "account": { + "name": "account", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "issuer": { + "name": "issuer", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "account_issuer_providerAccountId_unique": { + "name": "account_issuer_providerAccountId_unique", + "columns": [ + "issuer", + "account_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "apikey": { + "name": "apikey", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "config_id": { + "name": "config_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'default'" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "start": { + "name": "start", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refill_interval": { + "name": "refill_interval", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refill_amount": { + "name": "refill_amount", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "rate_limit_enabled": { + "name": "rate_limit_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "rate_limit_time_window": { + "name": "rate_limit_time_window", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rate_limit_max": { + "name": "rate_limit_max", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "request_count": { + "name": "request_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "remaining": { + "name": "remaining", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_request": { + "name": "last_request", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permissions": { + "name": "permissions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "apikey_config_id_idx": { + "name": "apikey_config_id_idx", + "columns": [ + "config_id" + ], + "isUnique": false + }, + "apikey_reference_id_idx": { + "name": "apikey_reference_id_idx", + "columns": [ + "reference_id" + ], + "isUnique": false + }, + "apikey_key_idx": { + "name": "apikey_key_idx", + "columns": [ + "key" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "deviceCode": { + "name": "deviceCode", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "device_code": { + "name": "device_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_code": { + "name": "user_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_polled_at": { + "name": "last_polled_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "polling_interval": { + "name": "polling_interval", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "deviceCode_device_code_idx": { + "name": "deviceCode_device_code_idx", + "columns": [ + "device_code" + ], + "isUnique": false + }, + "deviceCode_user_code_idx": { + "name": "deviceCode_user_code_idx", + "columns": [ + "user_code" + ], + "isUnique": false + }, + "deviceCode_status_idx": { + "name": "deviceCode_status_idx", + "columns": [ + "status" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "downloader_bootstrap_credentials": { + "name": "downloader_bootstrap_credentials", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_code": { + "name": "device_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "consumed_at": { + "name": "consumed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "downloader_bootstrap_credentials_token_hash_unique": { + "name": "downloader_bootstrap_credentials_token_hash_unique", + "columns": [ + "token_hash" + ], + "isUnique": true + }, + "downloader_bootstrap_token_hash_idx": { + "name": "downloader_bootstrap_token_hash_idx", + "columns": [ + "token_hash" + ], + "isUnique": false + }, + "downloader_bootstrap_user_idx": { + "name": "downloader_bootstrap_user_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "downloader_bootstrap_consumed_idx": { + "name": "downloader_bootstrap_consumed_idx", + "columns": [ + "consumed_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "downloader_bootstrap_credentials_user_id_user_id_fk": { + "name": "downloader_bootstrap_credentials_user_id_user_id_fk", + "tableFrom": "downloader_bootstrap_credentials", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invitation": { + "name": "invitation", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invitation_organizationId_idx": { + "name": "invitation_organizationId_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "invitation_email_idx": { + "name": "invitation_email_idx", + "columns": [ + "email" + ], + "isUnique": false + } + }, + "foreignKeys": { + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "invitation_inviter_id_user_id_fk": { + "name": "invitation_inviter_id_user_id_fk", + "tableFrom": "invitation", + "columnsFrom": [ + "inviter_id" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "jwks": { + "name": "jwks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "private_key": { + "name": "private_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "alg": { + "name": "alg", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "crv": { + "name": "crv", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "member": { + "name": "member", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'member'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "member_organizationId_idx": { + "name": "member_organizationId_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "member_userId_idx": { + "name": "member_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "member_user_id_user_id_fk": { + "name": "member_user_id_user_id_fk", + "tableFrom": "member", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthAccessToken": { + "name": "oauthAccessToken", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "authorization_code_id": { + "name": "authorization_code_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resources": { + "name": "resources", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "requested_user_info_claims": { + "name": "requested_user_info_claims", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_id": { + "name": "refresh_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "revoked": { + "name": "revoked", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "confirmation": { + "name": "confirmation", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "oauthAccessToken_token_unique": { + "name": "oauthAccessToken_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "oauthAccessToken_client_id_idx": { + "name": "oauthAccessToken_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthAccessToken_session_id_idx": { + "name": "oauthAccessToken_session_id_idx", + "columns": [ + "session_id" + ], + "isUnique": false + }, + "oauthAccessToken_user_id_idx": { + "name": "oauthAccessToken_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "oauthAccessToken_refresh_id_idx": { + "name": "oauthAccessToken_refresh_id_idx", + "columns": [ + "refresh_id" + ], + "isUnique": false + }, + "oauthAccessToken_token_idx": { + "name": "oauthAccessToken_token_idx", + "columns": [ + "token" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthAccessToken_client_id_oauthClient_client_id_fk": { + "name": "oauthAccessToken_client_id_oauthClient_client_id_fk", + "tableFrom": "oauthAccessToken", + "columnsFrom": [ + "client_id" + ], + "tableTo": "oauthClient", + "columnsTo": [ + "client_id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "oauthAccessToken_session_id_session_id_fk": { + "name": "oauthAccessToken_session_id_session_id_fk", + "tableFrom": "oauthAccessToken", + "columnsFrom": [ + "session_id" + ], + "tableTo": "session", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "oauthAccessToken_user_id_user_id_fk": { + "name": "oauthAccessToken_user_id_user_id_fk", + "tableFrom": "oauthAccessToken", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "oauthAccessToken_refresh_id_oauthRefreshToken_id_fk": { + "name": "oauthAccessToken_refresh_id_oauthRefreshToken_id_fk", + "tableFrom": "oauthAccessToken", + "columnsFrom": [ + "refresh_id" + ], + "tableTo": "oauthRefreshToken", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthClient": { + "name": "oauthClient", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_secret": { + "name": "client_secret", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "disabled": { + "name": "disabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "skip_consent": { + "name": "skip_consent", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enable_end_session": { + "name": "enable_end_session", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_type": { + "name": "subject_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "uri": { + "name": "uri", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "contacts": { + "name": "contacts", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tos": { + "name": "tos", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "policy": { + "name": "policy", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "software_id": { + "name": "software_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "software_version": { + "name": "software_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "software_statement": { + "name": "software_statement", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "redirect_uris": { + "name": "redirect_uris", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_logout_redirect_uris": { + "name": "post_logout_redirect_uris", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "backchannel_logout_uri": { + "name": "backchannel_logout_uri", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "backchannel_logout_session_required": { + "name": "backchannel_logout_session_required", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_endpoint_auth_method": { + "name": "token_endpoint_auth_method", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "jwks": { + "name": "jwks", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "jwks_uri": { + "name": "jwks_uri", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "grant_types": { + "name": "grant_types", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "response_types": { + "name": "response_types", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "public": { + "name": "public", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "require_pkce": { + "name": "require_pkce", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dpop_bound_access_tokens": { + "name": "dpop_bound_access_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "oauthClient_client_id_unique": { + "name": "oauthClient_client_id_unique", + "columns": [ + "client_id" + ], + "isUnique": true + }, + "oauthClient_client_id_idx": { + "name": "oauthClient_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthClient_user_id_idx": { + "name": "oauthClient_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthClient_user_id_user_id_fk": { + "name": "oauthClient_user_id_user_id_fk", + "tableFrom": "oauthClient", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthClientAssertion": { + "name": "oauthClientAssertion", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthClientResource": { + "name": "oauthClientResource", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "oauthClientResource_client_id_idx": { + "name": "oauthClientResource_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthClientResource_resource_id_idx": { + "name": "oauthClientResource_resource_id_idx", + "columns": [ + "resource_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthClientResource_client_id_oauthClient_client_id_fk": { + "name": "oauthClientResource_client_id_oauthClient_client_id_fk", + "tableFrom": "oauthClientResource", + "columnsFrom": [ + "client_id" + ], + "tableTo": "oauthClient", + "columnsTo": [ + "client_id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "oauthClientResource_resource_id_oauthResource_identifier_fk": { + "name": "oauthClientResource_resource_id_oauthResource_identifier_fk", + "tableFrom": "oauthClientResource", + "columnsFrom": [ + "resource_id" + ], + "tableTo": "oauthResource", + "columnsTo": [ + "identifier" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthConsent": { + "name": "oauthConsent", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resources": { + "name": "resources", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "requested_user_info_claims": { + "name": "requested_user_info_claims", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "last_used_at": { + "name": "last_used_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "oauthConsent_client_id_idx": { + "name": "oauthConsent_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthConsent_user_id_idx": { + "name": "oauthConsent_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthConsent_client_id_oauthClient_client_id_fk": { + "name": "oauthConsent_client_id_oauthClient_client_id_fk", + "tableFrom": "oauthConsent", + "columnsFrom": [ + "client_id" + ], + "tableTo": "oauthClient", + "columnsTo": [ + "client_id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "oauthConsent_user_id_user_id_fk": { + "name": "oauthConsent_user_id_user_id_fk", + "tableFrom": "oauthConsent", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthJwtRevocation": { + "name": "oauthJwtRevocation", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "oauthJwtRevocation_expires_at_idx": { + "name": "oauthJwtRevocation_expires_at_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthRefreshToken": { + "name": "oauthRefreshToken", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "authorization_code_id": { + "name": "authorization_code_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resources": { + "name": "resources", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "requested_user_info_claims": { + "name": "requested_user_info_claims", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "revoked": { + "name": "revoked", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rotated_at": { + "name": "rotated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rotation_replay_response": { + "name": "rotation_replay_response", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rotation_replay_expires_at": { + "name": "rotation_replay_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "auth_time": { + "name": "auth_time", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "confirmation": { + "name": "confirmation", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "oauthRefreshToken_token_unique": { + "name": "oauthRefreshToken_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "oauthRefreshToken_client_id_idx": { + "name": "oauthRefreshToken_client_id_idx", + "columns": [ + "client_id" + ], + "isUnique": false + }, + "oauthRefreshToken_session_id_idx": { + "name": "oauthRefreshToken_session_id_idx", + "columns": [ + "session_id" + ], + "isUnique": false + }, + "oauthRefreshToken_user_id_idx": { + "name": "oauthRefreshToken_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "oauthRefreshToken_token_idx": { + "name": "oauthRefreshToken_token_idx", + "columns": [ + "token" + ], + "isUnique": false + } + }, + "foreignKeys": { + "oauthRefreshToken_client_id_oauthClient_client_id_fk": { + "name": "oauthRefreshToken_client_id_oauthClient_client_id_fk", + "tableFrom": "oauthRefreshToken", + "columnsFrom": [ + "client_id" + ], + "tableTo": "oauthClient", + "columnsTo": [ + "client_id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "oauthRefreshToken_session_id_session_id_fk": { + "name": "oauthRefreshToken_session_id_session_id_fk", + "tableFrom": "oauthRefreshToken", + "columnsFrom": [ + "session_id" + ], + "tableTo": "session", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "oauthRefreshToken_user_id_user_id_fk": { + "name": "oauthRefreshToken_user_id_user_id_fk", + "tableFrom": "oauthRefreshToken", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oauthResource": { + "name": "oauthResource", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token_ttl": { + "name": "access_token_ttl", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_ttl": { + "name": "refresh_token_ttl", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "signing_algorithm": { + "name": "signing_algorithm", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "signing_key_id": { + "name": "signing_key_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "allowed_scopes": { + "name": "allowed_scopes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "custom_claims": { + "name": "custom_claims", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dpop_bound_access_tokens_required": { + "name": "dpop_bound_access_tokens_required", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "disabled": { + "name": "disabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "policy_version": { + "name": "policy_version", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 1 + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "oauthResource_identifier_unique": { + "name": "oauthResource_identifier_unique", + "columns": [ + "identifier" + ], + "isUnique": true + }, + "oauthResource_identifier_idx": { + "name": "oauthResource_identifier_idx", + "columns": [ + "identifier" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "organization": { + "name": "organization", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "columns": [ + "slug" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "session_token_unique": { + "name": "session_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "session_created_idx": { + "name": "session_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "banned": { + "name": "banned", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_username": { + "name": "display_username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_active_at": { + "name": "last_active_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ], + "isUnique": true + }, + "user_username_unique": { + "name": "user_username_unique", + "columns": [ + "username" + ], + "isUnique": true + }, + "user_created_idx": { + "name": "user_created_idx", + "columns": [ + "created_at" + ], + "isUnique": false + }, + "user_lastActiveAt_idx": { + "name": "user_lastActiveAt_idx", + "columns": [ + "last_active_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verification": { + "name": "verification", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + "identifier" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + }, + "internal": { + "indexes": { + "matters_webdav_children_idx": { + "columns": { + "\"dirtype\" desc": { + "isExpression": true + } + } + }, + "matters_list_page_idx": { + "columns": { + "\"dirtype\" desc": { + "isExpression": true + } + } + } + } + } +} \ No newline at end of file diff --git a/migrations/meta/_journal.json b/migrations/meta/_journal.json index f0dc9bcf..e47e4260 100644 --- a/migrations/meta/_journal.json +++ b/migrations/meta/_journal.json @@ -603,6 +603,27 @@ "when": 1785456041947, "tag": "0086_agent-audit-identity", "breakpoints": true + }, + { + "idx": 87, + "version": "6", + "when": 1785462114956, + "tag": "0087_x402_capacity_purchases", + "breakpoints": true + }, + { + "idx": 88, + "version": "6", + "when": 1785471548091, + "tag": "0088_x402_tenant_idempotency", + "breakpoints": true + }, + { + "idx": 89, + "version": "6", + "when": 1785506906336, + "tag": "0089_better-auth-account-issuer-backfill", + "breakpoints": true } ] } \ No newline at end of file diff --git a/package.json b/package.json index d2bbf0fa..93db9f07 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "storage:backfill": "tsx scripts/backfill-storage-usage.ts", "storage-status:backfill": "tsx scripts/backfill-storage-enabled-status.ts", "api-key-scopes:backfill": "tsx scripts/backfill-api-key-scopes.ts", + "agent-oauth-scopes:backfill": "tsx scripts/backfill-agent-oauth-scopes.ts", "typecheck": "tsc --noEmit -p server/tsconfig.json && tsc --noEmit -p src/tsconfig.json", "test": "vitest run --project unit --project integration", "test:cf": "vitest run --project cloudflare", @@ -108,7 +109,7 @@ "tailwind-merge": "^3.5.0", "yet-another-react-lightbox": "^3.30.1", "zod": "^4.4.3", - "zpan-cloud-sdk": "^2.4.0" + "zpan-cloud-sdk": "^2.5.1" }, "devDependencies": { "@biomejs/biome": "^2.4.10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4bf9ad8c..9e205a06 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -192,8 +192,8 @@ importers: specifier: ^4.4.3 version: 4.4.3 zpan-cloud-sdk: - specifier: ^2.4.0 - version: 2.4.0(hono@4.12.27)(zod@4.4.3) + specifier: ^2.5.1 + version: 2.5.1(hono@4.12.27)(zod@4.4.3) devDependencies: '@biomejs/biome': specifier: ^2.4.10 @@ -5902,8 +5902,8 @@ packages: zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} - zpan-cloud-sdk@2.4.0: - resolution: {integrity: sha512-kPyX9vjZXxtZdWQRE8ZPeICJmdwq4zx+4RFw0DvfY54e9G8T5vf3U9gpWndO1YVkd37zyKKRWZpify4m1dv4Mg==} + zpan-cloud-sdk@2.5.1: + resolution: {integrity: sha512-8db7VzBYl0yuzmU8f1RCoqGRFHSaVn6cDe9v7IS10WuLs+QPwbeBZZDQxfmmpAWfoOdl8M9gxJGjlgzfBHZy6A==} peerDependencies: hono: ^4.7.11 zod: ^4.3.6 @@ -11637,7 +11637,7 @@ snapshots: zod@4.4.3: {} - zpan-cloud-sdk@2.4.0(hono@4.12.27)(zod@4.4.3): + zpan-cloud-sdk@2.5.1(hono@4.12.27)(zod@4.4.3): dependencies: hono: 4.12.27 zod: 4.4.3 diff --git a/scripts/backfill-agent-oauth-scopes.ts b/scripts/backfill-agent-oauth-scopes.ts new file mode 100644 index 00000000..585760c1 --- /dev/null +++ b/scripts/backfill-agent-oauth-scopes.ts @@ -0,0 +1,213 @@ +#!/usr/bin/env tsx + +import { execFileSync } from 'node:child_process' +import Database from 'better-sqlite3' +import { AGENT_OAUTH_SCOPES } from '../shared/agent-oauth' +import { AuthorizationScope } from '../shared/authorization' + +export type AgentOAuthScopeBackfillTarget = + | { kind: 'sqlite'; path: string } + | { kind: 'd1'; database: string; remote: boolean; env?: string } + +export interface AgentOAuthScopeBackfillOptions { + apply: boolean + target: AgentOAuthScopeBackfillTarget +} + +interface OAuthResourceRow { + id: string + name: string + allowedScopes: string | null +} + +interface OAuthClientRow { + id: string + scopes: string | null +} + +export interface AgentOAuthScopeBackfill { + resources: Array<{ id: string; scopes: string }> + clients: Array<{ id: string; scopes: string }> +} + +export function buildAgentOAuthScopeBackfill( + resources: OAuthResourceRow[], + clients: OAuthClientRow[], +): AgentOAuthScopeBackfill { + const resourceScopes = JSON.stringify(AGENT_OAUTH_SCOPES) + return { + resources: resources.flatMap((resource) => + resource.name === 'ZPan API' && resource.allowedScopes !== resourceScopes + ? [{ id: resource.id, scopes: resourceScopes }] + : [], + ), + clients: clients.flatMap((client) => { + const scopes = parseScopes(client.scopes) + if (!scopes.includes(AuthorizationScope.OBJECTS_CREATE) || scopes.includes(AuthorizationScope.QUOTA_PURCHASE)) { + return [] + } + return [{ id: client.id, scopes: JSON.stringify([...scopes, AuthorizationScope.QUOTA_PURCHASE]) }] + }), + } +} + +function parseScopes(value: string | null): string[] { + if (!value) return [] + const parsed = JSON.parse(value) + if (!Array.isArray(parsed) || parsed.some((scope) => typeof scope !== 'string')) { + throw new Error('invalid_oauth_client_scopes') + } + return parsed +} + +export function parseAgentOAuthScopeBackfillOptions(argv: string[]): AgentOAuthScopeBackfillOptions { + const sqliteIndex = argv.indexOf('--sqlite') + const d1Index = argv.indexOf('--d1') + if ((sqliteIndex >= 0) === (d1Index >= 0)) usage() + if (sqliteIndex >= 0) { + const path = argv[sqliteIndex + 1] + if (!path) usage() + return { apply: argv.includes('--apply'), target: { kind: 'sqlite', path } } + } + const database = argv[d1Index + 1] + if (!database) usage() + const envIndex = argv.indexOf('--env') + return { + apply: argv.includes('--apply'), + target: { + kind: 'd1', + database, + remote: argv.includes('--remote'), + env: envIndex >= 0 ? argv[envIndex + 1] : undefined, + }, + } +} + +function usage(): never { + throw new Error( + 'Usage: pnpm agent-oauth-scopes:backfill -- (--sqlite | --d1 [--remote] [--env ]) [--apply]', + ) +} + +function d1Args(target: Extract): string[] { + return [ + 'exec', + 'wrangler', + 'd1', + 'execute', + target.database, + target.remote ? '--remote' : '--local', + ...(target.env ? ['--env', target.env] : []), + ] +} + +function executeD1(target: Extract, sql: string, json = false): string { + return execFileSync('pnpm', [...d1Args(target), '--command', sql, ...(json ? ['--json'] : [])], { + encoding: 'utf8', + stdio: json ? 'pipe' : 'inherit', + }) as string +} + +export type AgentOAuthScopeD1Executor = typeof executeD1 + +function d1Rows( + target: Extract, + sql: string, + execute: AgentOAuthScopeD1Executor, +): T[] { + const payload = JSON.parse(execute(target, sql, true)) as Array<{ results?: T[] }> + return payload.flatMap((entry) => entry.results ?? []) +} + +function readRows( + target: AgentOAuthScopeBackfillTarget, + execute: AgentOAuthScopeD1Executor, +): { resources: OAuthResourceRow[]; clients: OAuthClientRow[] } { + const resourceSql = 'SELECT id, name, allowed_scopes AS allowedScopes FROM oauthResource;' + const clientSql = 'SELECT id, scopes FROM oauthClient;' + if (target.kind === 'd1') { + return { + resources: d1Rows(target, resourceSql, execute), + clients: d1Rows(target, clientSql, execute), + } + } + const db = new Database(target.path, { readonly: true }) + try { + return { + resources: db.prepare(resourceSql).all() as OAuthResourceRow[], + clients: db.prepare(clientSql).all() as OAuthClientRow[], + } + } finally { + db.close() + } +} + +function sqlString(value: string): string { + return `'${value.replaceAll("'", "''")}'` +} + +function applyBackfill( + target: AgentOAuthScopeBackfillTarget, + changes: AgentOAuthScopeBackfill, + execute: AgentOAuthScopeD1Executor, +): void { + if (target.kind === 'd1') { + for (const resource of changes.resources) { + execute( + target, + `UPDATE oauthResource SET allowed_scopes = ${sqlString(resource.scopes)}, updated_at = cast(unixepoch('subsecond') * 1000 as integer) WHERE id = ${sqlString(resource.id)};`, + ) + } + for (const client of changes.clients) { + execute( + target, + `UPDATE oauthClient SET scopes = ${sqlString(client.scopes)}, updated_at = cast(unixepoch('subsecond') * 1000 as integer) WHERE id = ${sqlString(client.id)};`, + ) + } + return + } + const db = new Database(target.path) + try { + const updateResource = db.prepare('UPDATE oauthResource SET allowed_scopes = ?, updated_at = ? WHERE id = ?') + const updateClient = db.prepare('UPDATE oauthClient SET scopes = ?, updated_at = ? WHERE id = ?') + const now = Date.now() + db.transaction(() => { + for (const resource of changes.resources) updateResource.run(resource.scopes, now, resource.id) + for (const client of changes.clients) updateClient.run(client.scopes, now, client.id) + })() + } finally { + db.close() + } +} + +function countChanges(changes: AgentOAuthScopeBackfill): number { + return changes.resources.length + changes.clients.length +} + +export function runAgentOAuthScopeBackfill( + argv: string[], + log: (message: string) => void = console.log, + execute: AgentOAuthScopeD1Executor = executeD1, +): void { + const options = parseAgentOAuthScopeBackfillOptions(argv) + const rows = readRows(options.target, execute) + const changes = buildAgentOAuthScopeBackfill(rows.resources, rows.clients) + log( + JSON.stringify( + { + mode: options.apply ? 'apply' : 'dry-run', + resources: changes.resources.length, + clients: changes.clients.length, + }, + null, + 2, + ), + ) + if (!options.apply) return + applyBackfill(options.target, changes, execute) + const after = readRows(options.target, execute) + const remaining = buildAgentOAuthScopeBackfill(after.resources, after.clients) + if (countChanges(remaining) > 0) throw new Error(`agent_oauth_scope_backfill_failed:${countChanges(remaining)}`) +} + +if (process.argv[1]?.endsWith('backfill-agent-oauth-scopes.ts')) runAgentOAuthScopeBackfill(process.argv.slice(2)) diff --git a/scripts/cloud-e2e-resilience.mjs b/scripts/cloud-e2e-resilience.mjs new file mode 100644 index 00000000..006fd696 --- /dev/null +++ b/scripts/cloud-e2e-resilience.mjs @@ -0,0 +1,22 @@ +const QUICK_TUNNEL_502 = /trycloudflare\.com\s*\|\s*502:\s*Bad gateway/i +const CLIENT_TRANSPORT_FAILURE = /(?:\b502\b|ERR_(?:FAILED|TUNNEL_CONNECTION_FAILED)|ECONNRESET|socket hang up)/i +const TUNNEL_CONTEXT_CANCELED = /(?:Incoming request ended abruptly|Request failed)[^\n]*context canceled/i +const QUICK_TUNNEL_REQUEST = /trycloudflare\.com/i + +export function isRetryableQuickTunnelFailure({ commandOutput, tunnelOutput }) { + if (QUICK_TUNNEL_502.test(commandOutput)) return true + return ( + CLIENT_TRANSPORT_FAILURE.test(commandOutput) && + TUNNEL_CONTEXT_CANCELED.test(tunnelOutput) && + QUICK_TUNNEL_REQUEST.test(tunnelOutput) + ) +} + +export function cloudE2eAttemptCount(value) { + if (value === undefined) return 2 + const count = Number(value) + if (!Number.isInteger(count) || count < 1) { + throw new Error('E2E_TUNNEL_RUN_ATTEMPTS must be a positive integer') + } + return count +} diff --git a/scripts/cloud-e2e-resilience.test.mjs b/scripts/cloud-e2e-resilience.test.mjs new file mode 100644 index 00000000..42c952e0 --- /dev/null +++ b/scripts/cloud-e2e-resilience.test.mjs @@ -0,0 +1,46 @@ +import { describe, expect, it } from 'vitest' +import { cloudE2eAttemptCount, isRetryableQuickTunnelFailure } from './cloud-e2e-resilience.mjs' + +describe('cloud E2E resilience', () => { + it('retries a Cloudflare Quick Tunnel gateway page', () => { + expect( + isRetryableQuickTunnelFailure({ + commandOutput: 'trycloudflare.com | 502: Bad gateway', + tunnelOutput: '', + }), + ).toBe(true) + }) + + it('retries a client 502 corroborated by a canceled Quick Tunnel request', () => { + expect( + isRetryableQuickTunnelFailure({ + commandOutput: 'expected 200, got 502', + tunnelOutput: + 'Request failed error="context canceled" dest=https://fresh-tunnel.trycloudflare.com/api/events', + }), + ).toBe(true) + }) + + it('does not retry application failures or assertions', () => { + expect( + isRetryableQuickTunnelFailure({ + commandOutput: 'expected 200, got 500: checkout failed', + tunnelOutput: '', + }), + ).toBe(false) + expect( + isRetryableQuickTunnelFailure({ + commandOutput: 'expect(received).toEqual(expected)', + tunnelOutput: + 'Incoming request ended abruptly: context canceled dest=https://fresh-tunnel.trycloudflare.com/api/events', + }), + ).toBe(false) + }) + + it('uses two attempts by default and validates overrides', () => { + expect(cloudE2eAttemptCount()).toBe(2) + expect(cloudE2eAttemptCount('3')).toBe(3) + expect(() => cloudE2eAttemptCount('0')).toThrow('must be a positive integer') + expect(() => cloudE2eAttemptCount('nope')).toThrow('must be a positive integer') + }) +}) diff --git a/scripts/run-cloud-e2e.mjs b/scripts/run-cloud-e2e.mjs index b95f8c4e..5209851c 100644 --- a/scripts/run-cloud-e2e.mjs +++ b/scripts/run-cloud-e2e.mjs @@ -2,6 +2,7 @@ import { existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs' import { spawn } from 'node:child_process' import { Resolver } from 'node:dns/promises' import { createRequire } from 'node:module' +import { cloudE2eAttemptCount, isRetryableQuickTunnelFailure } from './cloud-e2e-resilience.mjs' const args = process.argv.slice(2) const require = createRequire(import.meta.url) @@ -26,49 +27,60 @@ const cloudEnv = { } const credentialsEnv = runtimeCloudCredentials(runtime) -const tunnel = local ? null : await startTunnel(localBaseUrl) -const tunnelHost = tunnel ? new URL(tunnel.url).hostname : '' -const tunnelIp = tunnel ? await waitForPublicTunnelIp(tunnelHost) : '' -const baseUrl = tunnel?.url ?? localBaseUrl -const tunnelEnv = { - E2E_BASE_URL: baseUrl, - E2E_LOCAL_BASE_URL: localBaseUrl, - E2E_APP_PORT: String(appPort), - E2E_API_PORT: String(apiPort), - BETTER_AUTH_URL: baseUrl, - TRUSTED_ORIGINS: `${baseUrl},${localBaseUrl}`, - ...(tunnel ? { E2E_CHROME_HOST_RESOLVER_RULES: `MAP ${tunnelHost} ${tunnelIp}` } : {}), -} -const e2eEnv = { - ...cloudEnv, - ...tunnelEnv, - ...s3MockEnv(), - ...credentialsEnv, - ...(runtime === 'cf' ? { E2E_RUNTIME: 'cf' } : {}), -} +if (runtime === 'cf' && local) rmSync('.wrangler/state/v3/d1', { recursive: true, force: true }) -if (runtime === 'cf') { - if (local) rmSync('.wrangler/state/v3/d1', { recursive: true, force: true }) - writeDevVars(e2eEnv) - await run('pnpm', ['exec', 'wrangler', 'd1', 'migrations', 'apply', 'DB', '--local'], e2eEnv) -} - -try { - await run(process.execPath, [require.resolve('@playwright/test/cli'), 'test', ...specs, `--project=${project}`], e2eEnv) -} finally { - if (tunnel) { - try { - tunnel.process.kill() - } catch {} - } - if (existsSync(pidFile)) { - const pid = Number(readFileSync(pidFile, 'utf8')) - if (Number.isInteger(pid)) { - try { - process.kill(pid) - } catch {} +const maxRunAttempts = local ? 1 : cloudE2eAttemptCount(process.env.E2E_TUNNEL_RUN_ATTEMPTS) +for (let attempt = 1; attempt <= maxRunAttempts; attempt += 1) { + const tunnel = local ? null : await startTunnel(localBaseUrl) + try { + const e2eEnv = await buildE2eEnv(tunnel) + if (runtime === 'cf') { + writeDevVars(e2eEnv) + await run('pnpm', ['exec', 'wrangler', 'd1', 'migrations', 'apply', 'DB', '--local'], e2eEnv) } - rmSync(pidFile, { force: true }) + + try { + await run( + process.execPath, + [require.resolve('@playwright/test/cli'), 'test', ...specs, `--project=${project}`], + e2eEnv, + true, + ) + break + } catch (error) { + const retryable = + error instanceof CommandError && + tunnel && + isRetryableQuickTunnelFailure({ + commandOutput: error.output, + tunnelOutput: tunnel.output(), + }) + if (!retryable || attempt === maxRunAttempts) throw error + console.warn( + `Quick Tunnel failed during cloud E2E; restarting the tunnel and test harness (${attempt + 1}/${maxRunAttempts})...`, + ) + } + } finally { + stopTunnel(tunnel) + } +} + +async function buildE2eEnv(tunnel) { + const tunnelHost = tunnel ? new URL(tunnel.url).hostname : '' + const tunnelIp = tunnel ? await waitForPublicTunnelIp(tunnelHost) : '' + const baseUrl = tunnel?.url ?? localBaseUrl + return { + ...cloudEnv, + E2E_BASE_URL: baseUrl, + E2E_LOCAL_BASE_URL: localBaseUrl, + E2E_APP_PORT: String(appPort), + E2E_API_PORT: String(apiPort), + BETTER_AUTH_URL: baseUrl, + TRUSTED_ORIGINS: `${baseUrl},${localBaseUrl}`, + ...(tunnel ? { E2E_CHROME_HOST_RESOLVER_RULES: `MAP ${tunnelHost} ${tunnelIp}` } : {}), + ...s3MockEnv(), + ...credentialsEnv, + ...(runtime === 'cf' ? { E2E_RUNTIME: 'cf' } : {}), } } @@ -137,6 +149,7 @@ function startTunnelOnce(target) { return new Promise((resolve, reject) => { let tunnelUrl = null let registered = false + let output = '' const timeout = setTimeout(() => { child.kill() reject(new Error('Timed out waiting for cloudflared tunnel registration')) @@ -144,13 +157,14 @@ function startTunnelOnce(target) { function handleOutput(chunk) { const text = chunk.toString() + output += text process.stdout.write(text) const match = text.match(tunnelUrlPattern) if (match) tunnelUrl = match[0] if (text.includes('Registered tunnel connection')) registered = true if (!tunnelUrl || !registered) return clearTimeout(timeout) - resolve({ process: child, url: tunnelUrl }) + resolve({ process: child, url: tunnelUrl, output: () => output }) } child.stdout.on('data', handleOutput) @@ -162,6 +176,18 @@ function startTunnelOnce(target) { }) } +function stopTunnel(tunnel) { + if (tunnel) tunnel.process.kill() + if (!existsSync(pidFile)) return + const pid = Number(readFileSync(pidFile, 'utf8')) + if (Number.isInteger(pid)) { + try { + process.kill(pid) + } catch {} + } + rmSync(pidFile, { force: true }) +} + function writeDevVars(env) { const updates = { BETTER_AUTH_SECRET: process.env.BETTER_AUTH_SECRET ?? 'ci-test-secret-that-is-at-least-32-chars', @@ -201,16 +227,33 @@ async function waitForPublicTunnelIp(hostname) { throw new Error(`Timed out waiting for public tunnel DNS: ${hostname}`) } -function run(command, commandArgs, env = {}) { +class CommandError extends Error { + constructor(command, commandArgs, code, output) { + super(`${command} ${commandArgs.join(' ')} exited with ${code}`) + this.output = output + } +} + +function run(command, commandArgs, env = {}, captureOutput = false) { return new Promise((resolve, reject) => { const child = spawn(command, commandArgs, { - stdio: 'inherit', + stdio: captureOutput ? ['inherit', 'pipe', 'pipe'] : 'inherit', env: { ...process.env, ...env }, shell: process.platform === 'win32', }) + let output = '' + if (captureOutput) { + for (const stream of [child.stdout, child.stderr]) { + stream.on('data', (chunk) => { + const text = chunk.toString() + output += text + process.stdout.write(text) + }) + } + } child.on('exit', (code) => { if (code === 0) resolve() - else reject(new Error(`${command} ${commandArgs.join(' ')} exited with ${code}`)) + else reject(new CommandError(command, commandArgs, code, output)) }) }) } diff --git a/scripts/seed-preview-admin.ts b/scripts/seed-preview-admin.ts index 6da42066..859689ba 100644 --- a/scripts/seed-preview-admin.ts +++ b/scripts/seed-preview-admin.ts @@ -6,6 +6,7 @@ import { fileURLToPath } from 'node:url' import { nanoid } from 'nanoid' export const PREVIEW_ADMIN_EMAIL = 'admin@zpan.space' +export const CREDENTIAL_ACCOUNT_ISSUER = 'local:credential' const STAGING_D1_DB = 'zpan-db-staging' const STAGING_ENV = 'staging' @@ -37,12 +38,13 @@ ON CONFLICT(email) DO UPDATE SET UPDATE account SET password = ${passwordHash}, + issuer = '${CREDENTIAL_ACCOUNT_ISSUER}', updated_at = ${options.now} WHERE provider_id = 'credential' AND user_id IN (SELECT id FROM user WHERE email = ${email}); -INSERT INTO account (id, account_id, provider_id, user_id, password, created_at, updated_at) -SELECT ${accountId}, u.id, 'credential', u.id, ${passwordHash}, ${options.now}, ${options.now} +INSERT INTO account (id, issuer, account_id, provider_id, user_id, password, created_at, updated_at) +SELECT ${accountId}, '${CREDENTIAL_ACCOUNT_ISSUER}', u.id, 'credential', u.id, ${passwordHash}, ${options.now}, ${options.now} FROM user AS u WHERE u.email = ${email} AND NOT EXISTS ( diff --git a/server/adapters/gateways/licensing-cloud.test.ts b/server/adapters/gateways/licensing-cloud.test.ts index 31c4cde7..acfad775 100644 --- a/server/adapters/gateways/licensing-cloud.test.ts +++ b/server/adapters/gateways/licensing-cloud.test.ts @@ -24,9 +24,7 @@ function makeResponse(body: unknown, status = 200): Response { } function headerValue(headers: HeadersInit | undefined, name: string): string | null { - if (headers instanceof Headers) return headers.get(name) - if (Array.isArray(headers)) return new Headers(headers).get(name) - return headers?.[name] ?? null + return new Headers(headers).get(name) } describe('licensing-cloud', () => { diff --git a/server/adapters/repos/cloud-store.ts b/server/adapters/repos/cloud-store.ts index 8ee7d797..8ed2a68d 100644 --- a/server/adapters/repos/cloud-store.ts +++ b/server/adapters/repos/cloud-store.ts @@ -98,8 +98,7 @@ async function requireTargetQuota(db: Database, orgId: string): Promise { } function insertQuotaEntitlementQueries(db: Database, event: CloudOrderQuotaChange, now: Date): AtomicQuery[] { - return quotaEntitlementValues(event, now).flatMap((value) => [ - ...revokeExistingPlanQueries(db, value, now), + return quotaEntitlementValues(event, now).map((value) => db .insert(orgQuotaEntitlements) .values(value) @@ -107,30 +106,7 @@ function insertQuotaEntitlementQueries(db: Database, event: CloudOrderQuotaChang target: [orgQuotaEntitlements.source, orgQuotaEntitlements.sourceId, orgQuotaEntitlements.resourceType], set: quotaEntitlementIncreaseValues(value, now), }), - ]) -} - -function revokeExistingPlanQueries( - db: Database, - value: typeof orgQuotaEntitlements.$inferInsert, - now: Date, -): AtomicQuery[] { - if (value.entitlementType !== 'plan') return [] - return [ - db - .update(orgQuotaEntitlements) - .set({ status: 'revoked', updatedAt: now }) - .where( - and( - eq(orgQuotaEntitlements.orgId, value.orgId), - eq(orgQuotaEntitlements.resourceType, value.resourceType), - eq(orgQuotaEntitlements.entitlementType, 'plan'), - eq(orgQuotaEntitlements.status, 'active'), - sql`${orgQuotaEntitlements.source} <> 'free_plan'`, - sql`${orgQuotaEntitlements.sourceId} != ${value.sourceId}`, - ), - ), - ] + ) } function revokeQuotaEntitlementQueries(db: Database, event: CloudOrderQuotaChange, now: Date): AtomicQuery[] { @@ -195,9 +171,10 @@ function quotaEntitlementValues(event: CloudOrderQuotaChange, now: Date): (typeo } function quotaEntitlementIncreaseValues(value: typeof orgQuotaEntitlements.$inferInsert, now: Date) { - const bytes = isSubscriptionSourceId(value.sourceId) - ? value.bytes - : (sql`CASE + const bytes = + value.entitlementType === 'plan' + ? value.bytes + : (sql`CASE WHEN ${orgQuotaEntitlements.status} = 'active' THEN ${orgQuotaEntitlements.bytes} + ${value.bytes} ELSE ${value.bytes} END` as unknown as number) @@ -231,11 +208,11 @@ function quotaEntitlementValue( id: nanoid(), orgId: event.targetOrgId, resourceType, - entitlementType: isSubscriptionSourceId(event.cloudOrderId) ? 'plan' : 'grant', + entitlementType: entitlementType(event), source: 'cloud_order', sourceId: event.cloudOrderId, bytes, - startsAt: now, + startsAt: eventStart(event, now), expiresAt: event.expiresAt ? new Date(event.expiresAt) : null, status: 'active', metadata: JSON.stringify(quotaEntitlementMetadata(event)), @@ -268,11 +245,25 @@ function quotaEntitlementMetadata(event: CloudOrderQuotaChange) { expiresAt: event.expiresAt ?? null, customerId: event.customerId ?? null, customerEmail: event.customerEmail ?? null, + paymentProvider: eventValue(event, 'paymentProvider'), + providerTransactionId: eventValue(event, 'providerTransactionId'), + x402AuditContext: eventValue(event, 'x402AuditContext'), } } -function isSubscriptionSourceId(sourceId: string) { - return sourceId.startsWith('stripe_subscription:') +function entitlementType(event: CloudOrderQuotaChange): 'plan' | 'grant' { + return eventValue(event, 'entitlementType') === 'plan' || event.cloudOrderId.startsWith('stripe_subscription:') + ? 'plan' + : 'grant' +} + +function eventStart(event: CloudOrderQuotaChange, fallback: Date): Date { + const value = eventValue(event, 'startsAt') + return typeof value === 'string' ? new Date(value) : fallback +} + +function eventValue(event: CloudOrderQuotaChange, key: string): unknown { + return key in event ? (event as unknown as Record)[key] : null } async function beginWebhookEvent( diff --git a/server/adapters/repos/x402-capacity-purchase.integration.test.ts b/server/adapters/repos/x402-capacity-purchase.integration.test.ts new file mode 100644 index 00000000..9d77f424 --- /dev/null +++ b/server/adapters/repos/x402-capacity-purchase.integration.test.ts @@ -0,0 +1,174 @@ +import { eq } from 'drizzle-orm' +import { describe, expect, it } from 'vitest' +import { x402CapacityPurchaseIntents } from '../../db/schema' +import { createTestApp } from '../../test/setup' +import { createX402CapacityPurchaseRepo } from './x402-capacity-purchase' + +describe('x402 capacity purchase repo', () => { + it('scopes client idempotency keys to the workspace', async () => { + const { db } = await createTestApp() + const repo = createX402CapacityPurchaseRepo(db) + + const first = await repo.create({ + orgId: 'org-1', + resourceId: 'resource-1', + requestHash: 'hash-1', + idempotencyKey: 'purchase-storage', + }) + const second = await repo.create({ + orgId: 'org-2', + resourceId: 'resource-1', + requestHash: 'hash-2', + idempotencyKey: 'purchase-storage', + }) + + if (!first || !second) throw new Error('Expected both workspace reservations to succeed') + expect(first.orgId).toBe('org-1') + expect(second.orgId).toBe('org-2') + }) + + it('rejects a reused idempotency key within the same workspace', async () => { + const { db } = await createTestApp() + const repo = createX402CapacityPurchaseRepo(db) + await repo.create({ + orgId: 'org-1', + resourceId: 'resource-1', + requestHash: 'hash-1', + idempotencyKey: 'purchase-storage', + }) + + await expect( + repo.create({ + orgId: 'org-1', + resourceId: 'resource-2', + requestHash: 'hash-2', + idempotencyKey: 'purchase-storage', + }), + ).rejects.toThrow() + }) + + it('allows only one active order creator and recovers a stale claim', async () => { + const { db } = await createTestApp() + const repo = createX402CapacityPurchaseRepo(db) + const intent = await repo.create({ + orgId: 'org-1', + resourceId: 'resource-1', + requestHash: 'hash-1', + idempotencyKey: 'purchase-storage', + }) + + if (!intent) throw new Error('Expected purchase reservation to succeed') + expect(await repo.claimCloudOrder(intent.id, new Date(0))).toBe(true) + expect(await repo.claimCloudOrder(intent.id, new Date(0))).toBe(false) + + await repo.updateCloudState(intent.id, { + status: 'ordering', + }) + expect(await repo.claimCloudOrder(intent.id, new Date(Date.now() + 1000))).toBe(true) + }) + + it('atomically caps pending unpaid intents per workspace', async () => { + const { db } = await createTestApp() + const repo = createX402CapacityPurchaseRepo(db) + + const reservations = await Promise.all( + Array.from({ length: 10 }, (_, i) => + repo.create({ + orgId: 'org-1', + resourceId: `resource-${i}`, + requestHash: `hash-${i}`, + idempotencyKey: `purchase-${i}`, + }), + ), + ) + expect(reservations.filter(Boolean)).toHaveLength(5) + await expect( + repo.create({ + orgId: 'org-2', + resourceId: 'resource-other-workspace', + requestHash: 'hash-other-workspace', + idempotencyKey: 'purchase-other-workspace', + }), + ).resolves.not.toBeNull() + }) + + it('removes abandoned unpaid intents before reserving capacity', async () => { + const { db } = await createTestApp() + const repo = createX402CapacityPurchaseRepo(db) + const abandoned = await repo.create({ + orgId: 'org-1', + resourceId: 'resource-abandoned', + requestHash: 'hash-abandoned', + idempotencyKey: 'purchase-abandoned', + }) + expect(abandoned).not.toBeNull() + await db + .update(x402CapacityPurchaseIntents) + .set({ updatedAt: new Date(Date.now() - 25 * 60 * 60 * 1000) }) + .where(eq(x402CapacityPurchaseIntents.id, abandoned!.id)) + + await expect( + repo.create({ + orgId: 'org-1', + resourceId: 'resource-fresh', + requestHash: 'hash-fresh', + idempotencyKey: 'purchase-fresh', + }), + ).resolves.not.toBeNull() + await expect( + db.select().from(x402CapacityPurchaseIntents).where(eq(x402CapacityPurchaseIntents.id, abandoned!.id)), + ).resolves.toEqual([]) + }) + + it('does not count expired quotes against the pending limit', async () => { + const { db } = await createTestApp() + const repo = createX402CapacityPurchaseRepo(db) + for (let i = 0; i < 5; i += 1) { + const intent = await repo.create({ + orgId: 'org-1', + resourceId: `expired-resource-${i}`, + requestHash: `expired-hash-${i}`, + idempotencyKey: `expired-idempotency-${i}`, + }) + expect(intent).not.toBeNull() + await repo.updateCloudState(intent!.id, { + status: 'quoted', + expiresAt: new Date(Date.now() - 1000), + }) + } + + await expect( + repo.create({ + orgId: 'org-1', + resourceId: 'resource-after-expiry', + requestHash: 'hash-after-expiry', + idempotencyKey: 'purchase-after-expiry', + }), + ).resolves.not.toBeNull() + }) + + it('caps total intent creation per workspace within the rolling hour', async () => { + const { db } = await createTestApp() + const repo = createX402CapacityPurchaseRepo(db) + + for (let i = 0; i < 20; i += 1) { + const intent = await repo.create({ + orgId: 'org-1', + resourceId: `resource-${i}`, + requestHash: `hash-${i}`, + idempotencyKey: `purchase-${i}`, + }) + expect(intent).not.toBeNull() + await repo.updateCloudState(intent!.id, { status: 'failed' }) + } + + await expect( + repo.create({ + orgId: 'org-1', + resourceId: 'resource-hourly-over-limit', + requestHash: 'hash-hourly-over-limit', + idempotencyKey: 'purchase-hourly-over-limit', + }), + ).resolves.toBeNull() + }) +}) diff --git a/server/adapters/repos/x402-capacity-purchase.ts b/server/adapters/repos/x402-capacity-purchase.ts new file mode 100644 index 00000000..d4cc0de7 --- /dev/null +++ b/server/adapters/repos/x402-capacity-purchase.ts @@ -0,0 +1,94 @@ +import { and, eq, isNull, lt, or, sql } from 'drizzle-orm' +import { nanoid } from 'nanoid' +import { x402CapacityPurchaseIntents } from '../../db/schema' +import { executeWriteTransactionWithResults } from '../../db/transaction' +import type { Database } from '../../platform/interface' +import type { X402CapacityPurchaseRepo } from '../../usecases/ports' + +const MAX_PENDING_INTENTS_PER_ORG = 5 +const MAX_INTENTS_PER_HOUR_PER_ORG = 20 +const INTENT_CREATION_WINDOW_MS = 60 * 60 * 1000 +const PENDING_INTENT_TTL_MS = 15 * 60 * 1000 +const ABANDONED_INTENT_RETENTION_MS = 24 * 60 * 60 * 1000 + +export function createX402CapacityPurchaseRepo(db: Database): X402CapacityPurchaseRepo { + return { + async get(orgId, resourceId, requestHash) { + const rows = await db + .select() + .from(x402CapacityPurchaseIntents) + .where( + and( + eq(x402CapacityPurchaseIntents.orgId, orgId), + eq(x402CapacityPurchaseIntents.resourceId, resourceId), + eq(x402CapacityPurchaseIntents.requestHash, requestHash), + ), + ) + .limit(1) + return rows[0] ?? null + }, + async create(input) { + const now = new Date() + const nowMs = now.getTime() + const id = nanoid() + const abandonedBefore = new Date(nowMs - PENDING_INTENT_TTL_MS) + const creationWindowStart = new Date(nowMs - INTENT_CREATION_WINDOW_MS) + const retentionBefore = new Date(nowMs - ABANDONED_INTENT_RETENTION_MS) + const cleanup = db.delete(x402CapacityPurchaseIntents).where(sql` + ${x402CapacityPurchaseIntents.updatedAt} < ${retentionBefore.getTime()} + AND ${x402CapacityPurchaseIntents.status} IN ('created', 'ordering', 'ordered', 'quoted', 'expired', 'failed', 'canceled') + `) + const insert = db + .insert(x402CapacityPurchaseIntents) + .select(sql` + SELECT + ${id}, ${input.orgId}, ${input.resourceId}, ${input.requestHash}, ${input.idempotencyKey}, + NULL, NULL, 'created', NULL, ${nowMs}, ${nowMs} + WHERE ( + SELECT COUNT(*) FROM ${x402CapacityPurchaseIntents} + WHERE ${x402CapacityPurchaseIntents.orgId} = ${input.orgId} + AND ${x402CapacityPurchaseIntents.createdAt} >= ${creationWindowStart.getTime()} + ) < ${MAX_INTENTS_PER_HOUR_PER_ORG} + AND ( + SELECT COUNT(*) FROM ${x402CapacityPurchaseIntents} + WHERE ${x402CapacityPurchaseIntents.orgId} = ${input.orgId} + AND ${x402CapacityPurchaseIntents.status} IN ('created', 'ordering', 'ordered', 'quoted') + AND ( + (${x402CapacityPurchaseIntents.status} = 'quoted' + AND (${x402CapacityPurchaseIntents.expiresAt} IS NULL OR ${x402CapacityPurchaseIntents.expiresAt} > ${nowMs})) + OR (${x402CapacityPurchaseIntents.status} <> 'quoted' AND ${x402CapacityPurchaseIntents.updatedAt} >= ${abandonedBefore.getTime()}) + ) + ) < ${MAX_PENDING_INTENTS_PER_ORG} + `) + .returning() + const [, inserted] = await executeWriteTransactionWithResults(db, [cleanup, insert], [1]) + return (inserted as (typeof x402CapacityPurchaseIntents.$inferSelect)[] | undefined)?.[0] ?? null + }, + async claimCloudOrder(id, staleBefore) { + const rows = await db + .update(x402CapacityPurchaseIntents) + .set({ status: 'ordering', updatedAt: new Date() }) + .where( + and( + eq(x402CapacityPurchaseIntents.id, id), + isNull(x402CapacityPurchaseIntents.cloudOrderId), + or( + eq(x402CapacityPurchaseIntents.status, 'created'), + and( + eq(x402CapacityPurchaseIntents.status, 'ordering'), + lt(x402CapacityPurchaseIntents.updatedAt, staleBefore), + ), + ), + ), + ) + .returning({ id: x402CapacityPurchaseIntents.id }) + return rows.length === 1 + }, + async updateCloudState(id, input) { + await db + .update(x402CapacityPurchaseIntents) + .set({ ...input, updatedAt: new Date() }) + .where(eq(x402CapacityPurchaseIntents.id, id)) + }, + } +} diff --git a/server/auth.integration.test.ts b/server/auth.integration.test.ts index 304fc136..b00a2156 100644 --- a/server/auth.integration.test.ts +++ b/server/auth.integration.test.ts @@ -1,7 +1,9 @@ import { createHash } from 'node:crypto' +import { readFileSync } from 'node:fs' +import { join } from 'node:path' import { isPersonalOrgLike } from '@shared/org-slugs' import { deriveDpopAth } from 'better-auth/oauth2' -import { eq } from 'drizzle-orm' +import { eq, sql } from 'drizzle-orm' import { exportJWK, generateKeyPair, SignJWT } from 'jose' import { afterEach, describe, expect, it, vi } from 'vitest' import { createInviteRepo } from './adapters/repos/invite.js' @@ -320,6 +322,46 @@ describe('isEmailConfigured — via emailVerification conditional', () => { }) }) +describe('Better Auth account issuer migration', () => { + it('restores email sign-in for a legacy credential account', async () => { + const ctx = await createTestApp() + const email = 'legacy-issuer@example.com' + await signUp(ctx, email) + await ctx.db + .update(authSchema.account) + .set({ issuer: '' }) + .where( + eq( + authSchema.account.userId, + (await ctx.db.query.user.findFirst({ where: eq(authSchema.user.email, email) }))!.id, + ), + ) + + const rejected = await ctx.app.request('/api/auth/sign-in/email', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ email, password: 'password123456' }), + }) + expect(rejected.status).toBe(401) + + const migration = readFileSync( + join(process.cwd(), 'migrations/0089_better-auth-account-issuer-backfill.sql'), + 'utf-8', + ) + for (const statement of migration.split('--> statement-breakpoint')) { + await ctx.db.run(sql.raw(statement)) + } + + const restored = await ctx.app.request('/api/auth/sign-in/email', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ email, password: 'password123456' }), + }) + expect(restored.status).toBe(200) + expect(restored.headers.getSetCookie()).not.toHaveLength(0) + }) +}) + describe('dynamic email verification policy', () => { it('requires verification immediately and resends the email on sign-in', async () => { const { vi } = await import('vitest') @@ -682,7 +724,7 @@ describe('loadProviderConfigs — builtin social provider resolution', () => { expect(res.status).not.toBe(200) }) - it('createAuth initializes provider config and the two OAuth resources with three DB reads', async () => { + it('createAuth initializes provider config and OAuth resources without scanning OAuth clients', async () => { const ctx = await createTestApp() let selectCalls = 0 const countingDb = new Proxy(ctx.db, { @@ -710,6 +752,49 @@ describe('loadProviderConfigs — builtin social provider resolution', () => { }) }) +describe('Cloudflare Workers preview auth origins', () => { + const configuredOrigin = 'https://zpan-staging.saltbo.workers.dev' + const commitOrigin = 'https://99dc50ae-zpan.saltbo.workers.dev' + const branchOrigin = 'https://feat-x402-paid-agent-uploads-zpan.saltbo.workers.dev' + + it('accepts official commit and branch aliases on the same cached auth instance', async () => { + const ctx = await createTestApp() + const auth = await createAuth(ctx.platform, 'test-secret', configuredOrigin, [configuredOrigin]) + const app = createApp(ctx.platform, auth) + const email = `preview-${Date.now()}@example.com` + const password = 'password123456' + const signUp = await app.request(`${configuredOrigin}/api/auth/sign-up/email`, { + method: 'POST', + headers: { Origin: configuredOrigin, 'Content-Type': 'application/json' }, + body: JSON.stringify({ name: 'Preview User', email, password }), + }) + expect(signUp.status).toBe(200) + + for (const origin of [commitOrigin, branchOrigin]) { + const signIn = await app.request(`${origin}/api/auth/sign-in/email`, { + method: 'POST', + headers: { Origin: origin, 'Content-Type': 'application/json' }, + body: JSON.stringify({ email, password, callbackURL: `${origin}/files` }), + }) + expect(signIn.status, await signIn.clone().text()).toBe(200) + } + }) + + it('rejects unrelated workers.dev origins', async () => { + const ctx = await createTestApp() + const auth = await createAuth(ctx.platform, 'test-secret', configuredOrigin, [configuredOrigin]) + const app = createApp(ctx.platform, auth) + const origin = 'https://unrelated-worker.other-account.workers.dev' + const signIn = await app.request(`${origin}/api/auth/sign-in/email`, { + method: 'POST', + headers: { Origin: origin, 'Content-Type': 'application/json' }, + body: JSON.stringify({ email: 'nobody@example.com', password: 'password123456', callbackURL: `${origin}/files` }), + }) + + expect(signIn.status).toBe(403) + }) +}) + describe('Agent OAuth consent guards', () => { it('publishes the external resource discovery contract at the exact API URL', async () => { const ctx = await createTestApp() diff --git a/server/auth.ts b/server/auth.ts index 41805f80..2fdf1dfb 100644 --- a/server/auth.ts +++ b/server/auth.ts @@ -136,6 +136,42 @@ async function dynamicRegistrationOrigins(request: Request): Promise { } } +export function officialWorkersPreviewOrigin( + baseURL: string | undefined, + candidate: string | null | undefined, +): string | null { + if (!baseURL || !candidate) return null + try { + const configured = new URL(baseURL) + const preview = new URL(candidate) + if (configured.protocol !== 'https:' || preview.protocol !== 'https:') return null + + const configuredLabels = configured.hostname.toLowerCase().split('.') + const previewLabels = preview.hostname.toLowerCase().split('.') + if ( + configuredLabels.length !== 4 || + previewLabels.length !== 4 || + configuredLabels[2] !== 'workers' || + configuredLabels[3] !== 'dev' || + previewLabels[2] !== 'workers' || + previewLabels[3] !== 'dev' || + configuredLabels[1] !== previewLabels[1] + ) { + return null + } + + const configuredWorker = configuredLabels[0] + const workerName = configuredWorker.endsWith('-staging') + ? configuredWorker.slice(0, -'-staging'.length) + : configuredWorker.replace(/^[0-9a-f]{8}-/, '') + const previewWorker = previewLabels[0] + if (!workerName || (previewWorker !== workerName && !previewWorker.endsWith(`-${workerName}`))) return null + return preview.origin + } catch { + return null + } +} + // One query loads every oauth_provider_* row. Configs are snapshotted at auth // instance creation: better-auth resolves social providers eagerly during its // context init, so per-request dynamic loading is not possible anyway. Admin @@ -405,7 +441,13 @@ export async function createAuth( const origin = request?.headers.get('origin') const list = trustedOrigins ?? [] const registrationOrigins = request ? await dynamicRegistrationOrigins(request) : [] - return [...list, ...(origin && isLocalNetworkOrigin(origin) ? [origin] : []), ...registrationOrigins] + const previewOrigin = officialWorkersPreviewOrigin(baseURL, origin) + return [ + ...list, + ...(origin && isLocalNetworkOrigin(origin) ? [origin] : []), + ...(previewOrigin ? [previewOrigin] : []), + ...registrationOrigins, + ] }, advanced: { cookiePrefix: 'zp', diff --git a/server/composition.ts b/server/composition.ts index 5888988d..09e1fa04 100644 --- a/server/composition.ts +++ b/server/composition.ts @@ -53,6 +53,7 @@ import { createTeamInviteRepo } from './adapters/repos/team-invite' import { createUserAdminRepo } from './adapters/repos/user-admin' import { createWebDavPathRepo } from './adapters/repos/webdav-path' import { createWebDavStateRepo } from './adapters/repos/webdav-state' +import { createX402CapacityPurchaseRepo } from './adapters/repos/x402-capacity-purchase' import { createZipPlanRepo } from './adapters/repos/zip' import type { Platform } from './platform/interface' import type { Deps } from './usecases/deps' @@ -128,5 +129,6 @@ export function createDeps(platform: Platform, options: CreateDepsOptions = {}): webdavState: createWebDavStateRepo(db), zip: createZipGateway(), zipPlan: createZipPlanRepo(db), + x402CapacityPurchases: createX402CapacityPurchaseRepo(db), } } diff --git a/server/db/migrations.test.ts b/server/db/migrations.test.ts index 70f85d22..3944172f 100644 --- a/server/db/migrations.test.ts +++ b/server/db/migrations.test.ts @@ -210,3 +210,73 @@ describe('migration 0069_storage-health-status-vocabulary.sql', () => { } }) }) + +describe('migration 0089_better-auth-account-issuer-backfill.sql', () => { + const migrationPath = join(process.cwd(), 'migrations/0089_better-auth-account-issuer-backfill.sql') + const migration = readFileSync(migrationPath, 'utf-8') + + it('backfills legacy credential and OAuth issuers without overwriting explicit issuers', () => { + const db = new Database(':memory:') + + try { + db.exec(` + CREATE TABLE account ( + id TEXT PRIMARY KEY NOT NULL, + issuer TEXT DEFAULT '' NOT NULL, + account_id TEXT NOT NULL, + provider_id TEXT NOT NULL + ); + CREATE UNIQUE INDEX account_issuer_providerAccountId_unique ON account (issuer, account_id); + INSERT INTO account (id, issuer, account_id, provider_id) VALUES + ('credential', '', 'user-1', 'credential'), + ('github', '', 'github-user', 'github'), + ('google', '', 'google-user', 'google'), + ('explicit', 'https://issuer.example.com', 'subject-1', 'external'); + `) + + db.exec(migration) + db.exec(migration) + + expect(db.prepare('SELECT id, issuer FROM account ORDER BY id').all()).toEqual([ + { id: 'credential', issuer: 'local:credential' }, + { id: 'explicit', issuer: 'https://issuer.example.com' }, + { id: 'github', issuer: 'local:oauth:github' }, + { id: 'google', issuer: 'https://accounts.google.com' }, + ]) + expect(() => + db + .prepare('INSERT INTO account (id, issuer, account_id, provider_id) VALUES (?, ?, ?, ?)') + .run('duplicate', 'local:oauth:github', 'github-user', 'github'), + ).toThrow(/UNIQUE constraint failed/) + } finally { + db.close() + } + }) + + it('fails before changing data when a legacy provider has no safe issuer mapping', () => { + const db = new Database(':memory:') + + try { + db.exec(` + CREATE TABLE account ( + id TEXT PRIMARY KEY NOT NULL, + issuer TEXT DEFAULT '' NOT NULL, + account_id TEXT NOT NULL, + provider_id TEXT NOT NULL + ); + CREATE UNIQUE INDEX account_issuer_providerAccountId_unique ON account (issuer, account_id); + INSERT INTO account (id, issuer, account_id, provider_id) VALUES + ('credential', '', 'user-1', 'credential'), + ('unknown', '', 'subject-1', 'unknown-provider'); + `) + + expect(() => db.exec(migration)).toThrow(/malformed JSON/) + expect(db.prepare('SELECT id, issuer FROM account ORDER BY id').all()).toEqual([ + { id: 'credential', issuer: '' }, + { id: 'unknown', issuer: '' }, + ]) + } finally { + db.close() + } + }) +}) diff --git a/server/db/schema.ts b/server/db/schema.ts index 6468744d..b1c5e43f 100644 --- a/server/db/schema.ts +++ b/server/db/schema.ts @@ -189,9 +189,6 @@ export const orgQuotaEntitlements = sqliteTable( (t) => [ index('org_quota_entitlements_org_resource_idx').on(t.orgId, t.resourceType, t.status), index('org_quota_entitlements_org_type_idx').on(t.orgId, t.resourceType, t.entitlementType, t.status), - uniqueIndex('org_quota_entitlements_active_plan_uniq') - .on(t.orgId, t.resourceType, t.entitlementType) - .where(sql`status = 'active' AND entitlement_type = 'plan' AND source <> 'free_plan'`), uniqueIndex('org_quota_entitlements_source_resource_uniq').on(t.source, t.sourceId, t.resourceType), ], ) @@ -218,6 +215,28 @@ export const webhookEvents = sqliteTable( ], ) +export const x402CapacityPurchaseIntents = sqliteTable( + 'x402_capacity_purchase_intents', + { + id: text('id').primaryKey(), + orgId: text('org_id').notNull(), + resourceId: text('resource_id').notNull(), + requestHash: text('request_hash').notNull(), + idempotencyKey: text('idempotency_key').notNull(), + cloudOrderId: text('cloud_order_id'), + cloudAttemptId: text('cloud_attempt_id'), + status: text('status').notNull().default('created'), + expiresAt: integer('expires_at', { mode: 'timestamp_ms' }), + createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(), + updatedAt: integer('updated_at', { mode: 'timestamp_ms' }).notNull(), + }, + (t) => [ + uniqueIndex('x402_capacity_purchase_intents_org_request_uniq').on(t.orgId, t.resourceId, t.requestHash), + uniqueIndex('x402_capacity_purchase_intents_org_idempotency_uniq').on(t.orgId, t.idempotencyKey), + index('x402_capacity_purchase_intents_attempt_idx').on(t.cloudAttemptId), + ], +) + export const inviteCodes = sqliteTable('invite_codes', { id: text('id').primaryKey(), code: text('code').notNull().unique(), diff --git a/server/http/arazzo.ts b/server/http/arazzo.ts index d25ae829..2e5e8016 100644 --- a/server/http/arazzo.ts +++ b/server/http/arazzo.ts @@ -24,7 +24,7 @@ export function createArazzoDocument(origin: string) { workflowId: 'prepareDirectFileUpload', summary: 'Prepare a direct file upload', description: - 'Creates a file draft and returns the runtime upload descriptor. PUT every local file slice identified by upload.parts[].offset and upload.parts[].length to upload.parts[].url with upload.parts[].headers. Capture each response ETag, then invoke completeDirectFileUpload. If a presigned URL expires, invoke refreshDirectFileUploadParts. File bytes are sent directly to storage, not to ZPan.', + 'Creates a file draft and returns the runtime upload descriptor. If capacity is insufficient, createObject returns 402 with requestHash and eligible offers; invoke purchaseStorageCapacityWithX402 for one offer, then retry createObject. PUT every local file slice identified by upload.parts[].offset and upload.parts[].length to upload.parts[].url with upload.parts[].headers. Capture each response ETag, then invoke completeDirectFileUpload. If a presigned URL expires, invoke refreshDirectFileUploadParts. File bytes are sent directly to storage, not to ZPan.', inputs: { type: 'object', properties: { @@ -68,6 +68,42 @@ export function createArazzoDocument(origin: string) { upload: '$steps.createUploadDraft.outputs.upload', }, }, + { + workflowId: 'purchaseStorageCapacityWithX402', + summary: 'Purchase workspace storage capacity', + description: + 'Select an offer returned by createObject 402. Call purchaseStorageCapacity without PAYMENT-SIGNATURE to obtain PAYMENT-REQUIRED, pay that challenge, then retry the same operation with PAYMENT-SIGNATURE. After a delivered response, retry the original createObject request.', + inputs: { + type: 'object', + properties: { + resourceId: { type: 'string', minLength: 1 }, + requestHash: { type: 'string', minLength: 1 }, + idempotencyKey: { type: 'string', minLength: 1 }, + }, + required: ['resourceId', 'requestHash', 'idempotencyKey'], + }, + steps: [ + { + stepId: 'requestPaymentChallenge', + operationId: 'purchaseStorageCapacity', + parameters: [{ name: 'resourceId', in: 'path', value: '$inputs.resourceId' }], + requestBody: { + contentType: 'application/json', + payload: { + requestHash: '$inputs.requestHash', + idempotencyKey: '$inputs.idempotencyKey', + }, + }, + successCriteria: [{ condition: '$statusCode == 402' }], + outputs: { + paymentRequired: '$response.body', + }, + }, + ], + outputs: { + paymentRequired: '$steps.requestPaymentChallenge.outputs.paymentRequired', + }, + }, { workflowId: 'refreshDirectFileUploadParts', summary: 'Refresh expired direct-upload URLs', diff --git a/server/http/auth/auth.cf-test.ts b/server/http/auth/auth.cf-test.ts index 87a5f5c8..34e282ef 100644 --- a/server/http/auth/auth.cf-test.ts +++ b/server/http/auth/auth.cf-test.ts @@ -40,6 +40,40 @@ describe('[CF] Auth API', () => { expect(res.headers.get('set-cookie')).toBeTruthy() }) + it('accepts official Workers commit and branch aliases but rejects unrelated workers.dev', async () => { + const platform = createCloudflarePlatform(env) + const configuredOrigin = 'https://zpan-staging.saltbo.workers.dev' + const commitOrigin = 'https://99dc50ae-zpan.saltbo.workers.dev' + const branchOrigin = 'https://feat-x402-paid-agent-uploads-zpan.saltbo.workers.dev' + const auth = await createAuth(platform.db, env.BETTER_AUTH_SECRET, configuredOrigin, [configuredOrigin]) + const app = createApp(platform, auth) + const email = `cf-preview-${Date.now()}@example.com` + const password = 'password123456' + const signUp = await app.request(`${configuredOrigin}/api/auth/sign-up/email`, { + method: 'POST', + headers: { Origin: configuredOrigin, 'Content-Type': 'application/json' }, + body: JSON.stringify({ name: 'CF Preview User', email, password }), + }) + expect(signUp.status).toBe(200) + + for (const origin of [commitOrigin, branchOrigin]) { + const signIn = await app.request(`${origin}/api/auth/sign-in/email`, { + method: 'POST', + headers: { Origin: origin, 'Content-Type': 'application/json' }, + body: JSON.stringify({ email, password, callbackURL: `${origin}/files` }), + }) + expect(signIn.status, await signIn.clone().text()).toBe(200) + } + + const unrelatedOrigin = 'https://unrelated-worker.other-account.workers.dev' + const rejected = await app.request(`${unrelatedOrigin}/api/auth/sign-in/email`, { + method: 'POST', + headers: { Origin: unrelatedOrigin, 'Content-Type': 'application/json' }, + body: JSON.stringify({ email, password, callbackURL: `${unrelatedOrigin}/files` }), + }) + expect(rejected.status).toBe(403) + }) + it('completes managed Agent OAuth consent on D1', async () => { const app = await buildApp() const signUp = await app.request('/api/auth/sign-up/email', { diff --git a/server/http/downloads/download-tasks.integration.test.ts b/server/http/downloads/download-tasks.integration.test.ts index e9e0f592..0dc1f4d1 100644 --- a/server/http/downloads/download-tasks.integration.test.ts +++ b/server/http/downloads/download-tasks.integration.test.ts @@ -1628,6 +1628,9 @@ describe('Download tasks API integration', () => { }) expect(taskRes.status).toBe(201) const task = (await taskRes.json()) as DownloadTask + await db.run( + sql`UPDATE org_quota_entitlements SET bytes = ${10 * 1024 * 1024 * 1024} WHERE org_id = ${task.orgId} AND resource_type = 'storage'`, + ) await claimTaskForDownloader(app, createdDownloader.token, task.id) const tasksRes = await app.request('/api/downloads/downloaders/me/tasks?status=assigned', { @@ -1845,6 +1848,9 @@ describe('Download tasks API integration', () => { ...(await authedHeaders(app, 'multipart-complete-user@example.com')), 'Content-Type': 'application/json', } + await db.run( + sql`UPDATE org_quota_entitlements SET bytes = ${10 * 1024 * 1024 * 1024} WHERE resource_type = 'storage'`, + ) const createObjectRes = await app.request('/api/objects', { method: 'POST', diff --git a/server/http/objects.integration.test.ts b/server/http/objects.integration.test.ts index 8cfeec9c..268e2f8c 100644 --- a/server/http/objects.integration.test.ts +++ b/server/http/objects.integration.test.ts @@ -19,6 +19,7 @@ import type { MatterListFilters, UpdateMatterInput, } from '../usecases/ports.js' +import { createCapacityRequestHash } from './objects.js' type TestDbForMatter = Awaited>['db'] @@ -86,6 +87,18 @@ beforeEach(() => { vi.spyOn(S3Service.prototype, 'completeMultipartUpload').mockResolvedValue(undefined) }) +describe('capacity purchase challenges', () => { + it('creates a fresh request hash for repeated identical uploads', async () => { + const input = { name: 'same.bin', type: 'application/octet-stream', size: 1024 } + const first = await createCapacityRequestHash('org-1', input) + const second = await createCapacityRequestHash('org-1', input) + + expect(first).toMatch(/^[0-9a-f]{64}$/) + expect(second).toMatch(/^[0-9a-f]{64}$/) + expect(second).not.toBe(first) + }) +}) + afterEach(() => { vi.unstubAllGlobals() }) @@ -1851,6 +1864,69 @@ describe('Objects API — quota enforcement', () => { }) } + function stubCapacityStoreWithoutOffers() { + vi.stubGlobal( + 'fetch', + vi.fn(async (input: string | URL | Request) => { + const url = String(input instanceof Request ? input.url : input) + if (url.includes('/products')) { + return Response.json({ items: [], total: 0, limit: 100, offset: 0 }) + } + if (url.endsWith('/publication')) { + return Response.json({ + storeId: 'store-test-binding', + mode: 'directory', + listingStatus: 'listed', + displayName: 'ZPan', + summary: null, + publicMetadata: {}, + skillUrl: null, + termsUrl: null, + healthUrl: 'https://files.example/api/health', + healthStatus: 'healthy', + resources: [], + createdAt: '2026-07-30T00:00:00.000Z', + updatedAt: '2026-07-30T00:00:00.000Z', + }) + } + throw new Error(`Unexpected Cloud request: ${url}`) + }), + ) + } + + it('surfaces capacity-offer lookup failures instead of reporting quota exhaustion', async () => { + const { app, db } = await createTestApp({ ZPAN_CLOUD_URL: 'https://cloud.example' }) + await seedBusinessLicense(db) + const headers = await authedHeaders(app) + await insertStorage(db) + const orgId = await getOrgId(db) + await setOrgQuota(db, orgId, 100, 90) + vi.stubGlobal( + 'fetch', + vi.fn(async () => Response.json({ error: { code: 'cloud_unavailable' } }, { status: 503 })), + ) + + const res = await app.request('/api/objects', { + method: 'POST', + headers: { ...headers, 'Content-Type': 'application/json' }, + body: JSON.stringify({ + dirtype: 0, + name: 'toobig.txt', + parent: '', + size: 50, + type: 'text/plain', + }), + }) + + expect(res.status).toBe(502) + await expect(res.json()).resolves.toMatchObject({ + error: { + message: 'cloud_unavailable', + details: [{ reason: 'UNAVAILABLE' }], + }, + }) + }) + // ─── POST /api/objects/copy — quota enforcement ────────────────────────── describe('POST /api/objects/copy — quota enforcement', () => { @@ -2220,14 +2296,21 @@ describe('Objects API — quota enforcement', () => { headers: Record, body: { name: string; size: number; onConflict?: string }, ): Promise<{ id: string; sessionId: string }> { - const res = await app.request('/api/objects', { + const res = await createDraftResponse(app, headers, body) + if (res.status !== 201) throw new Error(`create failed: ${res.status} ${await res.text()}`) + const created = (await res.json()) as { id: string; upload: { sessionId: string } } + return { id: created.id, sessionId: created.upload.sessionId } + } + function createDraftResponse( + app: Awaited>['app'], + headers: Record, + body: { name: string; size: number; onConflict?: string }, + ) { + return app.request('/api/objects', { method: 'POST', headers: { ...headers, 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'text/plain', parent: '', dirtype: 0, ...body }), }) - if (res.status !== 201) throw new Error(`create failed: ${res.status} ${await res.text()}`) - const created = (await res.json()) as { id: string; upload: { sessionId: string } } - return { id: created.id, sessionId: created.upload.sessionId } } // The conflict strategy is fixed at create time (stored on the session); the // completions body carries only the uploaded parts. @@ -2279,7 +2362,7 @@ describe('Objects API — quota enforcement', () => { expect(quotaRows[0]).toEqual({ used: 140, quota: 100 }) }) - it('enforces storage entitlements when the legacy quota column is zero', async () => { + it('rejects upload preparation when storage entitlements are exhausted', async () => { const { app, db } = await createTestApp() await seedProLicense(db) const headers = await authedHeaders(app) @@ -2287,9 +2370,8 @@ describe('Objects API — quota enforcement', () => { const orgId = await getOrgId(db) await setOrgQuota(db, orgId, 0, 90) await addStorageEntitlement(db, orgId, 100) - const ref = await createDraft(app, headers, { name: 'limited.txt', size: 11 }) - - const res = await complete(app, headers, ref) + stubCapacityStoreWithoutOffers() + const res = await createDraftResponse(app, headers, { name: 'limited.txt', size: 11 }) expect(res.status).toBe(422) await expect(res.json()).resolves.toMatchObject({ error: { message: 'Quota exceeded' } }) }) @@ -2308,7 +2390,7 @@ describe('Objects API — quota enforcement', () => { expect(storageRows[0].used).toBe(500) }) - it('returns 422 when finalizing upload would exceed quota', async () => { + it('returns 422 before upload when the file would exceed quota', async () => { const { app, db } = await createTestApp() await seedProLicense(db) const headers = await authedHeaders(app) @@ -2316,9 +2398,8 @@ describe('Objects API — quota enforcement', () => { const orgId = await getOrgId(db) // quota = 100, used = 90, file size = 50 → exceeds await setOrgQuota(db, orgId, 100, 90) - const ref = await createDraft(app, headers, { name: 'toobig.txt', size: 50 }) - - const res = await complete(app, headers, ref) + stubCapacityStoreWithoutOffers() + const res = await createDraftResponse(app, headers, { name: 'toobig.txt', size: 50 }) expect(res.status).toBe(422) const body = (await res.json()) as { error: { message: string; details: Array<{ reason: string }> } } expect(body.error.message).toBe('Quota exceeded') @@ -2343,16 +2424,14 @@ describe('Objects API — quota enforcement', () => { expect(quotaRows[0].used).toBe(50) }) - it('returns 422 when no quota row or entitlement exists', async () => { + it('returns 422 before upload when no quota row or entitlement exists', async () => { const { app, db } = await createTestApp() const headers = await authedHeaders(app) await insertStorage(db) const orgId = await getOrgId(db) await db.delete(orgQuotaEntitlements).where(eq(orgQuotaEntitlements.orgId, orgId)) await db.delete(orgQuotas).where(eq(orgQuotas.orgId, orgId)) - const ref = await createDraft(app, headers, { name: 'nolimit.txt', size: 5000 }) - - const res = await complete(app, headers, ref) + const res = await createDraftResponse(app, headers, { name: 'nolimit.txt', size: 5000 }) expect(res.status).toBe(422) await expect(res.json()).resolves.toMatchObject({ error: { details: [{ reason: 'QUOTA_EXCEEDED' }] } }) }) diff --git a/server/http/objects.ts b/server/http/objects.ts index eb327fc5..39cb0c91 100644 --- a/server/http/objects.ts +++ b/server/http/objects.ts @@ -32,7 +32,8 @@ import { trashObject, updateObject, } from '../usecases/object' -import { badRequest, forbidden, type Matter, type MatterListItem } from '../usecases/ports' +import { badRequest, forbidden, type Matter, type MatterListItem, quotaExceeded } from '../usecases/ports' +import { describeCapacityRequirement } from '../usecases/store/store' import { recordDownloadIssued } from '../usecases/transfer-activity' import { authRoute, errorResponse, jsonBody, jsonContent } from './openapi' import { decodeOptionalPageToken, directoryCursorCodec, encodeNextPageToken, pageQueryFingerprint } from './page-token' @@ -86,6 +87,12 @@ function toMatterDTO(m: Matter): MatterDTO { } } +export async function createCapacityRequestHash(orgId: string, input: unknown): Promise { + const bytes = new TextEncoder().encode(JSON.stringify({ orgId, input, challengeId: crypto.randomUUID() })) + const digest = await crypto.subtle.digest('SHA-256', bytes) + return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, '0')).join('') +} + const objectListItemSchema = matterSchema.extend({ hasChildren: z.boolean() }).openapi('ObjectListItem') type ObjectListItemDTO = z.infer @@ -99,6 +106,30 @@ const objectPageSchema = cursorPageSchema(objectListItemSchema, 'ObjectPage') // instructions: the server-decided part size and the presigned URLs to PUT each // slice to (1 URL = single PutObject, N URLs = multipart). const objectCreateResultSchema = matterSchema.extend({ upload: objectUploadInstructionsSchema.optional() }) +const capacityRequiredSchema = z + .object({ + error: z.literal('CAPACITY_REQUIRED'), + requestHash: z.string(), + requestedBytes: z.number().int().nonnegative(), + usedBytes: z.number().int().nonnegative(), + quotaBytes: z.number().int().nonnegative(), + offers: z.array( + z.object({ + resourceId: z.string(), + productId: z.string(), + priceId: z.string(), + name: z.string(), + description: z.string().nullable(), + storageBytes: z.number().int().nonnegative(), + amount: z.number().int().positive(), + currency: z.string(), + interval: z.string().nullable(), + intervalCount: z.number().int().positive().nullable(), + purchaseUrl: z.string(), + }), + ), + }) + .openapi('CapacityRequired') // GET /{id} returns the object plus, when egress is metered/allowed, a presigned // download URL. @@ -209,6 +240,7 @@ const createObjectRoute = authRoute( request: jsonBody(createMatterSchema), responses: { 201: jsonContent(objectCreateResultSchema, 'Created object (folder, or file draft with upload instructions)'), + 402: jsonContent(capacityRequiredSchema, 'Additional workspace storage capacity is required'), 400: errorResponse('No active organization or file too large'), 403: errorResponse('Forbidden'), 409: errorResponse('Name conflict'), @@ -431,7 +463,34 @@ const objects = app if (input.storageId && c.get('userRole') !== 'admin') throw forbidden('Forbidden') const result = await createObject(c.get('deps'), { orgId, actor: objectActor(c), input }) - if (!result.ok) throw result.error + if (!result.ok) { + if ('error' in result) throw result.error + const capacity = await describeCapacityRequirement(c.get('deps'), cloudBaseUrl(c), { + orgId, + requestedBytes: result.capacityRequired.requestedBytes, + }) + if (!capacity.ok) { + // Paid capacity is optional. An instance without a bound Cloud store + // still enforces its local quota using the established 422 contract. + // Once a store is bound, however, Cloud failures must remain visible so + // callers do not mistake a broken payment path for exhausted capacity. + if (capacity.error.message === 'quota_store_binding_missing') throw quotaExceeded() + throw capacity.error + } + if (capacity.value.offers.length === 0) throw quotaExceeded() + const requestHash = await createCapacityRequestHash(orgId, input) + return c.json( + { + error: 'CAPACITY_REQUIRED' as const, + requestHash, + requestedBytes: capacity.value.requestedBytes, + usedBytes: capacity.value.usedBytes, + quotaBytes: capacity.value.quotaBytes, + offers: capacity.value.offers, + }, + 402, + ) + } if ('upload' in result) return c.json({ ...toMatterDTO(result.matter), upload: result.upload }, 201) return c.json(toMatterDTO(result.matter), 201) }) diff --git a/server/http/store/store.integration.test.ts b/server/http/store/store.integration.test.ts index d6e88288..ac69f470 100644 --- a/server/http/store/store.integration.test.ts +++ b/server/http/store/store.integration.test.ts @@ -96,6 +96,131 @@ function cloudOrder(overrides: Record = {}) { } } +function capacityPublication() { + return { + storeId: 'store-test-binding', + mode: 'directory', + listingStatus: 'listed', + displayName: 'ZPan', + summary: null, + publicMetadata: {}, + skillUrl: null, + termsUrl: null, + healthUrl: 'https://files.example/api/health', + healthStatus: 'healthy', + resources: [ + { + id: 'publication-resource-1', + storeId: 'store-test-binding', + resourceId: 'cloud-pkg-1:price-usd', + offerId: 'pro-monthly', + title: 'Pro', + description: null, + productId: 'cloud-pkg-1', + priceId: 'price-usd', + postResourceUrl: 'https://files.example/api/store/capacity-purchases/cloud-pkg-1%3Aprice-usd', + status: 'active', + tags: [], + capabilities: ['storage.capacity.purchase'], + publicDeliverable: { type: 'zpan.plan', storageBytes: 4096 }, + productSnapshot: null, + bazaarRequestMethod: 'POST', + bazaarBodyType: 'json', + bazaarInput: null, + bazaarInputSchema: null, + bazaarOutput: null, + bazaarValidationStatus: 'unknown', + bazaarValidationDiagnostic: null, + bazaarValidatedAt: null, + createdAt: '2026-07-30T00:00:00.000Z', + updatedAt: '2026-07-30T00:00:00.000Z', + }, + ], + createdAt: '2026-07-30T00:00:00.000Z', + updatedAt: '2026-07-30T00:00:00.000Z', + } +} + +function capacityAttempt() { + const paymentRequired = { + x402Version: 2, + resource: { url: 'https://files.example/api/store/capacity-purchases/cloud-pkg-1%3Aprice-usd' }, + accepts: [ + { + scheme: 'exact', + network: 'eip155:8453', + asset: '0xusdc', + amount: '500', + payTo: '0xmerchant', + maxTimeoutSeconds: 300, + extra: {}, + }, + ], + } + return { + id: 'attempt-1', + storeId: 'store-test-binding', + orderId: 'order-cloud-1', + paymentId: null, + customerId: 'org-placeholder', + idempotencyKey: 'idem-1', + resourceId: 'cloud-pkg-1:price-usd', + offerId: 'pro-monthly', + resourceUrl: paymentRequired.resource.url, + resourceDescription: null, + requestHash: 'hash-1', + productId: 'cloud-pkg-1', + priceId: 'price-usd', + scheme: 'exact', + network: 'eip155:8453', + asset: '0xusdc', + amount: 500, + currency: 'usd', + payTo: '0xmerchant', + recurringPlan: true, + billingPeriodStart: '2026-08-01T00:00:00.000Z', + billingPeriodEnd: '2026-09-01T00:00:00.000Z', + paymentRequired, + paymentRequiredHeader: 'required-header', + paymentSignatureHeader: null, + payer: null, + paymentIdentifier: null, + authorizationHash: null, + planFamily: 'storage', + planKey: 'pro', + tierRank: 1, + billingInterval: 'month', + settlementTransaction: null, + settlementResponseHeader: null, + status: 'quoted', + lastErrorCode: null, + quotedAt: '2026-07-30T00:00:00.000Z', + expiresAt: '2099-07-30T00:05:00.000Z', + verifiedAt: null, + settlingAt: null, + settledAt: null, + canceledAt: null, + createdAt: '2026-07-30T00:00:00.000Z', + updatedAt: '2026-07-30T00:00:00.000Z', + } +} + +function capacityReceiver() { + return { + id: 'receiver-1', + storeId: 'store-test-binding', + scheme: 'exact', + network: 'eip155:8453', + asset: '0xusdc', + networkFamily: 'evm', + payTo: '0xmerchant', + status: 'active', + verifiedAt: '2026-07-01T00:00:00.000Z', + createdAt: '2026-07-01T00:00:00.000Z', + updatedAt: '2026-07-01T00:00:00.000Z', + } +} + function paymentPayload() { const call = vi.mocked(fetch).mock.calls.find(([url]) => String(url).includes('/payments')) as | [URL, RequestInit] @@ -612,6 +737,154 @@ describe('Quota Store API', () => { expect(res.status).toBe(403) }) + it('rejects team capacity purchases from non-owner members', async () => { + const { app, db } = await createTestApp() + await seedBusinessLicense(db) + const { headers } = await memberInTeamOrg(app, db, 'editor') + + const res = await app.request('/api/store/capacity-purchases/plan-monthly', { + method: 'POST', + headers: { ...headers, 'Content-Type': 'application/json' }, + body: JSON.stringify({ requestHash: 'hash-1', idempotencyKey: 'idem-1' }), + }) + + expect(res.status).toBe(403) + }) + + it('returns the standard x402 challenge for an owner capacity purchase', async () => { + const { app, db } = await createTestApp() + await seedBusinessLicense(db) + const headers = await authedHeaders(app, 'capacity-owner@example.com') + const response = (body: unknown, status = 200) => + ({ ok: status >= 200 && status < 300, status, json: async () => body }) as Response + vi.mocked(fetch) + .mockResolvedValueOnce(response(capacityPublication())) + .mockResolvedValueOnce(response(cloudProduct())) + .mockResolvedValueOnce( + response({ + id: 'receiver-1', + storeId: 'store-test-binding', + scheme: 'exact', + network: 'eip155:8453', + asset: '0xusdc', + networkFamily: 'evm', + payTo: '0xmerchant', + status: 'active', + verifiedAt: '2026-07-01T00:00:00.000Z', + createdAt: '2026-07-01T00:00:00.000Z', + updatedAt: '2026-07-01T00:00:00.000Z', + }), + ) + .mockResolvedValueOnce(response(cloudOrder({ status: 'pending', paymentStatus: 'pending' }), 201)) + .mockResolvedValueOnce(response({ ...capacityAttempt(), reused: false }, 201)) + + const res = await app.request('/api/store/capacity-purchases/cloud-pkg-1%3Aprice-usd', { + method: 'POST', + headers: { ...headers, 'Content-Type': 'application/json' }, + body: JSON.stringify({ requestHash: 'hash-1', idempotencyKey: 'idem-1' }), + }) + + expect(res.status).toBe(402) + expect(res.headers.get('PAYMENT-REQUIRED')).toBe('required-header') + await expect(res.json()).resolves.toEqual(capacityAttempt().paymentRequired) + expect(orderPayload().idempotencyKey).toMatch(/^zpan-x402-capacity:/) + }) + + it('rate-limits unpaid capacity purchases before creating another Cloud order', async () => { + const { app, db, deps } = await createTestApp() + await seedBusinessLicense(db) + const headers = await authedHeaders(app, 'capacity-limited@example.com') + const orgId = await getFirstOrgId(db) + for (let i = 0; i < 5; i += 1) { + const intent = await deps.x402CapacityPurchases.create({ + orgId, + resourceId: `existing-resource-${i}`, + requestHash: `existing-hash-${i}`, + idempotencyKey: `existing-idempotency-${i}`, + }) + expect(intent).not.toBeNull() + } + const response = (body: unknown) => ({ ok: true, status: 200, json: async () => body }) as Response + vi.mocked(fetch) + .mockClear() + .mockResolvedValueOnce(response(capacityPublication())) + .mockResolvedValueOnce(response(cloudProduct())) + .mockResolvedValueOnce( + response({ + id: 'receiver-1', + storeId: 'store-test-binding', + scheme: 'exact', + network: 'eip155:8453', + asset: '0xusdc', + networkFamily: 'evm', + payTo: '0xmerchant', + status: 'active', + verifiedAt: '2026-07-01T00:00:00.000Z', + createdAt: '2026-07-01T00:00:00.000Z', + updatedAt: '2026-07-01T00:00:00.000Z', + }), + ) + + const res = await app.request('/api/store/capacity-purchases/cloud-pkg-1%3Aprice-usd', { + method: 'POST', + headers: { ...headers, 'Content-Type': 'application/json' }, + body: JSON.stringify({ requestHash: 'limited-hash', idempotencyKey: 'limited-idempotency' }), + }) + + expect(res.status).toBe(429) + expect(res.headers.get('Retry-After')).toBe('3600') + expect(vi.mocked(fetch).mock.calls.some(([url]) => String(url).endsWith('/orders'))).toBe(false) + }) + + it('returns pending and delivered x402 attempts with their transport contracts', async () => { + const { app, db, deps } = await createTestApp() + await seedBusinessLicense(db) + const headers = await authedHeaders(app, 'capacity-status@example.com') + const orgId = await getFirstOrgId(db) + const intent = await deps.x402CapacityPurchases.create({ + orgId, + resourceId: 'cloud-pkg-1:price-usd', + requestHash: 'status-hash', + idempotencyKey: 'status-idempotency', + }) + expect(intent).not.toBeNull() + await deps.x402CapacityPurchases.updateCloudState(intent!.id, { + cloudOrderId: 'order-cloud-1', + cloudAttemptId: 'attempt-1', + status: 'quoted', + }) + const response = (body: unknown) => ({ ok: true, status: 200, json: async () => body }) as Response + const verified = { ...capacityAttempt(), status: 'verified', verifiedAt: '2026-07-30T00:01:00.000Z' } + const delivered = { + ...capacityAttempt(), + status: 'delivered', + settlementResponseHeader: 'receipt-header', + settledAt: '2026-07-30T00:02:00.000Z', + } + vi.mocked(fetch) + .mockClear() + .mockResolvedValueOnce(response(capacityPublication())) + .mockResolvedValueOnce(response(cloudProduct())) + .mockResolvedValueOnce(response(capacityReceiver())) + .mockResolvedValueOnce(response(verified)) + .mockResolvedValueOnce(response(capacityPublication())) + .mockResolvedValueOnce(response(cloudProduct())) + .mockResolvedValueOnce(response(capacityReceiver())) + .mockResolvedValueOnce(response(delivered)) + + const request = () => + app.request('/api/store/capacity-purchases/cloud-pkg-1%3Aprice-usd', { + method: 'POST', + headers: { ...headers, 'Content-Type': 'application/json' }, + body: JSON.stringify({ requestHash: 'status-hash', idempotencyKey: 'status-idempotency' }), + }) + const pendingResponse = await request() + expect(pendingResponse.status).toBe(202) + const deliveredResponse = await request() + expect(deliveredResponse.status).toBe(200) + expect(deliveredResponse.headers.get('PAYMENT-RESPONSE')).toBe('receipt-header') + }) + it('allows team checkout for the team owner and targets the team org [spec: quota-store/team-checkout]', async () => { const { app, db } = await createTestApp() await seedBusinessLicense(db) @@ -2404,13 +2677,18 @@ describe('Quota Store API — storefront proxy error branches', () => { headers: { ...headers, 'Content-Type': 'application/json' }, body: JSON.stringify({ packageId: 'cloud-pkg-1' }), }) + const capacity = await app.request('/api/store/capacity-purchases/plan-monthly', { + method: 'POST', + headers: { ...headers, 'Content-Type': 'application/json' }, + body: JSON.stringify({ requestHash: 'hash-1', idempotencyKey: 'idem-1' }), + }) const redeem = await app.request('/api/store/credits/redemptions', { method: 'POST', headers: { ...headers, 'Content-Type': 'application/json' }, body: JSON.stringify({ code: 'ZS-TEST-1' }), }) - for (const res of [credits, ledger, billing, checkout, redeem]) { + for (const res of [credits, ledger, billing, checkout, capacity, redeem]) { expect(res.status).toBe(403) const body = (await res.json()) as { error: { message: string } } expect(body.error.message).toBe('quota_store_binding_missing') diff --git a/server/http/store/storefront.ts b/server/http/store/storefront.ts index 354515d7..885acd43 100644 --- a/server/http/store/storefront.ts +++ b/server/http/store/storefront.ts @@ -16,6 +16,7 @@ import { listCreditProducts, listPackages, listTargets, + purchaseCapacity, redeemGiftCard, } from '../../usecases/store/store' import { authRoute, errorResponse, jsonBody, jsonContent } from '../openapi' @@ -27,6 +28,10 @@ import { getCloudOrders, getInstanceOrigin } from './shared' // opaque objects rather than mirrored field-for-field here. const cloudValue = z.unknown().openapi('CloudStoreValue') const cloudBody = (description: string) => jsonContent(cloudValue, description) +const capacityPurchaseInputSchema = z.object({ + requestHash: z.string().min(1).max(256), + idempotencyKey: z.string().min(1).max(200), +}) const packagesRoute = authRoute( { scopes: [AuthorizationScope.STORE_READ] }, @@ -154,6 +159,41 @@ const checkoutRoute = authRoute( }, ) +const capacityPurchaseRoute = authRoute( + { scopes: [AuthorizationScope.QUOTA_PURCHASE], minTeamRole: 'owner' }, + { + operationId: 'purchaseStorageCapacity', + summary: 'Purchase workspace storage capacity with x402', + description: + 'Call without PAYMENT-SIGNATURE to receive a standard x402 PAYMENT-REQUIRED challenge. Pay it and retry this same request with PAYMENT-SIGNATURE. A delivered response means the workspace capacity entitlement is active; retry the original createObject request.', + tags: ['Store'], + method: 'post', + path: '/capacity-purchases/{resourceId}', + middleware: [requireFeature('quota_store')] as const, + request: { + params: z.object({ resourceId: z.string().min(1) }), + headers: z.object({ + 'payment-signature': z + .string() + .min(1) + .max(64 * 1024) + .optional(), + }), + ...jsonBody(capacityPurchaseInputSchema), + }, + responses: { + 200: cloudBody('Capacity delivered'), + 202: cloudBody('Payment accepted; capacity fulfillment is pending'), + 400: errorResponse('Invalid capacity offer'), + 402: cloudBody('x402 payment required'), + 403: errorResponse('License not bound'), + 409: errorResponse('Purchase request conflict'), + 429: errorResponse('Too many pending capacity purchases'), + 502: errorResponse('Cloud error'), + }, + }, +) + const discountRoute = authRoute( { scopes: [AuthorizationScope.STORE_CREATE] }, { @@ -303,6 +343,27 @@ export const cloudStore = app if (!result.ok) throw result.error return c.json(result.value, 200) }) + .openapi(capacityPurchaseRoute, async (c) => { + const orgId = c.get('orgId') + if (!orgId) throw badRequest('No active organization') + const body = c.req.valid('json') + const result = await purchaseCapacity(c.get('deps'), getCloudBaseUrl(c), { + userId: c.get('userId')!, + orgId, + origin: await getInstanceOrigin(c), + resourceId: c.req.valid('param').resourceId, + requestHash: body.requestHash, + idempotencyKey: body.idempotencyKey, + paymentSignature: c.req.valid('header')['payment-signature'] ?? null, + }) + if (!result.ok) throw result.error + if (result.kind === 'payment_required') { + c.header('PAYMENT-REQUIRED', result.paymentRequiredHeader) + return c.json(result.paymentRequired, 402) + } + if (result.paymentResponseHeader) c.header('PAYMENT-RESPONSE', result.paymentResponseHeader) + return c.json(result.attempt, result.kind === 'delivered' ? 200 : 202) + }) .openapi(discountRoute, async (c) => { const result = await getDiscountQuote(c.get('deps'), getCloudBaseUrl(c), c.req.valid('json')) if (!result.ok) throw result.error diff --git a/server/openapi.test.ts b/server/openapi.test.ts index c8a4d595..d6ffd06d 100644 --- a/server/openapi.test.ts +++ b/server/openapi.test.ts @@ -94,6 +94,7 @@ describe('global OpenAPI document', () => { }) expect(workflows.workflows?.map((workflow) => workflow.workflowId)).toEqual([ 'prepareDirectFileUpload', + 'purchaseStorageCapacityWithX402', 'refreshDirectFileUploadParts', 'completeDirectFileUpload', 'abortDirectFileUpload', @@ -103,6 +104,7 @@ describe('global OpenAPI document', () => { .map((step) => step.operationId) expect(workflowOperationIds).toEqual([ 'createObject', + 'purchaseStorageCapacity', 'presignObjectUploadParts', 'completeObjectUpload', 'abortObjectUpload', @@ -153,6 +155,7 @@ describe('global OpenAPI document', () => { [AuthorizationScope.OBJECTS_READ]: 'List, inspect, and download objects', [AuthorizationScope.OBJECTS_CREATE]: 'Create folders and upload objects', [AuthorizationScope.SHARES_CREATE]: 'Create public shares', + [AuthorizationScope.QUOTA_PURCHASE]: 'Purchase workspace storage capacity', }), }, }, @@ -185,6 +188,10 @@ describe('global OpenAPI document', () => { value: AuthorizationScope.OBJECTS_UPDATE, description: 'Rename, move, and copy objects', }, + { + value: AuthorizationScope.QUOTA_PURCHASE, + description: 'Purchase workspace storage capacity', + }, ]), ) expect(document.paths['/api/oauth-resource-scopes']?.get).toMatchObject({ @@ -498,6 +505,14 @@ describe('global OpenAPI document', () => { scopes: [AuthorizationScope.OBJECTS_CREATE], }, }) + expect(doc.paths['/api/store/capacity-purchases/{resourceId}']?.post).toMatchObject({ + operationId: 'purchaseStorageCapacity', + 'x-zpan-auth': { + public: false, + scopes: [AuthorizationScope.QUOTA_PURCHASE], + }, + responses: { 429: expect.any(Object) }, + }) expect(doc.paths['/api/objects']?.post?.security).toBeUndefined() expect(doc.paths['/api/objects']?.post?.responses?.['201']).toBeDefined() expect(doc.paths['/api/objects']?.post?.requestBody).toBeDefined() diff --git a/server/scripts/backfill-agent-oauth-scopes.test.ts b/server/scripts/backfill-agent-oauth-scopes.test.ts new file mode 100644 index 00000000..ea82dc79 --- /dev/null +++ b/server/scripts/backfill-agent-oauth-scopes.test.ts @@ -0,0 +1,166 @@ +import { mkdtempSync, rmSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import Database from 'better-sqlite3' +import { afterEach, describe, expect, it, vi } from 'vitest' +import { + buildAgentOAuthScopeBackfill, + parseAgentOAuthScopeBackfillOptions, + runAgentOAuthScopeBackfill, +} from '../../scripts/backfill-agent-oauth-scopes' +import { AGENT_OAUTH_SCOPES } from '../../shared/agent-oauth' +import { AuthorizationScope } from '../../shared/authorization' + +const tempDirs: string[] = [] + +afterEach(() => { + for (const dir of tempDirs.splice(0)) rmSync(dir, { recursive: true, force: true }) +}) + +function createScopeDatabase() { + const dir = mkdtempSync(join(tmpdir(), 'zpan-agent-oauth-backfill-')) + tempDirs.push(dir) + const path = join(dir, 'zpan.db') + const db = new Database(path) + db.exec(` + CREATE TABLE oauthResource (id TEXT PRIMARY KEY, name TEXT NOT NULL, allowed_scopes TEXT, updated_at INTEGER); + CREATE TABLE oauthClient (id TEXT PRIMARY KEY, scopes TEXT, updated_at INTEGER); + `) + return { db, path } +} + +describe('buildAgentOAuthScopeBackfill', () => { + it('updates ZPan resources and upload clients without expanding read-only clients', () => { + const changes = buildAgentOAuthScopeBackfill( + [ + { + id: 'zpan-resource', + name: 'ZPan API', + allowedScopes: JSON.stringify([AuthorizationScope.OBJECTS_CREATE]), + }, + { + id: 'other-resource', + name: 'Other API', + allowedScopes: JSON.stringify([AuthorizationScope.OBJECTS_CREATE]), + }, + ], + [ + { + id: 'upload-client', + scopes: JSON.stringify([AuthorizationScope.OBJECTS_CREATE]), + }, + { + id: 'read-client', + scopes: JSON.stringify([AuthorizationScope.OBJECTS_READ]), + }, + ], + ) + + expect(changes).toEqual({ + resources: [{ id: 'zpan-resource', scopes: JSON.stringify(AGENT_OAUTH_SCOPES) }], + clients: [ + { + id: 'upload-client', + scopes: JSON.stringify([AuthorizationScope.OBJECTS_CREATE, AuthorizationScope.QUOTA_PURCHASE]), + }, + ], + }) + }) + + it('is idempotent after the scopes are current', () => { + const changes = buildAgentOAuthScopeBackfill( + [{ id: 'zpan-resource', name: 'ZPan API', allowedScopes: JSON.stringify(AGENT_OAUTH_SCOPES) }], + [ + { + id: 'upload-client', + scopes: JSON.stringify([AuthorizationScope.OBJECTS_CREATE, AuthorizationScope.QUOTA_PURCHASE]), + }, + ], + ) + + expect(changes).toEqual({ resources: [], clients: [] }) + }) + + it('rejects malformed client scope documents', () => { + expect(() => buildAgentOAuthScopeBackfill([], [{ id: 'bad', scopes: '{' }])).toThrow(SyntaxError) + expect(() => buildAgentOAuthScopeBackfill([], [{ id: 'bad', scopes: '["objects:create", 1]' }])).toThrow( + 'invalid_oauth_client_scopes', + ) + expect(buildAgentOAuthScopeBackfill([], [{ id: 'empty', scopes: null }])).toEqual({ resources: [], clients: [] }) + }) + + it('parses sqlite and D1 targets and rejects ambiguous invocations', () => { + expect(parseAgentOAuthScopeBackfillOptions(['--sqlite', '/tmp/zpan.db', '--apply'])).toEqual({ + apply: true, + target: { kind: 'sqlite', path: '/tmp/zpan.db' }, + }) + expect(parseAgentOAuthScopeBackfillOptions(['--d1', 'zpan-db', '--remote', '--env', 'staging'])).toEqual({ + apply: false, + target: { kind: 'd1', database: 'zpan-db', remote: true, env: 'staging' }, + }) + expect(() => parseAgentOAuthScopeBackfillOptions([])).toThrow('Usage:') + expect(() => parseAgentOAuthScopeBackfillOptions(['--sqlite', 'a', '--d1', 'b'])).toThrow('Usage:') + expect(() => parseAgentOAuthScopeBackfillOptions(['--sqlite'])).toThrow('Usage:') + expect(() => parseAgentOAuthScopeBackfillOptions(['--d1'])).toThrow('Usage:') + }) + + it('dry-runs and applies the SQLite backfill end to end', () => { + const { db, path } = createScopeDatabase() + db.prepare('INSERT INTO oauthResource (id, name, allowed_scopes) VALUES (?, ?, ?)').run( + 'zpan-resource', + 'ZPan API', + JSON.stringify([AuthorizationScope.OBJECTS_CREATE]), + ) + db.prepare('INSERT INTO oauthClient (id, scopes) VALUES (?, ?)').run( + 'upload-client', + JSON.stringify([AuthorizationScope.OBJECTS_CREATE]), + ) + db.close() + const logs: string[] = [] + + runAgentOAuthScopeBackfill(['--sqlite', path], (message) => logs.push(message)) + expect(JSON.parse(logs[0])).toEqual({ mode: 'dry-run', resources: 1, clients: 1 }) + + runAgentOAuthScopeBackfill(['--sqlite', path, '--apply'], (message) => logs.push(message)) + const after = new Database(path, { readonly: true }) + expect(after.prepare('SELECT allowed_scopes FROM oauthResource WHERE id = ?').pluck().get('zpan-resource')).toBe( + JSON.stringify(AGENT_OAUTH_SCOPES), + ) + expect(after.prepare('SELECT scopes FROM oauthClient WHERE id = ?').pluck().get('upload-client')).toBe( + JSON.stringify([AuthorizationScope.OBJECTS_CREATE, AuthorizationScope.QUOTA_PURCHASE]), + ) + after.close() + expect(JSON.parse(logs[1])).toEqual({ mode: 'apply', resources: 1, clients: 1 }) + }) + + it('reads and applies a remote D1 backfill with escaped identifiers', () => { + const resourceScopes = JSON.stringify(AGENT_OAUTH_SCOPES) + const clientScopes = JSON.stringify([AuthorizationScope.OBJECTS_CREATE, AuthorizationScope.QUOTA_PURCHASE]) + const execute = vi + .fn() + .mockReturnValueOnce(JSON.stringify([{ results: [{ id: "resource'1", name: 'ZPan API', allowedScopes: '[]' }] }])) + .mockReturnValueOnce( + JSON.stringify([ + { results: [{ id: 'client-1', scopes: JSON.stringify([AuthorizationScope.OBJECTS_CREATE]) }] }, + ]), + ) + .mockReturnValueOnce('') + .mockReturnValueOnce('') + .mockReturnValueOnce( + JSON.stringify([{ results: [{ id: "resource'1", name: 'ZPan API', allowedScopes: resourceScopes }] }]), + ) + .mockReturnValueOnce(JSON.stringify([{ results: [{ id: 'client-1', scopes: clientScopes }] }])) + + runAgentOAuthScopeBackfill(['--d1', 'zpan-db', '--remote', '--env', 'production', '--apply'], () => {}, execute) + + expect(execute).toHaveBeenCalledTimes(6) + expect(execute.mock.calls[0]?.[0]).toEqual({ + kind: 'd1', + database: 'zpan-db', + remote: true, + env: 'production', + }) + expect(execute.mock.calls[0]?.[2]).toBe(true) + expect(execute.mock.calls[2]?.[1]).toContain("resource''1") + }) +}) diff --git a/server/test/seed-preview-admin.test.ts b/server/test/seed-preview-admin.test.ts index 085e34c3..c83be3d1 100644 --- a/server/test/seed-preview-admin.test.ts +++ b/server/test/seed-preview-admin.test.ts @@ -1,5 +1,9 @@ import { describe, expect, it } from 'vitest' -import { buildPreviewAdminSeedSql, buildWranglerArgs } from '../../scripts/seed-preview-admin' +import { + buildPreviewAdminSeedSql, + buildWranglerArgs, + CREDENTIAL_ACCOUNT_ISSUER, +} from '../../scripts/seed-preview-admin' describe('seed-preview-admin script', () => { it('builds idempotent SQL for the preview admin account', () => { @@ -18,7 +22,9 @@ describe('seed-preview-admin script', () => { expect(sql).toContain('ban_expires = NULL') expect(sql).toContain('UPDATE account') expect(sql).toContain("SET password = 'hash''quoted'") - expect(sql).toContain('INSERT INTO account') + expect(sql).toContain(`issuer = '${CREDENTIAL_ACCOUNT_ISSUER}'`) + expect(sql).toContain('INSERT INTO account (id, issuer, account_id, provider_id') + expect(sql).toContain(`SELECT 'account''quoted', '${CREDENTIAL_ACCOUNT_ISSUER}', u.id, 'credential'`) expect(sql).toContain('AND NOT EXISTS') expect(sql).not.toContain('BEGIN') expect(sql).not.toContain('COMMIT') diff --git a/server/test/setup.ts b/server/test/setup.ts index c06a8522..f13d5c6c 100644 --- a/server/test/setup.ts +++ b/server/test/setup.ts @@ -403,11 +403,27 @@ const APP_SCHEMA_SQL = ` ON org_quota_entitlements(org_id, resource_type, status); CREATE INDEX IF NOT EXISTS org_quota_entitlements_org_type_idx ON org_quota_entitlements(org_id, resource_type, entitlement_type, status); - CREATE UNIQUE INDEX IF NOT EXISTS org_quota_entitlements_active_plan_uniq - ON org_quota_entitlements(org_id, resource_type, entitlement_type) - WHERE status = 'active' AND entitlement_type = 'plan' AND source <> 'free_plan'; CREATE UNIQUE INDEX IF NOT EXISTS org_quota_entitlements_source_resource_uniq ON org_quota_entitlements(source, source_id, resource_type); + CREATE TABLE IF NOT EXISTS x402_capacity_purchase_intents ( + id TEXT PRIMARY KEY, + org_id TEXT NOT NULL, + resource_id TEXT NOT NULL, + request_hash TEXT NOT NULL, + idempotency_key TEXT NOT NULL, + cloud_order_id TEXT, + cloud_attempt_id TEXT, + status TEXT NOT NULL DEFAULT 'created', + expires_at INTEGER, + created_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL + ); + CREATE UNIQUE INDEX IF NOT EXISTS x402_capacity_purchase_intents_org_request_uniq + ON x402_capacity_purchase_intents(org_id, resource_id, request_hash); + CREATE UNIQUE INDEX IF NOT EXISTS x402_capacity_purchase_intents_org_idempotency_uniq + ON x402_capacity_purchase_intents(org_id, idempotency_key); + CREATE INDEX IF NOT EXISTS x402_capacity_purchase_intents_attempt_idx + ON x402_capacity_purchase_intents(cloud_attempt_id); CREATE TABLE IF NOT EXISTS webhook_events ( id TEXT PRIMARY KEY, source TEXT NOT NULL, diff --git a/server/usecases/deps.ts b/server/usecases/deps.ts index 4a87ed41..798fec19 100644 --- a/server/usecases/deps.ts +++ b/server/usecases/deps.ts @@ -50,6 +50,7 @@ import type { UserAdminRepo, WebDavPathRepo, WebDavStateRepo, + X402CapacityPurchaseRepo, ZipGateway, ZipPlanRepo, } from './ports' @@ -104,4 +105,5 @@ export interface Deps { webdavState: WebDavStateRepo zip: ZipGateway zipPlan: ZipPlanRepo + x402CapacityPurchases: X402CapacityPurchaseRepo } diff --git a/server/usecases/object.test.ts b/server/usecases/object.test.ts index 6ebfa91a..eb14b0e5 100644 --- a/server/usecases/object.test.ts +++ b/server/usecases/object.test.ts @@ -151,6 +151,7 @@ function makeDeps( licenseBinding: {} as unknown as LicenseBindingRepo, licensingCloud: {} as unknown as LicensingCloudGateway, quota: { + hasQuotaForBytes: async () => true, incrementUsageIfEffectiveQuotaAllows: async () => true, refundTraffic: async () => {}, ...overrides.quota, @@ -293,6 +294,93 @@ describe('object usecase', () => { }) describe('createObject', () => { + it('requires capacity before creating a draft or presigning storage', async () => { + const create = vi.fn() + const presignUpload = vi.fn() + const hasQuotaForBytes = vi.fn(async () => false) + const { deps } = makeDeps({ + matter: { create }, + s3: { presignUpload }, + quota: { hasQuotaForBytes }, + }) + + const out = await createObject(deps, { + orgId: 'o1', + actor: user, + input: { name: 'large.bin', size: 50, dirtype: DirType.FILE, parent: '' }, + }) + + expect(out).toEqual({ ok: false, capacityRequired: { requestedBytes: 50 } }) + expect(hasQuotaForBytes).toHaveBeenCalledWith('o1', 50) + expect(create).not.toHaveBeenCalled() + expect(presignUpload).not.toHaveBeenCalled() + }) + + it('checks only the net additional bytes for a replace upload', async () => { + const hasQuotaForBytes = vi.fn(async () => false) + const incumbent = file('old', { size: 40, parent: '', name: 'same.bin' }) + const planConflictResolution = vi.fn(async () => ({ finalName: 'same.bin', toTrash: incumbent })) + const { deps } = makeDeps({ + matter: { planConflictResolution }, + quota: { hasQuotaForBytes }, + }) + + const out = await createObject(deps, { + orgId: 'o1', + actor: user, + input: { name: 'same.bin', size: 50, dirtype: DirType.FILE, parent: '', onConflict: 'replace' }, + }) + + expect(out).toEqual({ ok: false, capacityRequired: { requestedBytes: 10 } }) + expect(planConflictResolution).toHaveBeenCalledWith('o1', '', 'same.bin', 'replace', { isFolder: false }) + expect(hasQuotaForBytes).toHaveBeenCalledWith('o1', 10) + }) + + it('rejects a deterministic name conflict before checking quota or selecting storage', async () => { + const conflict = file('existing', { parent: '', name: 'same.bin' }) + const planConflictResolution = vi.fn(async () => { + throw new (await import('./ports')).NameConflictError(conflict.name, conflict.id) + }) + const select = vi.fn() + const hasQuotaForBytes = vi.fn(async () => false) + const { deps } = makeDeps({ + matter: { planConflictResolution }, + storages: { select }, + quota: { hasQuotaForBytes }, + }) + + await expect( + createObject(deps, { + orgId: 'o1', + actor: user, + input: { name: 'same.bin', size: 50, dirtype: DirType.FILE, parent: '' }, + }), + ).rejects.toMatchObject({ name: 'NameConflictError', conflictingId: 'existing' }) + expect(hasQuotaForBytes).not.toHaveBeenCalled() + expect(select).not.toHaveBeenCalled() + }) + + it('rejects unavailable storage before checking quota', async () => { + const hasQuotaForBytes = vi.fn(async () => false) + const { deps } = makeDeps({ + storages: { + select: async () => { + throw new Error('No available storage') + }, + }, + quota: { hasQuotaForBytes }, + }) + + const out = await createObject(deps, { + orgId: 'o1', + actor: user, + input: { name: 'large.bin', size: 50, dirtype: DirType.FILE, parent: '', storageId: 'missing' }, + }) + + expectError(out, 503, 'Storage is not active or has no available capacity', 'NO_STORAGE_CONFIGURED') + expect(hasQuotaForBytes).not.toHaveBeenCalled() + }) + it('creates a folder without presigning an upload', async () => { const create = vi.fn(async () => folder('f1', { name: 'My Folder' })) const presignUpload = vi.fn() diff --git a/server/usecases/object.ts b/server/usecases/object.ts index 80867a27..87a48da4 100644 --- a/server/usecases/object.ts +++ b/server/usecases/object.ts @@ -156,10 +156,11 @@ export const UPLOAD_PRESIGNED_URL_TTL_SECONDS = 15 * 60 export type CreateObjectOutcome = | { ok: true; matter: Matter } | { ok: true; matter: Matter; upload: ObjectUploadInstructions } + | { ok: false; capacityRequired: { requestedBytes: number } } | { ok: false; error: AppError } export async function createObject( - deps: Pick, + deps: Pick, params: { orgId: string; actor: ObjectActor; input: CreateMatterInput }, ): Promise { const { orgId, actor, input } = params @@ -187,6 +188,10 @@ export async function createObject( return { ok: false, error: badRequest('File exceeds the 5 TiB maximum', 'FILE_TOO_LARGE') } } + const conflictPlan = isFolder + ? null + : await deps.matter.planConflictResolution(orgId, parent, name, onConflict ?? 'fail', { isFolder: false }) + let storage: StorageRecord try { storage = await deps.storages.select(input.storageId) @@ -200,6 +205,13 @@ export async function createObject( throw error } + if (!isFolder) { + const requestedBytes = Math.max(0, size - (conflictPlan?.toTrash?.size ?? 0)) + if (!(await deps.quota.hasQuotaForBytes(orgId, requestedBytes))) { + return { ok: false, capacityRequired: { requestedBytes } } + } + } + const objectKey = isFolder ? '' : buildObjectKey({ uid: ownerUserId(actor), orgId, rawExt: fileExt(name) }) const matter = await deps.matter.create({ diff --git a/server/usecases/ports.ts b/server/usecases/ports.ts index ad0db0c5..abc0249a 100644 --- a/server/usecases/ports.ts +++ b/server/usecases/ports.ts @@ -49,4 +49,5 @@ export * from './ports/team-invite' export * from './ports/user' export * from './ports/webdav-path' export * from './ports/webdav-state' +export * from './ports/x402-capacity-purchase' export * from './ports/zip' diff --git a/server/usecases/ports/x402-capacity-purchase.ts b/server/usecases/ports/x402-capacity-purchase.ts new file mode 100644 index 00000000..916933eb --- /dev/null +++ b/server/usecases/ports/x402-capacity-purchase.ts @@ -0,0 +1,33 @@ +export interface X402CapacityPurchaseIntent { + id: string + orgId: string + resourceId: string + requestHash: string + idempotencyKey: string + cloudOrderId: string | null + cloudAttemptId: string | null + status: string + expiresAt: Date | null + createdAt: Date + updatedAt: Date +} + +export interface X402CapacityPurchaseRepo { + get(orgId: string, resourceId: string, requestHash: string): Promise + create(input: { + orgId: string + resourceId: string + requestHash: string + idempotencyKey: string + }): Promise + claimCloudOrder(id: string, staleBefore: Date): Promise + updateCloudState( + id: string, + input: { + cloudOrderId?: string + cloudAttemptId?: string + status: string + expiresAt?: Date | null + }, + ): Promise +} diff --git a/server/usecases/store/store.test.ts b/server/usecases/store/store.test.ts index 496b7804..90e79ed9 100644 --- a/server/usecases/store/store.test.ts +++ b/server/usecases/store/store.test.ts @@ -8,6 +8,8 @@ import { type EffectiveQuota, type LicensingCloudGateway, type QuotaRepo, + type X402CapacityPurchaseIntent, + type X402CapacityPurchaseRepo, } from '../ports' // Asserts a failed outcome carries the expected AppError (status / reason / message). @@ -32,10 +34,12 @@ import { createCheckout, getCreditBalance, getStoreReadiness, + listCapacityOffers, listCreditProducts, listPackages, listTargets, processDeliveryWebhook, + purchaseCapacity, redeemGiftCard, } from './store' @@ -60,14 +64,25 @@ const BINDING: CloudStoreBinding = { type CloudResponse = { status: number; ok: boolean; json: () => Promise } function fakeCloudClient(responses: CloudResponse[]) { let i = 0 + const requests: Array<{ method: string; path: string; input: unknown }> = [] const next = () => responses[i++] ?? { status: 200, ok: true, json: async () => ({}) } - const handler: ProxyHandler> = { - get(_t, prop) { - if (prop === '$get' || prop === '$post' || prop === '$patch') return async () => next() - return new Proxy({}, handler) - }, - } - return new Proxy({}, handler) as never + const proxy = (path: string[]): Record => + new Proxy( + {}, + { + get(_target, property) { + const segment = String(property) + if (segment === '$get' || segment === '$post' || segment === '$patch') { + return async (input: unknown) => { + requests.push({ method: segment.slice(1).toUpperCase(), path: path.join('/'), input }) + return next() + } + } + return proxy([...path, segment]) + }, + }, + ) + return { client: proxy([]) as never, requests } } const ok = (body: unknown): CloudResponse => ({ status: 200, ok: true, json: async () => body }) @@ -90,6 +105,52 @@ function pkg(overrides: Record = {}) { } } +function publication(overrides: Record = {}) { + return { + storeId: 'store-1', + mode: 'directory', + listingStatus: 'listed', + displayName: 'ZPan', + summary: null, + publicMetadata: {}, + skillUrl: null, + termsUrl: null, + healthUrl: 'https://files.example/api/health', + healthStatus: 'healthy', + resources: [ + { + id: 'publication-resource-1', + storeId: 'store-1', + resourceId: 'pkg-1:price-usd', + offerId: 'pro-monthly', + title: 'Pro', + description: null, + productId: 'pkg-1', + priceId: 'price-usd', + postResourceUrl: 'https://files.example/api/store/capacity-purchases/pkg-1%3Aprice-usd', + status: 'active', + tags: [], + capabilities: ['storage.capacity.purchase'], + publicDeliverable: { type: 'zpan.plan', storageBytes: 4096 }, + productSnapshot: null, + bazaarRequestMethod: 'POST', + bazaarBodyType: 'json', + bazaarInput: null, + bazaarInputSchema: null, + bazaarOutput: null, + bazaarValidationStatus: 'unknown', + bazaarValidationDiagnostic: null, + bazaarValidatedAt: null, + createdAt: '2026-07-30T00:00:00.000Z', + updatedAt: '2026-07-30T00:00:00.000Z', + }, + ], + createdAt: '2026-07-30T00:00:00.000Z', + updatedAt: '2026-07-30T00:00:00.000Z', + ...overrides, + } +} + function order(overrides: Record = {}) { return { id: 'order-1', @@ -114,6 +175,82 @@ function order(overrides: Record = {}) { } const payment = { status: 'pending', paymentId: 'pay-1', orderId: 'order-1', url: 'https://cloud.example/checkout' } +const receiver = { + id: 'receiver-1', + storeId: 'store-1', + scheme: 'exact', + network: 'eip155:8453', + asset: '0xusdc', + networkFamily: 'evm', + payTo: '0xmerchant', + status: 'active', + verifiedAt: '2026-07-01T00:00:00.000Z', + createdAt: '2026-07-01T00:00:00.000Z', + updatedAt: '2026-07-01T00:00:00.000Z', +} + +function attempt(status = 'quoted') { + return { + id: 'attempt-1', + storeId: 'store-1', + orderId: 'order-1', + paymentId: status === 'delivered' ? 'payment-1' : null, + customerId: 'org-1', + idempotencyKey: 'idem-1', + resourceId: 'pkg-1:price-usd', + offerId: null, + resourceUrl: 'https://files.example/api/store/capacity-purchases/pkg-1%3Aprice-usd', + resourceDescription: null, + requestHash: 'hash-1', + productId: 'pkg-1', + priceId: 'price-usd', + scheme: 'exact', + network: receiver.network, + asset: receiver.asset, + amount: 500, + currency: 'usd', + payTo: receiver.payTo, + recurringPlan: true, + billingPeriodStart: '2026-08-01T00:00:00.000Z', + billingPeriodEnd: '2026-09-01T00:00:00.000Z', + paymentRequired: { + x402Version: 2, + resource: { url: 'https://files.example/api/store/capacity-purchases/pkg-1%3Aprice-usd' }, + accepts: [ + { + scheme: 'exact', + network: receiver.network, + asset: receiver.asset, + amount: '500', + payTo: receiver.payTo, + maxTimeoutSeconds: 300, + extra: {}, + }, + ], + }, + paymentRequiredHeader: 'required-header', + paymentSignatureHeader: status === 'quoted' ? null : 'signature', + payer: status === 'quoted' ? null : '0xpayer', + paymentIdentifier: null, + authorizationHash: null, + planFamily: 'storage', + planKey: 'pro', + tierRank: 1, + billingInterval: 'month', + settlementTransaction: status === 'delivered' ? '0xtx' : null, + settlementResponseHeader: status === 'delivered' ? 'response-header' : null, + status, + lastErrorCode: null, + quotedAt: '2026-07-30T00:00:00.000Z', + expiresAt: '2099-07-30T00:05:00.000Z', + verifiedAt: status === 'quoted' ? null : '2026-07-30T00:01:00.000Z', + settlingAt: null, + settledAt: status === 'delivered' ? '2026-07-30T00:02:00.000Z' : null, + canceledAt: null, + createdAt: '2026-07-30T00:00:00.000Z', + updatedAt: '2026-07-30T00:00:00.000Z', + } +} const noPlanQuota = { currentPlan: null } as EffectiveQuota const subscribedQuota = { currentPlan: { subscription: true } } as EffectiveQuota @@ -147,12 +284,43 @@ function makeDeps( // every cloudRequest), so the fake must be a single instance whose response queue // advances across calls — rebuilding it per call would reset the counter and replay // response #0, breaking multi-call flows (checkout, continue/cancel order). - const client = fakeCloudClient(options.responses ?? []) - const createBoundCloudClient = vi.fn(() => client) + const fake = fakeCloudClient(options.responses ?? []) + const createBoundCloudClient = vi.fn(() => fake.client) const licensingCloud = { createBoundCloudClient } as unknown as LicensingCloudGateway const quota = { getEffectiveQuota: async () => options.quota ?? noPlanQuota } as unknown as QuotaRepo - const deps: CloudStoreDeps = { cloudStore, licensingCloud, quota } - return { deps, getCloudStoreBinding, processCloudOrderQuotaChange, createBoundCloudClient } + let purchaseIntent: X402CapacityPurchaseIntent | null = null + const x402CapacityPurchases: X402CapacityPurchaseRepo = { + get: async () => purchaseIntent, + create: async (input) => { + purchaseIntent = { + id: 'intent-1', + ...input, + cloudOrderId: null, + cloudAttemptId: null, + status: 'created', + expiresAt: null, + createdAt: new Date(), + updatedAt: new Date(), + } + return purchaseIntent + }, + claimCloudOrder: async () => { + if (!purchaseIntent || purchaseIntent.cloudOrderId) return false + purchaseIntent = { ...purchaseIntent, status: 'ordering', updatedAt: new Date() } + return true + }, + updateCloudState: async (_id, input) => { + if (!purchaseIntent) throw new Error('missing_intent') + purchaseIntent = { ...purchaseIntent, ...input, updatedAt: new Date() } + }, + } + const deps: CloudStoreDeps & { x402CapacityPurchases: X402CapacityPurchaseRepo } = { + cloudStore, + licensingCloud, + quota, + x402CapacityPurchases, + } + return { deps, getCloudStoreBinding, processCloudOrderQuotaChange, createBoundCloudClient, requests: fake.requests } } const CLOUD = 'https://cloud.example' @@ -215,6 +383,58 @@ describe('cloud-store usecase', () => { expectError(await listPackages(deps, CLOUD), { httpStatus: 502, message: 'invalid_cloud_response' }) }) + it('lists every standard capacity price that closes the workspace gap', async () => { + const { deps } = makeDeps({ + responses: [ + ok({ + items: [ + pkg({ + prices: [ + { id: 'monthly', currency: 'usd', amount: 500, recurring: { interval: 'month', intervalCount: 1 } }, + { id: 'yearly', currency: 'usd', amount: 5000, recurring: { interval: 'year', intervalCount: 1 } }, + ], + }), + pkg({ + id: 'too-small', + metadata: { deliverable: { type: 'zpan.plan', storageBytes: 100 } }, + }), + ], + total: 2, + limit: 100, + offset: 0, + }), + ok( + publication({ + resources: [ + { + ...publication().resources[0], + priceId: 'monthly', + resourceId: 'pro-monthly', + }, + { + ...publication().resources[0], + priceId: 'yearly', + resourceId: 'pro-yearly', + }, + ], + }), + ), + ], + quota: { + used: 1000, + quota: 900, + currentPlan: { storageBytes: 800 }, + } as EffectiveQuota, + }) + + const out = await listCapacityOffers(deps, CLOUD, { orgId: 'org-1', requestedBytes: 200 }) + + expect(out.ok && out.value).toMatchObject([ + { resourceId: 'pro-monthly', productId: 'pkg-1', priceId: 'monthly', storageBytes: 4096 }, + { resourceId: 'pro-yearly', productId: 'pkg-1', priceId: 'yearly', storageBytes: 4096 }, + ]) + }) + it('listTargets returns the accessible targets without a cloud call', async () => { const targets = [{ orgId: 'org-1', type: 'personal' }] as unknown as CloudStoreTarget[] const { deps, createBoundCloudClient } = makeDeps({ targets }) @@ -330,6 +550,366 @@ describe('cloud-store usecase', () => { }) }) + describe('purchaseCapacity', () => { + const params = { + userId: 'user-1', + orgId: 'org-1', + origin: 'https://files.example', + resourceId: 'pkg-1:price-usd', + requestHash: 'hash-1', + idempotencyKey: 'idem-1', + paymentSignature: null, + } + + it('creates an idempotent order and returns the standard x402 challenge', async () => { + const quote = { ...attempt(), reused: false } + const { deps, requests } = makeDeps({ + responses: [ok(publication()), ok(pkg()), ok(receiver), ok(order()), ok(quote)], + }) + + const out = await purchaseCapacity(deps, CLOUD, params) + + expect(out).toEqual({ + ok: true, + kind: 'payment_required', + paymentRequired: quote.paymentRequired, + paymentRequiredHeader: quote.paymentRequiredHeader, + }) + expect(requests[3]?.input).toMatchObject({ + json: { + idempotencyKey: 'zpan-x402-capacity:intent-1', + }, + }) + expect(requests[4]).toMatchObject({ + method: 'POST', + path: 'stores/:storeId/orders/:orderId/x402/payment-attempts', + input: { + header: { 'Idempotency-Key': params.idempotencyKey }, + json: { + requestHash: params.requestHash, + resourceId: params.resourceId, + }, + }, + }) + expect(requests[4]?.input).not.toMatchObject({ json: { idempotencyKey: expect.anything() } }) + }) + + it('returns forbidden before calling Cloud when the quota store is not bound', async () => { + const { deps, createBoundCloudClient } = makeDeps({ binding: 'missing' }) + + const out = await purchaseCapacity(deps, CLOUD, params) + + expectError(out, { httpStatus: 403, message: 'quota_store_binding_missing' }) + expect(createBoundCloudClient).not.toHaveBeenCalled() + }) + + it('returns bad request when the published capacity offer does not exist', async () => { + const { deps } = makeDeps({ + responses: [ok(publication({ resources: [] }))], + }) + + const out = await purchaseCapacity(deps, CLOUD, params) + + expectError(out, { + httpStatus: 400, + reason: 'CAPACITY_OFFER_NOT_FOUND', + message: 'Invalid capacity offer', + }) + }) + + it('returns a retryable conflict when another request is creating the Cloud order', async () => { + const { deps, requests } = makeDeps({ + responses: [ok(publication()), ok(pkg()), ok(receiver)], + }) + deps.x402CapacityPurchases.claimCloudOrder = vi.fn(async () => false) + + const out = await purchaseCapacity(deps, CLOUD, params) + + expectError(out, { + httpStatus: 409, + reason: 'X402_PURCHASE_IN_PROGRESS', + message: 'Purchase initialization is in progress', + }) + expect(requests).toHaveLength(3) + }) + + it('rate-limits new unpaid purchase intents before creating a Cloud order', async () => { + const { deps, requests } = makeDeps({ + responses: [ok(publication()), ok(pkg()), ok(receiver)], + }) + deps.x402CapacityPurchases.create = vi.fn(async () => null) + + const out = await purchaseCapacity(deps, CLOUD, params) + + expectError(out, { + httpStatus: 429, + message: 'Too many pending capacity purchases', + }) + expect((out as { error: AppError }).error.meta.headers).toEqual({ 'Retry-After': '3600' }) + expect(requests).toHaveLength(3) + }) + + it('returns a purchase conflict when intent reservation fails without a concurrent winner', async () => { + const { deps, requests } = makeDeps({ + responses: [ok(publication()), ok(pkg()), ok(receiver)], + }) + deps.x402CapacityPurchases.create = vi.fn(async () => { + throw new Error('unique constraint') + }) + + const out = await purchaseCapacity(deps, CLOUD, params) + + expectError(out, { + httpStatus: 409, + reason: 'X402_PURCHASE_CONFLICT', + message: 'Purchase request conflict', + }) + expect(requests).toHaveLength(3) + }) + + it('rejects a different idempotency key for an existing purchase request', async () => { + const { deps, requests } = makeDeps({ + responses: [ + ok(publication()), + ok(pkg()), + ok(receiver), + ok(order()), + ok({ ...attempt(), reused: false }), + ok(publication()), + ok(pkg()), + ok(receiver), + ], + }) + await purchaseCapacity(deps, CLOUD, params) + + const out = await purchaseCapacity(deps, CLOUD, { ...params, idempotencyKey: 'different-key' }) + + expectError(out, { + httpStatus: 409, + reason: 'X402_PURCHASE_CONFLICT', + message: 'Purchase request conflict', + }) + expect(requests).toHaveLength(8) + }) + + it('releases the local order claim when Cloud order creation fails', async () => { + const { deps } = makeDeps({ + responses: [ok(publication()), ok(pkg()), ok(receiver), fail(503, { error: 'cloud_down' })], + }) + const updateCloudState = vi.spyOn(deps.x402CapacityPurchases, 'updateCloudState') + + const out = await purchaseCapacity(deps, CLOUD, params) + + expectError(out, { httpStatus: 502, message: 'cloud_down' }) + expect(updateCloudState).toHaveBeenCalledWith('intent-1', { status: 'created' }) + }) + + it('reuses the intent, verifies payment, settles, and returns the receipt', async () => { + const quoted = attempt() + const verifiedAttempt = attempt('verified') + const paidPendingFulfillment = attempt('paid_pending_fulfillment') + const delivered = attempt('delivered') + const { deps, requests } = makeDeps({ + responses: [ + ok(publication()), + ok(pkg()), + ok(receiver), + ok(order()), + ok({ ...quoted, reused: false }), + ok(publication()), + ok(pkg()), + ok(receiver), + ok(quoted), + ok(verifiedAttempt), + ok(paidPendingFulfillment), + ok(delivered), + ], + }) + await purchaseCapacity(deps, CLOUD, params) + + const out = await purchaseCapacity(deps, CLOUD, { ...params, paymentSignature: 'signature' }) + + expect(out).toMatchObject({ + ok: true, + kind: 'delivered', + paymentResponseHeader: 'response-header', + attempt: { id: 'attempt-1', status: 'delivered' }, + }) + expect(requests[8]).toMatchObject({ + method: 'GET', + path: 'stores/:storeId/orders/:orderId/x402/payment-attempts/:attemptId', + }) + expect(requests[9]).toMatchObject({ + method: 'POST', + path: 'stores/:storeId/orders/:orderId/x402/payment-attempts/:attemptId/verifications', + input: { + header: { 'PAYMENT-SIGNATURE': 'signature' }, + json: { requestHash: params.requestHash }, + }, + }) + expect(requests[9]?.input).not.toMatchObject({ json: { paymentSignature: expect.anything() } }) + expect(requests[10]).toMatchObject({ + method: 'POST', + path: 'stores/:storeId/orders/:orderId/x402/payment-attempts/:attemptId/settlements', + }) + expect(requests[11]).toMatchObject({ + method: 'POST', + path: 'stores/:storeId/orders/:orderId/x402/payment-attempts/:attemptId/fulfillment-attempts', + }) + }) + + it('returns an already delivered attempt after quote expiry without creating a replacement quote', async () => { + const quoted = attempt() + const delivered = { ...attempt('delivered'), expiresAt: '2026-07-30T00:00:00.000Z' } + const { deps, requests } = makeDeps({ + responses: [ + ok(publication()), + ok(pkg()), + ok(receiver), + ok(order()), + ok({ ...quoted, reused: false }), + ok(publication()), + ok(pkg()), + ok(receiver), + ok(delivered), + ], + }) + await purchaseCapacity(deps, CLOUD, params) + + const out = await purchaseCapacity(deps, CLOUD, params) + + expect(out).toMatchObject({ + ok: true, + kind: 'delivered', + paymentResponseHeader: 'response-header', + attempt: { id: 'attempt-1', status: 'delivered' }, + }) + expect( + requests.filter((request) => request.path === 'stores/:storeId/orders/:orderId/x402/payment-attempts'), + ).toHaveLength(1) + }) + + it('retries paid-pending fulfillment after quote expiry without creating a replacement quote', async () => { + const quoted = attempt() + const paidPending = { ...attempt('paid_pending_fulfillment'), expiresAt: '2026-07-30T00:00:00.000Z' } + const delivered = { ...attempt('delivered'), expiresAt: '2026-07-30T00:00:00.000Z' } + const { deps, requests } = makeDeps({ + responses: [ + ok(publication()), + ok(pkg()), + ok(receiver), + ok(order()), + ok({ ...quoted, reused: false }), + ok(publication()), + ok(pkg()), + ok(receiver), + ok(paidPending), + ok(delivered), + ], + }) + await purchaseCapacity(deps, CLOUD, params) + + const out = await purchaseCapacity(deps, CLOUD, { ...params, paymentSignature: 'signature' }) + + expect(out).toMatchObject({ + ok: true, + kind: 'delivered', + paymentResponseHeader: 'response-header', + attempt: { id: 'attempt-1', status: 'delivered' }, + }) + expect( + requests.filter((request) => request.path === 'stores/:storeId/orders/:orderId/x402/payment-attempts'), + ).toHaveLength(1) + expect(requests.at(-1)).toMatchObject({ + method: 'POST', + path: 'stores/:storeId/orders/:orderId/x402/payment-attempts/:attemptId/fulfillment-attempts', + }) + }) + + it('returns a client error when Cloud rejects the payment signature', async () => { + const quoted = attempt() + const { deps } = makeDeps({ + responses: [ + ok(publication()), + ok(pkg()), + ok(receiver), + ok(order()), + ok({ ...quoted, reused: false }), + ok(publication()), + ok(pkg()), + ok(receiver), + ok(quoted), + fail(400, { error: 'x402_payment_proof_invalid' }), + ], + }) + await purchaseCapacity(deps, CLOUD, params) + + const out = await purchaseCapacity(deps, CLOUD, { ...params, paymentSignature: 'invalid-signature' }) + + expectError(out, { + httpStatus: 400, + reason: 'X402_PAYMENT_PROOF_INVALID', + message: 'x402_payment_proof_invalid', + }) + }) + + it('replaces an expired quote with a fresh challenge for the same purchase intent', async () => { + const quoted = attempt() + const expired = { ...attempt(), expiresAt: '2026-07-30T00:00:00.000Z' } + const replacement = { + ...attempt(), + id: 'attempt-2', + idempotencyKey: 'replacement-idempotency', + paymentRequiredHeader: 'replacement-required-header', + expiresAt: '2099-07-30T00:05:00.000Z', + reused: false, + } + const { deps, requests } = makeDeps({ + responses: [ + ok(publication()), + ok(pkg()), + ok(receiver), + ok(order()), + ok({ ...quoted, reused: false }), + ok(publication()), + ok(pkg()), + ok(receiver), + ok(expired), + ok(replacement), + ], + }) + await purchaseCapacity(deps, CLOUD, params) + + const out = await purchaseCapacity(deps, CLOUD, { ...params, paymentSignature: 'expired-signature' }) + + expect(out).toMatchObject({ + ok: true, + kind: 'payment_required', + paymentRequiredHeader: 'replacement-required-header', + }) + const quoteRequests = requests.filter( + (request) => + request.method === 'POST' && + typeof request.input === 'object' && + request.input !== null && + 'json' in request.input && + typeof request.input.json === 'object' && + request.input.json !== null && + 'requestHash' in request.input.json, + ) + expect(quoteRequests).toHaveLength(2) + expect(quoteRequests[1]?.input).toMatchObject({ + header: { + 'Idempotency-Key': expect.stringMatching(/^x402-retry:[0-9a-f]{64}$/), + }, + json: { + requestHash: params.requestHash, + resourceId: params.resourceId, + }, + }) + }) + }) + describe('order actions', () => { it('continueOrderPayment returns not_found for an empty orderId', async () => { const { deps } = makeDeps() @@ -384,9 +964,17 @@ describe('cloud-store usecase', () => { describe('createBillingPortalSession', () => { it('proxies a portal session with the org return URL', async () => { const session = { url: 'https://billing.example', stripeSubscriptionId: 'sub_1' } - const { deps } = makeDeps({ responses: [ok(session)] }) + const { deps, requests } = makeDeps({ responses: [ok(session)] }) const out = await createBillingPortalSession(deps, CLOUD, { orgId: 'org-1', origin: 'https://files.example' }) expect(out).toEqual({ ok: true, value: session }) + expect(requests[0]).toMatchObject({ + method: 'POST', + path: 'stores/:storeId/billing/portal-sessions', + input: { + param: { storeId: 'store-1' }, + json: { customerId: 'org-1', returnUrl: 'https://files.example/storage' }, + }, + }) }) }) @@ -451,6 +1039,49 @@ describe('cloud-store usecase', () => { ) }) + it('accepts x402 recurring fulfillment with a provider-neutral billing period identity', async () => { + const body = { + eventId: 'evt-x402', + eventType: 'commerce.order_item.fulfilled', + orderId: 'order-x402', + orderItemId: 'item-x402', + productId: 'product-pro', + productName: 'Pro', + quantity: 1, + deliverable: { type: 'zpan.plan', storageBytes: 1024 }, + target: { orgId: 'org-1', customerId: 'org-1' }, + context: { + storeId: 'store-1', + paymentProvider: 'x402', + providerTransactionId: '0xtx', + x402AuditContext: { network: 'eip155:8453' }, + billingPeriodStart: '2026-08-01T00:00:00.000Z', + billingPeriodEnd: '2026-09-01T00:00:00.000Z', + }, + occurredAt: '2026-07-30T00:00:00.000Z', + } + verified('evt-x402') + const { deps, processCloudOrderQuotaChange } = makeDeps({ + processResult: { duplicate: false, eventId: 'evt-x402' }, + }) + + const out = await processDeliveryWebhook(deps, params(body)) + + expect(out).toMatchObject({ ok: true, eventId: 'evt-x402' }) + expect(processCloudOrderQuotaChange).toHaveBeenCalledWith( + expect.objectContaining({ + cloudOrderId: 'x402:period:product-pro:2026-08-01T00:00:00.000Z:2026-09-01T00:00:00.000Z:org-1', + entitlementType: 'plan', + startsAt: '2026-08-01T00:00:00.000Z', + expiresAt: '2026-09-01T00:00:00.000Z', + paymentProvider: 'x402', + providerTransactionId: '0xtx', + }), + JSON.stringify(body), + 'hash', + ) + }) + it('reports duplicate=true on an idempotent replay', async () => { verified('evt-1') const { deps } = makeDeps({ processResult: { duplicate: true, eventId: 'evt-1' } }) diff --git a/server/usecases/store/store.ts b/server/usecases/store/store.ts index c8ea2f82..ca9a434a 100644 --- a/server/usecases/store/store.ts +++ b/server/usecases/store/store.ts @@ -31,10 +31,21 @@ import type { z } from 'zod' import { billingPortalSessionResponseSchema, type CloudClient, + type CommerceProduct, commerceProductSchema, + createX402PaymentAttempt, + getX402PaymentAttempt, paymentCreateResponseSchema, productListResponseSchema, + settleX402PaymentAttempt, + storePublicationSchema, + triggerX402PaymentAttemptFulfillment, + verifyX402PaymentAttempt, + x402PaymentAttemptSchema, + x402QuoteCreateResponseSchema, + x402ReceiverSchema, } from 'zpan-cloud-sdk' +import type { Deps } from '../deps' import { AppError, badGateway, @@ -45,6 +56,7 @@ import { type LicensingCloudGateway, notFound, type QuotaRepo, + rateLimited, } from '../ports' import { verifyCloudEventToken } from '../site/licensing' @@ -58,6 +70,7 @@ const cloudBillingPortalSessionResponseSchema = billingPortalSessionResponseSche const cloudDiscountQuoteResponseSchema = discountQuoteSchema const CLOUD_STORE_REQUEST_TIMEOUT_MS = 10_000 +const X402_ORDER_CLAIM_TIMEOUT_MS = 30_000 export type CloudStoreDeps = { cloudStore: CloudStoreRepo @@ -69,7 +82,16 @@ export type CloudStoreDeps = { // proxy threads this through a request callback. export type BoundCloudClient = { client: CloudClient; storeId: string } -type CloudError = { error: string } +type CloudError = { error: string; status?: number } + +class CloudResponseError extends Error { + constructor( + readonly status: number, + message: string, + ) { + super(message) + } +} // Storefront proxy outcomes. An unbound store renders 403 (`forbidden`); an // upstream Cloud failure or malformed body renders 502 (`badGateway`). Each @@ -132,7 +154,9 @@ export async function unwrapCloudResponse( ): Promise { if (response.status === 204) return null as U const data = await response.json().catch(() => null) - if (!response.ok) throw new Error(cloudErrorCode(data) ?? `cloud_request_failed_${response.status}`) + if (!response.ok) { + throw new CloudResponseError(response.status, cloudErrorCode(data) ?? `cloud_request_failed_${response.status}`) + } const payload = data && typeof data === 'object' && 'data' in data ? data.data : data if (!responseSchema) return payload as U const parsed = responseSchema.safeParse(payload) @@ -158,7 +182,10 @@ async function cloudRequest( try { return await withCloudRequestTimeout(request(await buildBoundCloudClient(deps, cloudBaseUrl))) } catch (error) { - return { error: (error as Error).message } + return { + error: (error as Error).message, + ...(error instanceof CloudResponseError ? { status: error.status } : {}), + } } } @@ -166,6 +193,16 @@ function isCloudError(result: unknown): result is CloudError { return Boolean(result && typeof result === 'object' && 'error' in result) } +function capacityPurchaseCloudError(error: CloudError): AppError { + if (error.error === 'capacity_offer_not_found') { + return badRequest('Invalid capacity offer', 'CAPACITY_OFFER_NOT_FOUND') + } + const reason = error.error.toUpperCase() + if (error.status === 400 || error.status === 422) return badRequest(error.error, reason) + if (error.status === 404 || error.status === 409) return conflict(error.error, reason) + return badGateway(error.error) +} + // ─── Storefront reads ──────────────────────────────────────────────────────── // Fetches active store_item products and keeps only those whose deliverable @@ -191,6 +228,394 @@ async function listDeliverables( return { ok: true, value: { ...result, items, total: items.length } } } +export interface CapacityOffer { + resourceId: string + productId: string + priceId: string + name: string + description: string | null + storageBytes: number + amount: number + currency: string + interval: string | null + intervalCount: number | null + purchaseUrl: string +} + +export async function listCapacityOffers( + deps: CloudStoreDeps, + cloudBaseUrl: string, + params: { orgId: string; requestedBytes: number }, +): Promise> { + const packages = await listPackages(deps, cloudBaseUrl) + if (!packages.ok) return packages + const publication = await cloudRequest(deps, cloudBaseUrl, async ({ client, storeId }) => + unwrapCloudResponse( + await client.stores[':storeId'].publication.$get({ param: { storeId } }), + storePublicationSchema, + ), + ) + if (isCloudError(publication)) return { ok: false, error: badGateway(publication.error) } + const quota = await deps.quota.getEffectiveQuota(params.orgId) + const capacityOutsideCurrentPlan = Math.max(0, quota.quota - (quota.currentPlan?.storageBytes ?? 0)) + const minimumStorageBytes = Math.max(1, quota.used + params.requestedBytes - capacityOutsideCurrentPlan) + const offers = (packages.value.items as CommerceProduct[]).flatMap((product) => { + const storageBytes = product.metadata.deliverable.storageBytes + if (typeof storageBytes !== 'number' || !Number.isSafeInteger(storageBytes) || storageBytes < minimumStorageBytes) { + return [] + } + return product.prices.flatMap((price) => { + if (!price.id || price.recurring?.usageType === 'metered') return [] + const resource = publication.resources.find( + (candidate) => + candidate.productId === product.id && + candidate.priceId === price.id && + candidate.status !== 'disabled' && + candidate.capabilities.includes('storage.capacity.purchase'), + ) + if (!resource) return [] + return [ + { + resourceId: resource.resourceId, + productId: product.id, + priceId: price.id, + name: product.name, + description: product.description, + storageBytes, + amount: price.amount, + currency: price.currency, + interval: price.recurring?.interval ?? null, + intervalCount: price.recurring?.intervalCount ?? null, + purchaseUrl: resource.postResourceUrl, + }, + ] + }) + }) + return { ok: true, value: offers } +} + +export async function describeCapacityRequirement( + deps: CloudStoreDeps, + cloudBaseUrl: string, + params: { orgId: string; requestedBytes: number }, +): Promise< + StorefrontReadOutcome<{ + requestedBytes: number + usedBytes: number + quotaBytes: number + offers: CapacityOffer[] + }> +> { + const offers = await listCapacityOffers(deps, cloudBaseUrl, params) + if (!offers.ok) return offers + const quota = await deps.quota.getEffectiveQuota(params.orgId) + return { + ok: true, + value: { + requestedBytes: params.requestedBytes, + usedBytes: quota.used, + quotaBytes: quota.quota, + offers: offers.value, + }, + } +} + +export type CapacityPurchaseOutcome = + | { + ok: true + kind: 'payment_required' + paymentRequired: unknown + paymentRequiredHeader: string + } + | { + ok: true + kind: 'pending' | 'delivered' + attempt: z.infer + paymentResponseHeader: string | null + } + | { ok: false; error: AppError } + +async function capacityQuoteRetryKey(idempotencyKey: string, expiredAttemptId: string): Promise { + const input = new TextEncoder().encode(`${idempotencyKey}:${expiredAttemptId}`) + const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', input)) + return `x402-retry:${Array.from(digest, (byte) => byte.toString(16).padStart(2, '0')).join('')}` +} + +function capacityAttemptExpired(attempt: z.infer, now = new Date()): boolean { + return ( + attempt.status === 'expired' || + (attempt.status === 'quoted' && new Date(attempt.expiresAt).getTime() <= now.getTime()) + ) +} + +export async function purchaseCapacity( + deps: CloudStoreDeps & Pick, + cloudBaseUrl: string, + params: { + userId: string + orgId: string + origin: string + resourceId: string + requestHash: string + idempotencyKey: string + paymentSignature: string | null + }, +): Promise { + const ready = await getStoreReadiness(deps) + if (!ready.ready) return { ok: false, error: forbidden(ready.error) } + + const context = await cloudRequest(deps, cloudBaseUrl, async (bound) => { + const publication = await unwrapCloudResponse( + await bound.client.stores[':storeId'].publication.$get({ param: { storeId: bound.storeId } }), + storePublicationSchema, + ) + const resource = publication.resources.find( + (candidate) => + candidate.resourceId === params.resourceId && + candidate.status !== 'disabled' && + candidate.capabilities.includes('storage.capacity.purchase'), + ) + if (!resource) throw new Error('capacity_offer_not_found') + const { productId, priceId } = resource + const product = await unwrapCloudResponse( + await bound.client.stores[':storeId'].products[':productId'].$get({ + param: { storeId: bound.storeId, productId }, + }), + cloudPackageResponseSchema, + ) + const storageBytes = product.metadata.deliverable.storageBytes + const price = product.prices.find((item) => item.id === priceId && item.recurring?.usageType !== 'metered') + if ( + product.metadata.deliverable.type !== 'zpan.plan' || + typeof storageBytes !== 'number' || + !Number.isSafeInteger(storageBytes) || + storageBytes <= 0 || + !price + ) { + throw new Error('capacity_offer_not_found') + } + const receiver = await unwrapCloudResponse( + await bound.client.stores[':storeId']['payment-methods'].x402.receiver.$get({ + param: { storeId: bound.storeId }, + }), + x402ReceiverSchema, + ) + if (receiver.status !== 'active') throw new Error('x402_receiver_not_active') + return { ...bound, productId, priceId, product, price, receiver } + }) + if (isCloudError(context)) return { ok: false, error: capacityPurchaseCloudError(context) } + + let intent = await deps.x402CapacityPurchases.get(params.orgId, params.resourceId, params.requestHash) + if (!intent) { + try { + intent = await deps.x402CapacityPurchases.create({ + orgId: params.orgId, + resourceId: params.resourceId, + requestHash: params.requestHash, + idempotencyKey: params.idempotencyKey, + }) + if (!intent) { + return { + ok: false, + error: rateLimited('Too many pending capacity purchases', 3600), + } + } + } catch { + intent = await deps.x402CapacityPurchases.get(params.orgId, params.resourceId, params.requestHash) + if (!intent) { + return { ok: false, error: conflict('Purchase request conflict', 'X402_PURCHASE_CONFLICT') } + } + } + } + if (intent.idempotencyKey !== params.idempotencyKey) { + return { ok: false, error: conflict('Purchase request conflict', 'X402_PURCHASE_CONFLICT') } + } + + let cloudOrderId = intent.cloudOrderId + if (!cloudOrderId) { + const claimed = await deps.x402CapacityPurchases.claimCloudOrder( + intent.id, + new Date(Date.now() - X402_ORDER_CLAIM_TIMEOUT_MS), + ) + if (!claimed) { + const currentIntent = await deps.x402CapacityPurchases.get(params.orgId, params.resourceId, params.requestHash) + cloudOrderId = currentIntent?.cloudOrderId ?? null + if (!cloudOrderId) { + return { + ok: false, + error: conflict('Purchase initialization is in progress', 'X402_PURCHASE_IN_PROGRESS'), + } + } + } + } + if (!cloudOrderId) { + const customerLabel = await deps.cloudStore.getCustomerLabel(params.userId, params.orgId) + const order = await cloudRequest(deps, cloudBaseUrl, async ({ client, storeId }) => + unwrapCloudResponse( + await client.stores[':storeId'].orders.$post({ + param: { storeId }, + json: { + items: [{ productId: context.productId, priceId: context.priceId, quantity: 1 }], + currency: context.price.currency, + idempotencyKey: `zpan-x402-capacity:${intent.id}`, + deliveryCallbackUrl: `${params.origin}/api/store/webhook`, + target: { orgId: params.orgId, customerId: params.orgId, customerLabel }, + }, + }), + cloudOrderResponseSchema, + ), + ) + if (isCloudError(order)) { + await deps.x402CapacityPurchases.updateCloudState(intent.id, { status: 'created' }) + return { ok: false, error: capacityPurchaseCloudError(order) } + } + cloudOrderId = order.id + await deps.x402CapacityPurchases.updateCloudState(intent.id, { + cloudOrderId, + status: 'ordered', + }) + } + + const createQuote = async (idempotencyKey: string) => + cloudRequest(deps, cloudBaseUrl, async ({ client, storeId }) => + unwrapCloudResponse( + await createX402PaymentAttempt(client, { + storeId, + orderId: cloudOrderId, + idempotencyKey, + requestHash: params.requestHash, + resourceId: params.resourceId, + resourceDescription: `Add ${context.product.name} capacity to workspace`, + network: context.receiver.network, + asset: context.receiver.asset, + }), + x402QuoteCreateResponseSchema, + ), + ) + + let attempt: z.infer + let quoteWasReplaced = false + if (intent.cloudAttemptId) { + const found = await cloudRequest(deps, cloudBaseUrl, async ({ client, storeId }) => + unwrapCloudResponse( + await getX402PaymentAttempt(client, { + storeId, + orderId: cloudOrderId, + attemptId: intent.cloudAttemptId!, + }), + x402PaymentAttemptSchema, + ), + ) + if (isCloudError(found)) return { ok: false, error: capacityPurchaseCloudError(found) } + attempt = found + if (capacityAttemptExpired(attempt)) { + const replacement = await createQuote(await capacityQuoteRetryKey(intent.idempotencyKey, attempt.id)) + if (isCloudError(replacement)) return { ok: false, error: capacityPurchaseCloudError(replacement) } + attempt = replacement + quoteWasReplaced = true + await deps.x402CapacityPurchases.updateCloudState(intent.id, { + cloudOrderId, + cloudAttemptId: attempt.id, + status: attempt.status, + expiresAt: new Date(attempt.expiresAt), + }) + } + } else { + const quoted = await createQuote(params.idempotencyKey) + if (isCloudError(quoted)) return { ok: false, error: capacityPurchaseCloudError(quoted) } + attempt = quoted + await deps.x402CapacityPurchases.updateCloudState(intent.id, { + cloudOrderId, + cloudAttemptId: attempt.id, + status: attempt.status, + expiresAt: new Date(attempt.expiresAt), + }) + } + + if (!params.paymentSignature || quoteWasReplaced) { + if (attempt.status !== 'quoted') { + return terminalCapacityPurchaseOutcome(attempt) + } + return { + ok: true, + kind: 'payment_required', + paymentRequired: attempt.paymentRequired, + paymentRequiredHeader: attempt.paymentRequiredHeader, + } + } + + if (attempt.status === 'quoted') { + const verified = await cloudRequest(deps, cloudBaseUrl, async ({ client, storeId }) => + unwrapCloudResponse( + await verifyX402PaymentAttempt(client, { + storeId, + orderId: cloudOrderId, + attemptId: attempt.id, + paymentSignature: params.paymentSignature!, + requestHash: params.requestHash, + }), + x402PaymentAttemptSchema, + ), + ) + if (isCloudError(verified)) return { ok: false, error: capacityPurchaseCloudError(verified) } + attempt = verified + } + + if (attempt.status === 'verified') { + const settled = await cloudRequest(deps, cloudBaseUrl, async ({ client, storeId }) => + unwrapCloudResponse( + await settleX402PaymentAttempt(client, { + storeId, + orderId: cloudOrderId, + attemptId: attempt.id, + requestHash: params.requestHash, + }), + x402PaymentAttemptSchema, + ), + ) + if (isCloudError(settled)) return { ok: false, error: capacityPurchaseCloudError(settled) } + attempt = settled + } + + if (attempt.status === 'paid_pending_fulfillment') { + const delivered = await cloudRequest(deps, cloudBaseUrl, async ({ client, storeId }) => + unwrapCloudResponse( + await triggerX402PaymentAttemptFulfillment(client, { + storeId, + orderId: cloudOrderId, + attemptId: attempt.id, + }), + x402PaymentAttemptSchema, + ), + ) + if (isCloudError(delivered)) return { ok: false, error: capacityPurchaseCloudError(delivered) } + attempt = delivered + } + + await deps.x402CapacityPurchases.updateCloudState(intent.id, { + cloudOrderId, + cloudAttemptId: attempt.id, + status: attempt.status, + expiresAt: new Date(attempt.expiresAt), + }) + return terminalCapacityPurchaseOutcome(attempt) +} + +function terminalCapacityPurchaseOutcome(attempt: z.infer): CapacityPurchaseOutcome { + if (attempt.status === 'failed' || attempt.status === 'canceled' || attempt.status === 'expired') { + return { + ok: false, + error: conflict('Payment was not completed', `X402_PAYMENT_${attempt.status.toUpperCase()}`), + } + } + return { + ok: true, + kind: attempt.status === 'delivered' ? 'delivered' : 'pending', + attempt, + paymentResponseHeader: attempt.settlementResponseHeader, + } +} + export function listPackages(deps: Pick, cloudBaseUrl: string) { return listDeliverables(deps, cloudBaseUrl, 'zpan.plan') } diff --git a/shared/agent-oauth.ts b/shared/agent-oauth.ts index 07568f2b..4e5276f2 100644 --- a/shared/agent-oauth.ts +++ b/shared/agent-oauth.ts @@ -17,6 +17,7 @@ export const AGENT_OAUTH_RESOURCE_SCOPES = [ AuthorizationScope.SHARES_CREATE, AuthorizationScope.SHARES_DELETE, AuthorizationScope.QUOTA_READ, + AuthorizationScope.QUOTA_PURCHASE, AuthorizationScope.STORAGE_USAGE_READ, ] as const export const AGENT_OAUTH_SCOPES = [...AGENT_OAUTH_STANDARD_SCOPES, ...AGENT_OAUTH_RESOURCE_SCOPES] as const @@ -29,5 +30,6 @@ export const AGENT_OAUTH_SCOPE_DESCRIPTIONS: Record<(typeof AGENT_OAUTH_RESOURCE [AuthorizationScope.SHARES_CREATE]: 'Create public shares', [AuthorizationScope.SHARES_DELETE]: 'Revoke shares', [AuthorizationScope.QUOTA_READ]: 'Inspect workspace quota', + [AuthorizationScope.QUOTA_PURCHASE]: 'Purchase workspace storage capacity', [AuthorizationScope.STORAGE_USAGE_READ]: 'Inspect workspace storage usage', } diff --git a/shared/authorization.ts b/shared/authorization.ts index 2ecfb3f9..e6ffd70e 100644 --- a/shared/authorization.ts +++ b/shared/authorization.ts @@ -8,6 +8,7 @@ export const AuthorizationScope = { SHARES_CREATE: 'shares:create', SHARES_DELETE: 'shares:delete', QUOTA_READ: 'quota:read', + QUOTA_PURCHASE: 'quota:purchase', STORAGE_USAGE_READ: 'storage-usage:read', IMAGES_UPLOAD: 'images:upload', DOWNLOAD_TASKS_READ: 'download-tasks:read', diff --git a/shared/schemas/cloud-store-legacy.test.ts b/shared/schemas/cloud-store-legacy.test.ts new file mode 100644 index 00000000..00b4ff5d --- /dev/null +++ b/shared/schemas/cloud-store-legacy.test.ts @@ -0,0 +1,56 @@ +import { describe, expect, it } from 'vitest' +import { cloudOrderQuotaChangeSchema } from './cloud-store-legacy' + +function deliveryEvent(context: Record) { + return { + eventId: 'event-1', + eventType: 'commerce.order_item.fulfilled', + orderId: 'order-1', + orderItemId: 'item-1', + productId: 'product-1', + productName: 'Storage', + quantity: 1, + deliverable: { storageBytes: 1024 }, + target: { orgId: 'org-1' }, + context: { + storeId: 'store-1', + paymentProvider: 'x402', + ...context, + }, + occurredAt: '2026-07-31T00:00:00.000Z', + } +} + +describe('cloudOrderQuotaChangeSchema', () => { + it('accepts ISO billing periods', () => { + expect( + cloudOrderQuotaChangeSchema.safeParse( + deliveryEvent({ + billingPeriodStart: '2026-07-31T00:00:00.000Z', + billingPeriodEnd: '2026-08-31T00:00:00.000Z', + }), + ).success, + ).toBe(true) + }) + + it('rejects malformed billing periods', () => { + expect( + cloudOrderQuotaChangeSchema.safeParse( + deliveryEvent({ + billingPeriodStart: 'not-a-date', + billingPeriodEnd: '2026-08-31T00:00:00.000Z', + }), + ).success, + ).toBe(false) + }) + + it('rejects incomplete billing periods', () => { + expect( + cloudOrderQuotaChangeSchema.safeParse( + deliveryEvent({ + billingPeriodStart: '2026-07-31T00:00:00.000Z', + }), + ).success, + ).toBe(false) + }) +}) diff --git a/shared/schemas/cloud-store-legacy.ts b/shared/schemas/cloud-store-legacy.ts index fe2a3598..f784e477 100644 --- a/shared/schemas/cloud-store-legacy.ts +++ b/shared/schemas/cloud-store-legacy.ts @@ -55,18 +55,29 @@ const storeDeliveryEventSchema = z quantity: z.number().int().positive(), deliverable: z.record(z.string(), z.unknown()), target: z.record(z.string(), z.unknown()).nullable(), - context: z.object({ - storeId: z.string().min(1), - paymentProvider: z.enum(['stripe', 'gift_card', 'credits']).nullable(), - stripePriceId: z.string().nullable().optional(), - stripePriceLookupKey: z.string().nullable().optional(), - stripePriceRecurring: z.unknown().optional(), - stripePriceMetadata: z.record(z.string(), z.string()).optional(), - stripeSubscriptionId: z.string().nullable().optional(), - stripeInvoiceId: z.string().nullable().optional(), - billingPeriodStart: z.string().nullable().optional(), - billingPeriodEnd: z.string().nullable().optional(), - }), + context: z + .object({ + storeId: z.string().min(1), + paymentProvider: z.enum(['stripe', 'gift_card', 'credits', 'x402']).nullable(), + providerTransactionId: z.string().nullable().optional(), + x402AuditContext: z.record(z.string(), z.unknown()).nullable().optional(), + stripePriceId: z.string().nullable().optional(), + stripePriceLookupKey: z.string().nullable().optional(), + stripePriceRecurring: z.unknown().optional(), + stripePriceMetadata: z.record(z.string(), z.string()).optional(), + stripeSubscriptionId: z.string().nullable().optional(), + stripeInvoiceId: z.string().nullable().optional(), + billingPeriodStart: z.string().datetime().nullable().optional(), + billingPeriodEnd: z.string().datetime().nullable().optional(), + }) + .superRefine((context, ctx) => { + if (Boolean(context.billingPeriodStart) === Boolean(context.billingPeriodEnd)) return + ctx.addIssue({ + code: z.ZodIssueCode.custom, + path: [context.billingPeriodStart ? 'billingPeriodEnd' : 'billingPeriodStart'], + message: 'Billing period start and end must be provided together', + }) + }), occurredAt: z.string().min(1), }) .superRefine((event, ctx) => { @@ -104,6 +115,16 @@ function targetOrgId(target: Record | null) { function sourceId(event: z.infer) { const orgId = targetOrgId(event.target) if (event.context.stripeSubscriptionId) return `stripe_subscription:${event.context.stripeSubscriptionId}:${orgId}` + if (event.context.billingPeriodStart && event.context.billingPeriodEnd) { + return [ + event.context.paymentProvider ?? 'commerce', + 'period', + event.productId, + event.context.billingPeriodStart, + event.context.billingPeriodEnd, + orgId, + ].join(':') + } return event.orderId } @@ -128,7 +149,12 @@ export const cloudOrderQuotaChangeSchema = z.union([ storageBytes: numberDeliverableValue(event.deliverable, 'storageBytes'), trafficBytes: numberDeliverableValue(event.deliverable, 'trafficBytes'), trafficOveragePriceCents: optionalNumberDeliverableValue(event.deliverable, 'trafficOveragePriceCents'), - source: event.context.stripeSubscriptionId ? 'stripe_subscription' : 'stripe', + source: event.context.billingPeriodStart ? 'commerce_period' : (event.context.paymentProvider ?? 'commerce'), + entitlementType: event.context.billingPeriodStart ? ('plan' as const) : ('grant' as const), + startsAt: event.context.billingPeriodStart ?? event.occurredAt, + paymentProvider: event.context.paymentProvider, + providerTransactionId: event.context.providerTransactionId, + x402AuditContext: event.context.x402AuditContext, packageId: event.productId, packageName: stringDeliverableValue(event.deliverable, 'packageName') ?? event.productName, occurredAt: event.occurredAt, diff --git a/shared/schemas/oauth-resource.ts b/shared/schemas/oauth-resource.ts index b0837d5b..d805f957 100644 --- a/shared/schemas/oauth-resource.ts +++ b/shared/schemas/oauth-resource.ts @@ -14,5 +14,6 @@ export const oauthResourceScopeLabels = { [AuthorizationScope.SHARES_CREATE]: 'settings.agentAccess.scope.sharesCreate', [AuthorizationScope.SHARES_DELETE]: 'settings.agentAccess.scope.sharesDelete', [AuthorizationScope.QUOTA_READ]: 'settings.agentAccess.scope.quotaRead', + [AuthorizationScope.QUOTA_PURCHASE]: 'settings.agentAccess.scope.quotaPurchase', [AuthorizationScope.STORAGE_USAGE_READ]: 'settings.agentAccess.scope.storageUsageRead', } as const satisfies Record diff --git a/src/components/oauth-buttons.test.ts b/src/components/oauth-buttons.test.ts index 601be6ac..8217f191 100644 --- a/src/components/oauth-buttons.test.ts +++ b/src/components/oauth-buttons.test.ts @@ -2,6 +2,7 @@ import { BUILTIN_PROVIDER_IDS, OAuthProviderMeta } from '@shared/oauth-providers import type { SiteConfig } from '@shared/schemas' import { describe, expect, it } from 'vitest' import { hasOAuthProviderIcon } from '@/components/oauth-provider-icon' +import { absoluteAuthCallbackURL } from '@/lib/auth-callback' // OAuthButtons is a React rendering component. The project has no jsdom or // @testing-library/react setup, so we cannot render it here. @@ -91,22 +92,24 @@ describe('OAuthButtons — provider data contract', () => { }) // --------------------------------------------------------------------------- -// OAuth sign-in handler — callbackURL defaults to '/files' and can continue +// OAuth sign-in handler — callbackURL defaults to the current origin's /files and can continue // an authorization request supplied by the sign-in page. // --------------------------------------------------------------------------- +const PREVIEW_ORIGIN = 'https://feat-x402-paid-agent-uploads-zpan.saltbo.workers.dev' + function buildOAuthCallbackUrl(callbackURL = '/files'): string { - return callbackURL + return absoluteAuthCallbackURL(callbackURL, PREVIEW_ORIGIN) } describe('OAuthButtons — OAuth callback URL', () => { - it('defaults the OAuth sign-in callback URL to "/files"', () => { - expect(buildOAuthCallbackUrl()).toBe('/files') + it('defaults the OAuth sign-in callback URL to the absolute current-origin files URL', () => { + expect(buildOAuthCallbackUrl()).toBe(`${PREVIEW_ORIGIN}/files`) }) it('uses the supplied authorization continuation', () => { expect(buildOAuthCallbackUrl('/api/auth/oauth2/authorize?state=oauth-state')).toBe( - '/api/auth/oauth2/authorize?state=oauth-state', + `${PREVIEW_ORIGIN}/api/auth/oauth2/authorize?state=oauth-state`, ) }) }) diff --git a/src/components/oauth-buttons.tsx b/src/components/oauth-buttons.tsx index 8a95b328..18970314 100644 --- a/src/components/oauth-buttons.tsx +++ b/src/components/oauth-buttons.tsx @@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next' import { OAuthProviderIcon } from '@/components/oauth-provider-icon' import { Button } from '@/components/ui/button' import { useSiteConfig } from '@/hooks/use-site-config' +import { absoluteAuthCallbackURL } from '@/lib/auth-callback' import { authClient } from '@/lib/auth-client' export function useOAuthProviders() { @@ -29,7 +30,10 @@ export function OAuthButtons({ async function handleOAuth(providerId: string) { setError('') onSignIn?.() - const result = await authClient.signIn.social({ provider: providerId, callbackURL }) + const result = await authClient.signIn.social({ + provider: providerId, + callbackURL: absoluteAuthCallbackURL(callbackURL, window.location.origin), + }) if (result.error) { setError(result.error.message ?? t('auth.signInFailed')) } diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 10613273..a82de5cd 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -1218,6 +1218,7 @@ "settings.agentAccess.scope.sharesCreate": "Shares: create shares", "settings.agentAccess.scope.sharesDelete": "Shares: revoke shares", "settings.agentAccess.scope.quotaRead": "Quota: read workspace quota", + "settings.agentAccess.scope.quotaPurchase": "Quota: purchase workspace storage capacity", "settings.agentAccess.scope.storageUsageRead": "Storage usage: read workspace usage", "settings.agentAccess.colWorkspace": "Workspace", "settings.agentAccess.colScopes": "Scopes", diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index 788e25b7..8d03274d 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -1218,6 +1218,7 @@ "settings.agentAccess.scope.sharesCreate": "分享:创建分享", "settings.agentAccess.scope.sharesDelete": "分享:撤销分享", "settings.agentAccess.scope.quotaRead": "配额:读取工作空间配额", + "settings.agentAccess.scope.quotaPurchase": "配额:购买工作空间存储容量", "settings.agentAccess.scope.storageUsageRead": "存储用量:读取工作空间用量", "settings.agentAccess.colWorkspace": "工作空间", "settings.agentAccess.colScopes": "权限", diff --git a/src/lib/auth-callback.test.ts b/src/lib/auth-callback.test.ts new file mode 100644 index 00000000..f04dc623 --- /dev/null +++ b/src/lib/auth-callback.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, it } from 'vitest' +import { absoluteAuthCallbackURL } from './auth-callback' + +const PREVIEW_ORIGIN = 'https://feat-x402-paid-agent-uploads-zpan.saltbo.workers.dev' + +describe('absoluteAuthCallbackURL', () => { + it('resolves a site path against the current preview origin', () => { + expect(absoluteAuthCallbackURL('/files', PREVIEW_ORIGIN)).toBe(`${PREVIEW_ORIGIN}/files`) + }) + + it('preserves a same-origin OAuth authorization continuation', () => { + const continuation = '/api/auth/oauth2/authorize?state=oauth-state&scope=objects%3Aread' + expect(absoluteAuthCallbackURL(continuation, PREVIEW_ORIGIN)).toBe(`${PREVIEW_ORIGIN}${continuation}`) + }) + + it('preserves an already absolute same-origin callback', () => { + expect(absoluteAuthCallbackURL(`${PREVIEW_ORIGIN}/files`, PREVIEW_ORIGIN)).toBe(`${PREVIEW_ORIGIN}/files`) + }) + + it.each([ + 'https://attacker.example/files', + '//attacker.example/files', + 'http://[invalid', + ])('falls back to the current origin for unsafe callback %s', (callbackURL) => { + expect(absoluteAuthCallbackURL(callbackURL, PREVIEW_ORIGIN)).toBe(`${PREVIEW_ORIGIN}/files`) + }) +}) diff --git a/src/lib/auth-callback.ts b/src/lib/auth-callback.ts new file mode 100644 index 00000000..845b4435 --- /dev/null +++ b/src/lib/auth-callback.ts @@ -0,0 +1,11 @@ +const DEFAULT_AUTH_CALLBACK_PATH = '/files' + +export function absoluteAuthCallbackURL(callbackURL: string, origin: string): string { + const fallback = new URL(DEFAULT_AUTH_CALLBACK_PATH, origin).toString() + try { + const resolved = new URL(callbackURL, origin) + return resolved.origin === new URL(origin).origin ? resolved.toString() : fallback + } catch { + return fallback + } +} diff --git a/src/routes/(auth)/sign-in.test.ts b/src/routes/(auth)/sign-in.test.ts index 38219182..e5a61f11 100644 --- a/src/routes/(auth)/sign-in.test.ts +++ b/src/routes/(auth)/sign-in.test.ts @@ -1,5 +1,6 @@ import { SignupMode } from '@shared/constants' import { describe, expect, it } from 'vitest' +import { absoluteAuthCallbackURL } from '@/lib/auth-callback' import { isCredentialLoginMethod } from '@/lib/last-login-method' // SignIn is a React rendering component. The project has no jsdom or @@ -88,11 +89,12 @@ describe('SignIn — sign-up link visibility', () => { // Default callback URL used when no continuation is present // --------------------------------------------------------------------------- -const DEFAULT_SIGN_IN_CALLBACK_URL = '/files' +const PREVIEW_ORIGIN = 'https://feat-x402-paid-agent-uploads-zpan.saltbo.workers.dev' +const DEFAULT_SIGN_IN_CALLBACK_URL = absoluteAuthCallbackURL('/files', PREVIEW_ORIGIN) describe('SignIn — default callback URL', () => { - it('uses "/files" for an ordinary sign-in', () => { - expect(DEFAULT_SIGN_IN_CALLBACK_URL).toBe('/files') + it('uses the absolute current-origin files URL for an ordinary sign-in', () => { + expect(DEFAULT_SIGN_IN_CALLBACK_URL).toBe(`${PREVIEW_ORIGIN}/files`) }) }) diff --git a/src/routes/(auth)/sign-in.tsx b/src/routes/(auth)/sign-in.tsx index a2f52b7a..dc93a60d 100644 --- a/src/routes/(auth)/sign-in.tsx +++ b/src/routes/(auth)/sign-in.tsx @@ -10,6 +10,7 @@ import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Separator } from '@/components/ui/separator' import { useSiteConfig } from '@/hooks/use-site-config' +import { absoluteAuthCallbackURL } from '@/lib/auth-callback' import { authClient, signIn } from '@/lib/auth-client' import { isCredentialLoginMethod } from '@/lib/last-login-method' import { clearSignInRedirect, loadSignInRedirect } from '@/lib/sign-in-redirect' @@ -24,7 +25,7 @@ function SignIn() { const [redirectTo] = useState(() => loadSignInRedirect(window.location.search, window.location.origin, window.sessionStorage), ) - const callbackURL = redirectTo ?? '/files' + const callbackURL = absoluteAuthCallbackURL(redirectTo ?? '/files', window.location.origin) const { data: siteConfig } = useSiteConfig() const authSignupMode = siteConfig?.auth.signupMode const captcha = siteConfig?.auth.captcha diff --git a/src/routes/(auth)/sign-up.test.ts b/src/routes/(auth)/sign-up.test.ts index 289dd909..3e756e22 100644 --- a/src/routes/(auth)/sign-up.test.ts +++ b/src/routes/(auth)/sign-up.test.ts @@ -1,5 +1,8 @@ import { SignupMode } from '@shared/constants' import { describe, expect, it } from 'vitest' +import { absoluteAuthCallbackURL } from '@/lib/auth-callback' + +const PREVIEW_ORIGIN = 'https://feat-x402-paid-agent-uploads-zpan.saltbo.workers.dev' // SignUp is a React rendering component. The project has no jsdom or // @testing-library/react setup, so we cannot render it here. @@ -86,7 +89,7 @@ function buildSignUpPayload( name: fields.name, email: fields.email, password: fields.password, - callbackURL: '/files', + callbackURL: absoluteAuthCallbackURL('/files', PREVIEW_ORIGIN), ...(authSignupMode === SignupMode.INVITE_ONLY ? { inviteCode: fields.inviteCode } : {}), ...(authSignupMode === SignupMode.CLOSED && fields.siteInvitationToken ? { siteInvitationToken: fields.siteInvitationToken } @@ -134,12 +137,12 @@ describe('SignUp — submission payload construction', () => { expect(payload.siteInvitationToken).toBeUndefined() }) - it('always sets callbackURL to "/files"', () => { + it('always sets callbackURL to the absolute current-origin files URL', () => { const payloadOpen = buildSignUpPayload(SignupMode.OPEN, baseFields) const payloadInvite = buildSignUpPayload(SignupMode.INVITE_ONLY, baseFields) - expect(payloadOpen.callbackURL).toBe('/files') - expect(payloadInvite.callbackURL).toBe('/files') + expect(payloadOpen.callbackURL).toBe(`${PREVIEW_ORIGIN}/files`) + expect(payloadInvite.callbackURL).toBe(`${PREVIEW_ORIGIN}/files`) }) it('includes all base fields in payload', () => { diff --git a/src/routes/(auth)/sign-up.tsx b/src/routes/(auth)/sign-up.tsx index fbd0d03c..d2833561 100644 --- a/src/routes/(auth)/sign-up.tsx +++ b/src/routes/(auth)/sign-up.tsx @@ -12,6 +12,7 @@ import { Label } from '@/components/ui/label' import { Separator } from '@/components/ui/separator' import { useSiteConfig } from '@/hooks/use-site-config' import { ApiError, getSiteInvitation } from '@/lib/api' +import { absoluteAuthCallbackURL } from '@/lib/auth-callback' import { signUp } from '@/lib/auth-client' export const Route = createFileRoute('/(auth)/sign-up')({ @@ -151,7 +152,7 @@ function SignUp() { name: '', email, password, - callbackURL: '/files', + callbackURL: absoluteAuthCallbackURL('/files', window.location.origin), fetchOptions: captcha?.enabled ? { headers: { 'x-captcha-response': captchaToken } } : undefined, ...(authSignupMode === SignupMode.INVITE_ONLY ? { inviteCode } : {}), ...(hasValidInvite && invite ? { siteInvitationToken: invite } : {}), diff --git a/vite.config.ts b/vite.config.ts index 496f0f15..27485605 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,6 +10,10 @@ const appPort = Number(process.env.E2E_APP_PORT ?? 5185) const apiPort = Number(process.env.E2E_API_PORT ?? 8222) const appVersion = resolveAppVersion() const appCommit = resolveAppCommit() +const configuredDevHosts = (process.env.ZPAN_DEV_ALLOWED_HOSTS ?? '') + .split(',') + .map((host) => host.trim()) + .filter(Boolean) export default defineConfig(({ mode }) => ({ define: { @@ -53,7 +57,12 @@ export default defineConfig(({ mode }) => ({ }, server: { port: appPort, - allowedHosts: process.env.E2E_BASE_URL ? true : undefined, + allowedHosts: + process.env.E2E_BASE_URL + ? true + : mode === 'development' + ? ['.trycloudflare.com', ...configuredDevHosts] + : undefined, ...(mode === 'node' ? { proxy: {