diff --git a/packages/ingest-types/src/index.ts b/packages/ingest-types/src/index.ts index 84d3d936a67..164eba21809 100644 --- a/packages/ingest-types/src/index.ts +++ b/packages/ingest-types/src/index.ts @@ -12,11 +12,6 @@ export type { AddAssetTagsErrors, AddAssetTagsResponse, AddAssetTagsResponses, - AdminDeleteHubWorkflowData, - AdminDeleteHubWorkflowError, - AdminDeleteHubWorkflowErrors, - AdminDeleteHubWorkflowResponse, - AdminDeleteHubWorkflowResponses, Asset, AssetCreated, AssetCreatedWritable, @@ -89,11 +84,6 @@ export type { CreateAssetFromHashResponses, CreateAssetResponse, CreateAssetResponses, - CreateDeletionRequestData, - CreateDeletionRequestError, - CreateDeletionRequestErrors, - CreateDeletionRequestResponse, - CreateDeletionRequestResponses, CreateDesktopLoginCodeData, CreateDesktopLoginCodeError, CreateDesktopLoginCodeErrors, @@ -170,9 +160,6 @@ export type { DeleteHubWorkflowErrors, DeleteHubWorkflowResponse, DeleteHubWorkflowResponses, - DeleteMonitoringTasksSubpathData, - DeleteMonitoringTasksSubpathErrors, - DeleteMonitoringTasksSubpathResponses, DeleteSecretData, DeleteSecretError, DeleteSecretErrors, @@ -199,8 +186,6 @@ export type { DeleteWorkspaceErrors, DeleteWorkspaceResponse, DeleteWorkspaceResponses, - DeletionRequest, - DeletionStatus, DesktopLoginCodeCreateRequest, DesktopLoginCodeCreateResponse, DesktopLoginCodeExchangeRequest, @@ -212,14 +197,6 @@ export type { DownloadExportErrors, DownloadExportResponse, DownloadExportResponses, - EnsureWorkspaceBillingLegacySnapshot, - EnsureWorkspaceBillingProvisionedData, - EnsureWorkspaceBillingProvisionedError, - EnsureWorkspaceBillingProvisionedErrors, - EnsureWorkspaceBillingProvisionedRequest, - EnsureWorkspaceBillingProvisionedResponse, - EnsureWorkspaceBillingProvisionedResponse2, - EnsureWorkspaceBillingProvisionedResponses, ErrorResponse, ExchangeDesktopLoginCodeData, ExchangeDesktopLoginCodeError, @@ -242,7 +219,6 @@ export type { ExportDownloadUrlResponse, FeedbackRequest, FeedbackResponse, - FeedbackResponseWritable, ForkWorkflowData, ForkWorkflowError, ForkWorkflowErrors, @@ -305,11 +281,6 @@ export type { GetCustomNodeProxyData, GetCustomNodeProxyErrors, GetCustomNodeProxyResponses, - GetDeletionRequestData, - GetDeletionRequestError, - GetDeletionRequestErrors, - GetDeletionRequestResponse, - GetDeletionRequestResponses, GetEmbeddingsData, GetEmbeddingsResponse, GetEmbeddingsResponses, @@ -319,11 +290,6 @@ export type { GetFeaturesData, GetFeaturesResponse, GetFeaturesResponses, - GetFilesData, - GetFilesError, - GetFilesErrors, - GetFilesResponse, - GetFilesResponses, GetGlobalSubgraphData, GetGlobalSubgraphError, GetGlobalSubgraphErrors, @@ -342,11 +308,6 @@ export type { GetHistoryData, GetHistoryError, GetHistoryErrors, - GetHistoryEventsData, - GetHistoryEventsError, - GetHistoryEventsErrors, - GetHistoryEventsResponse, - GetHistoryEventsResponses, GetHistoryForPromptData, GetHistoryForPromptError, GetHistoryForPromptErrors, @@ -409,11 +370,6 @@ export type { GetLegacyUserdataV2Errors, GetLegacyViewMetadataData, GetLegacyViewMetadataErrors, - GetLogsData, - GetLogsError, - GetLogsErrors, - GetLogsResponse, - GetLogsResponses, GetMaskLayersData, GetMaskLayersError, GetMaskLayersErrors, @@ -431,12 +387,6 @@ export type { GetModelsInFolderErrors, GetModelsInFolderResponse, GetModelsInFolderResponses, - GetMonitoringTasksData, - GetMonitoringTasksErrors, - GetMonitoringTasksResponses, - GetMonitoringTasksSubpathData, - GetMonitoringTasksSubpathErrors, - GetMonitoringTasksSubpathResponses, GetMyHubProfileData, GetMyHubProfileError, GetMyHubProfileErrors, @@ -480,12 +430,6 @@ export type { GetPaymentPortalErrors, GetPaymentPortalResponse, GetPaymentPortalResponses, - GetPprofData, - GetPprofProfileData, - GetPprofProfileResponses, - GetPprofResponses, - GetPprofTraceData, - GetPprofTraceResponses, GetPromptInfoData, GetPromptInfoError, GetPromptInfoErrors, @@ -598,7 +542,6 @@ export type { HistoryDetailEntry, HistoryDetailResponse, HistoryEntry, - HistoryEventRequest, HistoryManageRequest, HistoryResponse, HubAssetUploadUrlRequest, @@ -620,11 +563,6 @@ export type { ImportPublishedAssetsResponse, ImportPublishedAssetsResponse2, ImportPublishedAssetsResponses, - InsertDynamicConfigData, - InsertDynamicConfigError, - InsertDynamicConfigErrors, - InsertDynamicConfigResponse, - InsertDynamicConfigResponses, InterruptJobData, InterruptJobError, InterruptJobErrors, @@ -672,13 +610,6 @@ export type { ListJobsErrors, ListJobsResponse, ListJobsResponses, - ListLinkedFirebaseUidsData, - ListLinkedFirebaseUidsError, - ListLinkedFirebaseUidsErrors, - ListLinkedFirebaseUidsRequest, - ListLinkedFirebaseUidsResponse, - ListLinkedFirebaseUidsResponse2, - ListLinkedFirebaseUidsResponses, ListMembersResponse, ListSecretProvidersData, ListSecretProvidersError, @@ -728,7 +659,6 @@ export type { ListWorkspacesResponse, ListWorkspacesResponse2, ListWorkspacesResponses, - LogsResponse, ManageHistoryData, ManageHistoryError, ManageHistoryErrors, @@ -759,8 +689,6 @@ export type { OAuthTokenError, OAuthTokenResponse, PaginationInfo, - PartnerUsageRequest, - PartnerUsageResponse, PaymentPortalRequest, PaymentPortalResponse, PendingInvite, @@ -776,9 +704,6 @@ export type { PostCustomNodeProxyData, PostCustomNodeProxyErrors, PostCustomNodeProxyResponses, - PostMonitoringTasksSubpathData, - PostMonitoringTasksSubpathErrors, - PostMonitoringTasksSubpathResponses, PostOAuthAuthorizeData, PostOAuthAuthorizeError, PostOAuthAuthorizeErrors, @@ -794,8 +719,6 @@ export type { PostOAuthTokenErrors, PostOAuthTokenResponse, PostOAuthTokenResponses, - PostPprofSymbolData, - PostPprofSymbolResponses, PostUserdataFileData, PostUserdataFileError, PostUserdataFileErrors, @@ -837,12 +760,6 @@ export type { RedeemDesktopLoginCodeErrors, RedeemDesktopLoginCodeResponse, RedeemDesktopLoginCodeResponses, - ReleaseDeletionHoldData, - ReleaseDeletionHoldError, - ReleaseDeletionHoldErrors, - ReleaseDeletionHoldResponse, - ReleaseDeletionHoldResponses, - ReleaseHoldResponse, RemoveAssetTagsData, RemoveAssetTagsError, RemoveAssetTagsErrors, @@ -853,16 +770,6 @@ export type { RemoveWorkspaceMemberErrors, RemoveWorkspaceMemberResponse, RemoveWorkspaceMemberResponses, - ReportHistoryEventData, - ReportHistoryEventError, - ReportHistoryEventErrors, - ReportHistoryEventResponse, - ReportHistoryEventResponses, - ReportPartnerUsageData, - ReportPartnerUsageError, - ReportPartnerUsageErrors, - ReportPartnerUsageResponse, - ReportPartnerUsageResponses, ResubscribeData, ResubscribeError, ResubscribeErrors, @@ -887,15 +794,6 @@ export type { SeedAssetsData, SeedAssetsResponse, SeedAssetsResponses, - SetReviewStatusData, - SetReviewStatusError, - SetReviewStatusErrors, - SetReviewStatusRequest, - SetReviewStatusResponse, - SetReviewStatusResponse2, - SetReviewStatusResponses, - ShortLinkRedirectData, - ShortLinkRedirectErrors, SubmitFeedbackData, SubmitFeedbackError, SubmitFeedbackErrors, @@ -912,13 +810,6 @@ export type { SubscribeToLogsResponses, SubscriptionDuration, SubscriptionTier, - SyncApiKeyData, - SyncApiKeyError, - SyncApiKeyErrors, - SyncApiKeyRequest, - SyncApiKeyResponse, - SyncApiKeyResponse2, - SyncApiKeyResponses, SystemStatsResponse, TagInfo, TagsModificationResponse, @@ -940,12 +831,6 @@ export type { UpdateHubProfileRequest, UpdateHubProfileResponse, UpdateHubProfileResponses, - UpdateHubWorkflowData, - UpdateHubWorkflowError, - UpdateHubWorkflowErrors, - UpdateHubWorkflowRequest, - UpdateHubWorkflowResponse, - UpdateHubWorkflowResponses, UpdateMemberRoleRequest, UpdateMultipleSettingsData, UpdateMultipleSettingsError, @@ -963,11 +848,6 @@ export type { UpdateSettingByIdErrors, UpdateSettingByIdResponse, UpdateSettingByIdResponses, - UpdateSubscriptionCacheData, - UpdateSubscriptionCacheError, - UpdateSubscriptionCacheErrors, - UpdateSubscriptionCacheResponse, - UpdateSubscriptionCacheResponses, UpdateWorkflowData, UpdateWorkflowError, UpdateWorkflowErrors, @@ -999,13 +879,6 @@ export type { UserResponse, ValidationError, ValidationResult, - VerifyApiKeyRequest, - VerifyApiKeyResponse, - VerifyWorkspaceApiKeyData, - VerifyWorkspaceApiKeyError, - VerifyWorkspaceApiKeyErrors, - VerifyWorkspaceApiKeyResponse, - VerifyWorkspaceApiKeyResponses, ViewFileData, ViewFileError, ViewFileErrors, diff --git a/packages/ingest-types/src/types.gen.ts b/packages/ingest-types/src/types.gen.ts index 19f04d9742c..a201f833332 100644 --- a/packages/ingest-types/src/types.gen.ts +++ b/packages/ingest-types/src/types.gen.ts @@ -5,202 +5,160 @@ export type ClientOptions = { } /** - * Response indicating whether a Hub username is available. + * Workspace entity annotated with the requesting user's role. */ -export type HubUsernameCheckResponse = { - /** - * The username that was checked. - */ - username: string - /** - * Whether the username is available for the caller's workspace. - */ - available: boolean +export type WorkspaceWithRole = { /** - * Up to 5 available alternative usernames (only present when unavailable). + * When the workspace was created */ - suggestions?: Array + created_at: string + id: string /** - * If the username format is invalid, describes the format requirement. + * When the user joined the workspace (same as created_at for the workspace creator) */ - validation_error?: string + joined_at: string + name: string + role: 'owner' | 'member' + subscription_tier?: SubscriptionTier + type: 'personal' | 'team' } /** - * Response containing a signed upload URL and the target asset path. + * Subscription tier (uppercase to match comfy-api) */ -export type HubAssetUploadUrlResponse = { - /** - * Presigned R2 URL for uploading the file via PUT. - */ - upload_url: string - /** - * The public URL where the file will be accessible after upload. - */ - public_url: string - /** - * Signed token to pass in the publish request. Has a server-determined TTL. - */ - token: string -} +export type SubscriptionTier = + | 'FREE' + | 'STANDARD' + | 'CREATOR' + | 'PRO' + | 'FOUNDERS_EDITION' + | 'TEAM' /** - * Request body for requesting a signed upload URL for a Hub asset. + * Abbreviated workspace metadata used in list responses. */ -export type HubAssetUploadUrlRequest = { - /** - * Original filename for display purposes. Not used in the storage key. - */ - filename: string - /** - * MIME type of the file (e.g. "image/jpeg", "video/mp4"). Validated against a whitelist; the canonical file extension is derived from this value. - * - */ - content_type: string +export type WorkspaceSummary = { + id: string + name: string + type: 'personal' | 'team' } /** - * Partial update for a published hub workflow (admin moderation). All fields are optional. Semantics match UpdateHubProfileRequest / avatar_token: - * - * * field omitted or null — leave unchanged - * * string field = "" — clear (for clearable string fields) - * * array field = [] — clear the list - * * any other value — set to the provided value - * - * Array fields use full-replacement (PUT) semantics when a value is supplied. The two single-value thumbnail token fields accept only upload tokens (not existing URLs) since omitting them already expresses "keep the current value". - * Backend note: cleared string columns are persisted as the empty string "" in the Ent schema (description, thumbnail_url, thumbnail_comparison_url, tutorial_url). thumbnail_type is the only true SQL-nullable column but is not clearable via this endpoint. - * + * Metadata for a workspace-scoped API key (secret is never returned). */ -export type UpdateHubWorkflowRequest = { - /** - * Display name. Not clearable. Null/omit leaves unchanged; empty string is invalid. - */ - name?: string | null +export type WorkspaceApiKeyInfo = { /** - * Workflow description. Send "" to clear. Null/omit leaves unchanged. + * When the key was created */ - description?: string | null + created_at: string /** - * Full replacement of tag slugs. Must exist in hub_labels. Send [] to clear. Null/omit leaves unchanged. + * User-provided description of the key's purpose. Limit is byte-based (UTF-8 encoding); 5000 bytes equals 5000 ASCII characters or fewer multi-byte characters. */ - tags?: Array | null + description: string /** - * Full replacement of model slugs. Must exist in hub_labels. Send [] to clear. Null/omit leaves unchanged. + * When the key expires (if set) */ - models?: Array | null + expires_at?: string /** - * Full replacement of custom_node slugs. Must exist in hub_labels. Send [] to clear. Null/omit leaves unchanged. + * API key ID */ - custom_nodes?: Array | null + id: string /** - * Tutorial URL. Send "" to clear. Null/omit leaves unchanged. + * First 8 chars after prefix for display */ - tutorial_url?: string | null + key_prefix: string /** - * Thumbnail kind. Null/omit leaves unchanged; not clearable via this endpoint. If set to image_comparison, both the thumbnail and comparison thumbnail must resolve to a value on the stored record after this update is applied (either already present and not being cleared, or supplied as a token in this request). - * + * Last time the key was used */ - thumbnail_type?: 'image' | 'video' | 'image_comparison' + last_used_at?: string /** - * Token from POST /api/hub/assets/upload-url for a newly uploaded thumbnail. Null/omit leaves the existing thumbnail unchanged. Send "" to clear. (PATCH does not accept an existing public URL here — to keep the current thumbnail, simply omit the field.) - * + * User-provided label */ - thumbnail_token?: string | null + name: string /** - * Token from POST /api/hub/assets/upload-url for a newly uploaded comparison thumbnail. Null/omit leaves unchanged. Send "" to clear. (PATCH does not accept an existing public URL here — to keep the current comparison thumbnail, simply omit the field.) - * + * When the key was revoked (if revoked) */ - thumbnail_comparison_token?: string | null + revoked_at?: string /** - * Full replacement of sample images. Each element is either a token from /api/hub/assets/upload-url or an existing public URL. Send [] to clear. Null/omit leaves unchanged. - * + * User who created this key */ - sample_image_tokens_or_urls?: Array | null + user_id: string /** - * Admin-only full replacement of the hub_workflow_detail.metadata JSON object. Null/omit leaves unchanged. Send {} to clear all keys. Accepts arbitrary JSON (size, vram, open_source, media_type, logos, etc.). - * + * Workspace this key belongs to */ - metadata?: { - [key: string]: unknown - } | null + workspace_id: string } /** - * Request body for publishing or updating a workflow on the Hub. + * Full workspace entity with configuration and ownership details. */ -export type PublishHubWorkflowRequest = { - /** - * Username of the hub profile to publish under. The authenticated user must belong to the workspace that owns this profile. - */ - username: string - /** - * Display name for the published workflow on the hub. - */ +export type Workspace = { + created_at: string + id: string name: string - /** - * Userdata path of the workflow file (e.g. "workflows/my-flow.json"). - */ - workflow_filename: string - /** - * IDs of assets (inputs and models) to snapshot. - */ - asset_ids: Array - /** - * Workflow description for the hub listing. - */ - description?: string - /** - * Searchable tag slugs. Must exist in hub_labels. - */ - tags?: Array - /** - * Model slugs. Must exist in hub_labels. - */ - models?: Array - /** - * Custom node slugs. Must exist in hub_labels. - */ - custom_nodes?: Array - /** - * URL to a tutorial for this workflow. - */ - tutorial_url?: string - /** - * Arbitrary metadata (size, vram, open_source, etc.). Reserved keys (extended_description, meta_description, how_to_use, suggested_use_cases, faq_items, content_template) are backend-managed and will be stripped if supplied. - */ - metadata?: { + type: 'personal' | 'team' +} + +/** + * Metadata for a single workflow version. + */ +export type WorkflowVersionResponse = { + created_at: string + created_by: string + id: string + latest_version: number + version: number +} + +/** + * Full workflow version including the serialized workflow JSON. + */ +export type WorkflowVersionContentResponse = { + created_at: string + created_by: string + dependency_asset_ids?: Array + id: string + version: number + workflow_json: { [key: string]: unknown } - thumbnail_type?: 'image' | 'video' | 'image_comparison' - /** - * Token (from /api/hub/assets/upload-url) for a new upload, or an existing public URL from the previous published version. Omit to have no thumbnail. - * - */ - thumbnail_token_or_url?: string - /** - * Token or existing public URL from the previous published version. Omit to have no comparison image. - * - */ - thumbnail_comparison_token_or_url?: string - /** - * Array of tokens or existing public URLs from the previous published version. Full replacement (PUT semantics). Omit or pass [] to have no sample images. - * - */ - sample_image_tokens_or_urls?: Array } /** - * Paginated list of Hub workflows matching search criteria. + * Full workflow entity including metadata and version history. */ -export type HubWorkflowListResponse = { - /** - * Array of HubWorkflowSummary (default) or HubWorkflowDetail (when detail=true). - */ - workflows: Array +export type WorkflowResponse = { + created_at: string + created_by: string + default_view?: 'workflow' | 'app' + description?: string + forked_from?: WorkflowForkedFrom + id: string + latest_version: number + name?: string + updated_at: string +} + +/** + * Reference to the parent workflow from which this workflow was forked. + */ +export type WorkflowForkedFrom = { + workflow_id?: string + workflow_version_id?: string +} + +/** + * Publishing metadata for a workflow shared to the Hub. + */ +export type WorkflowPublishInfo = { /** - * Cursor for the next page, empty if no more results. + * Published assets (inputs and models). */ - next_cursor?: string + assets: Array + listed: boolean + publish_time?: string | null + share_id: string + workflow_id: string } /** @@ -211,255 +169,210 @@ export type AssetInfo = { * Asset identifier. */ id: string - name: string /** - * Signed URL for previewing the asset. + * Whether the caller already owns this asset. */ - preview_url: string - storage_url: string + in_library: boolean /** * Whether this asset is a model. */ model: boolean + name: string /** - * Whether this is a public (platform-provided) asset. + * Signed URL for previewing the asset. */ - public: boolean + preview_url: string /** - * Whether the caller already owns this asset. + * Whether this is a public (platform-provided) asset. */ - in_library: boolean + public: boolean + storage_url: string } /** - * Full Hub workflow detail including versions, assets, and statistics. + * Paginated list of saved workflows. */ -export type HubWorkflowDetail = { - share_id: string - workflow_id: string - name: string - status: HubWorkflowStatus - description?: string - tags?: Array - thumbnail_type?: 'image' | 'video' | 'image_comparison' - thumbnail_url?: string - thumbnail_comparison_url?: string - models?: Array - custom_nodes?: Array - tutorial_url?: string - metadata?: { - [key: string]: unknown - } - sample_image_urls?: Array - publish_time?: string | null - workflow_json: { - [key: string]: unknown - } - /** - * Published assets. Each asset's id is the published asset ID (not the original private asset ID). - */ - assets: Array - profile: HubProfileSummary +export type WorkflowListResponse = { + data: Array + pagination: PaginationInfo } /** - * Abbreviated Hub profile used in workflow listings. + * Pagination metadata included in list responses. Supports both legacy + * offset/limit pagination and cursor-based pagination. When cursor-based + * pagination is used, `next_cursor` is the primary pagination token and + * `offset`/`total` may be zero. + * */ -export type HubProfileSummary = { - username: string - display_name?: string +export type PaginationInfo = { /** - * Public URL of the profile avatar image. + * Whether more items are available beyond this page */ - avatar_url?: string -} - -/** - * Reference to a Hub label by ID. - */ -export type LabelRef = { + has_more: boolean /** - * Slug identifier (e.g. "video-generation", "flux"). + * Items per page */ - name: string + limit: number /** - * Human-readable display name (e.g. "Video Generation", "Flux"). + * Opaque cursor for the next page. Pass this value as the `after` + * query parameter on the next request. Empty or absent when there + * are no more results. + * */ - display_name: string + next_cursor?: string + /** + * Current offset (0-based). Deprecated: use cursor-based pagination. + * + * @deprecated + */ + offset: number + /** + * Total number of items matching filters (may be 0 when using cursor pagination) + */ + total: number } /** - * Public workflow status. NULL in the database is represented as pending in API responses. + * Response containing assets associated with a workflow. */ -export type HubWorkflowStatus = - | 'pending' - | 'approved' - | 'rejected' - | 'deprecated' +export type WorkflowApiAssetsResponse = { + assets: Array +} /** - * Abbreviated Hub workflow metadata used in search and listing results. + * Request body for querying assets associated with a workflow. */ -export type HubWorkflowSummary = { - share_id: string - name: string - status: HubWorkflowStatus - description?: string - tags?: Array - models?: Array - custom_nodes?: Array - thumbnail_type?: 'image' | 'video' | 'image_comparison' - thumbnail_url?: string - thumbnail_comparison_url?: string - publish_time?: string | null - profile: HubProfileSummary - metadata?: { +export type WorkflowApiAssetsRequest = { + workflow_api_json: { [key: string]: unknown } - tutorial_url?: string - sample_image_urls?: Array } /** - * Metadata for a single Hub label. + * Result of validating a set of asset operations. */ -export type HubLabelInfo = { - /** - * Slug identifier. - */ - name: string - /** - * Human-readable display name. - */ - display_name: string +export type ValidationResult = { /** - * Optional description of the label. + * Blocking validation errors that prevent download */ - description?: string + errors?: Array /** - * Label category. + * Overall validation status (true if all checks passed) */ - type: 'tag' | 'model' | 'custom_node' -} - -/** - * List of available Hub labels for categorizing workflows. - */ -export type HubLabelListResponse = { + is_valid: boolean /** - * Available labels filtered by type (or all if no type specified). + * Non-blocking validation warnings (informational only) */ - labels: Array + warnings?: Array } /** - * Entry in the curated workflow template gallery shown on the home page. + * Details of a single validation error encountered during asset operations. */ -export type HubWorkflowTemplateEntry = { - /** - * Slug identifier for the template - */ - name: string - title: string - status: HubWorkflowStatus - description?: string - tags?: Array - models?: Array - requiresCustomNodes?: Array - thumbnailVariant?: string - mediaType?: string - mediaSubtype?: string - /** - * Workflow asset size in bytes. - */ - size?: number - /** - * Approximate VRAM requirement in bytes. - */ - vram?: number +export type ValidationError = { /** - * Usage count reported upstream. + * Machine-readable error code */ - usage?: number + code: string /** - * Search ranking score reported upstream. + * Field that failed validation */ - searchRank?: number + field: string /** - * Whether the template belongs to a module marked as essential. + * Human-readable error message */ - isEssential?: boolean - openSource?: boolean - profile?: HubProfileSummary - tutorialUrl?: string - logos?: Array<{ - [key: string]: unknown - }> + message: string +} + +/** + * User information response + */ +export type UserResponse = { /** - * Publication date in YYYY-MM-DD format + * Firebase UID of the authenticated user */ - date?: string - io?: { - inputs?: Array<{ - [key: string]: unknown - }> - outputs?: Array<{ - [key: string]: unknown - }> - } - includeOnDistributions?: Array + id: string /** - * Public URL of the primary thumbnail + * User status (always "active" for authenticated users) */ - thumbnailUrl?: string + status: string +} + +/** + * User data listing entry with file metadata (path, size, modification time). + */ +export type UserDataResponseFull = { /** - * Public URL of the comparison thumbnail + * UNIX timestamp of the last modification in milliseconds. */ - thumbnailComparisonUrl?: string + modified?: number + path?: string + size?: number +} + +/** + * Request body for updating an existing workspace's settings. + */ +export type UpdateWorkspaceRequest = { /** - * Share ID for linking to the hub workflow detail + * New display name for the workspace */ - shareId?: string + name?: string +} + +/** + * Request body for updating an existing saved workflow. + */ +export type UpdateWorkflowRequest = { /** - * AI-generated extended description of the workflow + * New default view mode */ - extendedDescription?: string + default_view?: 'workflow' | 'app' /** - * AI-generated SEO meta description (under 160 chars) + * New description */ - metaDescription?: string + description?: string /** - * AI-generated step-by-step usage instructions + * New display name */ - howToUse?: Array + name?: string +} + +/** + * Request body for updating an existing user secret. + */ +export type UpdateSecretRequest = { /** - * AI-generated suggested use cases + * New name for the secret */ - suggestedUseCases?: Array + name?: string /** - * AI-generated FAQ items + * New secret value (API key, token, etc.) */ - faqItems?: Array<{ - question: string - answer: string - }> + secret_value?: string +} + +/** + * Request body for changing a workspace member's role. + */ +export type UpdateMemberRoleRequest = { /** - * Content template used for generation (tutorial, showcase, comparison, breakthrough) + * The role to assign to the member */ - contentTemplate?: string + role: 'owner' | 'member' } /** * Request body for updating an existing Hub profile. */ export type UpdateHubProfileRequest = { - display_name?: string - description?: string /** * Token (from /api/hub/assets/upload-url) for a new avatar image. Omit or send null to leave unchanged; send empty string "" to remove. * */ avatar_token?: string | null + description?: string + display_name?: string /** * List of website URLs. */ @@ -467,665 +380,656 @@ export type UpdateHubProfileRequest = { } /** - * Request body for creating a new Hub profile. + * Credit-stop ladder for the pricing slider (BE-1254). Returned by GET /api/billing/plans for every workspace regardless of the caller's token or workspace type (the personal/team distinction was removed); omitted only when the catalog defines no stops. */ -export type CreateHubProfileRequest = { - /** - * ID of the workspace to create the hub profile for. The authenticated user must belong to this workspace. - */ - workspace_id: string - /** - * Unique URL-safe slug for the hub profile. Immutable after creation. - */ - username: string - display_name?: string - description?: string - /** - * Token (from /api/hub/assets/upload-url) for an avatar image. Omit to have no avatar. - * - */ - avatar_token?: string +export type TeamCreditStops = { /** - * List of website URLs. + * Index into stops[] for the slider's initial position */ - website_urls?: Array + default_stop_index: number + stops: Array } /** - * Full public profile for a Hub creator. + * Pre/post-discount price for a team credit stop, in cents. */ -export type HubProfile = { - username: string - display_name?: string - description?: string +export type TeamCreditStopPrice = { /** - * Public URL of the profile avatar image. + * Pre-discount (struck-through) price in cents */ - avatar_url?: string + list_price_cents: number /** - * List of website URLs. + * Post-discount (bold) price in cents */ - website_urls?: Array -} - -/** - * Response after importing published workflow assets. - */ -export type ImportPublishedAssetsResponse = { - assets: Array + price_cents: number } /** - * Request body for importing assets from a published workflow. + * A selectable preset on the team pricing slider. Echoed on subscribe via + * team_credit_stop_id; the backend owns the resolved amounts. credits is a + * RAW monthly credit count (not cents). Save% is derived by the FE as + * (list_price_cents - price_cents) / list_price_cents. + * */ -export type ImportPublishedAssetsRequest = { +export type TeamCreditStop = { /** - * IDs of published assets (inputs and models) to import. + * Raw monthly credit count granted at this stop */ - published_asset_ids: Array + credits: number /** - * Optional. Share ID of the published workflow these assets belong to. - * When provided (non-null, non-empty): all published_asset_ids must - * belong to this share's workflow version; returns - * 400/CodeInvalidAssets if the share is not found or any asset does - * not belong to it. - * When omitted, null, or empty string: no share-scoped validation is - * performed and the assets are validated only against global rules - * (legacy behaviour, preserved for clients that have not yet adopted - * share_id). - * + * Stable stop id echoed on subscribe (e.g. "team_700") */ - share_id?: string | null + id: string + monthly: TeamCreditStopPrice + yearly: TeamCreditStopPrice } /** - * Full detail of a publicly published workflow on the Hub. + * The team credit stop a workspace is currently subscribed to: the + * per-workspace slider choice recorded at subscribe time + * (workspace_subscriptions.team_credit_stop_id). Amounts are owned by the + * catalog, not the subscription row. Returned on GET /api/billing/status + * for per-credit Team plans (BE-1254). + * */ -export type PublishedWorkflowDetail = { - share_id: string - workflow_id: string +export type TeamCreditStopSummary = { /** - * Human-readable workflow name. + * Raw monthly credit count granted at this stop */ - name: string - listed: boolean - publish_time?: string | null + credits_monthly: number /** - * The workflow JSON content at publish time. + * Stable stop id (e.g. "team_200") */ - workflow_json: { - [key: string]: unknown - } + id: string /** - * Published assets with their library status for the caller. + * Monthly USD commitment for this stop */ - assets: Array -} - -/** - * Response containing assets associated with a workflow. - */ -export type WorkflowApiAssetsResponse = { - assets: Array -} - -/** - * Request body for querying assets associated with a workflow. - */ -export type WorkflowApiAssetsRequest = { - workflow_api_json: { - [key: string]: unknown - } + stop_usd: number } /** - * Request body for publishing workflow assets to the Hub. + * Paginated list of background tasks for the authenticated user. */ -export type PublishWorkflowAssetsRequest = { +export type TasksListResponse = { + pagination: PaginationInfo /** - * IDs of assets (inputs and models) to snapshot. + * Array of tasks ordered by create_time */ - asset_ids: Array + tasks: Array } /** - * Publishing metadata for a workflow shared to the Hub. + * Task data for list views */ -export type WorkflowPublishInfo = { - workflow_id: string - share_id: string - publish_time?: string | null - listed: boolean +export type TaskEntry = { /** - * Published assets (inputs and models). + * When task completed or failed (null if not finished) */ - assets: Array -} - -/** - * Request body for forking an existing workflow into the user's account. - */ -export type ForkWorkflowRequest = { + completed_at?: string /** - * Version number to fork from + * Task creation timestamp */ - source_version: number + create_time: string /** - * Name for the forked workflow + * Unique task identifier */ - name?: string -} - -/** - * Full workflow version including the serialized workflow JSON. - */ -export type WorkflowVersionContentResponse = { id: string - version: number - workflow_json: { - [key: string]: unknown - } - created_by: string - created_at: string - dependency_asset_ids?: Array + /** + * When task execution started (null if not started) + */ + started_at?: string + /** + * Current task status + */ + status: 'created' | 'running' | 'completed' | 'failed' + /** + * Task type name (e.g., model_upload) + */ + task_name: string } /** - * Metadata for a single workflow version. + * Full task details including payload and result */ -export type WorkflowVersionResponse = { +export type TaskResponse = { + /** + * When task completed or failed (null if not finished) + */ + completed_at?: string + /** + * Task creation timestamp + */ + create_time: string + /** + * Error message on failure (null if not failed) + */ + error_message?: string + /** + * Unique task identifier + */ id: string - version: number - latest_version: number - created_by: string - created_at: string -} - -/** - * Request body for creating a new version of a saved workflow. - */ -export type CreateWorkflowVersionRequest = { /** - * The version number this change is based on (for optimistic concurrency) + * Caller-provided key for idempotent task creation */ - base_version: number + idempotency_key: string /** - * The updated ComfyUI workflow JSON + * Task input data */ - workflow_json: { + payload: { [key: string]: unknown } -} - -/** - * Paginated list of saved workflows. - */ -export type WorkflowListResponse = { - data: Array - pagination: PaginationInfo -} - -/** - * Pagination metadata included in list responses. Supports both legacy - * offset/limit pagination and cursor-based pagination. When cursor-based - * pagination is used, `next_cursor` is the primary pagination token and - * `offset`/`total` may be zero. - * - */ -export type PaginationInfo = { /** - * Current offset (0-based). Deprecated: use cursor-based pagination. - * - * @deprecated + * Task output data (null if not completed) */ - offset: number + result?: { + [key: string]: unknown + } /** - * Items per page + * When task execution started (null if not started) */ - limit: number + started_at?: string /** - * Total number of items matching filters (may be 0 when using cursor pagination) + * Current task status */ - total: number + status: 'created' | 'running' | 'completed' | 'failed' /** - * Whether more items are available beyond this page + * Task type name (e.g., model_upload) */ - has_more: boolean + task_name: string /** - * Opaque cursor for the next page. Pass this value as the `after` - * query parameter on the next request. Empty or absent when there - * are no more results. - * + * Task last update timestamp */ - next_cursor?: string + update_time: string } /** - * Reference to the parent workflow from which this workflow was forked. + * Response after adding, updating, or removing tags on an asset. */ -export type WorkflowForkedFrom = { - workflow_id?: string - workflow_version_id?: string +export type TagsModificationResponse = { + /** + * Tags that were successfully added (for add operation) + */ + added?: Array + /** + * Tags that were already present (for add operation) + */ + already_present?: Array + /** + * Tags that were not present (for remove operation) + */ + not_present?: Array + /** + * Tags that were successfully removed (for remove operation) + */ + removed?: Array + /** + * All tags on the asset after the operation + */ + total_tags: Array } /** - * Full workflow entity including metadata and version history. + * Metadata for a single tag that can be applied to assets. */ -export type WorkflowResponse = { - id: string - name?: string - description?: string - default_view?: 'workflow' | 'app' - latest_version: number - forked_from?: WorkflowForkedFrom - created_by: string - created_at: string - updated_at: string +export type TagInfo = { + /** + * Number of assets using this tag + */ + count: number + /** + * Tag name + */ + name: string } /** - * Request body for updating an existing saved workflow. + * System statistics response */ -export type UpdateWorkflowRequest = { +export type SystemStatsResponse = { + devices: Array<{ + /** + * Device name + */ + name: string + /** + * Device type + */ + type: string + /** + * Free VRAM in bytes + */ + vram_free?: number + /** + * Total VRAM in bytes + */ + vram_total?: number + }> + system: { + /** + * Command line arguments + */ + argv: Array + /** + * Cloud ingest service version (commit hash) + */ + cloud_version?: string + /** + * ComfyUI frontend version (commit hash or tag) + */ + comfyui_frontend_version?: string + /** + * ComfyUI version + */ + comfyui_version: string + /** + * How this ComfyUI instance is deployed (e.g. cloud, local-git, local-portable, local-desktop) + */ + deploy_environment?: string + /** + * Whether using embedded Python + */ + embedded_python: boolean + /** + * Operating system + */ + os: string + /** + * Python version + */ + python_version: string + /** + * PyTorch version + */ + pytorch_version: string + /** + * Free RAM in bytes + */ + ram_free: number + /** + * Total RAM in bytes + */ + ram_total: number + /** + * Workflow templates version + */ + workflow_templates_version?: string + } +} + +/** + * Billing period (uppercase to match comfy-api) + */ +export type SubscriptionDuration = 'MONTHLY' | 'ANNUAL' + +/** + * Response after successfully subscribing to a billing plan. + */ +export type SubscribeResponse = { /** - * New display name + * Billing operation ID to poll for status via GET /api/billing/ops/{id} */ - name?: string + billing_op_id: string /** - * New description + * When the subscription became/becomes active (present when status=subscribed or pending_payment) */ - description?: string + effective_at?: string /** - * New default view mode + * URL to redirect user to add payment method (present when status=needs_payment_method) */ - default_view?: 'workflow' | 'app' + payment_method_url?: string + /** + * Status of the subscription operation: + * - subscribed: Subscription is active immediately + * - needs_payment_method: User must add payment method via payment_method_url + * - pending_payment: Upgrade initiated, waiting for payment to complete + * + */ + status: 'subscribed' | 'needs_payment_method' | 'pending_payment' } /** - * Request body for creating a new saved workflow. + * Request body for subscribing a workspace to a billing plan. */ -export type CreateWorkflowRequest = { +export type SubscribeRequest = { /** - * Display name for the workflow + * Billing cycle for the team slider contract. When present it must be + * consistent with plan_slug (monthly -> team_per_credit_monthly, + * yearly -> team_per_credit_annual). + * */ - name?: string + billing_cycle?: 'monthly' | 'yearly' /** - * Description of the workflow + * URL to redirect if user cancels the payment method flow. + * If not provided, return_url is used for both success and cancel. + * */ - description?: string + cancel_url?: string /** - * Default view mode + * Client-provided key to prevent duplicate operations. + * If a billing op with this key already exists, returns the existing op instead of creating a new one. + * */ - default_view?: 'workflow' | 'app' + idempotency_key?: string /** - * The ComfyUI workflow JSON + * Target plan slug to subscribe to */ - workflow_json: { - [key: string]: unknown - } + plan_slug: string /** - * ID of the source workflow if forked + * URL to redirect after payment method is added successfully. + * Required if workspace has no payment method on file. + * */ - forked_from_workflow_id?: string + return_url?: string /** - * ID of the source workflow version if forked + * Selected team credit-stop preset id (e.g. "team_700") for the + * per-credit Team plan. Required when subscribing to a per-credit Team + * plan; rejected for non-team plans. The backend owns the resolved + * amounts (credits/price) for the stop. + * */ - forked_from_workflow_version_id?: string + team_credit_stop_id?: string } /** - * Request body for forwarding a comfy-api audit/history event. Identify the target workspace by either user_id (cloud resolves the user's personal workspace via the converged identity, BE-1047) or an explicit workspace_id. At least one must be provided; workspace_id wins when both are set. + * User secret metadata (the secret value itself is never returned after creation). */ -export type HistoryEventRequest = { - /** - * Originating comfy-api user (Firebase UID). The cloud resolves this to the user's personal workspace. Required unless workspace_id is set. - */ - user_id?: string - /** - * Cloud workspace ID to attach the history event to. Optional when user_id is provided. - */ - workspace_id?: string +export type SecretResponse = { /** - * Cloud billing event_type string for the user-facing history event. + * When the secret was created */ - event_type: string + created_at: string /** - * Unique event ID for idempotency. + * Unique identifier for the secret */ - event_id: string + id: string /** - * Event-specific properties copied from comfy-api audit_logs.params. + * When the secret was last used for decryption */ - params?: { - [key: string]: unknown - } + last_used_at?: string /** - * Optional credential class that produced the event. + * User-provided label for the secret */ - auth_method?: 'api_key' | 'bearer_token' + name: string /** - * Optional originating comfy-api customer ID. + * Provider identifier (e.g., huggingface, civitai) */ - customer_ref?: string + provider?: string /** - * Optional source event timestamp; stored for forward compatibility. + * When the secret was last updated */ - timestamp?: string + updated_at: string } /** - * Response after recording partner usage data. + * The providers available to the authenticated user in the current workspace. */ -export type PartnerUsageResponse = { - /** - * Result status (e.g., "ok") - */ - status: string +export type SecretProvidersResponse = { + data: Array } /** - * Request body for reporting partner resource usage (admin endpoint). + * A provider the user may configure a secret for. The shape is deliberately minimal (identifier only) and reserved for future per-provider fields such as sub-keys. */ -export type PartnerUsageRequest = { - /** - * The workspace ID to bill usage against - */ - workspace_id: string - /** - * The user who triggered the usage (for attribution) - */ - user_id?: string +export type SecretProvider = { /** - * Unique transaction ID for idempotency + * Provider identifier (e.g., huggingface, civitai, runway, gemini) */ - transaction_id: string + id: string +} + +/** + * List of user secrets with metadata only. + */ +export type SecretListResponse = { + data: Array +} + +/** + * Response after accepting a resubscribe request. + */ +export type ResubscribeResponse = { /** - * Type of usage event (e.g., "api_node_usage") + * Billing operation ID to poll for status via GET /api/billing/ops/{id} */ - event_type: string + billing_op_id: string /** - * When the usage occurred. Defaults to current time if omitted. + * Human-readable confirmation message */ - timestamp?: string + message?: string /** - * Event-specific properties for billing + * Subscription outcome. `active` means the resubscribe committed (the scheduled cancellation was undone); `pending` means the operation is still executing — poll the billing operation for the final outcome. */ - properties?: { - [key: string]: unknown - } + status: 'active' | 'pending' } /** - * Status of an asynchronous billing operation. + * Request body for reactivating a previously cancelled subscription. */ -export type BillingOpStatusResponse = { +export type ResubscribeRequest = { /** - * Unique identifier for the billing operation - */ - id: string - /** - * Current status of the operation - */ - status: 'pending' | 'succeeded' | 'failed' - /** - * Error message if status is failed - */ - error_message?: string - /** - * When the operation was initiated - */ - started_at: string - /** - * When the operation completed (success or failure) + * Client-provided key to prevent duplicate operations. + * If a billing op with this key already exists, returns the existing op instead of creating a new one. + * */ - completed_at?: string + idempotency_key?: string } /** - * Response after successfully purchasing a credit top-up. + * Response after a queue management action (delete or clear). */ -export type CreateTopupResponse = { - /** - * Billing operation ID to poll for status via GET /api/billing/ops/{id} - */ - billing_op_id: string - /** - * Unique identifier for the top-up request (same as billing_op_id, deprecated) - */ - topup_id: string +export type QueueManageResponse = { /** - * Current status of the top-up + * Whether the queue was cleared */ - status: 'pending' | 'completed' | 'failed' + cleared?: boolean /** - * Amount being charged in cents + * Array of job IDs that were successfully cancelled */ - amount_cents: number + deleted?: Array } /** - * Request body for purchasing a one-time credit top-up. + * Request to manage queue operations */ -export type CreateTopupRequest = { +export type QueueManageRequest = { /** - * Amount to charge and grant as credits (in cents). Minimum $5.00. + * If true, clear all pending jobs from the queue */ - amount_cents: number + clear?: boolean /** - * Client-provided key to prevent duplicate operations. - * If a billing op with this key already exists, returns the existing op instead of creating a new one. - * + * Array of job IDs to cancel; pending and running jobs transition to cancelled */ - idempotency_key?: string + delete?: Array } /** - * Response containing a redirect URL to the payment portal. + * Queue information with pending and running jobs */ -export type PaymentPortalResponse = { +export type QueueInfo = { /** - * Stripe Billing Portal URL + * Array of pending job items (ordered by creation time, oldest first) */ - url: string -} - -/** - * Request body for generating a payment portal session URL. - */ -export type PaymentPortalRequest = { + queue_pending?: Array<[unknown, unknown, unknown, unknown, unknown]> /** - * URL to redirect after the user exits the portal + * Array of currently running job items */ - return_url?: string + queue_running?: Array<[unknown, unknown, unknown, unknown, unknown]> } /** - * Response after accepting a resubscribe request. + * Full detail of a publicly published workflow on the Hub. */ -export type ResubscribeResponse = { +export type PublishedWorkflowDetail = { /** - * Billing operation ID to poll for status via GET /api/billing/ops/{id} + * Published assets with their library status for the caller. */ - billing_op_id: string + assets: Array + listed: boolean /** - * Subscription outcome. `active` means the resubscribe committed (the scheduled cancellation was undone); `pending` means the operation is still executing — poll the billing operation for the final outcome. + * Human-readable workflow name. */ - status: 'active' | 'pending' + name: string + publish_time?: string | null + share_id: string + workflow_id: string /** - * Human-readable confirmation message + * The workflow JSON content at publish time. */ - message?: string + workflow_json: { + [key: string]: unknown + } } /** - * Request body for reactivating a previously cancelled subscription. + * Request body for publishing workflow assets to the Hub. */ -export type ResubscribeRequest = { +export type PublishWorkflowAssetsRequest = { /** - * Client-provided key to prevent duplicate operations. - * If a billing op with this key already exists, returns the existing op instead of creating a new one. - * + * IDs of assets (inputs and models) to snapshot. */ - idempotency_key?: string + asset_ids: Array } /** - * Response after successfully cancelling a subscription. + * Request body for publishing or updating a workflow on the Hub. */ -export type CancelSubscriptionResponse = { +export type PublishHubWorkflowRequest = { /** - * Billing operation ID to poll for status via GET /api/billing/ops/{id} + * IDs of assets (inputs and models) to snapshot. */ - billing_op_id: string + asset_ids: Array /** - * The date when the subscription will end (end of current billing period) + * Custom node slugs. Must exist in hub_labels. */ - cancel_at: string -} - -/** - * Request body for cancelling the current subscription. - */ -export type CancelSubscriptionRequest = { + custom_nodes?: Array /** - * Client-provided key to prevent duplicate operations. - * If a billing op with this key already exists, returns the existing op instead of creating a new one. - * + * Workflow description for the hub listing. */ - idempotency_key?: string -} - -/** - * Response after successfully subscribing to a billing plan. - */ -export type SubscribeResponse = { + description?: string /** - * Billing operation ID to poll for status via GET /api/billing/ops/{id} + * Arbitrary metadata (size, vram, open_source, etc.). Reserved keys (extended_description, meta_description, how_to_use, suggested_use_cases, faq_items, content_template) are backend-managed and will be stripped if supplied. */ - billing_op_id: string + metadata?: { + [key: string]: unknown + } /** - * Status of the subscription operation: - * - subscribed: Subscription is active immediately - * - needs_payment_method: User must add payment method via payment_method_url - * - pending_payment: Upgrade initiated, waiting for payment to complete - * + * Model slugs. Must exist in hub_labels. */ - status: 'subscribed' | 'needs_payment_method' | 'pending_payment' + models?: Array /** - * When the subscription became/becomes active (present when status=subscribed or pending_payment) + * Display name for the published workflow on the hub. */ - effective_at?: string + name: string /** - * URL to redirect user to add payment method (present when status=needs_payment_method) + * Array of tokens or existing public URLs from the previous published version. Full replacement (PUT semantics). Omit or pass [] to have no sample images. + * */ - payment_method_url?: string -} - -/** - * Request body for subscribing a workspace to a billing plan. - */ -export type SubscribeRequest = { + sample_image_tokens_or_urls?: Array /** - * Target plan slug to subscribe to + * Searchable tag slugs. Must exist in hub_labels. */ - plan_slug: string + tags?: Array /** - * Selected team credit-stop preset id (e.g. "team_700") for the - * per-credit Team plan. Required when subscribing to a per-credit Team - * plan; rejected for non-team plans. The backend owns the resolved - * amounts (credits/price) for the stop. + * Token or existing public URL from the previous published version. Omit to have no comparison image. * */ - team_credit_stop_id?: string + thumbnail_comparison_token_or_url?: string /** - * Billing cycle for the team slider contract. When present it must be - * consistent with plan_slug (monthly -> team_per_credit_monthly, - * yearly -> team_per_credit_annual). + * Token (from /api/hub/assets/upload-url) for a new upload, or an existing public URL from the previous published version. Omit to have no thumbnail. * */ - billing_cycle?: 'monthly' | 'yearly' + thumbnail_token_or_url?: string + thumbnail_type?: 'image' | 'video' | 'image_comparison' /** - * Client-provided key to prevent duplicate operations. - * If a billing op with this key already exists, returns the existing op instead of creating a new one. - * + * URL to a tutorial for this workflow. */ - idempotency_key?: string + tutorial_url?: string /** - * URL to redirect after payment method is added successfully. - * Required if workspace has no payment method on file. - * + * Username of the hub profile to publish under. The authenticated user must belong to the workspace that owns this profile. */ - return_url?: string + username: string /** - * URL to redirect if user cancels the payment method flow. - * If not provided, return_url is used for both success and cancel. - * + * Userdata path of the workflow file (e.g. "workflows/my-flow.json"). */ - cancel_url?: string + workflow_filename: string } /** - * Plan information for preview display + * Response returned after successfully queuing a workflow prompt. */ -export type PreviewPlanInfo = { - /** - * Plan slug - */ - slug: string - tier: SubscriptionTier - duration: SubscriptionDuration - /** - * Per-seat price in cents - */ - price_cents: number +export type PromptResponse = { /** - * Per-seat credits in cents + * Any errors in the nodes of the prompt */ - credits_cents: number - seat_summary: PlanSeatSummary + node_errors?: { + [key: string]: unknown + } /** - * Current billing period start (only for current_plan) + * Priority number in the queue */ - period_start?: string + number?: number /** - * Current billing period end (only for current_plan) + * Unique identifier for the prompt execution */ - period_end?: string + prompt_id?: string } /** - * Summary of seat costs based on current workspace members + * Request body for submitting a ComfyUI workflow prompt for execution. */ -export type PlanSeatSummary = { +export type PromptRequest = { /** - * Total number of seats (owner + members) that would be charged + * Extra data to be associated with the prompt */ - seat_count: number + extra_data?: { + [key: string]: unknown + } /** - * Total cost for all seats in cents + * If true, adds the prompt to the front of the queue */ - total_cost_cents: number + front?: boolean /** - * Total credits granted for all seats in cents + * Priority number for the queue (lower numbers have higher priority) */ - total_credits_cents: number -} - -/** - * Billing period (uppercase to match comfy-api) - */ -export type SubscriptionDuration = 'MONTHLY' | 'ANNUAL' - -/** - * Subscription tier (uppercase to match comfy-api) + number?: number + /** + * List of node names to execute + */ + partial_execution_targets?: Array + /** + * The workflow graph to execute + */ + prompt: { + [key: string]: unknown + } + /** + * UUID identifying the cloud workflow entity to associate with this job + */ + workflow_id?: string + /** + * UUID identifying the workflow version to associate with this job + */ + workflow_version_id?: string +} + +/** + * Metadata about the currently running and queued prompts. */ -export type SubscriptionTier = - | 'FREE' - | 'STANDARD' - | 'CREATOR' - | 'PRO' - | 'FOUNDERS_EDITION' - | 'TEAM' +export type PromptInfo = { + exec_info?: { + /** + * Number of items remaining in the queue + */ + queue_remaining?: number + } +} + +/** + * Error response for ComfyUI prompt execution. + */ +export type PromptErrorResponse = { + [key: string]: unknown +} /** * Itemized cost preview for a pending subscription change. @@ -1136,110 +1040,100 @@ export type PreviewSubscribeResponse = { */ allowed: boolean /** - * Reason why the change is not allowed (only present if allowed=false) + * Amount that will be charged at next billing period in cents */ - reason?: string + cost_next_period_cents: number /** - * Type of subscription transition + * Amount to charge today in cents (0 for downgrades) */ - transition_type: - | 'new_subscription' - | 'upgrade' - | 'downgrade' - | 'duration_change' + cost_today_cents: number /** - * When the change takes effect + * Credits that will be granted at next billing period in cents */ - effective_at: string + credits_next_period_cents: number /** - * Whether the change takes effect immediately (true) or at period end (false) + * Credits granted today in cents (prorated for mid-period upgrades) */ - is_immediate: boolean + credits_today_cents: number + current_plan?: PreviewPlanInfo /** - * Amount to charge today in cents (0 for downgrades) + * When the change takes effect */ - cost_today_cents: number + effective_at: string /** - * Amount that will be charged at next billing period in cents + * Whether the change takes effect immediately (true) or at period end (false) */ - cost_next_period_cents: number + is_immediate: boolean + new_plan: PreviewPlanInfo /** - * Credits granted today in cents (prorated for mid-period upgrades) + * Reason why the change is not allowed (only present if allowed=false) */ - credits_today_cents: number + reason?: string /** - * Credits that will be granted at next billing period in cents + * Type of subscription transition */ - credits_next_period_cents: number - current_plan?: PreviewPlanInfo - new_plan: PreviewPlanInfo + transition_type: + | 'new_subscription' + | 'upgrade' + | 'downgrade' + | 'duration_change' } /** - * Request body for previewing the cost of a plan subscription change. + * Summary of seat costs based on current workspace members */ -export type PreviewSubscribeRequest = { +export type PlanSeatSummary = { /** - * Target plan slug to preview subscribing to + * Total number of seats (owner + members) that would be charged */ - plan_slug: string -} - -/** - * List of available billing plans for subscription. - */ -export type BillingPlansResponse = { + seat_count: number /** - * Current plan slug if subscribed + * Total cost for all seats in cents */ - current_plan_slug?: string - plans: Array - team_credit_stops?: TeamCreditStops + total_cost_cents: number + /** + * Total credits granted for all seats in cents + */ + total_credits_cents: number } /** - * Pre/post-discount price for a team credit stop, in cents. + * Plan information for preview display */ -export type TeamCreditStopPrice = { +export type PreviewPlanInfo = { /** - * Pre-discount (struck-through) price in cents + * Per-seat credits in cents */ - list_price_cents: number + credits_cents: number + duration: SubscriptionDuration /** - * Post-discount (bold) price in cents + * Current billing period end (only for current_plan) */ - price_cents: number -} - -/** - * A selectable preset on the team pricing slider. Echoed on subscribe via - * team_credit_stop_id; the backend owns the resolved amounts. credits is a - * RAW monthly credit count (not cents). Save% is derived by the FE as - * (list_price_cents - price_cents) / list_price_cents. - * - */ -export type TeamCreditStop = { + period_end?: string /** - * Stable stop id echoed on subscribe (e.g. "team_700") + * Current billing period start (only for current_plan) */ - id: string + period_start?: string /** - * Raw monthly credit count granted at this stop + * Per-seat price in cents */ - credits: number - monthly: TeamCreditStopPrice - yearly: TeamCreditStopPrice + price_cents: number + seat_summary: PlanSeatSummary + /** + * Plan slug + */ + slug: string + tier: SubscriptionTier } /** - * Credit-stop ladder for the pricing slider (BE-1254). Returned by GET /api/billing/plans for every workspace regardless of the caller's token or workspace type (the personal/team distinction was removed); omitted only when the catalog defines no stops. + * Request body for previewing the cost of a plan subscription change. */ -export type TeamCreditStops = { +export type PreviewSubscribeRequest = { /** - * Index into stops[] for the slider's initial position + * Target plan slug to preview subscribing to */ - default_stop_index: number - stops: Array + plan_slug: string } /** @@ -1267,315 +1161,249 @@ export type PlanAvailability = { * Billing plan details including pricing, limits, and features. */ export type Plan = { - /** - * Plan identifier (e.g., "pro-monthly", "team-standard-annual") - */ - slug: string - tier: SubscriptionTier - duration: SubscriptionDuration - /** - * Per-member price in cents (base + one seat) - */ - price_cents: number + availability: PlanAvailability /** * Per-member credits in cents (base + one seat) */ credits_cents: number + duration: SubscriptionDuration /** * Maximum number of seats allowed for this plan */ max_seats: number - availability: PlanAvailability + /** + * Per-member price in cents (base + one seat) + */ + price_cents: number seat_summary: PlanSeatSummary + /** + * Plan identifier (e.g., "pro-monthly", "team-standard-annual") + */ + slug: string + tier: SubscriptionTier } /** - * The team credit stop a workspace is currently subscribed to: the - * per-workspace slider choice recorded at subscribe time - * (workspace_subscriptions.team_credit_stop_id). Amounts are owned by the - * catalog, not the subscription row. Returned on GET /api/billing/status - * for per-credit Team plans (BE-1254). - * + * An outstanding workspace invitation that has not yet been accepted. */ -export type TeamCreditStopSummary = { +export type PendingInvite = { /** - * Stable stop id (e.g. "team_200") + * Email address of the invited user + */ + email: string + /** + * When the invite expires + */ + expires_at: string + /** + * Invite ID */ id: string /** - * Raw monthly credit count granted at this stop + * When the invite was created */ - credits_monthly: number + invited_at: string /** - * Monthly USD commitment for this stop + * Invite token for constructing invite links. Empty for expired invites. */ - stop_usd: number -} - -/** - * The providers available to the authenticated user in the current workspace. - */ -export type SecretProvidersResponse = { - data: Array + token?: string } /** - * A provider the user may configure a secret for. The shape is deliberately minimal (identifier only) and reserved for future per-provider fields such as sub-keys. + * Response containing a redirect URL to the payment portal. */ -export type SecretProvider = { +export type PaymentPortalResponse = { /** - * Provider identifier (e.g., huggingface, civitai, runway, gemini) + * Stripe Billing Portal URL */ - id: string + url: string } /** - * List of user secrets with metadata only. + * Request body for generating a payment portal session URL. */ -export type SecretListResponse = { - data: Array +export type PaymentPortalRequest = { + /** + * URL to redirect after the user exits the portal + */ + return_url?: string } /** - * User secret metadata (the secret value itself is never returned after creation). + * RFC 6749 §5.1 successful token response. */ -export type SecretResponse = { - /** - * Unique identifier for the secret - */ - id: string +export type OAuthTokenResponse = { /** - * User-provided label for the secret + * Resource-bound Cloud JWT (audience matches the protected resource). */ - name: string + access_token: string /** - * Provider identifier (e.g., huggingface, civitai) + * Access token lifetime in seconds. */ - provider?: string + expires_in: number /** - * When the secret was last used for decryption + * Opaque refresh token. Rotates on every successful refresh; presenting an already-rotated token revokes the entire family. */ - last_used_at?: string + refresh_token: string /** - * When the secret was created + * Space-delimited scopes granted with this token. */ - created_at: string - /** - * When the secret was last updated - */ - updated_at: string + scope: string + token_type: 'Bearer' } /** - * Request body for updating an existing user secret. + * RFC 6749 §5.2 error response. */ -export type UpdateSecretRequest = { +export type OAuthTokenError = { /** - * New name for the secret + * RFC 6749 §5.2 error code: invalid_request, invalid_client, invalid_grant, unauthorized_client, unsupported_grant_type, invalid_scope. */ - name?: string + error: string /** - * New secret value (API key, token, etc.) + * Human-readable, no leak of internal storage state. */ - secret_value?: string + error_description?: string } /** - * Request body for creating a new user secret. + * RFC 7591 §3.2.1 successful registration response. */ -export type CreateSecretRequest = { - /** - * User-provided label for the secret - */ - name: string +export type OAuthRegisterResponse = { + application_type: 'native' | 'web' /** - * Optional provider identifier (e.g., huggingface, civitai) + * Server-generated client_id. Always carries the `comfy-dyn-` prefix. */ - provider?: string + client_id: string /** - * The plaintext secret to encrypt and store + * Unix timestamp (seconds) when the client was registered. */ - secret_value: string + client_id_issued_at: number + client_name?: string + grant_types: Array + redirect_uris: Array + response_types: Array + token_endpoint_auth_method: 'none' } /** - * Paginated list of billing events for a workspace. + * RFC 7591 §2 client metadata document. Only the fields the server honors are listed; presence of `scope` or `resource_grants` in the request is rejected (`invalid_client_metadata`) because those are server-owned for dynamic clients. `additionalProperties: false` mirrors the runtime middleware that rejects any unknown metadata key. + * */ -export type BillingEventsResponse = { - /** - * Total number of events - */ - total: number - events: Array +export type OAuthRegisterRequest = { /** - * Current page number (1-indexed) + * RFC 7591 §2 application_type. **OPTIONAL** — omit the field to default to `native` (the loopback-friendly policy), rather than the RFC's nominal `web` default; the MCP SDK's DCR client omits it. `native` for desktop / CLI / MCP-spec-strict clients (loopback redirects); `web` for hosted clients (HTTPS only, host must be allowlisted). The realistic MCP-client population is overwhelmingly native/loopback, so defaulting to `web` would silently bounce those clients off the wrong redirect policy. A *present* value must be one of the enum members; any other value rejects with `invalid_client_metadata`. (The server has no runtime enum validation and defensively coerces a null/empty value to `native`, but spec-validating clients should omit the field rather than send `""` — the enum does not permit it.) + * */ - page: number + application_type?: 'native' | 'web' /** - * Items per page + * Human-readable name shown in the consent UI. Reserved-name list rejects impersonation of major MCP clients. */ - limit: number + client_name?: string /** - * Total number of pages + * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. */ - totalPages: number -} - -/** - * A single history event. The cloud history-events store is the single source of truth for both billing events (charges, credits, adjustments) and user-facing usage events. - */ -export type BillingEvent = { + client_uri?: string | null /** - * Type of history event. Billing types (e.g. invoice_paid, checkout_completed, topup_completed) and the migrated user-facing usage types (account_created, credit_added, api_usage_completed, cloud_subscription_created, cloud_subscription_paid, cloud_subscription_credit_added, cloud_workflow_executed, free_tier_credit_granted). Kept as a free-form string for back-compat with existing billing-event consumers. + * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. */ - event_type: string + contacts?: Array | null /** - * Unique event identifier + * Optional. Defaults to `["authorization_code","refresh_token"]`. */ - event_id: string + grant_types?: Array<'authorization_code' | 'refresh_token'> /** - * Event-specific parameters + * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. */ - params?: { + jwks?: { [key: string]: unknown - } - /** - * When the event occurred - */ - createdAt: string -} - -/** - * Current credit balance and usage details for a workspace. - */ -export type BillingBalanceResponse = { - /** - * The total remaining balance in microamount (1/1,000,000 of the currency unit) - */ - amount_micros: number - /** - * The remaining balance from prepaid commits in microamount - */ - prepaid_balance_micros?: number + } | null /** - * The remaining balance from cloud credits in microamount + * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. */ - cloud_credit_balance_micros?: number + jwks_uri?: string | null /** - * The total amount of pending/unbilled charges from draft invoices in microamount + * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. */ - pending_charges_micros?: number + logo_uri?: string | null /** - * The effective balance (total balance minus pending charges). Can be negative if pending charges exceed the balance. + * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. */ - effective_balance_micros?: number + policy_uri?: string | null /** - * Currency code + * 1–5 redirect URIs. Validated against `application_type` policy. */ - currency: string -} - -/** - * Current billing and subscription status for a workspace. - */ -export type BillingStatusResponse = { + redirect_uris: Array /** - * Whether the workspace has an active subscription + * **REJECTED IF PRESENT.** Same reason as `scope`. The set of resources and scopes a dynamic client may request is server-policy, not request-driven. + * */ - is_active: boolean + resource_grants?: { + [key: string]: Array + } | null /** - * Subscription activity status (scheduled subscriptions are not returned) + * Optional. Defaults to `["code"]`. */ - subscription_status?: 'active' | 'ended' | 'canceled' - subscription_tier?: SubscriptionTier - subscription_duration?: SubscriptionDuration + response_types?: Array<'code'> /** - * Plan identifier (e.g., standard-monthly, team-pro-annual) + * **REJECTED IF PRESENT.** Dynamic clients do not pick scopes — the server assigns scopes from the active MCP resource's published list. Sending `scope` in the registration body is treated as a privilege-escalation attempt and returns `invalid_client_metadata`. The field is documented here so clients see a well-defined error rather than silent drop. + * */ - plan_slug?: string - billing_status?: BillingStatus + scope?: string | null /** - * Whether the workspace has available credits + * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. */ - has_funds: boolean + software_id?: string | null /** - * When the subscription will become inactive (if canceled) + * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. */ - cancel_at?: string + software_version?: string | null /** - * When the current billing period ends and the next one begins + * Public clients only this phase — must be `none` if present. The server forces `none` regardless. */ - renewal_date?: string + token_endpoint_auth_method?: 'none' /** - * The team credit stop the workspace is currently subscribed to, for per-credit Team plans (BE-1254). Lets clients tell apart team subscriptions, which all share subscription_tier=TEAM. Always present; null for personal plans (use subscription_tier to distinguish those) and for legacy team plans without a credit stop. + * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. */ - team_credit_stop: TeamCreditStopSummary | null + tos_uri?: string | null } /** - * Payment lifecycle status + * RFC 7591 §3.2.2 error response. */ -export type BillingStatus = - | 'awaiting_payment_method' - | 'pending_payment' - | 'paid' - | 'payment_failed' - | 'inactive' +export type OAuthRegisterError = { + error: 'invalid_redirect_uri' | 'invalid_client_metadata' + error_description?: string | null +} /** - * A single JSON Web Key entry within a JWKS response. + * Union of the two 400 shapes /oauth/register can emit. `OAuthRegisterError` is the handler-shaped RFC 7591 §3.2.2 error; `ErrorResponse` is the strict-server binding-layer error fired when the request body fails OpenAPI-schema validation before the handler runs, normalized to the standard {code, message} shape by the custom Echo HTTPErrorHandler (BE-1178). + * */ -export type JwkKey = { - kty: string - crv: string - kid: string - use: string - alg: string - /** - * Base64url-encoded X coordinate - */ - x: string - /** - * Base64url-encoded Y coordinate - */ - y: string -} +export type OAuthRegisterBadRequestResponse = OAuthRegisterError | ErrorResponse /** - * RFC 6749 §5.2 error response. + * Standard error response with a machine-readable code and human-readable message. */ -export type OAuthTokenError = { - /** - * RFC 6749 §5.2 error code: invalid_request, invalid_client, invalid_grant, unauthorized_client, unsupported_grant_type, invalid_scope. - */ - error: string +export type ErrorResponse = { + code: string /** - * Human-readable, no leak of internal storage state. + * Optional open object carrying structured, machine-readable context about the error (e.g. offending field names, validation specifics). Absent for most errors; consumers must not assume any particular shape. */ - error_description?: string + details?: { + [key: string]: unknown + } + message: string } /** - * RFC 6749 §5.1 successful token response. + * OAuth 2.1 protected-resource metadata (RFC 9728). */ -export type OAuthTokenResponse = { - /** - * Resource-bound Cloud JWT (audience matches the protected resource). - */ - access_token: string - token_type: 'Bearer' - /** - * Access token lifetime in seconds. - */ - expires_in: number - /** - * Opaque refresh token. Rotates on every successful refresh; presenting an already-rotated token revokes the entire family. - */ - refresh_token: string - /** - * Space-delimited scopes granted with this token. - */ - scope: string +export type OAuthProtectedResourceMetadata = { + authorization_servers: Array + bearer_methods_supported?: Array + resource: string + scopes_supported: Array } /** @@ -1585,18 +1413,8 @@ export type OAuthTokenResponse = { export type OAuthConsentChallengeWorkspace = { id: string name: string - type: 'personal' | 'team' role: 'owner' | 'member' -} - -/** - * Redirect target produced after a JSON consent submission. The frontend must navigate the browser to this URL so custom-scheme client callbacks work without relying on fetch-visible 302 headers. - */ -export type OAuthAuthorizeRedirectResponse = { - /** - * OAuth client redirect URI with either code+state for allow, or error+state for deny. - */ - redirect_url: string + type: 'personal' | 'team' } /** @@ -1605,21 +1423,17 @@ export type OAuthAuthorizeRedirectResponse = { */ export type OAuthConsentChallenge = { /** - * Opaque server-side identifier for the authorization-request row. Carried back unchanged in the consent submission. + * Human-readable name of the OAuth client requesting authorization, from oauth_clients.display_name. */ - oauth_request_id: string + client_display_name: string /** * Per-row CSRF token bound to this authorization request (not to the session). Must be echoed back on POST. */ csrf_token: string /** - * Human-readable name of the OAuth client requesting authorization, from oauth_clients.display_name. - */ - client_display_name: string - /** - * Human-readable name of the protected resource, from oauth_resources.display_name. + * Opaque server-side identifier for the authorization-request row. Carried back unchanged in the consent submission. */ - resource_display_name: string + oauth_request_id: string /** * The exact redirect URI this authorization request was validated * against at GET time (oauth_authorization_requests.redirect_uri, @@ -1631,7 +1445,11 @@ export type OAuthConsentChallenge = { */ redirect_uri: string /** - * Scopes the client is requesting for this resource. The frontend should present these for the user to approve. + * Human-readable name of the protected resource, from oauth_resources.display_name. + */ + resource_display_name: string + /** + * Scopes the client is requesting for this resource. The frontend should present these for the user to approve. */ scopes: Array /** @@ -1641,1498 +1459,1317 @@ export type OAuthConsentChallenge = { } /** - * OAuth 2.1 protected-resource metadata (RFC 9728). - */ -export type OAuthProtectedResourceMetadata = { - resource: string - authorization_servers: Array - scopes_supported: Array - bearer_methods_supported?: Array -} - -/** - * RFC 7591 §3.2.2 error response. - */ -export type OAuthRegisterError = { - error: 'invalid_redirect_uri' | 'invalid_client_metadata' - error_description?: string | null -} - -/** - * Union of the two 400 shapes /oauth/register can emit. `OAuthRegisterError` is the handler-shaped RFC 7591 §3.2.2 error; `ErrorResponse` is the strict-server binding-layer error fired when the request body fails OpenAPI-schema validation before the handler runs, normalized to the standard {code, message} shape by the custom Echo HTTPErrorHandler (BE-1178). - * - */ -export type OAuthRegisterBadRequestResponse = OAuthRegisterError | ErrorResponse - -/** - * Standard error response with a machine-readable code and human-readable message. + * Redirect target produced after a JSON consent submission. The frontend must navigate the browser to this URL so custom-scheme client callbacks work without relying on fetch-visible 302 headers. */ -export type ErrorResponse = { - code: string - message: string +export type OAuthAuthorizeRedirectResponse = { /** - * Optional open object carrying structured, machine-readable context about the error (e.g. offending field names, validation specifics). Absent for most errors; consumers must not assume any particular shape. + * OAuth client redirect URI with either code+state for allow, or error+state for deny. */ - details?: { - [key: string]: unknown - } + redirect_url: string } /** - * RFC 7591 §3.2.1 successful registration response. + * OAuth 2.1 authorization-server metadata (RFC 8414). */ -export type OAuthRegisterResponse = { - /** - * Server-generated client_id. Always carries the `comfy-dyn-` prefix. - */ - client_id: string +export type OAuthAuthorizationServerMetadata = { + authorization_endpoint: string + code_challenge_methods_supported: Array + grant_types_supported: Array + issuer: string + jwks_uri: string /** - * Unix timestamp (seconds) when the client was registered. + * RFC 7591 §3.1 Dynamic Client Registration endpoint. Advertised so MCP-spec-compliant clients can auto-discover and self-register without operator involvement. Present only when DCR is enabled. + * */ - client_id_issued_at: number - client_name?: string - redirect_uris: Array - grant_types: Array - response_types: Array - token_endpoint_auth_method: 'none' - application_type: 'native' | 'web' + registration_endpoint?: string + response_types_supported: Array + scopes_supported?: Array + token_endpoint: string + token_endpoint_auth_methods_supported: Array } /** - * RFC 7591 §2 client metadata document. Only the fields the server honors are listed; presence of `scope` or `resource_grants` in the request is rejected (`invalid_client_metadata`) because those are server-owned for dynamic clients. `additionalProperties: false` mirrors the runtime middleware that rejects any unknown metadata key. - * + * Metadata describing a single ComfyUI node type and its inputs/outputs. */ -export type OAuthRegisterRequest = { +export type NodeInfo = { /** - * 1–5 redirect URIs. Validated against `application_type` policy. + * Whether this is an API node */ - redirect_uris: Array + api_node?: boolean /** - * Human-readable name shown in the consent UI. Reserved-name list rejects impersonation of major MCP clients. + * Category of the node */ - client_name?: string + category?: string /** - * RFC 7591 §2 application_type. **OPTIONAL** — omit the field to default to `native` (the loopback-friendly policy), rather than the RFC's nominal `web` default; the MCP SDK's DCR client omits it. `native` for desktop / CLI / MCP-spec-strict clients (loopback redirects); `web` for hosted clients (HTTPS only, host must be allowlisted). The realistic MCP-client population is overwhelmingly native/loopback, so defaulting to `web` would silently bounce those clients off the wrong redirect policy. A *present* value must be one of the enum members; any other value rejects with `invalid_client_metadata`. (The server has no runtime enum validation and defensively coerces a null/empty value to `native`, but spec-validating clients should omit the field rather than send `""` — the enum does not permit it.) - * + * Whether the node is deprecated */ - application_type?: 'native' | 'web' + deprecated?: boolean /** - * Public clients only this phase — must be `none` if present. The server forces `none` regardless. + * Description of the node */ - token_endpoint_auth_method?: 'none' + description?: string /** - * Optional. Defaults to `["authorization_code","refresh_token"]`. + * Display name of the node */ - grant_types?: Array<'authorization_code' | 'refresh_token'> + display_name?: string /** - * Optional. Defaults to `["code"]`. + * Whether the node is experimental */ - response_types?: Array<'code'> + experimental?: boolean /** - * **REJECTED IF PRESENT.** Dynamic clients do not pick scopes — the server assigns scopes from the active MCP resource's published list. Sending `scope` in the registration body is treated as a privilege-escalation attempt and returns `invalid_client_metadata`. The field is documented here so clients see a well-defined error rather than silent drop. - * + * Input specifications for the node */ - scope?: string | null + input?: { + [key: string]: unknown + } /** - * **REJECTED IF PRESENT.** Same reason as `scope`. The set of resources and scopes a dynamic client may request is server-policy, not request-driven. - * + * Order of inputs for display */ - resource_grants?: { + input_order?: { [key: string]: Array - } | null - /** - * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. - */ - client_uri?: string | null - /** - * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. - */ - logo_uri?: string | null - /** - * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. - */ - tos_uri?: string | null - /** - * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. - */ - policy_uri?: string | null + } /** - * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. + * Internal name of the node */ - software_id?: string | null + name?: string /** - * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. + * Output types of the node */ - software_version?: string | null + output?: Array /** - * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. + * Whether each output is a list */ - contacts?: Array | null + output_is_list?: Array /** - * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. + * Names of the outputs */ - jwks?: { - [key: string]: unknown - } | null + output_name?: Array /** - * **REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase. + * Whether this is an output node */ - jwks_uri?: string | null -} - -/** - * OAuth 2.1 authorization-server metadata (RFC 8414). - */ -export type OAuthAuthorizationServerMetadata = { - issuer: string - authorization_endpoint: string - token_endpoint: string - jwks_uri: string + output_node?: boolean /** - * RFC 7591 §3.1 Dynamic Client Registration endpoint. Advertised so MCP-spec-compliant clients can auto-discover and self-register without operator involvement. Present only when DCR is enabled. - * + * Tooltips for outputs */ - registration_endpoint?: string - response_types_supported: Array - grant_types_supported: Array - code_challenge_methods_supported: Array - token_endpoint_auth_methods_supported: Array - scopes_supported?: Array -} - -/** - * JSON Web Key Set containing the public keys used to verify Cloud JWTs. - */ -export type JwksResponse = { - keys: Array -} - -/** - * Response after synchronizing an API key into the local database. - */ -export type SyncApiKeyResponse = { + output_tooltips?: Array /** - * `revoked` — matching row found, was active, now revoked. - * `already_revoked` — matching row found, already revoked. - * `no_op` — no row matches the supplied hash. - * + * Python module implementing the node */ - result: 'revoked' | 'already_revoked' | 'no_op' + python_module?: string } /** - * Request body for synchronizing an API key from the external registry. + * Represents a folder containing models */ -export type SyncApiKeyRequest = { - /** - * Lifecycle event type. Only `delete` is supported in Phase 1. - */ - event: 'delete' +export type ModelFolder = { /** - * SHA-256 hex digest of the plaintext API key (64 hex characters). - * Case-insensitive: the server lowercases the value before lookup, so - * producers may emit lowercase or uppercase hex. The lowercase form - * is recommended for consistency with the rest of the codebase, which - * computes hashes via `hex.EncodeToString`. - * + * List of paths where models of this type are stored */ - key_hash: string + folders: Array /** - * Firebase UID of the key's owner according to comfy-api. Required on - * the request so cloud can detect drift between the two systems, but - * **advisory only**: `key_hash` is the sole authoritative identifier - * for the revocation. A mismatch against cloud's stored `user_id` is - * logged and emits `admin.api_key_sync.delete.customer_mismatch`, but - * does not change the outcome — the matching row is still revoked so - * a subsequent sync call can repair drift. - * + * The name of the model folder */ - customer_id: string + name: string } /** - * The personal workspace's provisioned billing identity. + * Represents a model file with metadata */ -export type EnsureWorkspaceBillingProvisionedResponse = { - /** - * The user's personal workspace ID. - */ - workspace_id: string - /** - * The Stripe customer ID attached to the workspace. - */ - stripe_customer_id: string +export type ModelFile = { /** - * The Metronome customer ID attached to the workspace. + * The filename of the model */ - metronome_customer_id: string + name: string /** - * The active Metronome contract ID on the workspace. + * Index of the path where this model is located */ - metronome_contract_id: string + pathIndex: number } /** - * The caller's already-resolved legacy (comfy-api) customer identity. When - * present and carrying provider IDs, provisioning ATTACHES this identity to - * the personal workspace (sharing the existing balance and subscription) - * instead of minting a net-new empty customer. Omit (or send with no - * provider IDs) for a free user with nothing to attach — provisioning then - * creates net-new. This closes the create-new-before-attach gap: a caller - * that already knows the legacy identity hands it over so the very first - * provisioning is an attach. - * + * Workspace member with profile and role information. */ -export type EnsureWorkspaceBillingLegacySnapshot = { - /** - * Legacy Stripe customer id to attach. - */ - stripe_customer_id?: string +export type Member = { /** - * Legacy Metronome customer id to attach (the balance holder). + * User's email address */ - metronome_customer_id?: string + email: string /** - * Active Metronome contract id on the legacy customer. + * User ID */ - metronome_contract_id?: string + id: string /** - * Whether the legacy customer currently has spendable funds. + * Whether this member is the workspace's immutable original owner (the creator). Derived as member.id == workspace.created_by_user_id; exactly one member per workspace is marked. The original owner can never be demoted, removed, or leave; a promoted owner is never marked. */ - has_funds?: boolean + is_original_owner: boolean /** - * Cached subscription tier of the legacy customer, if any. + * When the user joined the workspace */ - subscription_tier?: string + joined_at: string /** - * Active legacy Stripe subscription id, if the customer is subscribed. + * User's display name */ - legacy_stripe_subscription_id?: string + name: string /** - * Namespaced legacy comfy user id, for provider stamping and audit. + * User's role in the workspace */ - legacy_comfy_user_id?: string + role: 'owner' | 'member' } /** - * Request body for ensuring a user's personal workspace carries a fully - * provisioned billing identity. Sent by comfy-api's CreateCustomer (BE-1047) - * with the already canonical-resolved user identity. - * + * Paginated list of workspaces the authenticated user belongs to. */ -export type EnsureWorkspaceBillingProvisionedRequest = { - /** - * Canonical cloud user ID whose personal workspace should be ensured and - * provisioned. The caller (comfy-api) resolves canonical-sibling routing - * before calling, so this is taken as authoritative — the endpoint never - * re-resolves or self-maps. - * - */ - user_id: string - /** - * Owner email, used when minting a net-new vendor customer. Required for - * create-new; ignored on the already-provisioned fast-path. - * - */ - email: string - snapshot?: EnsureWorkspaceBillingLegacySnapshot +export type ListWorkspacesResponse = { + workspaces: Array } /** - * Firebase UIDs linked to the canonical comfy_user_id. Empty list when - * no mappings exist (not an error — callers can treat empty as "unknown - * canonical"). - * + * List of API keys associated with the current workspace. */ -export type ListLinkedFirebaseUidsResponse = { - /** - * Subjects from `identity_mappings` where provider = 'firebase' and - * comfy_user_id matches the request. Order is unspecified. - * - */ - firebase_uids: Array +export type ListWorkspaceApiKeysResponse = { + api_keys: Array } /** - * Request body for reverse-looking-up Firebase UIDs linked to a canonical comfy_user_id. + * Paginated list of available asset tags. */ -export type ListLinkedFirebaseUidsRequest = { +export type ListTagsResponse = { /** - * Canonical user ID to look up. Cloud's `identity_mappings` is queried - * for every `subject` whose `comfy_user_id` matches and whose `provider` - * equals `firebase`. - * + * Whether more tags are available */ - comfy_user_id: string -} - -/** - * Response confirming the validity and scope of a workspace API key. - */ -export type VerifyApiKeyResponse = { + has_more: boolean /** - * Firebase UID of the key creator + * List of tags */ - user_id: string + tags: Array /** - * User's email address + * Total number of tags */ - email: string - /** - * User's display name - */ - name: string - /** - * Whether the user is an admin - */ - is_admin: boolean - /** - * Workspace ID for billing attribution - */ - workspace_id: string - /** - * Type of workspace - */ - workspace_type: 'personal' | 'team' - /** - * User's role in the workspace - */ - role: 'owner' | 'member' - /** - * Whether the workspace has available funds for usage - */ - has_funds: boolean - /** - * Whether the workspace has an active subscription - */ - is_active: boolean - /** - * Permissions granted by this key. Always includes the role permission - * (`owner:*` or `member:*`). May also include `partner-node:use`, - * which is a **staging-only shim** used to gate partner-node access - * for non-admin users during testing. No production code path checks - * this permission today; it is emitted for parity with the Cloud JWT - * claim set so JWT and API-key callers see the same permissions. - * - */ - permissions: Array -} - -/** - * Request body for verifying a workspace API key (admin endpoint). - */ -export type VerifyApiKeyRequest = { - /** - * The full plaintext API key to verify - */ - api_key: string + total: number } /** - * Response after bulk-revoking API keys for a workspace member. + * List of members in the current workspace. */ -export type BulkRevokeApiKeysResponse = { - /** - * Number of API keys that were revoked - */ - revoked_count: number +export type ListMembersResponse = { + members: Array + pagination: PaginationInfo } /** - * List of API keys associated with the current workspace. + * List of pending invitations for the current workspace. */ -export type ListWorkspaceApiKeysResponse = { - api_keys: Array +export type ListInvitesResponse = { + invites: Array } /** - * Metadata for a workspace-scoped API key (secret is never returned). + * Paginated list of assets belonging to the authenticated user. */ -export type WorkspaceApiKeyInfo = { +export type ListAssetsResponse = { /** - * API key ID + * List of assets matching the query */ - id: string + assets: Array /** - * Workspace this key belongs to + * Whether more assets are available beyond this page */ - workspace_id: string + has_more: boolean /** - * User who created this key + * Opaque cursor to pass as the `after` query parameter to fetch the + * next page. Omitted from the response when there are no more results. + * */ - user_id: string + next_cursor?: string /** - * User-provided label + * Total number of assets matching the filters */ - name: string + total: number +} + +/** + * Represents a user-owned asset (image, video, or other generated output). + */ +export type Asset = { /** - * User-provided description of the key's purpose. Limit is byte-based (UTF-8 encoding); 5000 bytes equals 5000 ASCII characters or fewer multi-byte characters. + * Timestamp when the asset was created */ - description: string + created_at: string /** - * First 8 chars after prefix for display + * Display name of the asset. Mirrors name for backwards compatibility. */ - key_prefix: string + display_name?: string | null /** - * When the key expires (if set) + * Relative path in global-namespace-root form (e.g. "models/checkpoints/flux.safetensors") */ - expires_at?: string + file_path?: string | null /** - * Last time the key was used + * Blake3 hash of the asset content. */ - last_used_at?: string + hash?: string /** - * When the key was revoked (if revoked) + * Unique identifier for the asset */ - revoked_at?: string + id: string /** - * When the key was created + * Whether this asset is immutable (cannot be modified or deleted) */ - created_at: string -} - -/** - * Response containing the newly created workspace API key. - */ -export type CreateWorkspaceApiKeyResponse = { + is_immutable?: boolean /** - * API key ID + * ID of the job that created this asset, if available */ - id: string + job_id?: string | null /** - * User-provided label + * Timestamp when the asset was last accessed */ - name: string + last_access_time?: string /** - * User-provided description of the key's purpose. Limit is byte-based (UTF-8 encoding); 5000 bytes equals 5000 ASCII characters or fewer multi-byte characters. + * System-managed metadata from download sources (HuggingFace, CivitAI, etc.) - read-only, not user-modifiable */ - description: string + readonly metadata?: { + [key: string]: unknown + } /** - * The full plaintext API key (only shown once) + * MIME type of the asset */ - key: string + mime_type?: string /** - * First 8 chars after prefix for display + * Name of the asset file */ - key_prefix: string + name: string /** - * When the key expires (if set) + * ID of the preview asset if available */ - expires_at?: string + preview_id?: string | null /** - * When the key was created + * URL for asset preview/thumbnail */ - created_at: string -} - -/** - * Request body for creating a new workspace-scoped API key. - */ -export type CreateWorkspaceApiKeyRequest = { + preview_url?: string /** - * User-provided label for the key + * Durable, owner-gated short link to this asset's content (relative `/api/s/{id}` path). Stable across the underlying signed URL's expiry — resolving it re-mints a fresh signed URL on every request — so it is safe to persist or share into chat, unlike `preview_url`. Only the minting user can resolve it. Omitted when the short-link surface is disabled or the asset has no resolvable content hash. */ - name: string + short_url?: string | null /** - * User-provided description of the key's purpose. Limit is byte-based (UTF-8 encoding); 5000 bytes equals 5000 ASCII characters or fewer multi-byte characters. + * Size of the asset in bytes */ - description?: string + size?: number /** - * Optional expiration timestamp + * Tags associated with the asset */ - expires_at?: string -} - -/** - * Response returned after successfully accepting a workspace invitation. - */ -export type AcceptInviteResponse = { + tags?: Array /** - * ID of the workspace joined + * Timestamp when the asset was last updated */ - workspace_id: string + updated_at: string /** - * Name of the workspace joined + * Custom user metadata for the asset */ - workspace_name: string + user_metadata?: { + [key: string]: unknown + } } /** - * Request body for inviting a user to a workspace. + * Reference to a Hub label by ID. */ -export type CreateInviteRequest = { +export type LabelRef = { /** - * Email address to invite + * Human-readable display name (e.g. "Video Generation", "Flux"). */ - email: string + display_name: string + /** + * Slug identifier (e.g. "video-generation", "flux"). + */ + name: string } /** - * List of pending invitations for the current workspace. + * JSON Web Key Set containing the public keys used to verify Cloud JWTs. */ -export type ListInvitesResponse = { - invites: Array +export type JwksResponse = { + keys: Array } /** - * An outstanding workspace invitation that has not yet been accepted. + * A single JSON Web Key entry within a JWKS response. */ -export type PendingInvite = { - /** - * Invite ID - */ - id: string - /** - * Email address of the invited user - */ - email: string - /** - * Invite token for constructing invite links. Empty for expired invites. - */ - token?: string +export type JwkKey = { + alg: string + crv: string + kid: string + kty: string + use: string /** - * When the invite was created + * Base64url-encoded X coordinate */ - invited_at: string + x: string /** - * When the invite expires + * Base64url-encoded Y coordinate */ - expires_at: string + y: string } /** - * List of members in the current workspace. + * Paginated list of jobs for the authenticated user. */ -export type ListMembersResponse = { - members: Array +export type JobsListResponse = { + /** + * Array of jobs ordered by specified sort field + */ + jobs: Array pagination: PaginationInfo } /** - * Workspace member with profile and role information. + * Detailed execution error information from ComfyUI */ -export type Member = { +export type ExecutionError = { /** - * User ID + * Input values at time of failure (empty object if not available) */ - id: string + current_inputs: { + [key: string]: unknown + } /** - * User's display name + * Output values at time of failure (empty object if not available) */ - name: string + current_outputs: { + [key: string]: unknown + } /** - * User's email address + * Human-readable error message */ - email: string + exception_message: string /** - * User's role in the workspace + * Python exception type (e.g., "RuntimeError") */ - role: 'owner' | 'member' + exception_type: string /** - * When the user joined the workspace + * ID of the node that failed */ - joined_at: string + node_id: string /** - * Whether this member is the workspace's immutable original owner (the creator). Derived as member.id == workspace.created_by_user_id; exactly one member per workspace is marked. The original owner can never be demoted, removed, or leave; a promoted owner is never marked. + * Type name of the node (e.g., "KSampler") */ - is_original_owner: boolean -} - -/** - * Request body for changing a workspace member's role. - */ -export type UpdateMemberRoleRequest = { + node_type: string /** - * The role to assign to the member + * Array of traceback lines (empty array if not available) */ - role: 'owner' | 'member' + traceback: Array } /** - * Request body for updating an existing workspace's settings. + * Lightweight job data for list views (workflow and full outputs excluded) */ -export type UpdateWorkspaceRequest = { +export type JobEntry = { /** - * New display name for the workspace + * Job creation timestamp (Unix timestamp in milliseconds) */ - name?: string -} - -/** - * Request body for creating a new workspace. - */ -export type CreateWorkspaceRequest = { + create_time: number /** - * Display name for the workspace + * Workflow execution completion timestamp (Unix milliseconds, only present for terminal states) */ - name: string -} - -/** - * Workspace entity annotated with the requesting user's role. - */ -export type WorkspaceWithRole = { - id: string - name: string - type: 'personal' | 'team' - role: 'owner' | 'member' + execution_end_time?: number /** - * When the workspace was created + * Detailed execution error from ComfyUI (only for failed jobs with structured error data) */ - created_at: string + execution_error?: ExecutionError /** - * When the user joined the workspace (same as created_at for the workspace creator) + * Workflow execution start timestamp (Unix milliseconds, only present for terminal states) */ - joined_at: string - subscription_tier?: SubscriptionTier -} - -/** - * Paginated list of workspaces the authenticated user belongs to. - */ -export type ListWorkspacesResponse = { - workspaces: Array -} - -/** - * Full workspace entity with configuration and ownership details. - */ -export type Workspace = { - id: string - name: string - type: 'personal' | 'team' - created_at: string -} - -/** - * Exchange poll result. Pending until the code is redeemed in the browser. - */ -export type DesktopLoginCodeExchangeResponse = { + execution_start_time?: number /** - * Whether the code has been redeemed yet. + * Unique job identifier */ - status: 'pending' | 'complete' + id: string /** - * One-time Firebase custom token for the redeeming user. Present only when status is "complete". + * Total number of output files (omitted for non-terminal states) */ - custom_token?: string -} - -/** - * Request to exchange a redeemed login code for a custom token. - */ -export type DesktopLoginCodeExchangeRequest = { + outputs_count?: number /** - * The login code returned at creation. + * Primary preview output (only present for terminal states) */ - code: string + preview_output?: { + [key: string]: unknown + } /** - * PKCE code verifier matching the challenge supplied at creation. + * User-friendly job status */ - code_verifier: string -} - -/** - * Result of redeeming a desktop login code. - */ -export type DesktopLoginCodeRedeemResponse = { + status: 'pending' | 'in_progress' | 'completed' | 'failed' | 'cancelled' /** - * The code is now claimed for the authenticated user. + * UUID identifying the workflow graph definition */ - status: 'redeemed' + workflow_id?: string } /** - * Request to claim a desktop login code for the authenticated user. + * Response for POST /api/jobs/cancel. */ -export type DesktopLoginCodeRedeemRequest = { +export type JobsCancelResponse = { /** - * The login code the desktop app placed in the browser URL. + * Job IDs for which a cancel event was successfully dispatched by this + * call. Jobs already in a terminal or cancelling state are idempotently + * skipped and will not appear here. + * */ - code: string + cancelled: Array } /** - * A freshly minted desktop login code and its polling parameters. + * Request to cancel multiple jobs by ID. */ -export type DesktopLoginCodeCreateResponse = { - /** - * Opaque single-use login code ("dlc_" prefix). - */ - code: string - /** - * Seconds until the code expires if not redeemed. - */ - expires_in: number +export type JobsCancelRequest = { /** - * Suggested seconds between exchange polls. + * Job identifiers (UUIDs) to cancel. */ - poll_interval: number + job_ids: Array } /** - * Request to mint a desktop login code. + * Job status information */ -export type DesktopLoginCodeCreateRequest = { +export type JobStatusResponse = { /** - * Stable identifier of the desktop installation, used only for the login attribution event. Omit when telemetry consent is off - the login flow still works, but no attribution event is emitted. + * The inference instance assigned to this job (if any) */ - installation_id?: string + assigned_inference?: string | null /** - * Desktop platform identifier (e.g. darwin, win32, linux). + * When the job was created */ - platform: string + created_at: string /** - * Desktop app version string. + * Error message if the job failed */ - app_version: string + error_message?: string | null /** - * PKCE code challenge - base64url(SHA256(code_verifier)) per RFC 7636 (S256 only). + * The job ID */ - code_challenge: string -} - -/** - * Abbreviated workspace metadata used in list responses. - */ -export type WorkspaceSummary = { id: string - name: string - type: 'personal' | 'team' -} - -/** - * Response containing the issued Cloud JWT and its expiry. - */ -export type ExchangeTokenResponse = { - /** - * Cloud JWT token - */ - token: string - /** - * Token expiration time (RFC 3339) - */ - expires_at: string - workspace: WorkspaceSummary /** - * User's role in the workspace + * When the job status was last changed */ - role: 'owner' | 'member' + last_state_update?: string /** - * Permission strings for the role + * Current job status */ - permissions: Array -} - -/** - * Optional request body for the token exchange endpoint. The Firebase JWT - * being exchanged is supplied via the `Authorization: Bearer` header; this - * body only carries workspace-selection input. - * - */ -export type ExchangeTokenRequest = { + status: + | 'waiting_to_dispatch' + | 'pending' + | 'in_progress' + | 'completed' + | 'error' + | 'cancelled' /** - * Workspace ID to get token for. Defaults to personal workspace if omitted. + * When the job was last updated */ - workspace_id?: string + updated_at: string } /** - * Full task details including payload and result + * Full job details including workflow and outputs */ -export type TaskResponse = { +export type JobDetailResponse = { /** - * Unique task identifier + * Job creation timestamp (Unix timestamp in milliseconds) */ - id: string + create_time: number /** - * Caller-provided key for idempotent task creation + * Detailed execution error from ComfyUI (only for failed jobs with structured error data) */ - idempotency_key: string + execution_error?: ExecutionError /** - * Task type name (e.g., model_upload) + * Node-level execution metadata (only for terminal states) */ - task_name: string + execution_meta?: { + [key: string]: unknown + } /** - * Task input data + * ComfyUI execution status and timeline (only for terminal states) */ - payload: { + execution_status?: { [key: string]: unknown } /** - * Current task status + * Unique job identifier */ - status: 'created' | 'running' | 'completed' | 'failed' + id: string /** - * Task output data (null if not completed) + * Full outputs object from ComfyUI (only for terminal states) */ - result?: { + outputs?: { [key: string]: unknown } /** - * Error message on failure (null if not failed) + * Total number of output files (omitted for non-terminal states) */ - error_message?: string + outputs_count?: number /** - * Task creation timestamp + * Primary preview output (only for terminal states) */ - create_time: string + preview_output?: { + [key: string]: unknown + } /** - * Task last update timestamp + * User-friendly job status */ - update_time: string + status: 'pending' | 'in_progress' | 'completed' | 'failed' | 'cancelled' /** - * When task execution started (null if not started) + * Last update timestamp (Unix timestamp in milliseconds) */ - started_at?: string + update_time: number /** - * When task completed or failed (null if not finished) - */ - completed_at?: string -} - -/** - * Task data for list views - */ -export type TaskEntry = { - /** - * Unique task identifier - */ - id: string - /** - * Task type name (e.g., model_upload) - */ - task_name: string - /** - * Current task status - */ - status: 'created' | 'running' | 'completed' | 'failed' - /** - * Task creation timestamp - */ - create_time: string - /** - * When task execution started (null if not started) - */ - started_at?: string - /** - * When task completed or failed (null if not finished) + * Full ComfyUI workflow (10-100KB, omitted if not available). + * + * Sensitive credentials are redacted before the response is returned: + * `extra_data.api_key_comfy_org`, when present, is replaced with the + * literal string `"[REDACTED]"`. The field is preserved (not removed) + * so existence checks still pass, but the value is not usable. + * */ - completed_at?: string -} - -/** - * Paginated list of background tasks for the authenticated user. - */ -export type TasksListResponse = { + workflow?: { + [key: string]: unknown + } /** - * Array of tasks ordered by create_time + * UUID identifying the workflow graph definition */ - tasks: Array - pagination: PaginationInfo + workflow_id?: string } /** - * Result of authorizing a legal-hold release on a user's deletion. + * Response for POST /api/jobs/{job_id}/cancel. Returned on both fresh cancels and idempotent no-ops. */ -export type ReleaseHoldResponse = { - /** - * The Firebase ID of the user whose hold was released - */ - firebase_id: string - /** - * Whether the release authorization is recorded on the deletion request - */ - released: boolean +export type JobCancelResponse = { /** - * Human-readable outcome detail + * True when a cancel event was successfully dispatched by this call. + * False when the job was already in a terminal or cancelling state, + * in which case the call is a no-op (still 200 — idempotent). + * */ - message: string + cancelled: boolean } /** - * Details of a pending or completed user data deletion request. + * Response after importing published workflow assets. */ -export type DeletionRequest = { - /** - * Unique identifier for the deletion request - */ - id: string - /** - * The Firebase ID of the user being deleted - */ - firebase_id: string - /** - * The time the deletion request was created - */ - create_time: string - /** - * Array of deletion status objects - */ - deletion_status: Array +export type ImportPublishedAssetsResponse = { + assets: Array } /** - * Current status of a user data deletion request. + * Request body for importing assets from a published workflow. */ -export type DeletionStatus = { +export type ImportPublishedAssetsRequest = { /** - * The name of the deletion status + * IDs of published assets (inputs and models) to import. */ - status_name: string + published_asset_ids: Array /** - * Additional details about the deletion status + * Optional. Share ID of the published workflow these assets belong to. + * When provided (non-null, non-empty): all published_asset_ids must + * belong to this share's workflow version; returns + * 400/CodeInvalidAssets if the share is not found or any asset does + * not belong to it. + * When omitted, null, or empty string: no share-scoped validation is + * performed and the assets are validated only against global rules + * (legacy behaviour, preserved for clients that have not yet adopted + * share_id). + * */ - status_details: string + share_id?: string | null } /** - * Detailed execution error information from ComfyUI + * Entry in the curated workflow template gallery shown on the home page. */ -export type ExecutionError = { - /** - * ID of the node that failed - */ - node_id: string +export type HubWorkflowTemplateEntry = { /** - * Type name of the node (e.g., "KSampler") + * Content template used for generation (tutorial, showcase, comparison, breakthrough) */ - node_type: string + contentTemplate?: string /** - * Human-readable error message + * Publication date in YYYY-MM-DD format */ - exception_message: string + date?: string + description?: string /** - * Python exception type (e.g., "RuntimeError") + * AI-generated extended description of the workflow */ - exception_type: string + extendedDescription?: string /** - * Array of traceback lines (empty array if not available) + * AI-generated FAQ items */ - traceback: Array + faqItems?: Array<{ + answer: string + question: string + }> /** - * Input values at time of failure (empty object if not available) + * AI-generated step-by-step usage instructions */ - current_inputs: { - [key: string]: unknown + howToUse?: Array + includeOnDistributions?: Array + io?: { + inputs?: Array<{ + [key: string]: unknown + }> + outputs?: Array<{ + [key: string]: unknown + }> } /** - * Output values at time of failure (empty object if not available) + * Whether the template belongs to a module marked as essential. */ - current_outputs: { + isEssential?: boolean + logos?: Array<{ [key: string]: unknown - } -} - -/** - * Full job details including workflow and outputs - */ -export type JobDetailResponse = { - /** - * Unique job identifier - */ - id: string - /** - * User-friendly job status - */ - status: 'pending' | 'in_progress' | 'completed' | 'failed' | 'cancelled' + }> + mediaSubtype?: string + mediaType?: string /** - * Full ComfyUI workflow (10-100KB, omitted if not available). - * - * Sensitive credentials are redacted before the response is returned: - * `extra_data.api_key_comfy_org`, when present, is replaced with the - * literal string `"[REDACTED]"`. The field is preserved (not removed) - * so existence checks still pass, but the value is not usable. - * + * AI-generated SEO meta description (under 160 chars) */ - workflow?: { - [key: string]: unknown - } + metaDescription?: string + models?: Array /** - * Detailed execution error from ComfyUI (only for failed jobs with structured error data) + * Slug identifier for the template */ - execution_error?: ExecutionError + name: string + openSource?: boolean + profile?: HubProfileSummary + requiresCustomNodes?: Array /** - * Job creation timestamp (Unix timestamp in milliseconds) + * Search ranking score reported upstream. */ - create_time: number + searchRank?: number /** - * Last update timestamp (Unix timestamp in milliseconds) + * Share ID for linking to the hub workflow detail */ - update_time: number + shareId?: string /** - * Full outputs object from ComfyUI (only for terminal states) + * Workflow asset size in bytes. */ - outputs?: { - [key: string]: unknown - } + size?: number + status: HubWorkflowStatus /** - * Primary preview output (only for terminal states) + * AI-generated suggested use cases */ - preview_output?: { - [key: string]: unknown - } + suggestedUseCases?: Array + tags?: Array /** - * Total number of output files (omitted for non-terminal states) + * Public URL of the comparison thumbnail */ - outputs_count?: number + thumbnailComparisonUrl?: string /** - * UUID identifying the workflow graph definition + * Public URL of the primary thumbnail */ - workflow_id?: string + thumbnailUrl?: string + thumbnailVariant?: string + title: string + tutorialUrl?: string /** - * ComfyUI execution status and timeline (only for terminal states) + * Usage count reported upstream. */ - execution_status?: { - [key: string]: unknown - } + usage?: number /** - * Node-level execution metadata (only for terminal states) + * Approximate VRAM requirement in bytes. */ - execution_meta?: { - [key: string]: unknown - } + vram?: number } /** - * Response for POST /api/jobs/cancel. + * Public workflow status. NULL in the database is represented as pending in API responses. */ -export type JobsCancelResponse = { - /** - * Job IDs for which a cancel event was successfully dispatched by this - * call. Jobs already in a terminal or cancelling state are idempotently - * skipped and will not appear here. - * - */ - cancelled: Array -} +export type HubWorkflowStatus = + | 'pending' + | 'approved' + | 'rejected' + | 'deprecated' /** - * Request to cancel multiple jobs by ID. + * Abbreviated Hub profile used in workflow listings. */ -export type JobsCancelRequest = { +export type HubProfileSummary = { /** - * Job identifiers (UUIDs) to cancel. + * Public URL of the profile avatar image. */ - job_ids: Array + avatar_url?: string + display_name?: string + username: string } /** - * Response for POST /api/jobs/{job_id}/cancel. Returned on both fresh cancels and idempotent no-ops. + * Abbreviated Hub workflow metadata used in search and listing results. */ -export type JobCancelResponse = { - /** - * True when a cancel event was successfully dispatched by this call. - * False when the job was already in a terminal or cancelling state, - * in which case the call is a no-op (still 200 — idempotent). - * - */ - cancelled: boolean -} - +export type HubWorkflowSummary = { + custom_nodes?: Array + description?: string + metadata?: { + [key: string]: unknown + } + models?: Array + name: string + profile: HubProfileSummary + publish_time?: string | null + sample_image_urls?: Array + share_id: string + status: HubWorkflowStatus + tags?: Array + thumbnail_comparison_url?: string + thumbnail_type?: 'image' | 'video' | 'image_comparison' + thumbnail_url?: string + tutorial_url?: string +} + /** - * Lightweight job data for list views (workflow and full outputs excluded) + * Paginated list of Hub workflows matching search criteria. */ -export type JobEntry = { - /** - * Unique job identifier - */ - id: string - /** - * User-friendly job status - */ - status: 'pending' | 'in_progress' | 'completed' | 'failed' | 'cancelled' +export type HubWorkflowListResponse = { /** - * Detailed execution error from ComfyUI (only for failed jobs with structured error data) + * Cursor for the next page, empty if no more results. */ - execution_error?: ExecutionError + next_cursor?: string /** - * Job creation timestamp (Unix timestamp in milliseconds) + * Array of HubWorkflowSummary (default) or HubWorkflowDetail (when detail=true). */ - create_time: number + workflows: Array +} + +/** + * Full Hub workflow detail including versions, assets, and statistics. + */ +export type HubWorkflowDetail = { /** - * Primary preview output (only present for terminal states) + * Published assets. Each asset's id is the published asset ID (not the original private asset ID). */ - preview_output?: { + assets: Array + custom_nodes?: Array + description?: string + metadata?: { + [key: string]: unknown + } + models?: Array + name: string + profile: HubProfileSummary + publish_time?: string | null + sample_image_urls?: Array + share_id: string + status: HubWorkflowStatus + tags?: Array + thumbnail_comparison_url?: string + thumbnail_type?: 'image' | 'video' | 'image_comparison' + thumbnail_url?: string + tutorial_url?: string + workflow_id: string + workflow_json: { [key: string]: unknown } +} + +/** + * Response indicating whether a Hub username is available. + */ +export type HubUsernameCheckResponse = { /** - * Total number of output files (omitted for non-terminal states) + * Whether the username is available for the caller's workspace. */ - outputs_count?: number + available: boolean /** - * UUID identifying the workflow graph definition + * Up to 5 available alternative usernames (only present when unavailable). */ - workflow_id?: string + suggestions?: Array /** - * Workflow execution start timestamp (Unix milliseconds, only present for terminal states) + * The username that was checked. */ - execution_start_time?: number + username: string /** - * Workflow execution completion timestamp (Unix milliseconds, only present for terminal states) + * If the username format is invalid, describes the format requirement. */ - execution_end_time?: number + validation_error?: string } /** - * Paginated list of jobs for the authenticated user. + * Full public profile for a Hub creator. */ -export type JobsListResponse = { +export type HubProfile = { /** - * Array of jobs ordered by specified sort field + * Public URL of the profile avatar image. */ - jobs: Array - pagination: PaginationInfo + avatar_url?: string + description?: string + display_name?: string + username: string + /** + * List of website URLs. + */ + website_urls?: Array } /** - * Response after adding, updating, or removing tags on an asset. + * List of available Hub labels for categorizing workflows. */ -export type TagsModificationResponse = { +export type HubLabelListResponse = { /** - * Tags that were successfully added (for add operation) + * Available labels filtered by type (or all if no type specified). */ - added?: Array + labels: Array +} + +/** + * Metadata for a single Hub label. + */ +export type HubLabelInfo = { /** - * Tags that were successfully removed (for remove operation) + * Optional description of the label. */ - removed?: Array + description?: string /** - * Tags that were already present (for add operation) + * Human-readable display name. */ - already_present?: Array + display_name: string /** - * Tags that were not present (for remove operation) + * Slug identifier. */ - not_present?: Array + name: string /** - * All tags on the asset after the operation + * Label category. */ - total_tags: Array + type: 'tag' | 'model' | 'custom_node' } /** - * Details of a single validation error encountered during asset operations. + * Response containing a signed upload URL and the target asset path. */ -export type ValidationError = { +export type HubAssetUploadUrlResponse = { /** - * Machine-readable error code + * The public URL where the file will be accessible after upload. */ - code: string + public_url: string /** - * Human-readable error message + * Signed token to pass in the publish request. Has a server-determined TTL. */ - message: string + token: string /** - * Field that failed validation + * Presigned R2 URL for uploading the file via PUT. */ - field: string + upload_url: string } /** - * Result of validating a set of asset operations. + * Request body for requesting a signed upload URL for a Hub asset. */ -export type ValidationResult = { - /** - * Overall validation status (true if all checks passed) - */ - is_valid: boolean +export type HubAssetUploadUrlRequest = { /** - * Blocking validation errors that prevent download + * MIME type of the file (e.g. "image/jpeg", "video/mp4"). Validated against a whitelist; the canonical file extension is derived from this value. + * */ - errors?: Array + content_type: string /** - * Non-blocking validation warnings (informational only) + * Original filename for display purposes. Not used in the storage key. */ - warnings?: Array + filename: string } /** - * Acknowledgement of an async asset download task; clients poll GET /api/tasks/{task_id} for status. + * Execution history response with history array. + * Returns an object with a "history" key containing an array of history entries. + * Each entry includes prompt_id as a property along with execution data. + * */ -export type AssetDownloadResponse = { - /** - * Task ID for tracking download progress via GET /api/tasks/{task_id} - */ - task_id: string - /** - * Current task status - */ - status: 'created' | 'running' | 'completed' | 'failed' +export type HistoryResponse = { /** - * Human-readable message + * Array of history entries ordered by creation time (newest first) */ - message?: string + history: Array } /** - * Metadata for a remotely hosted asset resolved by URL. + * History entry with prompt_id and execution data */ -export type AssetMetadataResponse = { +export type HistoryEntry = { /** - * Size of the asset in bytes (-1 if unknown) + * Job creation timestamp (Unix timestamp in milliseconds) */ - content_length: number + create_time?: number /** - * MIME type of the asset + * Metadata about the execution and nodes */ - content_type?: string + meta?: { + [key: string]: unknown + } /** - * Suggested filename for the asset from source + * Output data from execution (generated images, files, etc.) */ - filename?: string + outputs?: { + [key: string]: unknown + } /** - * Display name or title for the asset from source + * Filtered prompt execution data (lightweight format) */ - name?: string + prompt?: { + /** + * Additional execution data (workflow removed from extra_pnginfo) + */ + extra_data?: { + [key: string]: unknown + } + /** + * Execution priority + */ + priority?: number + /** + * The prompt ID + */ + prompt_id?: string + } /** - * Tags for categorization from source + * Unique identifier for this prompt execution */ - tags?: Array + prompt_id: string /** - * Preview image as base64-encoded data URL + * Execution status and timeline information */ - preview_image?: string + status?: { + [key: string]: unknown + } /** - * Validation results for the file + * UUID identifying the workflow graph definition */ - validation?: ValidationResult + workflow_id?: string } /** - * Histogram of tag counts used for refining asset search results. + * Request to manage history operations */ -export type AssetTagHistogramResponse = { +export type HistoryManageRequest = { /** - * Map of tag names to their occurrence counts on matching assets + * If true, clear all history for the authenticated user */ - tag_counts: { - [key: string]: number - } + clear?: boolean + /** + * Array of job IDs to delete from history + */ + delete?: Array } /** - * Paginated list of available asset tags. + * Detailed execution history response for a specific prompt. + * Returns a dictionary with prompt_id as key and full history data as value. + * */ -export type ListTagsResponse = { +export type HistoryDetailResponse = { + [key: string]: HistoryDetailEntry +} + +/** + * History entry with full prompt data + */ +export type HistoryDetailEntry = { /** - * List of tags + * Metadata about the execution and nodes */ - tags: Array + meta?: { + [key: string]: unknown + } /** - * Total number of tags + * Output data from execution (generated images, files, etc.) */ - total: number + outputs?: { + [key: string]: unknown + } /** - * Whether more tags are available + * Full prompt execution data */ - has_more: boolean + prompt?: { + /** + * Additional execution data + */ + extra_data?: { + [key: string]: unknown + } + /** + * Output nodes to execute + */ + outputs_to_execute?: Array + /** + * Execution priority + */ + priority?: number + /** + * The workflow nodes + */ + prompt?: { + [key: string]: unknown + } + /** + * The prompt ID + */ + prompt_id?: string + } + /** + * Execution status and timeline information + */ + status?: { + [key: string]: unknown + } } /** - * Metadata for a single tag that can be applied to assets. + * Metadata for a global subgraph blueprint (without full data) */ -export type TagInfo = { +export type GlobalSubgraphInfo = { /** - * Tag name + * The full subgraph JSON data (may be empty in list view) + */ + data?: string + /** + * Additional information about the subgraph + */ + info: { + /** + * The node pack/module that provides this subgraph + */ + node_pack: string + } + /** + * Display name of the subgraph blueprint */ name: string /** - * Number of assets using this tag + * Source type of the subgraph - "templates" for workflow templates or "custom_node" for custom node subgraphs */ - count: number + source: string } /** - * Paginated list of assets belonging to the authenticated user. + * Full data for a global subgraph blueprint */ -export type ListAssetsResponse = { +export type GlobalSubgraphData = { /** - * List of assets matching the query + * The full subgraph JSON data as a string */ - assets: Array + data: string /** - * Total number of assets matching the filters + * Additional information about the subgraph */ - total: number + info: { + /** + * The node pack/module that provides this subgraph + */ + node_pack: string + } /** - * Whether more assets are available beyond this page + * Display name of the subgraph blueprint */ - has_more: boolean + name: string /** - * Opaque cursor to pass as the `after` query parameter to fetch the - * next page. Omitted from the response when there are no more results. - * + * Source type of the subgraph - "templates" for workflow templates or "custom_node" for custom node subgraphs */ - next_cursor?: string + source: string } /** - * Represents a user-owned asset (image, video, or other generated output). + * Individual file entry within a full user data response. */ -export type Asset = { - /** - * Unique identifier for the asset - */ - id: string - /** - * Name of the asset file - */ - name: string +export type GetUserDataResponseFullFile = { /** - * Display name of the asset. Mirrors name for backwards compatibility. + * UNIX timestamp of the last modification in milliseconds. */ - display_name?: string | null + modified?: number /** - * Blake3 hash of the asset content. + * File name or path relative to the user directory. */ - hash?: string + path?: string /** - * Size of the asset in bytes + * File size in bytes. */ size?: number +} + +/** + * List of user data file entries (each with path, size, and modification time) returned when full_info=true. + */ +export type GetUserDataResponseFull = Array + +/** + * Request body for forking an existing workflow into the user's account. + */ +export type ForkWorkflowRequest = { /** - * MIME type of the asset + * Name for the forked workflow */ - mime_type?: string + name?: string /** - * Tags associated with the asset + * Version number to fork from */ - tags?: Array + source_version: number +} + +/** + * Response after submitting feedback + */ +export type FeedbackResponse = { + [key: string]: unknown +} + +/** + * Request to submit user feedback + */ +export type FeedbackRequest = { /** - * Custom user metadata for the asset + * The feedback content or message */ - user_metadata?: { - [key: string]: unknown - } + content?: string /** - * System-managed metadata from download sources (HuggingFace, CivitAI, etc.) - read-only, not user-modifiable + * Additional metadata about the feedback */ - readonly metadata?: { + metadata?: { [key: string]: unknown } /** - * URL for asset preview/thumbnail + * User's rating of ComfyUI Cloud experience (1-5 stars) */ - preview_url?: string + rating?: number /** - * Durable, owner-gated short link to this asset's content (relative `/api/s/{id}` path). Stable across the underlying signed URL's expiry — resolving it re-mints a fresh signed URL on every request — so it is safe to persist or share into chat, unlike `preview_url`. Only the minting user can resolve it. Omitted when the short-link surface is disabled or the asset has no resolvable content hash. + * Type of feedback being submitted */ - short_url?: string | null + type: 'missing_nodes' | 'general' | 'missing_models' +} + +/** + * Response containing a signed download URL for an exported asset archive. + */ +export type ExportDownloadUrlResponse = { /** - * ID of the preview asset if available + * When the signed URL expires */ - preview_id?: string | null + expires_at?: string /** - * ID of the job that created this asset, if available + * Signed URL for downloading the export ZIP file */ - job_id?: string | null + url: string +} + +/** + * Response containing the issued Cloud JWT and its expiry. + */ +export type ExchangeTokenResponse = { /** - * Timestamp when the asset was created + * Token expiration time (RFC 3339) */ - created_at: string + expires_at: string /** - * Timestamp when the asset was last updated + * Permission strings for the role */ - updated_at: string + permissions: Array /** - * Timestamp when the asset was last accessed + * User's role in the workspace */ - last_access_time?: string + role: 'owner' | 'member' /** - * Whether this asset is immutable (cannot be modified or deleted) + * Cloud JWT token */ - is_immutable?: boolean + token: string + workspace: WorkspaceSummary +} + +/** + * Optional request body for the token exchange endpoint. The Firebase JWT + * being exchanged is supplied via the `Authorization: Bearer` header; this + * body only carries workspace-selection input. + * + */ +export type ExchangeTokenRequest = { /** - * Relative path in global-namespace-root form (e.g. "models/checkpoints/flux.safetensors") + * Workspace ID to get token for. Defaults to personal workspace if omitted. */ - file_path?: string | null + workspace_id?: string } /** - * Response returned when an existing asset is successfully updated. + * Result of redeeming a desktop login code. */ -export type AssetUpdated = { +export type DesktopLoginCodeRedeemResponse = { /** - * Asset ID + * The code is now claimed for the authenticated user. */ - id: string + status: 'redeemed' +} + +/** + * Request to claim a desktop login code for the authenticated user. + */ +export type DesktopLoginCodeRedeemRequest = { /** - * Updated name of the asset + * The login code the desktop app placed in the browser URL. */ - name?: string + code: string +} + +/** + * Exchange poll result. Pending until the code is redeemed in the browser. + */ +export type DesktopLoginCodeExchangeResponse = { /** - * Display name of the asset. Mirrors name for backwards compatibility. - */ - display_name?: string | null - /** - * Blake3 hash of the asset content. - */ - hash?: string - /** - * Tags associated with the asset - */ - tags?: Array - /** - * Updated MIME type of the asset - */ - mime_type?: string - /** - * Updated custom metadata - */ - user_metadata?: { - [key: string]: unknown - } - /** - * ID of the job that created this asset, if available - */ - job_id?: string | null - /** - * Timestamp of the update + * One-time Firebase custom token for the redeeming user. Present only when status is "complete". */ - updated_at: string + custom_token?: string /** - * Relative path in global-namespace-root form (e.g. "models/checkpoints/flux.safetensors") + * Whether the code has been redeemed yet. */ - file_path?: string | null + status: 'pending' | 'complete' } /** - * Response returned when a new asset is successfully created. + * Request to exchange a redeemed login code for a custom token. */ -export type AssetCreated = Asset & { +export type DesktopLoginCodeExchangeRequest = { /** - * Whether this was a new asset creation (true) or returned existing (false) + * The login code returned at creation. */ - created_new: boolean + code: string + /** + * PKCE code verifier matching the challenge supplied at creation. + */ + code_verifier: string } /** - * Response after updating the review status of a Hub workflow. + * A freshly minted desktop login code and its polling parameters. */ -export type SetReviewStatusResponse = { +export type DesktopLoginCodeCreateResponse = { /** - * The share IDs that were submitted for review + * Opaque single-use login code ("dlc_" prefix). + */ + code: string + /** + * Seconds until the code expires if not redeemed. */ - share_ids: Array + expires_in: number /** - * The applied review status + * Suggested seconds between exchange polls. */ - status: 'approved' | 'rejected' + poll_interval: number } /** - * Request body for setting the review status of a Hub workflow. + * Request to mint a desktop login code. */ -export type SetReviewStatusRequest = { +export type DesktopLoginCodeCreateRequest = { + /** + * Desktop app version string. + */ + app_version: string + /** + * PKCE code challenge - base64url(SHA256(code_verifier)) per RFC 7636 (S256 only). + */ + code_challenge: string /** - * The share IDs of the hub workflows to review + * Stable identifier of the desktop installation, used only for the login attribution event. Omit when telemetry consent is off - the login flow still works, but no attribution event is emitted. */ - share_ids: Array + installation_id?: string /** - * The review decision for the workflows + * Desktop platform identifier (e.g. darwin, win32, linux). */ - status: 'approved' | 'rejected' + platform: string } /** @@ -3146,682 +2783,562 @@ export type DeleteSessionResponse = { } /** - * Response after creating a session cookie + * Request body for creating a new workspace. */ -export type CreateSessionResponse = { - /** - * Whether the session was created successfully - */ - success: boolean +export type CreateWorkspaceRequest = { /** - * Session expiration time in seconds (5 days) + * Display name for the workspace */ - expiresIn?: number + name: string } /** - * User information response + * Response containing the newly created workspace API key. */ -export type UserResponse = { +export type CreateWorkspaceApiKeyResponse = { /** - * Firebase UID of the authenticated user + * When the key was created + */ + created_at: string + /** + * User-provided description of the key's purpose. Limit is byte-based (UTF-8 encoding); 5000 bytes equals 5000 ASCII characters or fewer multi-byte characters. + */ + description: string + /** + * When the key expires (if set) + */ + expires_at?: string + /** + * API key ID */ id: string /** - * User status (always "active" for authenticated users) + * The full plaintext API key (only shown once) */ - status: string -} - -/** - * System statistics response - */ -export type SystemStatsResponse = { - system: { - /** - * Operating system - */ - os: string - /** - * Python version - */ - python_version: string - /** - * Whether using embedded Python - */ - embedded_python: boolean - /** - * ComfyUI version - */ - comfyui_version: string - /** - * How this ComfyUI instance is deployed (e.g. cloud, local-git, local-portable, local-desktop) - */ - deploy_environment?: string - /** - * ComfyUI frontend version (commit hash or tag) - */ - comfyui_frontend_version?: string - /** - * Workflow templates version - */ - workflow_templates_version?: string - /** - * Cloud ingest service version (commit hash) - */ - cloud_version?: string - /** - * PyTorch version - */ - pytorch_version: string - /** - * Command line arguments - */ - argv: Array - /** - * Total RAM in bytes - */ - ram_total: number - /** - * Free RAM in bytes - */ - ram_free: number - } - devices: Array<{ - /** - * Device name - */ - name: string - /** - * Device type - */ - type: string - /** - * Total VRAM in bytes - */ - vram_total?: number - /** - * Free VRAM in bytes - */ - vram_free?: number - }> + key: string + /** + * First 8 chars after prefix for display + */ + key_prefix: string + /** + * User-provided label + */ + name: string } /** - * System logs response + * Request body for creating a new workspace-scoped API key. */ -export type LogsResponse = Array<{ +export type CreateWorkspaceApiKeyRequest = { /** - * When the log entry was created + * User-provided description of the key's purpose. Limit is byte-based (UTF-8 encoding); 5000 bytes equals 5000 ASCII characters or fewer multi-byte characters. */ - timestamp?: string + description?: string /** - * Log level + * Optional expiration timestamp */ - level?: 'debug' | 'info' | 'warn' | 'error' + expires_at?: string /** - * Log message + * User-provided label for the key */ - message?: string + name: string +} + +/** + * Request body for creating a new version of a saved workflow. + */ +export type CreateWorkflowVersionRequest = { /** - * Source of the log entry + * The version number this change is based on (for optimistic concurrency) */ - source?: string + base_version: number /** - * Additional log metadata + * The updated ComfyUI workflow JSON */ - metadata?: { + workflow_json: { [key: string]: unknown } -}> - -/** - * Response after submitting feedback - */ -export type FeedbackResponse = { - [key: string]: unknown } /** - * Request to submit user feedback + * Request body for creating a new saved workflow. */ -export type FeedbackRequest = { +export type CreateWorkflowRequest = { /** - * Type of feedback being submitted + * Default view mode */ - type: 'missing_nodes' | 'general' | 'missing_models' + default_view?: 'workflow' | 'app' /** - * The feedback content or message + * Description of the workflow */ - content?: string + description?: string /** - * User's rating of ComfyUI Cloud experience (1-5 stars) + * ID of the source workflow if forked */ - rating?: number + forked_from_workflow_id?: string /** - * Additional metadata about the feedback + * ID of the source workflow version if forked */ - metadata?: { - [key: string]: unknown - } -} - -/** - * Represents a model file with metadata - */ -export type ModelFile = { + forked_from_workflow_version_id?: string /** - * The filename of the model + * Display name for the workflow */ - name: string + name?: string /** - * Index of the path where this model is located + * The ComfyUI workflow JSON */ - pathIndex: number + workflow_json: { + [key: string]: unknown + } } /** - * Represents a folder containing models + * Response after successfully purchasing a credit top-up. */ -export type ModelFolder = { +export type CreateTopupResponse = { /** - * The name of the model folder + * Amount being charged in cents */ - name: string + amount_cents: number /** - * List of paths where models of this type are stored + * Billing operation ID to poll for status via GET /api/billing/ops/{id} */ - folders: Array + billing_op_id: string + /** + * Current status of the top-up + */ + status: 'pending' | 'completed' | 'failed' + /** + * Unique identifier for the top-up request (same as billing_op_id, deprecated) + */ + topup_id: string } /** - * Error response for ComfyUI prompt execution. + * Request body for purchasing a one-time credit top-up. */ -export type PromptErrorResponse = { - [key: string]: unknown +export type CreateTopupRequest = { + /** + * Amount to charge and grant as credits (in cents). Minimum $5.00. + */ + amount_cents: number + /** + * Client-provided key to prevent duplicate operations. + * If a billing op with this key already exists, returns the existing op instead of creating a new one. + * + */ + idempotency_key?: string } /** - * Individual file entry within a full user data response. + * Response after creating a session cookie */ -export type GetUserDataResponseFullFile = { +export type CreateSessionResponse = { /** - * File name or path relative to the user directory. + * Session expiration time in seconds (5 days) */ - path?: string + expiresIn?: number /** - * File size in bytes. + * Whether the session was created successfully */ - size?: number + success: boolean +} + +/** + * Request body for creating a new user secret. + */ +export type CreateSecretRequest = { /** - * UNIX timestamp of the last modification in milliseconds. + * User-provided label for the secret */ - modified?: number + name: string + /** + * Optional provider identifier (e.g., huggingface, civitai) + */ + provider?: string + /** + * The plaintext secret to encrypt and store + */ + secret_value: string } /** - * List of user data file entries (each with path, size, and modification time) returned when full_info=true. + * Request body for inviting a user to a workspace. */ -export type GetUserDataResponseFull = Array +export type CreateInviteRequest = { + /** + * Email address to invite + */ + email: string +} /** - * User data listing entry with file metadata (path, size, modification time). + * Request body for creating a new Hub profile. */ -export type UserDataResponseFull = { - path?: string - size?: number +export type CreateHubProfileRequest = { /** - * UNIX timestamp of the last modification in milliseconds. + * Token (from /api/hub/assets/upload-url) for an avatar image. Omit to have no avatar. + * */ - modified?: number + avatar_token?: string + description?: string + display_name?: string + /** + * Unique URL-safe slug for the hub profile. Immutable after creation. + */ + username: string + /** + * List of website URLs. + */ + website_urls?: Array + /** + * ID of the workspace to create the hub profile for. The authenticated user must belong to this workspace. + */ + workspace_id: string } /** - * Request to manage history operations + * Response after successfully cancelling a subscription. */ -export type HistoryManageRequest = { +export type CancelSubscriptionResponse = { /** - * Array of job IDs to delete from history + * Billing operation ID to poll for status via GET /api/billing/ops/{id} */ - delete?: Array + billing_op_id: string /** - * If true, clear all history for the authenticated user + * The date when the subscription will end (end of current billing period) */ - clear?: boolean + cancel_at: string } /** - * Job status information + * Request body for cancelling the current subscription. */ -export type JobStatusResponse = { +export type CancelSubscriptionRequest = { /** - * The job ID + * Client-provided key to prevent duplicate operations. + * If a billing op with this key already exists, returns the existing op instead of creating a new one. + * */ - id: string + idempotency_key?: string +} + +/** + * Response after bulk-revoking API keys for a workspace member. + */ +export type BulkRevokeApiKeysResponse = { /** - * Current job status + * Number of API keys that were revoked */ - status: - | 'waiting_to_dispatch' - | 'pending' - | 'in_progress' - | 'completed' - | 'error' - | 'cancelled' + revoked_count: number +} + +/** + * Current billing and subscription status for a workspace. + */ +export type BillingStatusResponse = { + billing_status?: BillingStatus /** - * When the job was created + * When the subscription will become inactive (if canceled) */ - created_at: string + cancel_at?: string /** - * When the job was last updated + * Whether the workspace has available credits */ - updated_at: string + has_funds: boolean /** - * When the job status was last changed + * Whether the workspace has an active subscription */ - last_state_update?: string + is_active: boolean /** - * The inference instance assigned to this job (if any) + * Plan identifier (e.g., standard-monthly, team-pro-annual) */ - assigned_inference?: string | null + plan_slug?: string /** - * Error message if the job failed + * When the current billing period ends and the next one begins */ - error_message?: string | null -} - -/** - * Response after a queue management action (delete or clear). - */ -export type QueueManageResponse = { + renewal_date?: string + subscription_duration?: SubscriptionDuration /** - * Array of job IDs that were successfully cancelled + * Subscription activity status (scheduled subscriptions are not returned) */ - deleted?: Array + subscription_status?: 'active' | 'ended' | 'canceled' + subscription_tier?: SubscriptionTier /** - * Whether the queue was cleared + * The team credit stop the workspace is currently subscribed to, for per-credit Team plans (BE-1254). Lets clients tell apart team subscriptions, which all share subscription_tier=TEAM. Always present; null for personal plans (use subscription_tier to distinguish those) and for legacy team plans without a credit stop. */ - cleared?: boolean + team_credit_stop: TeamCreditStopSummary | null } /** - * Request to manage queue operations + * Payment lifecycle status */ -export type QueueManageRequest = { - /** - * Array of job IDs to cancel; pending and running jobs transition to cancelled - */ - delete?: Array +export type BillingStatus = + | 'awaiting_payment_method' + | 'pending_payment' + | 'paid' + | 'payment_failed' + | 'inactive' + +/** + * List of available billing plans for subscription. + */ +export type BillingPlansResponse = { /** - * If true, clear all pending jobs from the queue + * Current plan slug if subscribed */ - clear?: boolean + current_plan_slug?: string + plans: Array + team_credit_stops?: TeamCreditStops } /** - * Queue information with pending and running jobs + * Status of an asynchronous billing operation. */ -export type QueueInfo = { +export type BillingOpStatusResponse = { /** - * Array of currently running job items + * When the operation completed (success or failure) */ - queue_running?: Array<[unknown, unknown, unknown, unknown, unknown]> + completed_at?: string /** - * Array of pending job items (ordered by creation time, oldest first) + * Error message if status is failed */ - queue_pending?: Array<[unknown, unknown, unknown, unknown, unknown]> + error_message?: string + /** + * Unique identifier for the billing operation + */ + id: string + /** + * When the operation was initiated + */ + started_at: string + /** + * Current status of the operation + */ + status: 'pending' | 'succeeded' | 'failed' } /** - * Detailed execution history response for a specific prompt. - * Returns a dictionary with prompt_id as key and full history data as value. - * + * Paginated list of billing events for a workspace. */ -export type HistoryDetailResponse = { - [key: string]: HistoryDetailEntry +export type BillingEventsResponse = { + events: Array + /** + * Items per page + */ + limit: number + /** + * Current page number (1-indexed) + */ + page: number + /** + * Total number of events + */ + total: number + /** + * Total number of pages + */ + totalPages: number } /** - * History entry with full prompt data + * A single history event. The cloud history-events store is the single source of truth for both billing events (charges, credits, adjustments) and user-facing usage events. */ -export type HistoryDetailEntry = { +export type BillingEvent = { /** - * Full prompt execution data + * When the event occurred */ - prompt?: { - /** - * Execution priority - */ - priority?: number - /** - * The prompt ID - */ - prompt_id?: string - /** - * The workflow nodes - */ - prompt?: { - [key: string]: unknown - } - /** - * Additional execution data - */ - extra_data?: { - [key: string]: unknown - } - /** - * Output nodes to execute - */ - outputs_to_execute?: Array - } + createdAt: string /** - * Output data from execution (generated images, files, etc.) + * Unique event identifier */ - outputs?: { - [key: string]: unknown - } + event_id: string /** - * Execution status and timeline information + * Type of history event. Billing types (e.g. invoice_paid, checkout_completed, topup_completed) and the migrated user-facing usage types (account_created, credit_added, api_usage_completed, cloud_subscription_created, cloud_subscription_paid, cloud_subscription_credit_added, cloud_workflow_executed, free_tier_credit_granted). Kept as a free-form string for back-compat with existing billing-event consumers. */ - status?: { - [key: string]: unknown - } + event_type: string /** - * Metadata about the execution and nodes + * Event-specific parameters */ - meta?: { + params?: { [key: string]: unknown } } /** - * History entry with prompt_id and execution data + * Current credit balance and usage details for a workspace. */ -export type HistoryEntry = { - /** - * Unique identifier for this prompt execution - */ - prompt_id: string +export type BillingBalanceResponse = { /** - * Job creation timestamp (Unix timestamp in milliseconds) + * The total remaining balance in microamount (1/1,000,000 of the currency unit) */ - create_time?: number + amount_micros: number /** - * UUID identifying the workflow graph definition + * The remaining balance from cloud credits in microamount */ - workflow_id?: string + cloud_credit_balance_micros?: number /** - * Filtered prompt execution data (lightweight format) + * Currency code */ - prompt?: { - /** - * Execution priority - */ - priority?: number - /** - * The prompt ID - */ - prompt_id?: string - /** - * Additional execution data (workflow removed from extra_pnginfo) - */ - extra_data?: { - [key: string]: unknown - } - } + currency: string /** - * Output data from execution (generated images, files, etc.) + * The effective balance (total balance minus pending charges). Can be negative if pending charges exceed the balance. */ - outputs?: { - [key: string]: unknown - } + effective_balance_micros?: number /** - * Execution status and timeline information + * The total amount of pending/unbilled charges from draft invoices in microamount */ - status?: { - [key: string]: unknown - } + pending_charges_micros?: number /** - * Metadata about the execution and nodes + * The remaining balance from prepaid commits in microamount */ - meta?: { - [key: string]: unknown - } + prepaid_balance_micros?: number } /** - * Execution history response with history array. - * Returns an object with a "history" key containing an array of history entries. - * Each entry includes prompt_id as a property along with execution data. - * + * Response returned when an existing asset is successfully updated. */ -export type HistoryResponse = { +export type AssetUpdated = { /** - * Array of history entries ordered by creation time (newest first) + * Display name of the asset. Mirrors name for backwards compatibility. */ - history: Array -} - -/** - * Full data for a global subgraph blueprint - */ -export type GlobalSubgraphData = { + display_name?: string | null /** - * Source type of the subgraph - "templates" for workflow templates or "custom_node" for custom node subgraphs + * Relative path in global-namespace-root form (e.g. "models/checkpoints/flux.safetensors") */ - source: string + file_path?: string | null /** - * Display name of the subgraph blueprint + * Blake3 hash of the asset content. */ - name: string + hash?: string /** - * Additional information about the subgraph + * Asset ID */ - info: { - /** - * The node pack/module that provides this subgraph - */ - node_pack: string - } + id: string /** - * The full subgraph JSON data as a string + * ID of the job that created this asset, if available */ - data: string -} - -/** - * Metadata for a global subgraph blueprint (without full data) - */ -export type GlobalSubgraphInfo = { + job_id?: string | null /** - * Source type of the subgraph - "templates" for workflow templates or "custom_node" for custom node subgraphs + * Updated MIME type of the asset */ - source: string + mime_type?: string /** - * Display name of the subgraph blueprint + * Updated name of the asset */ - name: string + name?: string /** - * Additional information about the subgraph + * Tags associated with the asset */ - info: { - /** - * The node pack/module that provides this subgraph - */ - node_pack: string - } + tags?: Array /** - * The full subgraph JSON data (may be empty in list view) + * Timestamp of the update */ - data?: string -} - -/** - * Metadata describing a single ComfyUI node type and its inputs/outputs. - */ -export type NodeInfo = { + updated_at: string /** - * Input specifications for the node + * Updated custom metadata */ - input?: { + user_metadata?: { [key: string]: unknown } +} + +/** + * Histogram of tag counts used for refining asset search results. + */ +export type AssetTagHistogramResponse = { /** - * Order of inputs for display + * Map of tag names to their occurrence counts on matching assets */ - input_order?: { - [key: string]: Array + tag_counts: { + [key: string]: number } +} + +/** + * Metadata for a remotely hosted asset resolved by URL. + */ +export type AssetMetadataResponse = { /** - * Output types of the node + * Size of the asset in bytes (-1 if unknown) */ - output?: Array + content_length: number /** - * Whether each output is a list + * MIME type of the asset */ - output_is_list?: Array + content_type?: string /** - * Names of the outputs + * Suggested filename for the asset from source */ - output_name?: Array + filename?: string /** - * Internal name of the node + * Display name or title for the asset from source */ name?: string /** - * Display name of the node + * Preview image as base64-encoded data URL */ - display_name?: string + preview_image?: string /** - * Description of the node + * Tags for categorization from source */ - description?: string + tags?: Array /** - * Python module implementing the node + * Validation results for the file */ - python_module?: string + validation?: ValidationResult +} + +/** + * Acknowledgement of an async asset download task; clients poll GET /api/tasks/{task_id} for status. + */ +export type AssetDownloadResponse = { /** - * Category of the node + * Human-readable message */ - category?: string + message?: string /** - * Whether this is an output node + * Current task status */ - output_node?: boolean + status: 'created' | 'running' | 'completed' | 'failed' /** - * Tooltips for outputs + * Task ID for tracking download progress via GET /api/tasks/{task_id} */ - output_tooltips?: Array + task_id: string +} + +/** + * Response returned when a new asset is successfully created. + */ +export type AssetCreated = Asset & { /** - * Whether the node is deprecated + * Whether this was a new asset creation (true) or returned existing (false) */ - deprecated?: boolean + created_new: boolean +} + +/** + * Response returned after successfully accepting a workspace invitation. + */ +export type AcceptInviteResponse = { /** - * Whether the node is experimental + * ID of the workspace joined */ - experimental?: boolean + workspace_id: string /** - * Whether this is an API node + * Name of the workspace joined */ - api_node?: boolean + workspace_name: string } /** - * Metadata about the currently running and queued prompts. - */ -export type PromptInfo = { - exec_info?: { - /** - * Number of items remaining in the queue - */ - queue_remaining?: number - } -} - -/** - * Response containing a signed download URL for an exported asset archive. - */ -export type ExportDownloadUrlResponse = { - /** - * Signed URL for downloading the export ZIP file - */ - url: string - /** - * When the signed URL expires - */ - expires_at?: string -} - -/** - * Response returned after successfully queuing a workflow prompt. - */ -export type PromptResponse = { - /** - * Unique identifier for the prompt execution - */ - prompt_id?: string - /** - * Priority number in the queue - */ - number?: number - /** - * Any errors in the nodes of the prompt - */ - node_errors?: { - [key: string]: unknown - } -} - -/** - * Request body for submitting a ComfyUI workflow prompt for execution. - */ -export type PromptRequest = { - /** - * The workflow graph to execute - */ - prompt: { - [key: string]: unknown - } - /** - * Priority number for the queue (lower numbers have higher priority) - */ - number?: number - /** - * If true, adds the prompt to the front of the queue - */ - front?: boolean - /** - * Extra data to be associated with the prompt - */ - extra_data?: { - [key: string]: unknown - } - /** - * List of node names to execute - */ - partial_execution_targets?: Array - /** - * UUID identifying the cloud workflow entity to associate with this job - */ - workflow_id?: string - /** - * UUID identifying the workflow version to associate with this job - */ - workflow_version_id?: string -} - -/** - * Paginated list of assets belonging to the authenticated user. + * Paginated list of assets belonging to the authenticated user. */ export type ListAssetsResponseWritable = { /** * List of assets matching the query */ assets: Array - /** - * Total number of assets matching the filters - */ - total: number /** * Whether more assets are available beyond this page */ @@ -3832,1637 +3349,320 @@ export type ListAssetsResponseWritable = { * */ next_cursor?: string + /** + * Total number of assets matching the filters + */ + total: number } /** * Represents a user-owned asset (image, video, or other generated output). */ export type AssetWritable = { - /** - * Unique identifier for the asset - */ - id: string - /** - * Name of the asset file - */ - name: string - /** - * Display name of the asset. Mirrors name for backwards compatibility. - */ - display_name?: string | null - /** - * Blake3 hash of the asset content. - */ - hash?: string - /** - * Size of the asset in bytes - */ - size?: number - /** - * MIME type of the asset - */ - mime_type?: string - /** - * Tags associated with the asset - */ - tags?: Array - /** - * Custom user metadata for the asset - */ - user_metadata?: { - [key: string]: unknown - } - /** - * URL for asset preview/thumbnail - */ - preview_url?: string - /** - * Durable, owner-gated short link to this asset's content (relative `/api/s/{id}` path). Stable across the underlying signed URL's expiry — resolving it re-mints a fresh signed URL on every request — so it is safe to persist or share into chat, unlike `preview_url`. Only the minting user can resolve it. Omitted when the short-link surface is disabled or the asset has no resolvable content hash. - */ - short_url?: string | null - /** - * ID of the preview asset if available - */ - preview_id?: string | null - /** - * ID of the job that created this asset, if available - */ - job_id?: string | null /** * Timestamp when the asset was created */ created_at: string /** - * Timestamp when the asset was last updated - */ - updated_at: string - /** - * Timestamp when the asset was last accessed - */ - last_access_time?: string - /** - * Whether this asset is immutable (cannot be modified or deleted) + * Display name of the asset. Mirrors name for backwards compatibility. */ - is_immutable?: boolean + display_name?: string | null /** * Relative path in global-namespace-root form (e.g. "models/checkpoints/flux.safetensors") */ file_path?: string | null -} - -/** - * Response returned when a new asset is successfully created. - */ -export type AssetCreatedWritable = AssetWritable & { - /** - * Whether this was a new asset creation (true) or returned existing (false) - */ - created_new: boolean -} - -/** - * Response after submitting feedback - */ -export type FeedbackResponseWritable = { - [key: string]: unknown -} - -export type GetPromptInfoData = { - body?: never - path?: never - query?: never - url: '/api/prompt' -} - -export type GetPromptInfoErrors = { - /** - * Unauthorized - */ - 401: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type GetPromptInfoError = GetPromptInfoErrors[keyof GetPromptInfoErrors] - -export type GetPromptInfoResponses = { /** - * Success - */ - 200: PromptInfo -} - -export type GetPromptInfoResponse = - GetPromptInfoResponses[keyof GetPromptInfoResponses] - -export type ExecutePromptData = { - body: PromptRequest - path?: never - query?: never - url: '/api/prompt' -} - -export type ExecutePromptErrors = { - /** - * Invalid prompt - */ - 400: PromptErrorResponse - /** - * Payment required - Insufficient credits - */ - 402: PromptErrorResponse - /** - * Workflow JSON too large - */ - 413: PromptErrorResponse - /** - * Payment required - User has not paid - */ - 429: PromptErrorResponse - /** - * Internal server error - */ - 500: PromptErrorResponse - /** - * Service unavailable - */ - 503: PromptErrorResponse -} - -export type ExecutePromptError = ExecutePromptErrors[keyof ExecutePromptErrors] - -export type ExecutePromptResponses = { - /** - * Success - Prompt accepted + * Blake3 hash of the asset content. */ - 200: PromptResponse -} - -export type ExecutePromptResponse = - ExecutePromptResponses[keyof ExecutePromptResponses] - -export type GetNodeInfoData = { - body?: never - path?: never - query?: never - url: '/api/object_info' -} - -export type GetNodeInfoResponses = { - /** - * Success - */ - 200: { - [key: string]: NodeInfo - } -} - -export type GetNodeInfoResponse = - GetNodeInfoResponses[keyof GetNodeInfoResponses] - -export type GetFeaturesData = { - body?: never - path?: never - query?: never - url: '/api/features' -} - -export type GetFeaturesResponses = { - /** - * Success - */ - 200: { - /** - * Whether the server supports preview metadata - */ - supports_preview_metadata?: boolean - /** - * Maximum upload size in bytes - */ - max_upload_size?: number - [key: string]: unknown | boolean | number | undefined - } -} - -export type GetFeaturesResponse = - GetFeaturesResponses[keyof GetFeaturesResponses] - -export type GetNodeReplacementsData = { - body?: never - path?: never - query?: never - url: '/api/node_replacements' -} - -export type GetNodeReplacementsErrors = { - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type GetNodeReplacementsError = - GetNodeReplacementsErrors[keyof GetNodeReplacementsErrors] - -export type GetNodeReplacementsResponses = { - /** - * Success - Node replacement mappings - */ - 200: { - [key: string]: unknown - } -} - -export type GetNodeReplacementsResponse = - GetNodeReplacementsResponses[keyof GetNodeReplacementsResponses] - -export type GetWorkflowTemplatesData = { - body?: never - path?: never - query?: never - url: '/api/workflow_templates' -} - -export type GetWorkflowTemplatesResponses = { - /** - * Empty object for workflow templates - */ - 200: { - [key: string]: unknown - } -} - -export type GetWorkflowTemplatesResponse = - GetWorkflowTemplatesResponses[keyof GetWorkflowTemplatesResponses] - -export type GetGlobalSubgraphsData = { - body?: never - path?: never - query?: never - url: '/api/global_subgraphs' -} - -export type GetGlobalSubgraphsErrors = { - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type GetGlobalSubgraphsError = - GetGlobalSubgraphsErrors[keyof GetGlobalSubgraphsErrors] - -export type GetGlobalSubgraphsResponses = { - /** - * Success - Map of subgraph IDs to their metadata - */ - 200: { - [key: string]: GlobalSubgraphInfo - } -} - -export type GetGlobalSubgraphsResponse = - GetGlobalSubgraphsResponses[keyof GetGlobalSubgraphsResponses] - -export type GetGlobalSubgraphData = { - body?: never - path: { - /** - * The unique identifier of the subgraph blueprint - */ - id: string - } - query?: never - url: '/api/global_subgraphs/{id}' -} - -export type GetGlobalSubgraphErrors = { - /** - * Subgraph not found - */ - 404: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type GetGlobalSubgraphError = - GetGlobalSubgraphErrors[keyof GetGlobalSubgraphErrors] - -export type GetGlobalSubgraphResponses = { - /** - * Success - Full subgraph data - */ - 200: GlobalSubgraphData -} - -export type GetGlobalSubgraphResponse = - GetGlobalSubgraphResponses[keyof GetGlobalSubgraphResponses] - -export type GetModelFoldersData = { - body?: never - path?: never - query?: never - url: '/api/experiment/models' -} - -export type GetModelFoldersErrors = { - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type GetModelFoldersError = - GetModelFoldersErrors[keyof GetModelFoldersErrors] - -export type GetModelFoldersResponses = { - /** - * Success - List of model folders - */ - 200: Array -} - -export type GetModelFoldersResponse = - GetModelFoldersResponses[keyof GetModelFoldersResponses] - -export type GetModelsInFolderData = { - body?: never - path: { - /** - * The folder name to list models from - */ - folder: string - } - query?: never - url: '/api/experiment/models/{folder}' -} - -export type GetModelsInFolderErrors = { - /** - * Folder not found or no models in folder - */ - 404: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type GetModelsInFolderError = - GetModelsInFolderErrors[keyof GetModelsInFolderErrors] - -export type GetModelsInFolderResponses = { - /** - * Success - List of models in the folder - */ - 200: Array -} - -export type GetModelsInFolderResponse = - GetModelsInFolderResponses[keyof GetModelsInFolderResponses] - -export type GetLegacyHistoryData = { - body?: never - path?: never - query?: never - url: '/api/history' -} - -export type GetLegacyHistoryErrors = { - /** - * Not Found — use /api/history_v2 instead - */ - 404: unknown -} - -export type ManageHistoryData = { - body: HistoryManageRequest - path?: never - query?: never - url: '/api/history' -} - -export type ManageHistoryErrors = { - /** - * Invalid request parameters - */ - 400: ErrorResponse - /** - * Unauthorized - Authentication required - */ - 401: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type ManageHistoryError = ManageHistoryErrors[keyof ManageHistoryErrors] - -export type ManageHistoryResponses = { - /** - * Success - History management operation completed - */ - 200: unknown -} - -export type GetHistoryData = { - body?: never - path?: never - query?: { - /** - * Maximum number of items to return - */ - max_items?: number - /** - * Starting position (default 0) - */ - offset?: number - } - url: '/api/history_v2' -} - -export type GetHistoryErrors = { - /** - * Unauthorized - Authentication required - */ - 401: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type GetHistoryError = GetHistoryErrors[keyof GetHistoryErrors] - -export type GetHistoryResponses = { - /** - * Success - Execution history retrieved - */ - 200: HistoryResponse -} - -export type GetHistoryResponse = GetHistoryResponses[keyof GetHistoryResponses] - -export type GetHistoryForPromptData = { - body?: never - path: { - /** - * The prompt ID to retrieve history for - */ - prompt_id: string - } - query?: never - url: '/api/history_v2/{prompt_id}' -} - -export type GetHistoryForPromptErrors = { - /** - * Unauthorized - Authentication required - */ - 401: ErrorResponse - /** - * Prompt not found - */ - 404: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type GetHistoryForPromptError = - GetHistoryForPromptErrors[keyof GetHistoryForPromptErrors] - -export type GetHistoryForPromptResponses = { - /** - * Success - History for prompt retrieved - */ - 200: HistoryDetailResponse -} - -export type GetHistoryForPromptResponse = - GetHistoryForPromptResponses[keyof GetHistoryForPromptResponses] - -export type ListJobsData = { - body?: never - path?: never - query?: { - /** - * Filter by one or more statuses (comma-separated). If not provided, returns all jobs. - */ - status?: string - /** - * Filter by workflow ID (exact match) - */ - workflow_id?: string - /** - * Filter by output media type (only applies to completed jobs with outputs) - */ - output_type?: 'image' | 'video' | 'audio' | '3d' - /** - * Field to sort by (create_time = when job was submitted, execution_time = how long workflow took to run) - */ - sort_by?: 'create_time' | 'execution_time' - /** - * Sort direction (asc = ascending, desc = descending) - */ - sort_order?: 'asc' | 'desc' - /** - * Opaque cursor for keyset pagination. Pass the `next_cursor` value - * from a previous response to fetch the next page. - * Cursor pagination is supported only when `sort_by=create_time` - * (default). If `sort_by=execution_time`, `after` is ignored and - * offset/limit pagination is used. - * Cursors are opaque base64url payloads — clients should treat them - * as strings and not parse the contents. - * - */ - after?: string - /** - * Pagination offset (0-based). Deprecated: prefer cursor-based pagination via `after`. - * - * @deprecated - */ - offset?: number - /** - * Maximum items per page (1-1000) - */ - limit?: number - } - url: '/api/jobs' -} - -export type ListJobsErrors = { - /** - * Bad request (e.g. malformed pagination cursor). - */ - 400: ErrorResponse - /** - * Unauthorized - Authentication required - */ - 401: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type ListJobsError = ListJobsErrors[keyof ListJobsErrors] - -export type ListJobsResponses = { - /** - * Success - Jobs retrieved - */ - 200: JobsListResponse -} - -export type ListJobsResponse = ListJobsResponses[keyof ListJobsResponses] - -export type GetJobDetailData = { - body?: never - path: { - /** - * Job identifier (UUID) - */ - job_id: string - } - query?: { - /** - * When present, each output item in the response receives a `short_url` field containing a short link for that asset. Omit this parameter (the default) to receive a response identical to the no-param baseline. The value selects the link's lifetime and auth model: use `ephemeral_tool_chain` for short-lived (≤5 minute) machine-to-machine handoffs — these are public bearer links where the link ID itself is the credential, so anyone holding the link can resolve it (intended for pasting into an agent/MCP tool chain); use `default` for durable (30 day) human-revisitable links, which are owner-gated and resolvable only by the authenticated owner. Links are always minted under the authenticated request owner's identity; the auth model is selected by the server and is never settable by the caller. - * - */ - short_link?: 'ephemeral_tool_chain' | 'default' - } - url: '/api/jobs/{job_id}' -} - -export type GetJobDetailErrors = { - /** - * Unauthorized - Authentication required - */ - 401: ErrorResponse - /** - * Forbidden - Job does not belong to user - */ - 403: ErrorResponse - /** - * Job not found - */ - 404: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type GetJobDetailError = GetJobDetailErrors[keyof GetJobDetailErrors] - -export type GetJobDetailResponses = { - /** - * Success - Job details retrieved - */ - 200: JobDetailResponse -} - -export type GetJobDetailResponse = - GetJobDetailResponses[keyof GetJobDetailResponses] - -export type CancelJobData = { - body?: never - path: { - /** - * Job identifier (UUID) - */ - job_id: string - } - query?: never - url: '/api/jobs/{job_id}/cancel' -} - -export type CancelJobErrors = { - /** - * Bad Request - job_id is not a valid UUID (emitted by request validation before the handler runs) - */ - 400: ErrorResponse - /** - * Unauthorized - Authentication required - */ - 401: ErrorResponse - /** - * Job not found for this user - */ - 404: ErrorResponse - /** - * Internal server error - cancellation failed - */ - 500: ErrorResponse -} - -export type CancelJobError = CancelJobErrors[keyof CancelJobErrors] - -export type CancelJobResponses = { - /** - * Success - Cancel request accepted (or job was already terminal) - */ - 200: JobCancelResponse -} - -export type CancelJobResponse = CancelJobResponses[keyof CancelJobResponses] - -export type CancelJobsData = { - body: JobsCancelRequest - path?: never - query?: never - url: '/api/jobs/cancel' -} - -export type CancelJobsErrors = { - /** - * Bad Request - job_ids is missing, empty, exceeds the maximum count, or contains an invalid UUID - */ - 400: ErrorResponse - /** - * Unauthorized - Authentication required - */ - 401: ErrorResponse - /** - * One or more job IDs not found for this user (no jobs cancelled) - */ - 404: ErrorResponse - /** - * Internal server error - cancellation failed - */ - 500: ErrorResponse -} - -export type CancelJobsError = CancelJobsErrors[keyof CancelJobsErrors] - -export type CancelJobsResponses = { - /** - * Success - cancel requests dispatched (or jobs were already terminal) - */ - 200: JobsCancelResponse -} - -export type CancelJobsResponse = CancelJobsResponses[keyof CancelJobsResponses] - -export type ViewFileData = { - body?: never - path?: never - query: { - /** - * Name of the file to view - */ - filename: string - /** - * Subfolder path where the file is located - */ - subfolder?: string - /** - * Type of file (e.g., output, input, temp) - */ - type?: string - /** - * Full path to the file (used for temp files) - */ - fullpath?: string - /** - * Format of the file - */ - format?: string - /** - * Frame rate for video files - */ - frame_rate?: number - /** - * Workflow identifier - */ - workflow?: string - /** - * Timestamp parameter - */ - timestamp?: number - /** - * Image channel to extract from PNG images. - * - 'rgb': Return only RGB channels (alpha set to fully opaque) - * - 'a' or 'alpha': Return alpha channel as grayscale image - * - If not specified, return original image unchanged via redirect - * - */ - channel?: string - /** - * Maximum dimension (width or height) to resize the image to, preserving aspect ratio. - * The image is fit within a res x res box. Returns a JPEG thumbnail. - * Only applies to raster image files (PNG, JPEG, WebP, GIF). - * - */ - res?: number - } - url: '/api/view' -} - -export type ViewFileErrors = { - /** - * Invalid request parameters - */ - 400: ErrorResponse - /** - * File not found or unauthorized - */ - 404: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type ViewFileError = ViewFileErrors[keyof ViewFileErrors] - -export type ViewFileResponses = { - /** - * Processed PNG image with extracted channel - */ - 200: Blob | File -} - -export type ViewFileResponse = ViewFileResponses[keyof ViewFileResponses] - -export type GetMaskLayersData = { - body?: never - path?: never - query: { - /** - * Hash filename of any mask layer file - */ - filename: string - } - url: '/api/files/mask-layers' -} - -export type GetMaskLayersErrors = { - /** - * File not found or not a mask file - */ - 404: ErrorResponse -} - -export type GetMaskLayersError = GetMaskLayersErrors[keyof GetMaskLayersErrors] - -export type GetMaskLayersResponses = { - /** - * Success - Related mask layers returned - */ - 200: { - /** - * Filename of the mask layer - */ - mask?: string | null - /** - * Filename of the paint strokes layer - */ - paint?: string | null - /** - * Filename of the painted image layer - */ - painted?: string | null - /** - * Filename of the final composite layer - */ - painted_masked?: string | null - } -} - -export type GetMaskLayersResponse = - GetMaskLayersResponses[keyof GetMaskLayersResponses] - -export type GetFilesData = { - body?: never - path: { - /** - * Type of directory to list files from - */ - directory_type: 'output' | 'input' | 'temp' - } - query?: never - url: '/internal/files/{directory_type}' -} - -export type GetFilesErrors = { - /** - * Invalid directory type - */ - 400: ErrorResponse - /** - * Unauthorized - Authentication required - */ - 401: ErrorResponse -} - -export type GetFilesError = GetFilesErrors[keyof GetFilesErrors] - -export type GetFilesResponses = { - /** - * Array of file names sorted by modification time (newest first) - */ - 200: Array -} - -export type GetFilesResponse = GetFilesResponses[keyof GetFilesResponses] - -export type ListAssetsData = { - body?: never - path?: never - query?: { - /** - * Filter assets that have ALL of these tags - */ - include_tags?: Array - /** - * Exclude assets that have ANY of these tags - */ - exclude_tags?: Array - /** - * Filter assets where name contains this substring (case-insensitive) - */ - name_contains?: string - /** - * JSON object for filtering by metadata fields - */ - metadata_filter?: string - /** - * Maximum number of assets to return (1-500) - */ - limit?: number - /** - * Number of assets to skip for pagination - */ - offset?: number - /** - * Field to sort by - */ - sort?: 'name' | 'created_at' | 'updated_at' | 'size' | 'last_access_time' - /** - * Sort order - */ - order?: 'asc' | 'desc' - /** - * Whether to include public/shared assets in results - */ - include_public?: boolean - /** - * Filter assets by exact content hash. - */ - hash?: string - /** - * Opaque cursor for keyset pagination. Pass the `next_cursor` value - * from the previous response to fetch the next page. When provided, - * `offset` is ignored. Cursor pagination is only supported with - * `sort` values `created_at`, `updated_at`, `name`, or `size`; - * requests combining `after` with other sort fields return 400. - * The cursor must have been minted under the same `sort` value used - * in the follow-up request. - * - */ - after?: string - } - url: '/api/assets' -} - -export type ListAssetsErrors = { - /** - * Invalid request parameters - */ - 400: ErrorResponse - /** - * Unauthorized - */ - 401: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type ListAssetsError = ListAssetsErrors[keyof ListAssetsErrors] - -export type ListAssetsResponses = { - /** - * Success - Assets returned - */ - 200: ListAssetsResponse -} - -export type ListAssetsResponse2 = ListAssetsResponses[keyof ListAssetsResponses] - -export type CreateAssetData = { - body: { - /** - * The asset file to upload - */ - file: Blob | File - /** - * Content hash of the file. - */ - hash?: string - /** - * JSON-encoded array of freeform tag strings, e.g. '["models","checkpoint"]'. Common types include "models", "input", "output", and "temp", but any tag can be used in any order. - */ - tags?: string - /** - * Optional asset ID for idempotent creation. If provided and asset exists, returns existing asset. - */ - id?: string - /** - * Optional preview asset ID. If not provided, images will use their own ID as preview. - */ - preview_id?: string - /** - * Display name for the asset - */ - name?: string - /** - * MIME type of the asset (e.g., "image/png", "video/mp4") - */ - mime_type?: string - /** - * Custom JSON metadata as a string - */ - user_metadata?: string - } - path?: never - query?: never - url: '/api/assets' -} - -export type CreateAssetErrors = { - /** - * Invalid request (bad file, invalid content type, etc.) - */ - 400: ErrorResponse - /** - * Unauthorized - */ - 401: ErrorResponse - /** - * File too large - */ - 413: ErrorResponse - /** - * Unsupported media type - */ - 415: ErrorResponse - /** - * Validation error (e.g., disallowed model_type tag) - */ - 422: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type CreateAssetError = CreateAssetErrors[keyof CreateAssetErrors] - -export type CreateAssetResponses = { - /** - * Asset already existed for this user (deduplicated by content hash); the - * existing asset is returned with created_new=false. - * - */ - 200: AssetCreated - /** - * Asset created successfully (created_new=true) - */ - 201: AssetCreated -} - -export type CreateAssetResponse = - CreateAssetResponses[keyof CreateAssetResponses] - -export type CreateAssetFromHashData = { - body: { - /** - * Blake3 content hash of the existing asset (blake3: prefix) - */ - hash: string - /** - * Display name for the asset reference (optional) - */ - name?: string - /** - * Freeform tags for the asset. Common types include "models", "input", "output", and "temp", but any tag can be used in any order. - */ - tags: Array - /** - * MIME type of the asset (e.g., "image/png", "video/mp4") - */ - mime_type?: string - /** - * Custom metadata for this asset reference - */ - user_metadata?: { - [key: string]: unknown - } - } - path?: never - query?: never - url: '/api/assets/from-hash' -} - -export type CreateAssetFromHashErrors = { - /** - * Invalid request (bad hash format, invalid tags, etc.) - */ - 400: ErrorResponse - /** - * Unauthorized - */ - 401: ErrorResponse - /** - * Source asset with given hash not found - */ - 404: ErrorResponse - /** - * Validation error (e.g., disallowed model_type tag) - */ - 422: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type CreateAssetFromHashError = - CreateAssetFromHashErrors[keyof CreateAssetFromHashErrors] - -export type CreateAssetFromHashResponses = { - /** - * Asset reference already existed for this user (deduplicated by content - * hash); the existing asset is returned with created_new=false. - * - */ - 200: AssetCreated - /** - * Asset reference created successfully (created_new=true) - */ - 201: AssetCreated -} - -export type CreateAssetFromHashResponse = - CreateAssetFromHashResponses[keyof CreateAssetFromHashResponses] - -export type GetRemoteAssetMetadataData = { - body?: never - path?: never - query: { - /** - * Download URL to retrieve metadata from - */ - url: string - } - url: '/api/assets/remote-metadata' -} - -export type GetRemoteAssetMetadataErrors = { - /** - * Invalid URL or missing required parameter - */ - 400: ErrorResponse - /** - * Unauthorized - */ - 401: ErrorResponse - /** - * Failed to retrieve metadata from source - */ - 422: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type GetRemoteAssetMetadataError = - GetRemoteAssetMetadataErrors[keyof GetRemoteAssetMetadataErrors] - -export type GetRemoteAssetMetadataResponses = { - /** - * Metadata retrieved successfully - */ - 200: AssetMetadataResponse -} - -export type GetRemoteAssetMetadataResponse = - GetRemoteAssetMetadataResponses[keyof GetRemoteAssetMetadataResponses] - -export type CreateAssetDownloadData = { - body: { - /** - * URL of the file to download (must be from huggingface.co, civitai.com, or civitai.red) - */ - source_url: string - /** - * Optional tags for the asset (e.g., ["model", "checkpoint"]) - */ - tags?: Array - /** - * Optional user-defined metadata to attach to the asset - */ - user_metadata?: { - [key: string]: unknown - } - /** - * Optional preview asset ID to associate with the downloaded asset - */ - preview_id?: string - } - path?: never - query?: never - url: '/api/assets/download' -} - -export type CreateAssetDownloadErrors = { - /** - * Invalid URL or unsupported source - */ - 400: ErrorResponse - /** - * Unauthorized - */ - 401: ErrorResponse - /** - * Validation errors - */ - 422: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse -} - -export type CreateAssetDownloadError = - CreateAssetDownloadErrors[keyof CreateAssetDownloadErrors] - -export type CreateAssetDownloadResponses = { - /** - * File already exists in storage - asset created/returned immediately - */ - 200: AssetCreated - /** - * Accepted - Download task created and processing in background - */ - 202: AssetDownloadResponse -} - -export type CreateAssetDownloadResponse = - CreateAssetDownloadResponses[keyof CreateAssetDownloadResponses] - -export type CreateAssetExportData = { - body: { - /** - * Job IDs whose output assets are included in the ZIP bundle. Preview assets of these jobs are additionally included when `include_previews` is true. - */ - job_ids?: Array - /** - * Asset IDs to include in the ZIP bundle. Supports input, output, and available temp assets. Additive to output assets associated with provided job IDs. - */ - asset_ids?: Array - /** - * Strategy for naming files in the ZIP: - * - group_by_job_id: Group assets by job ID as a parent directory (e.g., "833a1b5c-beab-436a-ae8e-f07e7cd7b2c4/ComfyUI_00001_.png") - * - preserve: Use original asset names, skip duplicates (first one wins) - * - asset_id: Use the asset ID as the filename (e.g., "833a1b5c-beab-436a-ae8e-f07e7cd7b2c4.png") - * - group_by_job_time: Group by job creation timestamp (e.g., "2026-03-26T16-13-00/ComfyUI_00001_.png") - * - */ - naming_strategy?: - | 'group_by_job_id' - | 'preserve' - | 'asset_id' - | 'group_by_job_time' - /** - * Optional per-job asset name filters. When provided for a job ID, - * only assets whose name matches one of the specified names are included. - * Job IDs present in `job_ids` but absent from this map include their output assets (plus previews when `include_previews` is true). - * - */ - job_asset_name_filters?: { - [key: string]: Array - } - /** - * When true, preview assets attached to the provided job_ids are included in the export. No effect on asset_ids. Preview assets are placed under a `previews/` subfolder in group-by-job layouts. - */ - include_previews?: boolean - } - path?: never - query?: never - url: '/api/assets/export' -} - -export type CreateAssetExportErrors = { + hash?: string /** - * Invalid request + * Unique identifier for the asset */ - 400: ErrorResponse + id: string /** - * Unauthorized + * Whether this asset is immutable (cannot be modified or deleted) */ - 401: ErrorResponse + is_immutable?: boolean /** - * Internal server error + * ID of the job that created this asset, if available */ - 500: ErrorResponse -} - -export type CreateAssetExportError = - CreateAssetExportErrors[keyof CreateAssetExportErrors] - -export type CreateAssetExportResponses = { + job_id?: string | null /** - * Accepted - Export task created and processing in background + * Timestamp when the asset was last accessed */ - 202: AssetDownloadResponse -} - -export type CreateAssetExportResponse = - CreateAssetExportResponses[keyof CreateAssetExportResponses] - -export type DownloadExportData = { - body?: never - path: { - /** - * Export filename with extension (e.g., "021e55cd-9785-4ac7-ac39-f4010138e3bc.zip") - */ - exportName: string - } - query?: never - url: '/api/assets/exports/{exportName}' -} - -export type DownloadExportErrors = { + last_access_time?: string /** - * Invalid export name + * MIME type of the asset */ - 400: ErrorResponse + mime_type?: string /** - * Unauthorized + * Name of the asset file */ - 401: ErrorResponse + name: string /** - * Export not found or not owned by user + * ID of the preview asset if available */ - 404: ErrorResponse + preview_id?: string | null /** - * Internal server error + * URL for asset preview/thumbnail */ - 500: ErrorResponse + preview_url?: string + /** + * Durable, owner-gated short link to this asset's content (relative `/api/s/{id}` path). Stable across the underlying signed URL's expiry — resolving it re-mints a fresh signed URL on every request — so it is safe to persist or share into chat, unlike `preview_url`. Only the minting user can resolve it. Omitted when the short-link surface is disabled or the asset has no resolvable content hash. + */ + short_url?: string | null + /** + * Size of the asset in bytes + */ + size?: number + /** + * Tags associated with the asset + */ + tags?: Array + /** + * Timestamp when the asset was last updated + */ + updated_at: string + /** + * Custom user metadata for the asset + */ + user_metadata?: { + [key: string]: unknown + } } -export type DownloadExportError = - DownloadExportErrors[keyof DownloadExportErrors] - -export type DownloadExportResponses = { +/** + * Response returned when a new asset is successfully created. + */ +export type AssetCreatedWritable = AssetWritable & { /** - * Signed URL for downloading the export + * Whether this was a new asset creation (true) or returned existing (false) */ - 200: ExportDownloadUrlResponse + created_new: boolean } -export type DownloadExportResponse = - DownloadExportResponses[keyof DownloadExportResponses] - -export type DeleteAssetData = { +export type GetJwksData = { body?: never - path: { - /** - * Asset ID - */ - id: string - } + path?: never query?: never - url: '/api/assets/{id}' + url: '/.well-known/jwks.json' } -export type DeleteAssetErrors = { +export type GetJwksResponses = { /** - * Unauthorized + * JWKS response */ - 401: ErrorResponse + 200: JwksResponse +} + +export type GetJwksResponse = GetJwksResponses[keyof GetJwksResponses] + +export type GetOAuthAuthorizationServerData = { + body?: never + path?: never + query?: never + url: '/.well-known/oauth-authorization-server' +} + +export type GetOAuthAuthorizationServerErrors = { /** - * Asset not found + * OAuth disabled */ 404: ErrorResponse - /** - * Asset cannot be deleted because it is referenced by another resource, e.g. a workflow version (error code: ASSET_IN_USE) - */ - 409: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse } -export type DeleteAssetError = DeleteAssetErrors[keyof DeleteAssetErrors] +export type GetOAuthAuthorizationServerError = + GetOAuthAuthorizationServerErrors[keyof GetOAuthAuthorizationServerErrors] -export type DeleteAssetResponses = { +export type GetOAuthAuthorizationServerResponses = { /** - * Asset record deleted successfully + * Authorization-server metadata */ - 204: void + 200: OAuthAuthorizationServerMetadata } -export type DeleteAssetResponse = - DeleteAssetResponses[keyof DeleteAssetResponses] +export type GetOAuthAuthorizationServerResponse = + GetOAuthAuthorizationServerResponses[keyof GetOAuthAuthorizationServerResponses] -export type GetAssetByIdData = { +export type GetOAuthProtectedResourceData = { body?: never - path: { - /** - * Asset ID - */ - id: string - } + path?: never query?: never - url: '/api/assets/{id}' + url: '/.well-known/oauth-protected-resource' } -export type GetAssetByIdErrors = { - /** - * Unauthorized - */ - 401: ErrorResponse +export type GetOAuthProtectedResourceErrors = { /** - * Asset not found + * OAuth disabled or no active resource configured */ 404: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse } -export type GetAssetByIdError = GetAssetByIdErrors[keyof GetAssetByIdErrors] +export type GetOAuthProtectedResourceError = + GetOAuthProtectedResourceErrors[keyof GetOAuthProtectedResourceErrors] -export type GetAssetByIdResponses = { +export type GetOAuthProtectedResourceResponses = { /** - * Asset details retrieved successfully + * Protected-resource metadata */ - 200: Asset + 200: OAuthProtectedResourceMetadata } -export type GetAssetByIdResponse = - GetAssetByIdResponses[keyof GetAssetByIdResponses] +export type GetOAuthProtectedResourceResponse = + GetOAuthProtectedResourceResponses[keyof GetOAuthProtectedResourceResponses] -export type UpdateAssetData = { - body: { - /** - * New display name for the asset - */ - name?: string - /** - * Updated MIME type of the asset - */ - mime_type?: string - /** - * Updated preview asset ID - */ - preview_id?: string - /** - * Updated custom metadata - */ - user_metadata?: { - [key: string]: unknown - } - } +export type GetOAuthProtectedResourceByPathData = { + body?: never path: { /** - * Asset ID + * Single-segment resource path without its leading slash (e.g. "mcp"). */ - id: string + resourcePath: string } query?: never - url: '/api/assets/{id}' + url: '/.well-known/oauth-protected-resource/{resourcePath}' } -export type UpdateAssetErrors = { - /** - * Invalid request — no fields provided, or `preview_id` is the zero UUID - * (`INVALID_PREVIEW_ID`). - * - */ - 400: ErrorResponse - /** - * Unauthorized - */ - 401: ErrorResponse +export type GetOAuthProtectedResourceByPathErrors = { /** - * Asset not found — returned both when the asset being updated does - * not exist and when `preview_id` does not reference an asset - * accessible to the caller. - * + * OAuth disabled, or no active resource at this path */ 404: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse } -export type UpdateAssetError = UpdateAssetErrors[keyof UpdateAssetErrors] +export type GetOAuthProtectedResourceByPathError = + GetOAuthProtectedResourceByPathErrors[keyof GetOAuthProtectedResourceByPathErrors] -export type UpdateAssetResponses = { +export type GetOAuthProtectedResourceByPathResponses = { /** - * Asset updated successfully + * Protected-resource metadata */ - 200: AssetUpdated + 200: OAuthProtectedResourceMetadata } -export type UpdateAssetResponse = - UpdateAssetResponses[keyof UpdateAssetResponses] +export type GetOAuthProtectedResourceByPathResponse = + GetOAuthProtectedResourceByPathResponses[keyof GetOAuthProtectedResourceByPathResponses] -export type RemoveAssetTagsData = { - body: { - /** - * Tags to remove from the asset - */ - tags: Array - } +export type GetCustomNodeProxyData = { + body?: never path: { /** - * Asset ID + * Custom node HTTP endpoint path being proxied to the CPU-backed worker. */ - id: string + path: string } query?: never - url: '/api/assets/{id}/tags' + url: '/__custom_node_proxy/{path}' } -export type RemoveAssetTagsErrors = { - /** - * Invalid request - */ - 400: ErrorResponse +export type GetCustomNodeProxyErrors = { /** * Unauthorized */ - 401: ErrorResponse - /** - * Asset not found - */ - 404: ErrorResponse - /** - * Validation error (e.g., reserved tag) - */ - 422: ErrorResponse + 401: unknown /** - * Internal server error + * Path not in allowlist */ - 500: ErrorResponse + 403: unknown } -export type RemoveAssetTagsError = - RemoveAssetTagsErrors[keyof RemoveAssetTagsErrors] - -export type RemoveAssetTagsResponses = { +export type GetCustomNodeProxyResponses = { /** - * Tags removed successfully + * Proxied response */ - 200: TagsModificationResponse + 200: unknown } -export type RemoveAssetTagsResponse = - RemoveAssetTagsResponses[keyof RemoveAssetTagsResponses] - -export type AddAssetTagsData = { - body: { - /** - * Tags to add to the asset - */ - tags: Array - } +export type PostCustomNodeProxyData = { + body?: never path: { /** - * Asset ID + * Custom node HTTP endpoint path being proxied to the CPU-backed worker. */ - id: string + path: string } query?: never - url: '/api/assets/{id}/tags' + url: '/__custom_node_proxy/{path}' } -export type AddAssetTagsErrors = { - /** - * Invalid request - */ - 400: ErrorResponse +export type PostCustomNodeProxyErrors = { /** * Unauthorized */ - 401: ErrorResponse - /** - * Asset not found - */ - 404: ErrorResponse - /** - * Validation error (e.g., reserved tag) - */ - 422: ErrorResponse + 401: unknown /** - * Internal server error + * Path not in allowlist */ - 500: ErrorResponse + 403: unknown } -export type AddAssetTagsError = AddAssetTagsErrors[keyof AddAssetTagsErrors] - -export type AddAssetTagsResponses = { +export type PostCustomNodeProxyResponses = { /** - * Tags added successfully + * Proxied response */ - 200: TagsModificationResponse + 200: unknown } -export type AddAssetTagsResponse = - AddAssetTagsResponses[keyof AddAssetTagsResponses] - -export type ListTagsData = { +export type ListAssetsData = { body?: never path?: never query?: { /** - * Filter tags by prefix + * Filter assets that have ALL of these tags */ - prefix?: string + include_tags?: Array /** - * Maximum number of tags to return (1-1000) + * Exclude assets that have ANY of these tags + */ + exclude_tags?: Array + /** + * Filter assets where name contains this substring (case-insensitive) + */ + name_contains?: string + /** + * JSON object for filtering by metadata fields + */ + metadata_filter?: string + /** + * Maximum number of assets to return (1-500) */ limit?: number /** - * Number of tags to skip for pagination + * Number of assets to skip for pagination */ offset?: number /** - * Sort order for tags + * Field to sort by */ - order?: 'count_desc' | 'name_asc' + sort?: 'name' | 'created_at' | 'updated_at' | 'size' | 'last_access_time' /** - * Include tags with zero usage count + * Sort order */ - include_zero?: boolean + order?: 'asc' | 'desc' /** - * Whether to include public/shared assets when counting tags + * Whether to include public/shared assets in results */ include_public?: boolean + /** + * Filter assets by exact content hash. + */ + hash?: string + /** + * Opaque cursor for keyset pagination. Pass the `next_cursor` value + * from the previous response to fetch the next page. When provided, + * `offset` is ignored. Cursor pagination is only supported with + * `sort` values `created_at`, `updated_at`, `name`, or `size`; + * requests combining `after` with other sort fields return 400. + * The cursor must have been minted under the same `sort` value used + * in the follow-up request. + * + */ + after?: string } - url: '/api/tags' + url: '/api/assets' } -export type ListTagsErrors = { +export type ListAssetsErrors = { /** * Invalid request parameters */ @@ -5477,94 +3677,115 @@ export type ListTagsErrors = { 500: ErrorResponse } -export type ListTagsError = ListTagsErrors[keyof ListTagsErrors] +export type ListAssetsError = ListAssetsErrors[keyof ListAssetsErrors] -export type ListTagsResponses = { +export type ListAssetsResponses = { /** - * Tags retrieved successfully + * Success - Assets returned */ - 200: ListTagsResponse + 200: ListAssetsResponse } -export type ListTagsResponse2 = ListTagsResponses[keyof ListTagsResponses] +export type ListAssetsResponse2 = ListAssetsResponses[keyof ListAssetsResponses] -export type GetAssetTagHistogramData = { - body?: never - path?: never - query?: { +export type CreateAssetData = { + body: { /** - * Filter assets that have ALL of these tags + * The asset file to upload */ - include_tags?: Array + file: Blob | File /** - * Exclude assets that have ANY of these tags + * Content hash of the file. */ - exclude_tags?: Array + hash?: string /** - * Filter assets where name contains this substring (case-insensitive) + * Optional asset ID for idempotent creation. If provided and asset exists, returns existing asset. */ - name_contains?: string + id?: string /** - * JSON object for filtering by metadata fields + * MIME type of the asset (e.g., "image/png", "video/mp4") */ - metadata_filter?: string + mime_type?: string /** - * Maximum number of tags to return (1-1000, default 100) + * Display name for the asset */ - limit?: number + name?: string /** - * Whether to include public/shared assets in results + * Optional preview asset ID. If not provided, images will use their own ID as preview. */ - include_public?: boolean + preview_id?: string + /** + * JSON-encoded array of freeform tag strings, e.g. '["models","checkpoint"]'. Common types include "models", "input", "output", and "temp", but any tag can be used in any order. + */ + tags?: string + /** + * Custom JSON metadata as a string + */ + user_metadata?: string } - url: '/api/assets/tags/refine' + path?: never + query?: never + url: '/api/assets' } -export type GetAssetTagHistogramErrors = { +export type CreateAssetErrors = { /** - * Invalid request parameters + * Invalid request (bad file, invalid content type, etc.) */ 400: ErrorResponse /** * Unauthorized */ 401: ErrorResponse + /** + * File too large + */ + 413: ErrorResponse + /** + * Unsupported media type + */ + 415: ErrorResponse + /** + * Validation error (e.g., disallowed model_type tag) + */ + 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type GetAssetTagHistogramError = - GetAssetTagHistogramErrors[keyof GetAssetTagHistogramErrors] +export type CreateAssetError = CreateAssetErrors[keyof CreateAssetErrors] -export type GetAssetTagHistogramResponses = { +export type CreateAssetResponses = { /** - * Success - Tag histogram returned + * Asset already existed for this user (deduplicated by content hash); the + * existing asset is returned with created_new=false. + * */ - 200: AssetTagHistogramResponse + 200: AssetCreated + /** + * Asset created successfully (created_new=true) + */ + 201: AssetCreated } -export type GetAssetTagHistogramResponse = - GetAssetTagHistogramResponses[keyof GetAssetTagHistogramResponses] +export type CreateAssetResponse = + CreateAssetResponses[keyof CreateAssetResponses] -export type CheckAssetByHashData = { +export type DeleteAssetData = { body?: never path: { /** - * Blake3 hash of the asset in format 'blake3:hex_digest' + * Asset ID */ - hash: string + id: string } query?: never - url: '/api/assets/hash/{hash}' + url: '/api/assets/{id}' } -export type CheckAssetByHashErrors = { - /** - * Invalid hash format - */ - 400: ErrorResponse +export type DeleteAssetErrors = { /** * Unauthorized */ @@ -5572,41 +3793,48 @@ export type CheckAssetByHashErrors = { /** * Asset not found */ - 404: unknown + 404: ErrorResponse + /** + * Asset cannot be deleted because it is referenced by another resource, e.g. a workflow version (error code: ASSET_IN_USE) + */ + 409: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type CheckAssetByHashError = - CheckAssetByHashErrors[keyof CheckAssetByHashErrors] +export type DeleteAssetError = DeleteAssetErrors[keyof DeleteAssetErrors] -export type CheckAssetByHashResponses = { +export type DeleteAssetResponses = { /** - * Asset exists + * Asset record deleted successfully */ - 200: unknown + 204: void } -export type PostAssetsFromWorkflowData = { - body: WorkflowApiAssetsRequest - path?: never +export type DeleteAssetResponse = + DeleteAssetResponses[keyof DeleteAssetResponses] + +export type GetAssetByIdData = { + body?: never + path: { + /** + * Asset ID + */ + id: string + } query?: never - url: '/api/assets/from-workflow' + url: '/api/assets/{id}' } -export type PostAssetsFromWorkflowErrors = { - /** - * Bad request - */ - 400: ErrorResponse +export type GetAssetByIdErrors = { /** * Unauthorized */ 401: ErrorResponse /** - * Not found + * Asset not found */ 404: ErrorResponse /** @@ -5615,191 +3843,338 @@ export type PostAssetsFromWorkflowErrors = { 500: ErrorResponse } -export type PostAssetsFromWorkflowError = - PostAssetsFromWorkflowErrors[keyof PostAssetsFromWorkflowErrors] +export type GetAssetByIdError = GetAssetByIdErrors[keyof GetAssetByIdErrors] -export type PostAssetsFromWorkflowResponses = { +export type GetAssetByIdResponses = { /** - * Success + * Asset details retrieved successfully */ - 200: WorkflowApiAssetsResponse + 200: Asset } -export type PostAssetsFromWorkflowResponse = - PostAssetsFromWorkflowResponses[keyof PostAssetsFromWorkflowResponses] +export type GetAssetByIdResponse = + GetAssetByIdResponses[keyof GetAssetByIdResponses] -export type ImportPublishedAssetsData = { - body: ImportPublishedAssetsRequest - path?: never +export type UpdateAssetData = { + body: { + /** + * Updated MIME type of the asset + */ + mime_type?: string + /** + * New display name for the asset + */ + name?: string + /** + * Updated preview asset ID + */ + preview_id?: string + /** + * Updated custom metadata + */ + user_metadata?: { + [key: string]: unknown + } + } + path: { + /** + * Asset ID + */ + id: string + } query?: never - url: '/api/assets/import' + url: '/api/assets/{id}' } -export type ImportPublishedAssetsErrors = { +export type UpdateAssetErrors = { /** - * Bad request + * Invalid request — no fields provided, or `preview_id` is the zero UUID + * (`INVALID_PREVIEW_ID`). + * */ 400: ErrorResponse /** * Unauthorized */ 401: ErrorResponse + /** + * Asset not found — returned both when the asset being updated does + * not exist and when `preview_id` does not reference an asset + * accessible to the caller. + * + */ + 404: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type ImportPublishedAssetsError = - ImportPublishedAssetsErrors[keyof ImportPublishedAssetsErrors] +export type UpdateAssetError = UpdateAssetErrors[keyof UpdateAssetErrors] -export type ImportPublishedAssetsResponses = { +export type UpdateAssetResponses = { /** - * Successfully imported assets + * Asset updated successfully */ - 200: ImportPublishedAssetsResponse + 200: AssetUpdated } -export type ImportPublishedAssetsResponse2 = - ImportPublishedAssetsResponses[keyof ImportPublishedAssetsResponses] +export type UpdateAssetResponse = + UpdateAssetResponses[keyof UpdateAssetResponses] -export type GetQueueInfoData = { +export type GetAssetContentData = { body?: never - path?: never - query?: never - url: '/api/queue' + path: { + /** + * Asset ID + */ + id: string + } + query?: { + /** + * Content-Disposition for the response: `attachment` (download) or + * `inline` (render in browser). Defaults to `attachment`. + * + */ + disposition?: 'inline' | 'attachment' + } + url: '/api/assets/{id}/content' } -export type GetQueueInfoErrors = { - /** - * Invalid request parameters - */ - 400: ErrorResponse +export type GetAssetContentErrors = { /** - * Unauthorized - Authentication required + * Asset not found */ - 401: ErrorResponse + 404: ErrorResponse /** - * Invalid request parameters + * Internal server error */ 500: ErrorResponse } -export type GetQueueInfoError = GetQueueInfoErrors[keyof GetQueueInfoErrors] +export type GetAssetContentError = + GetAssetContentErrors[keyof GetAssetContentErrors] -export type GetQueueInfoResponses = { +export type GetAssetContentResponses = { /** - * Success + * Asset content stream (local runtime streams the bytes directly) */ - 200: QueueInfo + 200: Blob | File } -export type GetQueueInfoResponse = - GetQueueInfoResponses[keyof GetQueueInfoResponses] +export type GetAssetContentResponse = + GetAssetContentResponses[keyof GetAssetContentResponses] -export type ManageQueueData = { - body: QueueManageRequest - path?: never +export type RemoveAssetTagsData = { + body: { + /** + * Tags to remove from the asset + */ + tags: Array + } + path: { + /** + * Asset ID + */ + id: string + } query?: never - url: '/api/queue' + url: '/api/assets/{id}/tags' } -export type ManageQueueErrors = { +export type RemoveAssetTagsErrors = { /** - * Invalid request parameters + * Invalid request */ 400: ErrorResponse /** * Unauthorized */ 401: ErrorResponse + /** + * Asset not found + */ + 404: ErrorResponse + /** + * Validation error (e.g., reserved tag) + */ + 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type ManageQueueError = ManageQueueErrors[keyof ManageQueueErrors] +export type RemoveAssetTagsError = + RemoveAssetTagsErrors[keyof RemoveAssetTagsErrors] -export type ManageQueueResponses = { +export type RemoveAssetTagsResponses = { /** - * Success + * Tags removed successfully */ - 200: QueueManageResponse + 200: TagsModificationResponse } -export type ManageQueueResponse = - ManageQueueResponses[keyof ManageQueueResponses] +export type RemoveAssetTagsResponse = + RemoveAssetTagsResponses[keyof RemoveAssetTagsResponses] -export type InterruptJobData = { - body?: never - path?: never +export type AddAssetTagsData = { + body: { + /** + * Tags to add to the asset + */ + tags: Array + } + path: { + /** + * Asset ID + */ + id: string + } query?: never - url: '/api/interrupt' + url: '/api/assets/{id}/tags' } -export type InterruptJobErrors = { +export type AddAssetTagsErrors = { /** - * Unauthorized - Authentication required + * Invalid request + */ + 400: ErrorResponse + /** + * Unauthorized */ 401: ErrorResponse + /** + * Asset not found + */ + 404: ErrorResponse + /** + * Validation error (e.g., reserved tag) + */ + 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type InterruptJobError = InterruptJobErrors[keyof InterruptJobErrors] +export type AddAssetTagsError = AddAssetTagsErrors[keyof AddAssetTagsErrors] -export type InterruptJobResponses = { +export type AddAssetTagsResponses = { /** - * Success - first active job cancelled, or no active job found + * Tags added successfully */ - 200: unknown + 200: TagsModificationResponse } -export type ListSecretsData = { - body?: never +export type AddAssetTagsResponse = + AddAssetTagsResponses[keyof AddAssetTagsResponses] + +export type CreateAssetDownloadData = { + body: { + /** + * Optional preview asset ID to associate with the downloaded asset + */ + preview_id?: string + /** + * URL of the file to download (must be from huggingface.co, civitai.com, or civitai.red) + */ + source_url: string + /** + * Optional tags for the asset (e.g., ["model", "checkpoint"]) + */ + tags?: Array + /** + * Optional user-defined metadata to attach to the asset + */ + user_metadata?: { + [key: string]: unknown + } + } path?: never query?: never - url: '/api/secrets' + url: '/api/assets/download' } -export type ListSecretsErrors = { +export type CreateAssetDownloadErrors = { + /** + * Invalid URL or unsupported source + */ + 400: ErrorResponse /** * Unauthorized */ 401: ErrorResponse /** - * Internal server error + * Validation errors */ - 500: ErrorResponse + 422: ErrorResponse /** - * Service unavailable - feature is disabled + * Internal server error */ - 503: ErrorResponse + 500: ErrorResponse } -export type ListSecretsError = ListSecretsErrors[keyof ListSecretsErrors] +export type CreateAssetDownloadError = + CreateAssetDownloadErrors[keyof CreateAssetDownloadErrors] -export type ListSecretsResponses = { +export type CreateAssetDownloadResponses = { /** - * Success + * File already exists in storage - asset created/returned immediately */ - 200: SecretListResponse + 200: AssetCreated + /** + * Accepted - Download task created and processing in background + */ + 202: AssetDownloadResponse } -export type ListSecretsResponse = - ListSecretsResponses[keyof ListSecretsResponses] +export type CreateAssetDownloadResponse = + CreateAssetDownloadResponses[keyof CreateAssetDownloadResponses] -export type CreateSecretData = { - body: CreateSecretRequest +export type CreateAssetExportData = { + body: { + /** + * Asset IDs to include in the ZIP bundle. Supports input, output, and available temp assets. Additive to output assets associated with provided job IDs. + */ + asset_ids?: Array + /** + * When true, preview assets attached to the provided job_ids are included in the export. No effect on asset_ids. Preview assets are placed under a `previews/` subfolder in group-by-job layouts. + */ + include_previews?: boolean + /** + * Optional per-job asset name filters. When provided for a job ID, + * only assets whose name matches one of the specified names are included. + * Job IDs present in `job_ids` but absent from this map include their output assets (plus previews when `include_previews` is true). + * + */ + job_asset_name_filters?: { + [key: string]: Array + } + /** + * Job IDs whose output assets are included in the ZIP bundle. Preview assets of these jobs are additionally included when `include_previews` is true. + */ + job_ids?: Array + /** + * Strategy for naming files in the ZIP: + * - group_by_job_id: Group assets by job ID as a parent directory (e.g., "833a1b5c-beab-436a-ae8e-f07e7cd7b2c4/ComfyUI_00001_.png") + * - preserve: Use original asset names, skip duplicates (first one wins) + * - asset_id: Use the asset ID as the filename (e.g., "833a1b5c-beab-436a-ae8e-f07e7cd7b2c4.png") + * - group_by_job_time: Group by job creation timestamp (e.g., "2026-03-26T16-13-00/ComfyUI_00001_.png") + * + */ + naming_strategy?: + | 'group_by_job_id' + | 'preserve' + | 'asset_id' + | 'group_by_job_time' + } path?: never query?: never - url: '/api/secrets' + url: '/api/assets/export' } -export type CreateSecretErrors = { +export type CreateAssetExportErrors = { /** * Invalid request */ @@ -5808,175 +4183,195 @@ export type CreateSecretErrors = { * Unauthorized */ 401: ErrorResponse - /** - * Conflict - secret with this name or provider already exists - */ - 409: ErrorResponse - /** - * Validation error - */ - 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse - /** - * Service unavailable - secrets feature disabled - */ - 503: ErrorResponse } -export type CreateSecretError = CreateSecretErrors[keyof CreateSecretErrors] +export type CreateAssetExportError = + CreateAssetExportErrors[keyof CreateAssetExportErrors] -export type CreateSecretResponses = { +export type CreateAssetExportResponses = { /** - * Secret created successfully + * Accepted - Export task created and processing in background */ - 201: SecretResponse + 202: AssetDownloadResponse } -export type CreateSecretResponse = - CreateSecretResponses[keyof CreateSecretResponses] +export type CreateAssetExportResponse = + CreateAssetExportResponses[keyof CreateAssetExportResponses] -export type ListSecretProvidersData = { +export type DownloadExportData = { body?: never - path?: never + path: { + /** + * Export filename with extension (e.g., "021e55cd-9785-4ac7-ac39-f4010138e3bc.zip") + */ + exportName: string + } query?: never - url: '/api/secrets/providers' + url: '/api/assets/exports/{exportName}' } -export type ListSecretProvidersErrors = { +export type DownloadExportErrors = { + /** + * Invalid export name + */ + 400: ErrorResponse /** * Unauthorized */ 401: ErrorResponse /** - * Service unavailable - secrets feature disabled + * Export not found or not owned by user */ - 503: ErrorResponse + 404: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type ListSecretProvidersError = - ListSecretProvidersErrors[keyof ListSecretProvidersErrors] +export type DownloadExportError = + DownloadExportErrors[keyof DownloadExportErrors] -export type ListSecretProvidersResponses = { +export type DownloadExportResponses = { /** - * Success + * Signed URL for downloading the export */ - 200: SecretProvidersResponse + 200: ExportDownloadUrlResponse } -export type ListSecretProvidersResponse = - ListSecretProvidersResponses[keyof ListSecretProvidersResponses] +export type DownloadExportResponse = + DownloadExportResponses[keyof DownloadExportResponses] -export type DeleteSecretData = { - body?: never - path: { +export type CreateAssetFromHashData = { + body: { /** - * The UUID of the secret + * Blake3 content hash of the existing asset (blake3: prefix) */ - id: string + hash: string + /** + * MIME type of the asset (e.g., "image/png", "video/mp4") + */ + mime_type?: string + /** + * Display name for the asset reference (optional) + */ + name?: string + /** + * Freeform tags for the asset. Common types include "models", "input", "output", and "temp", but any tag can be used in any order. + */ + tags: Array + /** + * Custom metadata for this asset reference + */ + user_metadata?: { + [key: string]: unknown + } } + path?: never query?: never - url: '/api/secrets/{id}' + url: '/api/assets/from-hash' } -export type DeleteSecretErrors = { +export type CreateAssetFromHashErrors = { + /** + * Invalid request (bad hash format, invalid tags, etc.) + */ + 400: ErrorResponse /** * Unauthorized */ 401: ErrorResponse /** - * Forbidden - user does not own this secret + * Source asset with given hash not found */ - 403: ErrorResponse + 404: ErrorResponse /** - * Secret not found + * Validation error (e.g., disallowed model_type tag) */ - 404: ErrorResponse + 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse - /** - * Service unavailable - secrets feature disabled - */ - 503: ErrorResponse } -export type DeleteSecretError = DeleteSecretErrors[keyof DeleteSecretErrors] +export type CreateAssetFromHashError = + CreateAssetFromHashErrors[keyof CreateAssetFromHashErrors] -export type DeleteSecretResponses = { +export type CreateAssetFromHashResponses = { /** - * Secret deleted successfully + * Asset reference already existed for this user (deduplicated by content + * hash); the existing asset is returned with created_new=false. + * */ - 204: void + 200: AssetCreated + /** + * Asset reference created successfully (created_new=true) + */ + 201: AssetCreated } -export type DeleteSecretResponse = - DeleteSecretResponses[keyof DeleteSecretResponses] +export type CreateAssetFromHashResponse = + CreateAssetFromHashResponses[keyof CreateAssetFromHashResponses] -export type GetSecretData = { - body?: never - path: { - /** - * The UUID of the secret - */ - id: string - } +export type PostAssetsFromWorkflowData = { + body: WorkflowApiAssetsRequest + path?: never query?: never - url: '/api/secrets/{id}' + url: '/api/assets/from-workflow' } -export type GetSecretErrors = { +export type PostAssetsFromWorkflowErrors = { /** - * Unauthorized + * Bad request */ - 401: ErrorResponse + 400: ErrorResponse /** - * Forbidden - user does not own this secret + * Unauthorized */ - 403: ErrorResponse + 401: ErrorResponse /** - * Secret not found + * Not found */ 404: ErrorResponse /** * Internal server error */ 500: ErrorResponse - /** - * Service unavailable - secrets feature disabled - */ - 503: ErrorResponse } -export type GetSecretError = GetSecretErrors[keyof GetSecretErrors] +export type PostAssetsFromWorkflowError = + PostAssetsFromWorkflowErrors[keyof PostAssetsFromWorkflowErrors] -export type GetSecretResponses = { +export type PostAssetsFromWorkflowResponses = { /** * Success */ - 200: SecretResponse + 200: WorkflowApiAssetsResponse } -export type GetSecretResponse = GetSecretResponses[keyof GetSecretResponses] +export type PostAssetsFromWorkflowResponse = + PostAssetsFromWorkflowResponses[keyof PostAssetsFromWorkflowResponses] -export type UpdateSecretData = { - body: UpdateSecretRequest +export type CheckAssetByHashData = { + body?: never path: { /** - * The UUID of the secret + * Blake3 hash of the asset in format 'blake3:hex_digest' */ - id: string + hash: string } query?: never - url: '/api/secrets/{id}' + url: '/api/assets/hash/{hash}' } -export type UpdateSecretErrors = { +export type CheckAssetByHashErrors = { /** - * Invalid request + * Invalid hash format */ 400: ErrorResponse /** @@ -5984,592 +4379,503 @@ export type UpdateSecretErrors = { */ 401: ErrorResponse /** - * Forbidden - user does not own this secret - */ - 403: ErrorResponse - /** - * Secret not found - */ - 404: ErrorResponse - /** - * Conflict - a secret with this name already exists + * Asset not found */ - 409: ErrorResponse + 404: unknown /** * Internal server error */ 500: ErrorResponse - /** - * Service unavailable - secrets feature disabled - */ - 503: ErrorResponse } -export type UpdateSecretError = UpdateSecretErrors[keyof UpdateSecretErrors] +export type CheckAssetByHashError = + CheckAssetByHashErrors[keyof CheckAssetByHashErrors] -export type UpdateSecretResponses = { +export type CheckAssetByHashResponses = { /** - * Secret updated successfully + * Asset exists */ - 200: SecretResponse + 200: unknown } -export type UpdateSecretResponse = - UpdateSecretResponses[keyof UpdateSecretResponses] - -export type GetAllSettingsData = { - body?: never +export type ImportPublishedAssetsData = { + body: ImportPublishedAssetsRequest path?: never query?: never - url: '/api/settings' + url: '/api/assets/import' } -export type GetAllSettingsErrors = { +export type ImportPublishedAssetsErrors = { + /** + * Bad request + */ + 400: ErrorResponse /** * Unauthorized */ 401: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetAllSettingsError = - GetAllSettingsErrors[keyof GetAllSettingsErrors] +export type ImportPublishedAssetsError = + ImportPublishedAssetsErrors[keyof ImportPublishedAssetsErrors] -export type GetAllSettingsResponses = { +export type ImportPublishedAssetsResponses = { /** - * User settings as key-value pairs + * Successfully imported assets */ - 200: { - [key: string]: unknown - } + 200: ImportPublishedAssetsResponse } -export type GetAllSettingsResponse = - GetAllSettingsResponses[keyof GetAllSettingsResponses] +export type ImportPublishedAssetsResponse2 = + ImportPublishedAssetsResponses[keyof ImportPublishedAssetsResponses] -export type UpdateMultipleSettingsData = { - /** - * Settings to update as key-value pairs - */ - body: { - [key: string]: unknown - } +export type PruneAssetsData = { + body?: never path?: never query?: never - url: '/api/settings' -} - -export type UpdateMultipleSettingsErrors = { - /** - * Invalid request - */ - 400: ErrorResponse - /** - * Unauthorized - */ - 401: ErrorResponse + url: '/api/assets/prune' } -export type UpdateMultipleSettingsError = - UpdateMultipleSettingsErrors[keyof UpdateMultipleSettingsErrors] - -export type UpdateMultipleSettingsResponses = { +export type PruneAssetsResponses = { /** - * Updated user settings + * Prune result */ 200: { - [key: string]: unknown + /** + * Number of assets marked as missing + */ + marked?: number + status?: string } } -export type UpdateMultipleSettingsResponse = - UpdateMultipleSettingsResponses[keyof UpdateMultipleSettingsResponses] +export type PruneAssetsResponse = + PruneAssetsResponses[keyof PruneAssetsResponses] -export type GetSettingByIdData = { +export type GetRemoteAssetMetadataData = { body?: never - path: { + path?: never + query: { /** - * Setting id to retrieve + * Download URL to retrieve metadata from */ - id: string + url: string } - query?: never - url: '/api/settings/{id}' + url: '/api/assets/remote-metadata' } -export type GetSettingByIdErrors = { +export type GetRemoteAssetMetadataErrors = { + /** + * Invalid URL or missing required parameter + */ + 400: ErrorResponse /** * Unauthorized */ 401: ErrorResponse /** - * Setting not found + * Failed to retrieve metadata from source */ - 404: ErrorResponse + 422: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetSettingByIdError = - GetSettingByIdErrors[keyof GetSettingByIdErrors] +export type GetRemoteAssetMetadataError = + GetRemoteAssetMetadataErrors[keyof GetRemoteAssetMetadataErrors] -export type GetSettingByIdResponses = { +export type GetRemoteAssetMetadataResponses = { /** - * Setting value response + * Metadata retrieved successfully */ - 200: { - /** - * The setting value - */ - value?: unknown - } + 200: AssetMetadataResponse } -export type GetSettingByIdResponse = - GetSettingByIdResponses[keyof GetSettingByIdResponses] +export type GetRemoteAssetMetadataResponse = + GetRemoteAssetMetadataResponses[keyof GetRemoteAssetMetadataResponses] -export type UpdateSettingByIdData = { - /** - * New value for the setting - */ - body: unknown - path: { +export type SeedAssetsData = { + body?: { /** - * Setting id to update + * Root folder paths to scan (if omitted, scans all) */ - id: string + roots?: Array } + path?: never query?: never - url: '/api/settings/{id}' -} - -export type UpdateSettingByIdErrors = { - /** - * Invalid request - */ - 400: ErrorResponse - /** - * Unauthorized - */ - 401: ErrorResponse + url: '/api/assets/seed' } -export type UpdateSettingByIdError = - UpdateSettingByIdErrors[keyof UpdateSettingByIdErrors] - -export type UpdateSettingByIdResponses = { +export type SeedAssetsResponses = { /** - * Updated setting value response + * Seed started */ 200: { - /** - * The updated setting value - */ - value?: unknown + status?: string } } -export type UpdateSettingByIdResponse = - UpdateSettingByIdResponses[keyof UpdateSettingByIdResponses] +export type SeedAssetsResponse = SeedAssetsResponses[keyof SeedAssetsResponses] -export type SubmitFeedbackData = { - body: FeedbackRequest +export type CancelAssetSeedData = { + body?: never path?: never query?: never - url: '/api/feedback' + url: '/api/assets/seed/cancel' } -export type SubmitFeedbackErrors = { - /** - * Invalid request - */ - 400: ErrorResponse - /** - * Unauthorized - */ - 401: ErrorResponse +export type CancelAssetSeedResponses = { /** - * Internal server error + * Scan cancelled */ - 500: ErrorResponse + 200: { + status?: string + } } -export type SubmitFeedbackError = - SubmitFeedbackErrors[keyof SubmitFeedbackErrors] +export type CancelAssetSeedResponse = + CancelAssetSeedResponses[keyof CancelAssetSeedResponses] -export type SubmitFeedbackResponses = { +export type GetAssetSeedStatusData = { + body?: never + path?: never + query?: never + url: '/api/assets/seed/status' +} + +export type GetAssetSeedStatusResponses = { /** - * Feedback submitted successfully + * Scan progress details (files scanned, total, status, etc.) */ - 201: FeedbackResponse + 200: { + [key: string]: unknown + } } -export type SubmitFeedbackResponse = - SubmitFeedbackResponses[keyof SubmitFeedbackResponses] +export type GetAssetSeedStatusResponse = + GetAssetSeedStatusResponses[keyof GetAssetSeedStatusResponses] -export type GetUserdataData = { +export type GetAssetTagHistogramData = { body?: never path?: never query?: { /** - * The directory to list files from. + * Filter assets that have ALL of these tags */ - dir?: string + include_tags?: Array /** - * Whether to list files recursively. + * Exclude assets that have ANY of these tags */ - recurse?: boolean + exclude_tags?: Array /** - * Whether to split file information by type. + * Filter assets where name contains this substring (case-insensitive) */ - split?: boolean + name_contains?: string /** - * Whether to return full file metadata. + * JSON object for filtering by metadata fields */ - full_info?: boolean + metadata_filter?: string + /** + * Maximum number of tags to return (1-1000, default 100) + */ + limit?: number + /** + * Whether to include public/shared assets in results + */ + include_public?: boolean } - url: '/api/userdata' -} - -export type GetUserdataErrors = { - /** - * Bad request (e.g., invalid filename). - */ - 400: string + url: '/api/assets/tags/refine' +} + +export type GetAssetTagHistogramErrors = { /** - * Unauthorized. + * Invalid request parameters */ - 401: string + 400: ErrorResponse /** - * File not found or invalid path. + * Unauthorized */ - 404: string + 401: ErrorResponse /** - * General error + * Internal server error */ - 500: string + 500: ErrorResponse } -export type GetUserdataError = GetUserdataErrors[keyof GetUserdataErrors] +export type GetAssetTagHistogramError = + GetAssetTagHistogramErrors[keyof GetAssetTagHistogramErrors] -export type GetUserdataResponses = { +export type GetAssetTagHistogramResponses = { /** - * A list of user data files. + * Success - Tag histogram returned */ - 200: GetUserDataResponseFull + 200: AssetTagHistogramResponse } -export type GetUserdataResponse = - GetUserdataResponses[keyof GetUserdataResponses] +export type GetAssetTagHistogramResponse = + GetAssetTagHistogramResponses[keyof GetAssetTagHistogramResponses] -export type GetUserdataFilePublishData = { - body?: never - path: { - /** - * The workflow file path within the user's data directory (URL encoded if necessary). - */ - file: string - } +export type CreateDesktopLoginCodeData = { + body: DesktopLoginCodeCreateRequest + path?: never query?: never - url: '/api/userdata/{file}/publish' + url: '/api/auth/desktop-login-codes' } -export type GetUserdataFilePublishErrors = { - /** - * Unauthorized - */ - 401: ErrorResponse +export type CreateDesktopLoginCodeErrors = { /** - * Workflow not found + * Invalid request */ - 404: ErrorResponse + 400: ErrorResponse /** - * Internal server error + * Service unavailable - login code store not available */ - 500: ErrorResponse + 503: ErrorResponse } -export type GetUserdataFilePublishError = - GetUserdataFilePublishErrors[keyof GetUserdataFilePublishErrors] +export type CreateDesktopLoginCodeError = + CreateDesktopLoginCodeErrors[keyof CreateDesktopLoginCodeErrors] -export type GetUserdataFilePublishResponses = { +export type CreateDesktopLoginCodeResponses = { /** - * Publish info (publish_time is null if never published) + * Login code created */ - 200: WorkflowPublishInfo + 201: DesktopLoginCodeCreateResponse } -export type GetUserdataFilePublishResponse = - GetUserdataFilePublishResponses[keyof GetUserdataFilePublishResponses] +export type CreateDesktopLoginCodeResponse = + CreateDesktopLoginCodeResponses[keyof CreateDesktopLoginCodeResponses] -export type PostUserdataFilePublishData = { - body: PublishWorkflowAssetsRequest - path: { - /** - * The workflow file path within the user's data directory (URL encoded if necessary). - */ - file: string - } +export type ExchangeDesktopLoginCodeData = { + body: DesktopLoginCodeExchangeRequest + path?: never query?: never - url: '/api/userdata/{file}/publish' + url: '/api/auth/desktop-login-codes/exchange' } -export type PostUserdataFilePublishErrors = { +export type ExchangeDesktopLoginCodeErrors = { /** - * Bad request + * Invalid request */ 400: ErrorResponse /** - * Unauthorized + * Code verifier does not match the challenge */ - 401: ErrorResponse + 403: ErrorResponse /** - * Workflow not found + * Unknown, expired, or already-consumed code */ 404: ErrorResponse /** - * Internal server error + * Service unavailable - login code store or token minting not available */ - 500: ErrorResponse + 503: ErrorResponse } -export type PostUserdataFilePublishError = - PostUserdataFilePublishErrors[keyof PostUserdataFilePublishErrors] +export type ExchangeDesktopLoginCodeError = + ExchangeDesktopLoginCodeErrors[keyof ExchangeDesktopLoginCodeErrors] -export type PostUserdataFilePublishResponses = { +export type ExchangeDesktopLoginCodeResponses = { /** - * Workflow published + * Pending (not yet redeemed) or complete with a custom token */ - 200: WorkflowPublishInfo + 200: DesktopLoginCodeExchangeResponse } -export type PostUserdataFilePublishResponse = - PostUserdataFilePublishResponses[keyof PostUserdataFilePublishResponses] +export type ExchangeDesktopLoginCodeResponse = + ExchangeDesktopLoginCodeResponses[keyof ExchangeDesktopLoginCodeResponses] -export type DeleteUserdataFileData = { - body?: never - path: { - /** - * The file path to delete (URL encoded if necessary). - */ - file: string - } +export type RedeemDesktopLoginCodeData = { + body: DesktopLoginCodeRedeemRequest + path?: never query?: never - url: '/api/userdata/{file}' + url: '/api/auth/desktop-login-codes/redeem' } -export type DeleteUserdataFileErrors = { +export type RedeemDesktopLoginCodeErrors = { /** - * Unauthorized. + * Unauthorized - authentication required */ - 401: string + 401: ErrorResponse /** - * File not found. + * Unknown or expired code */ - 404: string + 404: ErrorResponse /** - * Internal server error. + * Code already redeemed by a different user */ - 500: string + 409: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse + /** + * Service unavailable - login code store not available + */ + 503: ErrorResponse } -export type DeleteUserdataFileError = - DeleteUserdataFileErrors[keyof DeleteUserdataFileErrors] +export type RedeemDesktopLoginCodeError = + RedeemDesktopLoginCodeErrors[keyof RedeemDesktopLoginCodeErrors] -export type DeleteUserdataFileResponses = { +export type RedeemDesktopLoginCodeResponses = { /** - * File deleted successfully (No Content). + * Code redeemed (or already redeemed by the same user) */ - 204: void + 200: DesktopLoginCodeRedeemResponse } -export type DeleteUserdataFileResponse = - DeleteUserdataFileResponses[keyof DeleteUserdataFileResponses] +export type RedeemDesktopLoginCodeResponse = + RedeemDesktopLoginCodeResponses[keyof RedeemDesktopLoginCodeResponses] -export type GetUserdataFileData = { +export type DeleteSessionData = { body?: never - path: { - /** - * The filename of the user data to retrieve. - */ - file: string - } + path?: never query?: never - url: '/api/userdata/{file}' + url: '/api/auth/session' } -export type GetUserdataFileErrors = { +export type DeleteSessionErrors = { /** - * Bad request (e.g., invalid filename). + * Internal server error */ - 400: string + 500: ErrorResponse +} + +export type DeleteSessionError = DeleteSessionErrors[keyof DeleteSessionErrors] + +export type DeleteSessionResponses = { /** - * Unauthorized. + * Session deleted successfully */ - 401: string + 200: DeleteSessionResponse +} + +export type DeleteSessionResponse2 = + DeleteSessionResponses[keyof DeleteSessionResponses] + +export type CreateSessionData = { + body?: never + path?: never + query?: never + url: '/api/auth/session' +} + +export type CreateSessionErrors = { /** - * File not found or invalid path. + * Bad request - Invalid or old ID token */ - 404: string + 400: ErrorResponse /** - * General error + * Unauthorized - Authentication required */ - 500: string + 401: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetUserdataFileError = - GetUserdataFileErrors[keyof GetUserdataFileErrors] +export type CreateSessionError = CreateSessionErrors[keyof CreateSessionErrors] -export type GetUserdataFileResponses = { +export type CreateSessionResponses = { /** - * Successfully retrieved the file. + * Session created successfully */ - 200: Blob | File + 200: CreateSessionResponse } -export type GetUserdataFileResponse = - GetUserdataFileResponses[keyof GetUserdataFileResponses] +export type CreateSessionResponse2 = + CreateSessionResponses[keyof CreateSessionResponses] -export type PostUserdataFileData = { - body: Blob | File - path: { - /** - * The target file path (URL encoded if necessary). - */ - file: string - } - query?: { - /** - * If "false", prevents overwriting existing files. Defaults to "true". - */ - overwrite?: 'true' | 'false' - /** - * If "true", returns detailed file info; if "false", returns only the relative path. - */ - full_info?: 'true' | 'false' - } - url: '/api/userdata/{file}' +export type ExchangeTokenData = { + body?: ExchangeTokenRequest + path?: never + query?: never + url: '/api/auth/token' } -export type PostUserdataFileErrors = { - /** - * Missing or invalid 'file' parameter. - */ - 400: string - /** - * Unauthorized. - */ - 401: string +export type ExchangeTokenErrors = { /** - * The requested path is not allowed. + * Invalid or expired Firebase JWT */ - 403: string + 401: ErrorResponse /** - * File already exists and overwrite is set to false. + * Workspace not found or user not a member */ - 409: string + 404: ErrorResponse /** - * General error + * Internal server error */ - 500: string + 500: ErrorResponse } -export type PostUserdataFileError = - PostUserdataFileErrors[keyof PostUserdataFileErrors] +export type ExchangeTokenError = ExchangeTokenErrors[keyof ExchangeTokenErrors] -export type PostUserdataFileResponses = { +export type ExchangeTokenResponses = { /** - * File uploaded successfully. + * Token exchanged successfully */ - 200: UserDataResponseFull + 200: ExchangeTokenResponse } -export type PostUserdataFileResponse = - PostUserdataFileResponses[keyof PostUserdataFileResponses] +export type ExchangeTokenResponse2 = + ExchangeTokenResponses[keyof ExchangeTokenResponses] -export type MoveUserdataFileData = { +export type GetBillingBalanceData = { body?: never - path: { - /** - * The source file path (URL encoded if necessary). - */ - file: string - /** - * The destination file path (URL encoded if necessary). - */ - dest: string - } - query?: { - /** - * If "false", prevents overwriting existing files. Defaults to "true". - */ - overwrite?: 'true' | 'false' - } - url: '/api/userdata/{file}/move/{dest}' + path?: never + query?: never + url: '/api/billing/balance' } -export type MoveUserdataFileErrors = { - /** - * Missing or invalid parameters. - */ - 400: string - /** - * Unauthorized. - */ - 401: string - /** - * Source file not found. - */ - 404: string +export type GetBillingBalanceErrors = { /** - * Destination file already exists and overwrite is set to false. + * Unauthorized */ - 409: string + 401: ErrorResponse /** - * General error + * Internal server error */ - 500: string + 500: ErrorResponse } -export type MoveUserdataFileError = - MoveUserdataFileErrors[keyof MoveUserdataFileErrors] +export type GetBillingBalanceError = + GetBillingBalanceErrors[keyof GetBillingBalanceErrors] -export type MoveUserdataFileResponses = { +export type GetBillingBalanceResponses = { /** - * File moved successfully. + * Credit balance */ - 200: UserDataResponseFull + 200: BillingBalanceResponse } -export type MoveUserdataFileResponse = - MoveUserdataFileResponses[keyof MoveUserdataFileResponses] +export type GetBillingBalanceResponse = + GetBillingBalanceResponses[keyof GetBillingBalanceResponses] -export type UploadImageData = { - body: { - /** - * The image file to upload - */ - image: Blob | File - /** - * Whether to overwrite existing file (true/false) - */ - overwrite?: string +export type GetBillingEventsData = { + body?: never + path?: never + query?: { /** - * Optional subfolder path + * Page number (1-indexed) */ - subfolder?: string + page?: number /** - * Upload type (defaults to "output") + * Number of events per page */ - type?: string + limit?: number } - path?: never - query?: never - url: '/api/upload/image' + url: '/api/billing/events' } -export type UploadImageErrors = { - /** - * Bad request - */ - 400: ErrorResponse +export type GetBillingEventsErrors = { /** * Unauthorized */ @@ -6580,982 +4886,928 @@ export type UploadImageErrors = { 500: ErrorResponse } -export type UploadImageError = UploadImageErrors[keyof UploadImageErrors] +export type GetBillingEventsError = + GetBillingEventsErrors[keyof GetBillingEventsErrors] -export type UploadImageResponses = { +export type GetBillingEventsResponses = { /** - * Image uploaded successfully + * Paginated billing events */ - 200: { - /** - * Filename of the uploaded image - */ - name?: string - /** - * Subfolder path where image was saved - */ - subfolder?: string - /** - * Type of upload (e.g., "output") - */ - type?: string - } + 200: BillingEventsResponse } -export type UploadImageResponse = - UploadImageResponses[keyof UploadImageResponses] +export type GetBillingEventsResponse = + GetBillingEventsResponses[keyof GetBillingEventsResponses] -export type UploadMaskData = { - body: { - /** - * The mask image file to upload - */ - image: Blob | File +export type GetBillingOpStatusData = { + body?: never + path: { /** - * JSON string containing reference to the original image + * The billing operation ID */ - original_ref: string + id: string } - path?: never query?: never - url: '/api/upload/mask' + url: '/api/billing/ops/{id}' } -export type UploadMaskErrors = { - /** - * Bad request - */ - 400: ErrorResponse +export type GetBillingOpStatusErrors = { /** * Unauthorized */ 401: ErrorResponse + /** + * Billing operation not found + */ + 404: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type UploadMaskError = UploadMaskErrors[keyof UploadMaskErrors] +export type GetBillingOpStatusError = + GetBillingOpStatusErrors[keyof GetBillingOpStatusErrors] -export type UploadMaskResponses = { +export type GetBillingOpStatusResponses = { /** - * Mask uploaded successfully + * Billing operation status */ - 200: { - /** - * Filename of the uploaded mask - */ - name?: string - /** - * Subfolder path where mask was saved - */ - subfolder?: string - /** - * Type of upload (e.g., "output") - */ - type?: string - } + 200: BillingOpStatusResponse } -export type UploadMaskResponse = UploadMaskResponses[keyof UploadMaskResponses] +export type GetBillingOpStatusResponse = + GetBillingOpStatusResponses[keyof GetBillingOpStatusResponses] -export type GetLogsData = { - body?: never +export type GetPaymentPortalData = { + body?: PaymentPortalRequest path?: never query?: never - url: '/api/logs' + url: '/api/billing/payment-portal' } -export type GetLogsErrors = { +export type GetPaymentPortalErrors = { + /** + * Bad request (e.g., missing return_url) + */ + 400: ErrorResponse /** * Unauthorized */ 401: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetLogsError = GetLogsErrors[keyof GetLogsErrors] +export type GetPaymentPortalError = + GetPaymentPortalErrors[keyof GetPaymentPortalErrors] -export type GetLogsResponses = { +export type GetPaymentPortalResponses = { /** * Success */ - 200: LogsResponse + 200: PaymentPortalResponse } -export type GetLogsResponse = GetLogsResponses[keyof GetLogsResponses] +export type GetPaymentPortalResponse = + GetPaymentPortalResponses[keyof GetPaymentPortalResponses] -export type GetSystemStatsData = { +export type GetBillingPlansData = { body?: never path?: never query?: never - url: '/api/system_stats' + url: '/api/billing/plans' } -export type GetSystemStatsErrors = { +export type GetBillingPlansErrors = { /** * Unauthorized */ 401: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetSystemStatsError = - GetSystemStatsErrors[keyof GetSystemStatsErrors] +export type GetBillingPlansError = + GetBillingPlansErrors[keyof GetBillingPlansErrors] -export type GetSystemStatsResponses = { +export type GetBillingPlansResponses = { /** - * Success + * Available plans with pricing */ - 200: SystemStatsResponse + 200: BillingPlansResponse } -export type GetSystemStatsResponse = - GetSystemStatsResponses[keyof GetSystemStatsResponses] +export type GetBillingPlansResponse = + GetBillingPlansResponses[keyof GetBillingPlansResponses] -export type DeleteSessionData = { - body?: never +export type PreviewSubscribeData = { + body: PreviewSubscribeRequest path?: never query?: never - url: '/api/auth/session' + url: '/api/billing/preview-subscribe' } -export type DeleteSessionErrors = { +export type PreviewSubscribeErrors = { + /** + * Invalid request (e.g., invalid plan slug, seats below minimum) + */ + 400: ErrorResponse + /** + * Unauthorized + */ + 401: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type DeleteSessionError = DeleteSessionErrors[keyof DeleteSessionErrors] +export type PreviewSubscribeError = + PreviewSubscribeErrors[keyof PreviewSubscribeErrors] -export type DeleteSessionResponses = { +export type PreviewSubscribeResponses = { /** - * Session deleted successfully + * Subscription preview */ - 200: DeleteSessionResponse + 200: PreviewSubscribeResponse } -export type DeleteSessionResponse2 = - DeleteSessionResponses[keyof DeleteSessionResponses] +export type PreviewSubscribeResponse2 = + PreviewSubscribeResponses[keyof PreviewSubscribeResponses] -export type CreateSessionData = { +export type GetBillingStatusData = { body?: never path?: never query?: never - url: '/api/auth/session' + url: '/api/billing/status' } -export type CreateSessionErrors = { +export type GetBillingStatusErrors = { /** - * Bad request - Invalid or old ID token + * Unauthorized */ - 400: ErrorResponse + 401: ErrorResponse /** - * Unauthorized - Authentication required + * Workspace not found */ - 401: ErrorResponse + 404: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type CreateSessionError = CreateSessionErrors[keyof CreateSessionErrors] +export type GetBillingStatusError = + GetBillingStatusErrors[keyof GetBillingStatusErrors] -export type CreateSessionResponses = { +export type GetBillingStatusResponses = { /** - * Session created successfully + * Billing status */ - 200: CreateSessionResponse + 200: BillingStatusResponse } -export type CreateSessionResponse2 = - CreateSessionResponses[keyof CreateSessionResponses] +export type GetBillingStatusResponse = + GetBillingStatusResponses[keyof GetBillingStatusResponses] -export type ExchangeTokenData = { - body?: ExchangeTokenRequest +export type SubscribeData = { + body: SubscribeRequest path?: never query?: never - url: '/api/auth/token' + url: '/api/billing/subscribe' } -export type ExchangeTokenErrors = { +export type SubscribeErrors = { /** - * Invalid or expired Firebase JWT + * Invalid request (e.g., invalid plan slug, incompatible plan) */ - 401: ErrorResponse + 400: ErrorResponse /** - * Workspace not found or user not a member + * Unauthorized */ - 404: ErrorResponse + 401: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type ExchangeTokenError = ExchangeTokenErrors[keyof ExchangeTokenErrors] +export type SubscribeError = SubscribeErrors[keyof SubscribeErrors] -export type ExchangeTokenResponses = { +export type SubscribeResponses = { /** - * Token exchanged successfully + * Subscription created or payment method needed */ - 200: ExchangeTokenResponse + 200: SubscribeResponse } -export type ExchangeTokenResponse2 = - ExchangeTokenResponses[keyof ExchangeTokenResponses] +export type SubscribeResponse2 = SubscribeResponses[keyof SubscribeResponses] -export type CreateDesktopLoginCodeData = { - body: DesktopLoginCodeCreateRequest +export type CancelSubscriptionData = { + body: CancelSubscriptionRequest path?: never query?: never - url: '/api/auth/desktop-login-codes' + url: '/api/billing/subscription/cancel' } -export type CreateDesktopLoginCodeErrors = { +export type CancelSubscriptionErrors = { /** - * Invalid request + * Invalid request (e.g., no active subscription) */ 400: ErrorResponse /** - * Service unavailable - login code store not available + * Unauthorized */ - 503: ErrorResponse + 401: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type CreateDesktopLoginCodeError = - CreateDesktopLoginCodeErrors[keyof CreateDesktopLoginCodeErrors] +export type CancelSubscriptionError = + CancelSubscriptionErrors[keyof CancelSubscriptionErrors] -export type CreateDesktopLoginCodeResponses = { +export type CancelSubscriptionResponses = { /** - * Login code created + * Subscription cancellation scheduled */ - 201: DesktopLoginCodeCreateResponse + 200: CancelSubscriptionResponse } -export type CreateDesktopLoginCodeResponse = - CreateDesktopLoginCodeResponses[keyof CreateDesktopLoginCodeResponses] +export type CancelSubscriptionResponse2 = + CancelSubscriptionResponses[keyof CancelSubscriptionResponses] -export type RedeemDesktopLoginCodeData = { - body: DesktopLoginCodeRedeemRequest +export type ResubscribeData = { + body: ResubscribeRequest path?: never query?: never - url: '/api/auth/desktop-login-codes/redeem' + url: '/api/billing/subscription/resubscribe' } -export type RedeemDesktopLoginCodeErrors = { - /** - * Unauthorized - authentication required - */ - 401: ErrorResponse +export type ResubscribeErrors = { /** - * Unknown or expired code + * Invalid request (e.g., no active subscription, not in cancellation grace period) */ - 404: ErrorResponse + 400: ErrorResponse /** - * Code already redeemed by a different user + * Unauthorized */ - 409: ErrorResponse + 401: ErrorResponse /** * Internal server error */ 500: ErrorResponse - /** - * Service unavailable - login code store not available - */ - 503: ErrorResponse } -export type RedeemDesktopLoginCodeError = - RedeemDesktopLoginCodeErrors[keyof RedeemDesktopLoginCodeErrors] +export type ResubscribeError = ResubscribeErrors[keyof ResubscribeErrors] -export type RedeemDesktopLoginCodeResponses = { +export type ResubscribeResponses = { /** - * Code redeemed (or already redeemed by the same user) + * Subscription resumed successfully */ - 200: DesktopLoginCodeRedeemResponse + 200: ResubscribeResponse } -export type RedeemDesktopLoginCodeResponse = - RedeemDesktopLoginCodeResponses[keyof RedeemDesktopLoginCodeResponses] +export type ResubscribeResponse2 = + ResubscribeResponses[keyof ResubscribeResponses] -export type ExchangeDesktopLoginCodeData = { - body: DesktopLoginCodeExchangeRequest +export type CreateTopupData = { + body: CreateTopupRequest path?: never query?: never - url: '/api/auth/desktop-login-codes/exchange' + url: '/api/billing/topup' } -export type ExchangeDesktopLoginCodeErrors = { +export type CreateTopupErrors = { /** - * Invalid request + * Bad request (invalid amount, no payment method) */ 400: ErrorResponse /** - * Code verifier does not match the challenge + * Unauthorized */ - 403: ErrorResponse + 401: ErrorResponse /** - * Unknown, expired, or already-consumed code + * Internal server error */ - 404: ErrorResponse + 500: ErrorResponse +} + +export type CreateTopupError = CreateTopupErrors[keyof CreateTopupErrors] + +export type CreateTopupResponses = { /** - * Service unavailable - login code store or token minting not available + * Top-up initiated successfully */ - 503: ErrorResponse + 200: CreateTopupResponse } -export type ExchangeDesktopLoginCodeError = - ExchangeDesktopLoginCodeErrors[keyof ExchangeDesktopLoginCodeErrors] +export type CreateTopupResponse2 = + CreateTopupResponses[keyof CreateTopupResponses] -export type ExchangeDesktopLoginCodeResponses = { +export type GetEmbeddingsData = { + body?: never + path?: never + query?: never + url: '/api/embeddings' +} + +export type GetEmbeddingsResponses = { /** - * Pending (not yet redeemed) or complete with a custom token + * Embedding names */ - 200: DesktopLoginCodeExchangeResponse + 200: Array } -export type ExchangeDesktopLoginCodeResponse = - ExchangeDesktopLoginCodeResponses[keyof ExchangeDesktopLoginCodeResponses] +export type GetEmbeddingsResponse = + GetEmbeddingsResponses[keyof GetEmbeddingsResponses] -export type GetJwksData = { +export type GetModelFoldersData = { body?: never path?: never query?: never - url: '/.well-known/jwks.json' + url: '/api/experiment/models' } -export type GetJwksResponses = { +export type GetModelFoldersErrors = { /** - * JWKS response + * Internal server error */ - 200: JwksResponse + 500: ErrorResponse } -export type GetJwksResponse = GetJwksResponses[keyof GetJwksResponses] +export type GetModelFoldersError = + GetModelFoldersErrors[keyof GetModelFoldersErrors] -export type GetOAuthAuthorizationServerData = { +export type GetModelFoldersResponses = { + /** + * Success - List of model folders + */ + 200: Array +} + +export type GetModelFoldersResponse = + GetModelFoldersResponses[keyof GetModelFoldersResponses] + +export type GetModelsInFolderData = { body?: never - path?: never + path: { + /** + * The folder name to list models from + */ + folder: string + } query?: never - url: '/.well-known/oauth-authorization-server' + url: '/api/experiment/models/{folder}' } -export type GetOAuthAuthorizationServerErrors = { +export type GetModelsInFolderErrors = { /** - * OAuth disabled + * Folder not found or no models in folder */ 404: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetOAuthAuthorizationServerError = - GetOAuthAuthorizationServerErrors[keyof GetOAuthAuthorizationServerErrors] +export type GetModelsInFolderError = + GetModelsInFolderErrors[keyof GetModelsInFolderErrors] -export type GetOAuthAuthorizationServerResponses = { +export type GetModelsInFolderResponses = { /** - * Authorization-server metadata + * Success - List of models in the folder */ - 200: OAuthAuthorizationServerMetadata + 200: Array } -export type GetOAuthAuthorizationServerResponse = - GetOAuthAuthorizationServerResponses[keyof GetOAuthAuthorizationServerResponses] +export type GetModelsInFolderResponse = + GetModelsInFolderResponses[keyof GetModelsInFolderResponses] -export type GetOAuthProtectedResourceData = { +export type GetModelPreviewData = { body?: never - path?: never + path: { + /** + * The folder name containing the model. + */ + folder: string + /** + * The path index (usually 0 for cloud service). + */ + path_index: number + /** + * The model filename (with or without .webp extension). + */ + filename: string + } query?: never - url: '/.well-known/oauth-protected-resource' + url: '/api/experiment/models/preview/{folder}/{path_index}/{filename}' } -export type GetOAuthProtectedResourceErrors = { +export type GetModelPreviewErrors = { /** - * OAuth disabled or no active resource configured + * Preview not available on Cloud */ - 404: ErrorResponse + 404: unknown } -export type GetOAuthProtectedResourceError = - GetOAuthProtectedResourceErrors[keyof GetOAuthProtectedResourceErrors] +export type GetNodeInfoSchemaData = { + body?: never + path?: never + query?: never + url: '/api/experiment/nodes' +} -export type GetOAuthProtectedResourceResponses = { +export type GetNodeInfoSchemaResponses = { /** - * Protected-resource metadata + * Full node schema JSON */ - 200: OAuthProtectedResourceMetadata + 200: unknown } -export type GetOAuthProtectedResourceResponse = - GetOAuthProtectedResourceResponses[keyof GetOAuthProtectedResourceResponses] - -export type GetOAuthProtectedResourceByPathData = { +export type GetNodeByIdData = { body?: never path: { /** - * Single-segment resource path without its leading slash (e.g. "mcp"). + * Node class_type identifier */ - resourcePath: string + id: string } query?: never - url: '/.well-known/oauth-protected-resource/{resourcePath}' + url: '/api/experiment/nodes/{id}' } -export type GetOAuthProtectedResourceByPathErrors = { +export type GetNodeByIdErrors = { /** - * OAuth disabled, or no active resource at this path + * Node not found */ - 404: ErrorResponse + 404: unknown } -export type GetOAuthProtectedResourceByPathError = - GetOAuthProtectedResourceByPathErrors[keyof GetOAuthProtectedResourceByPathErrors] - -export type GetOAuthProtectedResourceByPathResponses = { +export type GetNodeByIdResponses = { /** - * Protected-resource metadata + * Node definition JSON */ - 200: OAuthProtectedResourceMetadata + 200: unknown } -export type GetOAuthProtectedResourceByPathResponse = - GetOAuthProtectedResourceByPathResponses[keyof GetOAuthProtectedResourceByPathResponses] - -export type GetOAuthAuthorizeData = { +export type GetExtensionsData = { body?: never path?: never - query?: { - response_type?: string - client_id?: string - redirect_uri?: string - scope?: string - /** - * RFC 6749 §10.12 marks `state` as RECOMMENDED. Our hardening makes - * it REQUIRED on the initial-entry path (omitted only on the resume - * path where `oauth_request_id` is supplied instead). This parameter - * is `required: false` at the spec level only because the operation - * is dual-mode (initial entry vs. resume); the runtime parser - * (services/ingest/server/implementation/oauth/protocol/request.go) - * rejects empty `state` on the initial-entry path with a stable - * `invalid_request` 400. - * - */ - state?: string - code_challenge?: string - code_challenge_method?: string - resource?: string - oauth_request_id?: string - } - url: '/oauth/authorize' + query?: never + url: '/api/extensions' } -export type GetOAuthAuthorizeErrors = { - /** - * Invalid authorize request (pre-redirect failure — unknown client, redirect mismatch, malformed params). Content-negotiated; browser navigations (Accept includes text/html without application/json) receive a self-contained HTML error page instead of JSON. - */ - 400: ErrorResponse +export type GetExtensionsResponses = { /** - * OAuth disabled + * URL paths (relative to web root) of available extension JS files */ - 404: ErrorResponse + 200: Array } -export type GetOAuthAuthorizeError = - GetOAuthAuthorizeErrors[keyof GetOAuthAuthorizeErrors] +export type GetExtensionsResponse = + GetExtensionsResponses[keyof GetExtensionsResponses] -export type GetOAuthAuthorizeResponses = { +export type GetFeaturesData = { + body?: never + path?: never + query?: never + url: '/api/features' +} + +export type GetFeaturesResponses = { /** - * Consent challenge payload (cookie present, email verified). Frontend renders the consent UI from this payload and POSTs back to /oauth/authorize. - * + * Success */ - 200: OAuthConsentChallenge + 200: { + /** + * Maximum upload size in bytes + */ + max_upload_size?: number + /** + * Whether the server supports preview metadata + */ + supports_preview_metadata?: boolean + [key: string]: unknown | number | boolean | undefined + } } -export type GetOAuthAuthorizeResponse = - GetOAuthAuthorizeResponses[keyof GetOAuthAuthorizeResponses] +export type GetFeaturesResponse = + GetFeaturesResponses[keyof GetFeaturesResponses] -export type PostOAuthAuthorizeData = { - body: { - oauth_request_id: string - csrf_token: string - decision: 'allow' | 'deny' - workspace_id: string - } +export type SubmitFeedbackData = { + body: FeedbackRequest path?: never query?: never - url: '/oauth/authorize' + url: '/api/feedback' } -export type PostOAuthAuthorizeErrors = { +export type SubmitFeedbackErrors = { /** - * Bad request (CSRF mismatch, expired/consumed request, inaccessible workspace) + * Invalid request */ 400: ErrorResponse /** - * Scope broadening on consent re-grant — fresh consent flow required + * Unauthorized */ - 403: ErrorResponse + 401: ErrorResponse /** - * OAuth disabled + * Internal server error */ - 404: ErrorResponse + 500: ErrorResponse } -export type PostOAuthAuthorizeError = - PostOAuthAuthorizeErrors[keyof PostOAuthAuthorizeErrors] +export type SubmitFeedbackError = + SubmitFeedbackErrors[keyof SubmitFeedbackErrors] -export type PostOAuthAuthorizeResponses = { +export type SubmitFeedbackResponses = { /** - * Redirect URL for the frontend to navigate to (allow → with code+state; deny → with error+state) + * Feedback submitted successfully */ - 200: OAuthAuthorizeRedirectResponse + 201: FeedbackResponse } -export type PostOAuthAuthorizeResponse = - PostOAuthAuthorizeResponses[keyof PostOAuthAuthorizeResponses] +export type SubmitFeedbackResponse = + SubmitFeedbackResponses[keyof SubmitFeedbackResponses] -export type PostOAuthTokenData = { - body: { - grant_type: 'authorization_code' | 'refresh_token' - client_id: string - code?: string - redirect_uri?: string - code_verifier?: string - refresh_token?: string - scope?: string - client_secret?: string - } +export type GetMaskLayersData = { + body?: never path?: never - query?: never - url: '/oauth/token' + query: { + /** + * Hash filename of any mask layer file + */ + filename: string + } + url: '/api/files/mask-layers' } -export type PostOAuthTokenErrors = { - /** - * RFC 6749 §5.2 error - */ - 400: OAuthTokenError +export type GetMaskLayersErrors = { /** - * OAuth disabled + * File not found or not a mask file */ 404: ErrorResponse } -export type PostOAuthTokenError = - PostOAuthTokenErrors[keyof PostOAuthTokenErrors] +export type GetMaskLayersError = GetMaskLayersErrors[keyof GetMaskLayersErrors] -export type PostOAuthTokenResponses = { +export type GetMaskLayersResponses = { /** - * New token pair + * Success - Related mask layers returned */ - 200: OAuthTokenResponse + 200: { + /** + * Filename of the mask layer + */ + mask?: string | null + /** + * Filename of the paint strokes layer + */ + paint?: string | null + /** + * Filename of the painted image layer + */ + painted?: string | null + /** + * Filename of the final composite layer + */ + painted_masked?: string | null + } } -export type PostOAuthTokenResponse = - PostOAuthTokenResponses[keyof PostOAuthTokenResponses] +export type GetMaskLayersResponse = + GetMaskLayersResponses[keyof GetMaskLayersResponses] -export type PostOAuthRegisterData = { - body: OAuthRegisterRequest +export type FreeMemoryData = { + body?: { + /** + * Run garbage collection and free cached memory + */ + free_memory?: boolean + /** + * Unload all models from VRAM/RAM + */ + unload_models?: boolean + } path?: never query?: never - url: '/oauth/register' -} - -export type PostOAuthRegisterErrors = { - /** - * Bad request. Two shapes possible: `OAuthRegisterError` (RFC 7591 §3.2.2, emitted by the handler for invalid client metadata, reserved client_name, etc.) OR `ErrorResponse` (emitted by the strict-server binding layer when the request body fails OpenAPI-schema validation — malformed JSON, missing required fields, `additionalProperties: false` violations — normalized to the standard {code, message} shape by the custom Echo HTTPErrorHandler, BE-1178). - * - */ - 400: OAuthRegisterBadRequestResponse - /** - * OAuth disabled - */ - 404: ErrorResponse - /** - * No active MCP resource is configured — DCR cannot mint a usable client until ops seeds an active oauth_resources row. - */ - 503: ErrorResponse + url: '/api/free' } -export type PostOAuthRegisterError = - PostOAuthRegisterErrors[keyof PostOAuthRegisterErrors] - -export type PostOAuthRegisterResponses = { +export type FreeMemoryResponses = { /** - * Registered. Body echoes the metadata RFC 7591 §3.2.1 requires. + * Memory freed */ - 201: OAuthRegisterResponse + 200: unknown } -export type PostOAuthRegisterResponse = - PostOAuthRegisterResponses[keyof PostOAuthRegisterResponses] - -export type ListWorkspacesData = { +export type GetGlobalSubgraphsData = { body?: never path?: never query?: never - url: '/api/workspaces' + url: '/api/global_subgraphs' } -export type ListWorkspacesErrors = { - /** - * Unauthorized - */ - 401: ErrorResponse - /** - * Feature not enabled for user - */ - 404: ErrorResponse +export type GetGlobalSubgraphsErrors = { /** * Internal server error */ 500: ErrorResponse } -export type ListWorkspacesError = - ListWorkspacesErrors[keyof ListWorkspacesErrors] +export type GetGlobalSubgraphsError = + GetGlobalSubgraphsErrors[keyof GetGlobalSubgraphsErrors] -export type ListWorkspacesResponses = { +export type GetGlobalSubgraphsResponses = { /** - * List of workspaces + * Success - Map of subgraph IDs to their metadata */ - 200: ListWorkspacesResponse + 200: { + [key: string]: GlobalSubgraphInfo + } } -export type ListWorkspacesResponse2 = - ListWorkspacesResponses[keyof ListWorkspacesResponses] +export type GetGlobalSubgraphsResponse = + GetGlobalSubgraphsResponses[keyof GetGlobalSubgraphsResponses] -export type CreateWorkspaceData = { - body: CreateWorkspaceRequest - path?: never +export type GetGlobalSubgraphData = { + body?: never + path: { + /** + * The unique identifier of the subgraph blueprint + */ + id: string + } query?: never - url: '/api/workspaces' + url: '/api/global_subgraphs/{id}' } -export type CreateWorkspaceErrors = { - /** - * Unauthorized - */ - 401: ErrorResponse +export type GetGlobalSubgraphErrors = { /** - * Feature not enabled for user + * Subgraph not found */ 404: ErrorResponse - /** - * Validation error - */ - 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type CreateWorkspaceError = - CreateWorkspaceErrors[keyof CreateWorkspaceErrors] +export type GetGlobalSubgraphError = + GetGlobalSubgraphErrors[keyof GetGlobalSubgraphErrors] -export type CreateWorkspaceResponses = { +export type GetGlobalSubgraphResponses = { /** - * Workspace created + * Success - Full subgraph data */ - 201: Workspace + 200: GlobalSubgraphData } -export type CreateWorkspaceResponse = - CreateWorkspaceResponses[keyof CreateWorkspaceResponses] +export type GetGlobalSubgraphResponse = + GetGlobalSubgraphResponses[keyof GetGlobalSubgraphResponses] -export type DeleteWorkspaceData = { +export type GetLegacyHistoryData = { body?: never - path: { - /** - * Workspace ID (w-{uuid} format) - */ - id: string - } + path?: never query?: never - url: '/api/workspaces/{id}' + url: '/api/history' } -export type DeleteWorkspaceErrors = { +export type GetLegacyHistoryErrors = { /** - * Unauthorized + * Not Found — use /api/history_v2 instead */ - 401: ErrorResponse + 404: unknown +} + +export type ManageHistoryData = { + body: HistoryManageRequest + path?: never + query?: never + url: '/api/history' +} + +export type ManageHistoryErrors = { /** - * Owner role required or cannot delete personal workspace + * Invalid request parameters */ - 403: ErrorResponse + 400: ErrorResponse /** - * Workspace not found + * Unauthorized - Authentication required */ - 404: ErrorResponse + 401: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type DeleteWorkspaceError = - DeleteWorkspaceErrors[keyof DeleteWorkspaceErrors] +export type ManageHistoryError = ManageHistoryErrors[keyof ManageHistoryErrors] -export type DeleteWorkspaceResponses = { +export type ManageHistoryResponses = { /** - * Workspace deleted + * Success - History management operation completed */ - 204: void + 200: unknown } -export type DeleteWorkspaceResponse = - DeleteWorkspaceResponses[keyof DeleteWorkspaceResponses] - -export type GetWorkspaceData = { +export type GetLegacyHistoryByIdData = { body?: never path: { - /** - * Workspace ID (w-{uuid} format) - */ - id: string + prompt_id: string } query?: never - url: '/api/workspaces/{id}' -} - -export type GetWorkspaceErrors = { - /** - * Unauthorized - */ - 401: ErrorResponse - /** - * Workspace not found or user not a member - */ - 404: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse + url: '/api/history/{prompt_id}' } -export type GetWorkspaceError = GetWorkspaceErrors[keyof GetWorkspaceErrors] - -export type GetWorkspaceResponses = { +export type GetLegacyHistoryByIdErrors = { /** - * Workspace details + * Not Found — use /api/jobs/{prompt_id} instead */ - 200: Workspace + 404: unknown } -export type GetWorkspaceResponse = - GetWorkspaceResponses[keyof GetWorkspaceResponses] - -export type UpdateWorkspaceData = { - body: UpdateWorkspaceRequest - path: { +export type GetHistoryData = { + body?: never + path?: never + query?: { /** - * Workspace ID (w-{uuid} format) + * Maximum number of items to return */ - id: string + max_items?: number + /** + * Starting position (default 0) + */ + offset?: number } - query?: never - url: '/api/workspaces/{id}' + url: '/api/history_v2' } -export type UpdateWorkspaceErrors = { +export type GetHistoryErrors = { /** - * Unauthorized + * Unauthorized - Authentication required */ 401: ErrorResponse - /** - * Owner role required - */ - 403: ErrorResponse - /** - * Workspace not found - */ - 404: ErrorResponse - /** - * Validation error - */ - 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type UpdateWorkspaceError = - UpdateWorkspaceErrors[keyof UpdateWorkspaceErrors] +export type GetHistoryError = GetHistoryErrors[keyof GetHistoryErrors] -export type UpdateWorkspaceResponses = { +export type GetHistoryResponses = { /** - * Workspace updated + * Success - Execution history retrieved */ - 200: Workspace + 200: HistoryResponse } -export type UpdateWorkspaceResponse = - UpdateWorkspaceResponses[keyof UpdateWorkspaceResponses] +export type GetHistoryResponse = GetHistoryResponses[keyof GetHistoryResponses] -export type ListWorkspaceMembersData = { +export type GetHistoryForPromptData = { body?: never - path?: never - query?: { - /** - * Pagination offset (0-based) - */ - offset?: number + path: { /** - * Maximum number of members to return + * The prompt ID to retrieve history for */ - limit?: number + prompt_id: string } - url: '/api/workspace/members' + query?: never + url: '/api/history_v2/{prompt_id}' } -export type ListWorkspaceMembersErrors = { +export type GetHistoryForPromptErrors = { /** - * Unauthorized + * Unauthorized - Authentication required */ 401: ErrorResponse /** - * Not a member of this workspace - */ - 403: ErrorResponse - /** - * Workspace not found + * Prompt not found */ 404: ErrorResponse - /** - * Validation error - */ - 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type ListWorkspaceMembersError = - ListWorkspaceMembersErrors[keyof ListWorkspaceMembersErrors] +export type GetHistoryForPromptError = + GetHistoryForPromptErrors[keyof GetHistoryForPromptErrors] -export type ListWorkspaceMembersResponses = { +export type GetHistoryForPromptResponses = { /** - * List of members + * Success - History for prompt retrieved */ - 200: ListMembersResponse + 200: HistoryDetailResponse } -export type ListWorkspaceMembersResponse = - ListWorkspaceMembersResponses[keyof ListWorkspaceMembersResponses] +export type GetHistoryForPromptResponse = + GetHistoryForPromptResponses[keyof GetHistoryForPromptResponses] -export type ListWorkspaceInvitesData = { - body?: never +export type CreateHubAssetUploadUrlData = { + body: HubAssetUploadUrlRequest path?: never query?: never - url: '/api/workspace/invites' + url: '/api/hub/assets/upload-url' } -export type ListWorkspaceInvitesErrors = { +export type CreateHubAssetUploadUrlErrors = { + /** + * Bad request (e.g. unsupported content type) + */ + 400: ErrorResponse /** * Unauthorized */ 401: ErrorResponse /** - * Owner role required + * Not found */ - 403: ErrorResponse + 404: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type ListWorkspaceInvitesError = - ListWorkspaceInvitesErrors[keyof ListWorkspaceInvitesErrors] +export type CreateHubAssetUploadUrlError = + CreateHubAssetUploadUrlErrors[keyof CreateHubAssetUploadUrlErrors] -export type ListWorkspaceInvitesResponses = { +export type CreateHubAssetUploadUrlResponses = { /** - * List of pending invites + * Presigned upload URL and token */ - 200: ListInvitesResponse + 200: HubAssetUploadUrlResponse } -export type ListWorkspaceInvitesResponse = - ListWorkspaceInvitesResponses[keyof ListWorkspaceInvitesResponses] +export type CreateHubAssetUploadUrlResponse = + CreateHubAssetUploadUrlResponses[keyof CreateHubAssetUploadUrlResponses] -export type CreateWorkspaceInviteData = { - body: CreateInviteRequest +export type ListHubLabelsData = { + body?: never path?: never - query?: never - url: '/api/workspace/invites' + query?: { + /** + * Filter by label type. Omit to return all labels. + */ + type?: 'tag' | 'model' | 'custom_node' + } + url: '/api/hub/labels' } -export type CreateWorkspaceInviteErrors = { - /** - * Unauthorized - */ - 401: ErrorResponse - /** - * Owner role required or personal workspace (invites not allowed) - */ - 403: ErrorResponse - /** - * Workspace not found - */ - 404: ErrorResponse - /** - * Invite already exists - */ - 409: ErrorResponse +export type ListHubLabelsErrors = { /** - * Validation error + * Bad request (e.g. invalid type parameter) */ - 422: ErrorResponse + 400: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type CreateWorkspaceInviteError = - CreateWorkspaceInviteErrors[keyof CreateWorkspaceInviteErrors] +export type ListHubLabelsError = ListHubLabelsErrors[keyof ListHubLabelsErrors] -export type CreateWorkspaceInviteResponses = { +export type ListHubLabelsResponses = { /** - * Invite created + * List of labels */ - 201: PendingInvite + 200: HubLabelListResponse } -export type CreateWorkspaceInviteResponse = - CreateWorkspaceInviteResponses[keyof CreateWorkspaceInviteResponses] +export type ListHubLabelsResponse = + ListHubLabelsResponses[keyof ListHubLabelsResponses] -export type AcceptWorkspaceInviteData = { - body?: never - path: { - /** - * Invite token - */ - token: string - } +export type CreateHubProfileData = { + body: CreateHubProfileRequest + path?: never query?: never - url: '/api/invites/{token}/accept' + url: '/api/hub/profiles' } -export type AcceptWorkspaceInviteErrors = { +export type CreateHubProfileErrors = { /** - * Unauthorized + * Bad request (e.g. invalid username) */ - 401: ErrorResponse + 400: ErrorResponse /** - * Email does not match invite + * Unauthorized */ - 403: ErrorResponse + 401: ErrorResponse /** - * Invite not found or expired + * Not found */ 404: ErrorResponse /** - * Already a member of this workspace + * Username already taken or profile already exists */ 409: ErrorResponse /** @@ -7564,37 +5816,34 @@ export type AcceptWorkspaceInviteErrors = { 500: ErrorResponse } -export type AcceptWorkspaceInviteError = - AcceptWorkspaceInviteErrors[keyof AcceptWorkspaceInviteErrors] +export type CreateHubProfileError = + CreateHubProfileErrors[keyof CreateHubProfileErrors] -export type AcceptWorkspaceInviteResponses = { +export type CreateHubProfileResponses = { /** - * Invite accepted, user is now a member + * Hub profile created */ - 200: AcceptInviteResponse + 201: HubProfile } -export type AcceptWorkspaceInviteResponse = - AcceptWorkspaceInviteResponses[keyof AcceptWorkspaceInviteResponses] +export type CreateHubProfileResponse = + CreateHubProfileResponses[keyof CreateHubProfileResponses] -export type LeaveWorkspaceData = { +export type GetHubProfileByUsernameData = { body?: never - path?: never + path: { + /** + * The hub profile username. + */ + username: string + } query?: never - url: '/api/workspace/leave' + url: '/api/hub/profiles/{username}' } -export type LeaveWorkspaceErrors = { - /** - * Unauthorized - */ - 401: ErrorResponse - /** - * Cannot leave as the only owner or cannot leave personal workspace - */ - 403: ErrorResponse +export type GetHubProfileByUsernameErrors = { /** - * Workspace not found or not a member + * Profile not found */ 404: ErrorResponse /** @@ -7603,42 +5852,42 @@ export type LeaveWorkspaceErrors = { 500: ErrorResponse } -export type LeaveWorkspaceError = - LeaveWorkspaceErrors[keyof LeaveWorkspaceErrors] +export type GetHubProfileByUsernameError = + GetHubProfileByUsernameErrors[keyof GetHubProfileByUsernameErrors] -export type LeaveWorkspaceResponses = { +export type GetHubProfileByUsernameResponses = { /** - * Successfully left workspace + * Hub profile */ - 204: void + 200: HubProfile } -export type LeaveWorkspaceResponse = - LeaveWorkspaceResponses[keyof LeaveWorkspaceResponses] +export type GetHubProfileByUsernameResponse = + GetHubProfileByUsernameResponses[keyof GetHubProfileByUsernameResponses] -export type RevokeWorkspaceInviteData = { - body?: never +export type UpdateHubProfileData = { + body: UpdateHubProfileRequest path: { /** - * Invite ID to revoke + * The hub profile username to update. */ - inviteId: string + username: string } query?: never - url: '/api/workspace/invites/{inviteId}' + url: '/api/hub/profiles/{username}' } -export type RevokeWorkspaceInviteErrors = { +export type UpdateHubProfileErrors = { /** - * Unauthorized + * Bad request (e.g. missing body, invalid avatar token) */ - 401: ErrorResponse + 400: ErrorResponse /** - * Owner role required + * Unauthorized */ - 403: ErrorResponse + 401: ErrorResponse /** - * Workspace or invite not found + * No hub profile exists with this username */ 404: ErrorResponse /** @@ -7647,42 +5896,35 @@ export type RevokeWorkspaceInviteErrors = { 500: ErrorResponse } -export type RevokeWorkspaceInviteError = - RevokeWorkspaceInviteErrors[keyof RevokeWorkspaceInviteErrors] +export type UpdateHubProfileError = + UpdateHubProfileErrors[keyof UpdateHubProfileErrors] -export type RevokeWorkspaceInviteResponses = { +export type UpdateHubProfileResponses = { /** - * Invite revoked + * Hub profile updated */ - 204: void + 200: HubProfile } -export type RevokeWorkspaceInviteResponse = - RevokeWorkspaceInviteResponses[keyof RevokeWorkspaceInviteResponses] +export type UpdateHubProfileResponse = + UpdateHubProfileResponses[keyof UpdateHubProfileResponses] -export type RemoveWorkspaceMemberData = { +export type CheckHubUsernameData = { body?: never - path: { - /** - * User ID to remove - */ - userId: string + path?: never + query: { + username: string } - query?: never - url: '/api/workspace/members/{userId}' + url: '/api/hub/profiles/check' } -export type RemoveWorkspaceMemberErrors = { +export type CheckHubUsernameErrors = { /** * Unauthorized */ 401: ErrorResponse /** - * Owner role required or cannot remove yourself - */ - 403: ErrorResponse - /** - * Workspace or member not found + * Not found */ 404: ErrorResponse /** @@ -7691,172 +5933,170 @@ export type RemoveWorkspaceMemberErrors = { 500: ErrorResponse } -export type RemoveWorkspaceMemberError = - RemoveWorkspaceMemberErrors[keyof RemoveWorkspaceMemberErrors] +export type CheckHubUsernameError = + CheckHubUsernameErrors[keyof CheckHubUsernameErrors] -export type RemoveWorkspaceMemberResponses = { +export type CheckHubUsernameResponses = { /** - * Member removed + * Username availability result */ - 204: void + 200: HubUsernameCheckResponse } -export type RemoveWorkspaceMemberResponse = - RemoveWorkspaceMemberResponses[keyof RemoveWorkspaceMemberResponses] +export type CheckHubUsernameResponse = + CheckHubUsernameResponses[keyof CheckHubUsernameResponses] -export type UpdateWorkspaceMemberRoleData = { - body: UpdateMemberRoleRequest - path: { - /** - * User ID whose role is being changed - */ - userId: string - } +export type GetMyHubProfileData = { + body?: never + path?: never query?: never - url: '/api/workspace/members/{userId}' + url: '/api/hub/profiles/me' } -export type UpdateWorkspaceMemberRoleErrors = { +export type GetMyHubProfileErrors = { /** * Unauthorized */ 401: ErrorResponse /** - * Owner role required, or the original owner cannot be demoted - */ - 403: ErrorResponse - /** - * Workspace or member not found + * No hub profile exists */ 404: ErrorResponse - /** - * Validation error - */ - 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type UpdateWorkspaceMemberRoleError = - UpdateWorkspaceMemberRoleErrors[keyof UpdateWorkspaceMemberRoleErrors] +export type GetMyHubProfileError = + GetMyHubProfileErrors[keyof GetMyHubProfileErrors] -export type UpdateWorkspaceMemberRoleResponses = { +export type GetMyHubProfileResponses = { /** - * Member role updated + * Hub profile */ - 200: Member + 200: HubProfile } -export type UpdateWorkspaceMemberRoleResponse = - UpdateWorkspaceMemberRoleResponses[keyof UpdateWorkspaceMemberRoleResponses] +export type GetMyHubProfileResponse = + GetMyHubProfileResponses[keyof GetMyHubProfileResponses] -export type ListWorkspaceApiKeysData = { +export type ListHubWorkflowsData = { body?: never path?: never - query?: never - url: '/api/workspace/api-keys' + query?: { + cursor?: string + limit?: number + /** + * Search by workflow name + */ + search?: string + /** + * Filter by tag + */ + tag?: string + /** + * Filter by profile username + */ + username?: string + /** + * When true, returns full HubWorkflowDetail objects in the workflows array instead of summaries. Requires limit <= 20. + */ + detail?: boolean + /** + * Filter by status (e.g. ?status=pending,approved). Defaults to approved if omitted. + */ + status?: Array + } + url: '/api/hub/workflows' } -export type ListWorkspaceApiKeysErrors = { +export type ListHubWorkflowsErrors = { /** - * Unauthorized + * Bad request (e.g. malformed pagination cursor) */ - 401: ErrorResponse + 400: ErrorResponse /** - * Forbidden + * Profile not found (when filtering by username) */ - 403: ErrorResponse + 404: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type ListWorkspaceApiKeysError = - ListWorkspaceApiKeysErrors[keyof ListWorkspaceApiKeysErrors] +export type ListHubWorkflowsError = + ListHubWorkflowsErrors[keyof ListHubWorkflowsErrors] -export type ListWorkspaceApiKeysResponses = { +export type ListHubWorkflowsResponses = { /** - * List of API keys + * Paginated list of hub workflows */ - 200: ListWorkspaceApiKeysResponse + 200: HubWorkflowListResponse } -export type ListWorkspaceApiKeysResponse2 = - ListWorkspaceApiKeysResponses[keyof ListWorkspaceApiKeysResponses] +export type ListHubWorkflowsResponse = + ListHubWorkflowsResponses[keyof ListHubWorkflowsResponses] -export type CreateWorkspaceApiKeyData = { - body: CreateWorkspaceApiKeyRequest +export type PublishHubWorkflowData = { + body: PublishHubWorkflowRequest path?: never query?: never - url: '/api/workspace/api-keys' + url: '/api/hub/workflows' } -export type CreateWorkspaceApiKeyErrors = { +export type PublishHubWorkflowErrors = { /** - * Unauthorized + * Bad request */ - 401: ErrorResponse + 400: ErrorResponse /** - * Not a workspace member + * Unauthorized */ - 403: ErrorResponse + 401: ErrorResponse /** - * Workspace not found + * Workflow or profile not found */ 404: ErrorResponse - /** - * Validation error - */ - 422: ErrorResponse - /** - * Key limit reached - */ - 429: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type CreateWorkspaceApiKeyError = - CreateWorkspaceApiKeyErrors[keyof CreateWorkspaceApiKeyErrors] +export type PublishHubWorkflowError = + PublishHubWorkflowErrors[keyof PublishHubWorkflowErrors] -export type CreateWorkspaceApiKeyResponses = { +export type PublishHubWorkflowResponses = { /** - * API key created (plaintext returned once) + * Workflow published to hub */ - 201: CreateWorkspaceApiKeyResponse + 200: HubWorkflowDetail } -export type CreateWorkspaceApiKeyResponse2 = - CreateWorkspaceApiKeyResponses[keyof CreateWorkspaceApiKeyResponses] +export type PublishHubWorkflowResponse = + PublishHubWorkflowResponses[keyof PublishHubWorkflowResponses] -export type RevokeWorkspaceApiKeyData = { +export type DeleteHubWorkflowData = { body?: never path: { /** - * API key ID to revoke + * The share ID of the hub workflow to unpublish. */ - id: string + share_id: string } query?: never - url: '/api/workspace/api-keys/{id}' + url: '/api/hub/workflows/{share_id}' } -export type RevokeWorkspaceApiKeyErrors = { +export type DeleteHubWorkflowErrors = { /** * Unauthorized */ 401: ErrorResponse /** - * Not authorized to revoke this key - */ - 403: ErrorResponse - /** - * API key not found + * Workflow not found */ 404: ErrorResponse /** @@ -7865,286 +6105,363 @@ export type RevokeWorkspaceApiKeyErrors = { 500: ErrorResponse } -export type RevokeWorkspaceApiKeyError = - RevokeWorkspaceApiKeyErrors[keyof RevokeWorkspaceApiKeyErrors] +export type DeleteHubWorkflowError = + DeleteHubWorkflowErrors[keyof DeleteHubWorkflowErrors] -export type RevokeWorkspaceApiKeyResponses = { +export type DeleteHubWorkflowResponses = { /** - * API key revoked + * Successfully unpublished */ 204: void } -export type RevokeWorkspaceApiKeyResponse = - RevokeWorkspaceApiKeyResponses[keyof RevokeWorkspaceApiKeyResponses] +export type DeleteHubWorkflowResponse = + DeleteHubWorkflowResponses[keyof DeleteHubWorkflowResponses] -export type BulkRevokeWorkspaceMemberApiKeysData = { +export type GetHubWorkflowData = { body?: never path: { /** - * Firebase UID of the member whose keys to revoke (must be non-empty) + * The share ID of the hub workflow. */ - user_id: string + share_id: string } query?: never - url: '/api/workspace/members/{user_id}/api-keys' + url: '/api/hub/workflows/{share_id}' } -export type BulkRevokeWorkspaceMemberApiKeysErrors = { - /** - * Unauthorized - */ - 401: ErrorResponse +export type GetHubWorkflowErrors = { /** - * Not authorized (must be workspace owner) + * Workflow not found */ - 403: ErrorResponse + 404: ErrorResponse /** - * Validation error (e.g. empty user_id) + * Workflow JSON too large */ - 422: ErrorResponse + 413: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type BulkRevokeWorkspaceMemberApiKeysError = - BulkRevokeWorkspaceMemberApiKeysErrors[keyof BulkRevokeWorkspaceMemberApiKeysErrors] +export type GetHubWorkflowError = + GetHubWorkflowErrors[keyof GetHubWorkflowErrors] -export type BulkRevokeWorkspaceMemberApiKeysResponses = { +export type GetHubWorkflowResponses = { /** - * Keys revoked successfully + * Hub workflow detail */ - 200: BulkRevokeApiKeysResponse + 200: HubWorkflowDetail } -export type BulkRevokeWorkspaceMemberApiKeysResponse = - BulkRevokeWorkspaceMemberApiKeysResponses[keyof BulkRevokeWorkspaceMemberApiKeysResponses] +export type GetHubWorkflowResponse = + GetHubWorkflowResponses[keyof GetHubWorkflowResponses] -export type VerifyWorkspaceApiKeyData = { - body: VerifyApiKeyRequest +export type ListHubWorkflowIndexData = { + body?: never path?: never query?: { /** - * When true, fetches real billing status from the billing service and populates has_funds and is_active accordingly. When false or omitted, the billing lookup is skipped and has_funds/is_active are returned as true (optimistic defaults). Use true when the caller needs to gate access based on billing (e.g. partner node auth); omit for identity-only lookups (e.g. key caching). + * Filter by status (e.g. ?status=pending,approved). Defaults to approved if omitted. */ - include_billing?: boolean + status?: Array } - url: '/admin/api/keys/verify' + url: '/api/hub/workflows/index' } -export type VerifyWorkspaceApiKeyErrors = { - /** - * Invalid key or unauthorized - */ - 401: ErrorResponse +export type ListHubWorkflowIndexErrors = { /** * Internal server error */ 500: ErrorResponse } -export type VerifyWorkspaceApiKeyError = - VerifyWorkspaceApiKeyErrors[keyof VerifyWorkspaceApiKeyErrors] +export type ListHubWorkflowIndexError = + ListHubWorkflowIndexErrors[keyof ListHubWorkflowIndexErrors] -export type VerifyWorkspaceApiKeyResponses = { +export type ListHubWorkflowIndexResponses = { /** - * Key is valid + * List of hub workflow template entries */ - 200: VerifyApiKeyResponse + 200: Array } -export type VerifyWorkspaceApiKeyResponse = - VerifyWorkspaceApiKeyResponses[keyof VerifyWorkspaceApiKeyResponses] +export type ListHubWorkflowIndexResponse = + ListHubWorkflowIndexResponses[keyof ListHubWorkflowIndexResponses] -export type GetUserData = { +export type GetI18nData = { body?: never path?: never query?: never - url: '/api/user' + url: '/api/i18n' } -export type GetUserErrors = { +export type GetI18nResponses = { /** - * Unauthorized + * Nested map of locale to translation key-value pairs */ - 401: ErrorResponse + 200: { + [key: string]: unknown + } } -export type GetUserError = GetUserErrors[keyof GetUserErrors] +export type GetI18nResponse = GetI18nResponses[keyof GetI18nResponses] -export type GetUserResponses = { +export type InterruptJobData = { + body?: never + path?: never + query?: never + url: '/api/interrupt' +} + +export type InterruptJobErrors = { /** - * Success + * Unauthorized - Authentication required */ - 200: UserResponse + 401: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetUserResponse = GetUserResponses[keyof GetUserResponses] +export type InterruptJobError = InterruptJobErrors[keyof InterruptJobErrors] -export type SetReviewStatusData = { - body: SetReviewStatusRequest - path?: never +export type InterruptJobResponses = { + /** + * Success - first active job cancelled, or no active job found + */ + 200: unknown +} + +export type AcceptWorkspaceInviteData = { + body?: never + path: { + /** + * Invite token + */ + token: string + } query?: never - url: '/admin/api/hub/workflows/status' + url: '/api/invites/{token}/accept' } -export type SetReviewStatusErrors = { - /** - * Bad request - invalid status value or empty share_ids - */ - 400: ErrorResponse +export type AcceptWorkspaceInviteErrors = { /** - * Unauthorized - authentication required + * Unauthorized */ 401: ErrorResponse /** - * Forbidden - insufficient permissions + * Email does not match invite */ 403: ErrorResponse /** - * Internal server error + * Invite not found or expired + */ + 404: ErrorResponse + /** + * Already a member of this workspace + */ + 409: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse +} + +export type AcceptWorkspaceInviteError = + AcceptWorkspaceInviteErrors[keyof AcceptWorkspaceInviteErrors] + +export type AcceptWorkspaceInviteResponses = { + /** + * Invite accepted, user is now a member + */ + 200: AcceptInviteResponse +} + +export type AcceptWorkspaceInviteResponse = + AcceptWorkspaceInviteResponses[keyof AcceptWorkspaceInviteResponses] + +export type GetLegacyJobByIdData = { + body?: never + path: { + job_id: string + } + query?: never + url: '/api/job/{job_id}' +} + +export type GetLegacyJobByIdErrors = { + /** + * Not Found — use /api/jobs/{job_id} instead */ - 500: ErrorResponse + 404: unknown } -export type SetReviewStatusError = - SetReviewStatusErrors[keyof SetReviewStatusErrors] +export type GetLegacyJobOutputsData = { + body?: never + path: { + job_id: string + } + query?: never + url: '/api/job/{job_id}/outputs' +} -export type SetReviewStatusResponses = { +export type GetLegacyJobOutputsErrors = { /** - * Status updated successfully + * Not Found — use /api/jobs/{job_id} instead */ - 200: SetReviewStatusResponse + 404: unknown } -export type SetReviewStatusResponse2 = - SetReviewStatusResponses[keyof SetReviewStatusResponses] - -export type AdminDeleteHubWorkflowData = { +export type GetJobStatusData = { body?: never path: { /** - * The share ID of the hub workflow to delete. + * The unique ID of the job */ - share_id: string + job_id: string } query?: never - url: '/admin/api/hub/workflows/{share_id}' + url: '/api/job/{job_id}/status' } -export type AdminDeleteHubWorkflowErrors = { +export type GetJobStatusErrors = { /** - * Unauthorized - authentication required + * Unauthorized */ 401: ErrorResponse /** - * Forbidden - insufficient permissions + * Forbidden - job belongs to another user */ 403: ErrorResponse /** - * Not found - no published workflow for the given share_id + * Job not found */ 404: ErrorResponse - /** - * Conflict - the workflow is not rejected and cannot be deleted - */ - 409: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type AdminDeleteHubWorkflowError = - AdminDeleteHubWorkflowErrors[keyof AdminDeleteHubWorkflowErrors] +export type GetJobStatusError = GetJobStatusErrors[keyof GetJobStatusErrors] -export type AdminDeleteHubWorkflowResponses = { +export type GetJobStatusResponses = { /** - * Successfully deleted + * Success - Job status returned */ - 204: void + 200: JobStatusResponse } -export type AdminDeleteHubWorkflowResponse = - AdminDeleteHubWorkflowResponses[keyof AdminDeleteHubWorkflowResponses] +export type GetJobStatusResponse = + GetJobStatusResponses[keyof GetJobStatusResponses] -export type UpdateHubWorkflowData = { - body: UpdateHubWorkflowRequest - path: { +export type ListJobsData = { + body?: never + path?: never + query?: { + /** + * Filter by one or more statuses (comma-separated). If not provided, returns all jobs. + */ + status?: string /** - * The share ID of the hub workflow to update. + * Filter by workflow ID (exact match) */ - share_id: string + workflow_id?: string + /** + * Filter by output media type (only applies to completed jobs with outputs) + */ + output_type?: 'image' | 'video' | 'audio' | '3d' + /** + * Field to sort by (create_time = when job was submitted, execution_time = how long workflow took to run) + */ + sort_by?: 'create_time' | 'execution_time' + /** + * Sort direction (asc = ascending, desc = descending) + */ + sort_order?: 'asc' | 'desc' + /** + * Opaque cursor for keyset pagination. Pass the `next_cursor` value + * from a previous response to fetch the next page. + * Cursor pagination is supported only when `sort_by=create_time` + * (default). If `sort_by=execution_time`, `after` is ignored and + * offset/limit pagination is used. + * Cursors are opaque base64url payloads — clients should treat them + * as strings and not parse the contents. + * + */ + after?: string + /** + * Pagination offset (0-based). Deprecated: prefer cursor-based pagination via `after`. + * + * @deprecated + */ + offset?: number + /** + * Maximum items per page (1-1000) + */ + limit?: number } - query?: never - url: '/admin/api/hub/workflows/{share_id}' + url: '/api/jobs' } -export type UpdateHubWorkflowErrors = { +export type ListJobsErrors = { /** - * Bad request - invalid field, unknown label slug, or invalid media token + * Bad request (e.g. malformed pagination cursor). */ 400: ErrorResponse /** - * Unauthorized - authentication required + * Unauthorized - Authentication required */ 401: ErrorResponse - /** - * Forbidden - insufficient permissions - */ - 403: ErrorResponse - /** - * Not found - no published workflow for the given share_id - */ - 404: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type UpdateHubWorkflowError = - UpdateHubWorkflowErrors[keyof UpdateHubWorkflowErrors] +export type ListJobsError = ListJobsErrors[keyof ListJobsErrors] -export type UpdateHubWorkflowResponses = { +export type ListJobsResponses = { /** - * Updated hub workflow detail + * Success - Jobs retrieved */ - 200: HubWorkflowDetail + 200: JobsListResponse } -export type UpdateHubWorkflowResponse = - UpdateHubWorkflowResponses[keyof UpdateHubWorkflowResponses] +export type ListJobsResponse = ListJobsResponses[keyof ListJobsResponses] -export type GetDeletionRequestData = { +export type GetJobDetailData = { body?: never - path?: never - query: { + path: { + /** + * Job identifier (UUID) + */ + job_id: string + } + query?: { /** - * The Firebase ID of the user + * When present, each output item in the response receives a `short_url` field containing a short link for that asset. Omit this parameter (the default) to receive a response identical to the no-param baseline. The value selects the link's lifetime and auth model: use `ephemeral_tool_chain` for short-lived (≤5 minute) machine-to-machine handoffs — these are public bearer links where the link ID itself is the credential, so anyone holding the link can resolve it (intended for pasting into an agent/MCP tool chain); use `default` for durable (30 day) human-revisitable links, which are owner-gated and resolvable only by the authenticated owner. Links are always minted under the authenticated request owner's identity; the auth model is selected by the server and is never settable by the caller. + * */ - firebase_id: string + short_link?: 'ephemeral_tool_chain' | 'default' } - url: '/admin/api/deletion_requests' + url: '/api/jobs/{job_id}' } -export type GetDeletionRequestErrors = { - /** - * Bad request - invalid request body - */ - 400: ErrorResponse +export type GetJobDetailErrors = { /** - * Unauthorized - authentication required + * Unauthorized - Authentication required */ 401: ErrorResponse /** - * Forbidden - insufficient permissions + * Forbidden - Job does not belong to user */ 403: ErrorResponse /** - * Deletion request not found + * Job not found */ 404: ErrorResponse /** @@ -8153,755 +6470,828 @@ export type GetDeletionRequestErrors = { 500: ErrorResponse } -export type GetDeletionRequestError = - GetDeletionRequestErrors[keyof GetDeletionRequestErrors] +export type GetJobDetailError = GetJobDetailErrors[keyof GetJobDetailErrors] -export type GetDeletionRequestResponses = { +export type GetJobDetailResponses = { /** - * Success - deletion request found + * Success - Job details retrieved */ - 200: Array + 200: JobDetailResponse } -export type GetDeletionRequestResponse = - GetDeletionRequestResponses[keyof GetDeletionRequestResponses] +export type GetJobDetailResponse = + GetJobDetailResponses[keyof GetJobDetailResponses] -export type CreateDeletionRequestData = { - body: { +export type CancelJobData = { + body?: never + path: { /** - * The Firebase ID of the user to delete + * Job identifier (UUID) */ - firebase_id: string + job_id: string } - path?: never query?: never - url: '/admin/api/deletion_requests' + url: '/api/jobs/{job_id}/cancel' } -export type CreateDeletionRequestErrors = { +export type CancelJobErrors = { /** - * Bad request - invalid request body + * Bad Request - job_id is not a valid UUID (emitted by request validation before the handler runs) */ 400: ErrorResponse /** - * Unauthorized - authentication required + * Unauthorized - Authentication required */ 401: ErrorResponse /** - * Forbidden - insufficient permissions + * Job not found for this user */ - 403: ErrorResponse + 404: ErrorResponse /** - * Internal server error + * Internal server error - cancellation failed */ 500: ErrorResponse } -export type CreateDeletionRequestError = - CreateDeletionRequestErrors[keyof CreateDeletionRequestErrors] +export type CancelJobError = CancelJobErrors[keyof CancelJobErrors] -export type CreateDeletionRequestResponses = { +export type CancelJobResponses = { /** - * Created - deletion request created or already exists + * Success - Cancel request accepted (or job was already terminal) */ - 201: { - /** - * Whether the user had a record in the cloud database - */ - user_found_in_cloud: boolean - } + 200: JobCancelResponse } -export type CreateDeletionRequestResponse = - CreateDeletionRequestResponses[keyof CreateDeletionRequestResponses] +export type CancelJobResponse = CancelJobResponses[keyof CancelJobResponses] -export type ReleaseDeletionHoldData = { - body: { - /** - * The Firebase ID of the user whose hold to release - */ - firebase_id: string - } +export type CancelJobsData = { + body: JobsCancelRequest path?: never query?: never - url: '/admin/api/deletion_requests/release_hold' + url: '/api/jobs/cancel' } -export type ReleaseDeletionHoldErrors = { +export type CancelJobsErrors = { /** - * Bad request - invalid request body + * Bad Request - job_ids is missing, empty, exceeds the maximum count, or contains an invalid UUID */ 400: ErrorResponse /** - * Unauthorized - authentication required + * Unauthorized - Authentication required */ 401: ErrorResponse /** - * Forbidden - insufficient permissions - */ - 403: ErrorResponse - /** - * No deletion request for this user + * One or more job IDs not found for this user (no jobs cancelled) */ 404: ErrorResponse /** - * Internal server error + * Internal server error - cancellation failed */ 500: ErrorResponse } -export type ReleaseDeletionHoldError = - ReleaseDeletionHoldErrors[keyof ReleaseDeletionHoldErrors] +export type CancelJobsError = CancelJobsErrors[keyof CancelJobsErrors] -export type ReleaseDeletionHoldResponses = { +export type CancelJobsResponses = { /** - * Release authorized; the deletion workflow will proceed + * Success - cancel requests dispatched (or jobs were already terminal) */ - 200: ReleaseHoldResponse + 200: JobsCancelResponse } -export type ReleaseDeletionHoldResponse = - ReleaseDeletionHoldResponses[keyof ReleaseDeletionHoldResponses] +export type CancelJobsResponse = CancelJobsResponses[keyof CancelJobsResponses] -export type ReportPartnerUsageData = { - body: PartnerUsageRequest +export type GetLegacyModelsData = { + body?: never path?: never query?: never - url: '/admin/api/partner-usage' + url: '/api/models' } -export type ReportPartnerUsageErrors = { +export type GetLegacyModelsErrors = { /** - * Workspace not found + * Not Found — use /api/experiment/models instead */ - 404: ErrorResponse + 404: unknown +} + +export type GetLegacyModelsByFolderData = { + body?: never + path: { + folder: string + } + query?: never + url: '/api/models/{folder}' +} + +export type GetLegacyModelsByFolderErrors = { /** - * Validation error - missing or empty required fields + * Not Found — use /api/experiment/models/{folder} instead */ - 422: ErrorResponse + 404: unknown +} + +export type GetNodeReplacementsData = { + body?: never + path?: never + query?: never + url: '/api/node_replacements' +} + +export type GetNodeReplacementsErrors = { /** * Internal server error */ 500: ErrorResponse } -export type ReportPartnerUsageError = - ReportPartnerUsageErrors[keyof ReportPartnerUsageErrors] +export type GetNodeReplacementsError = + GetNodeReplacementsErrors[keyof GetNodeReplacementsErrors] + +export type GetNodeReplacementsResponses = { + /** + * Success - Node replacement mappings + */ + 200: { + [key: string]: unknown + } +} + +export type GetNodeReplacementsResponse = + GetNodeReplacementsResponses[keyof GetNodeReplacementsResponses] + +export type GetNodeInfoData = { + body?: never + path?: never + query?: never + url: '/api/object_info' +} + +export type GetNodeInfoResponses = { + /** + * Success + */ + 200: { + [key: string]: NodeInfo + } +} + +export type GetNodeInfoResponse = + GetNodeInfoResponses[keyof GetNodeInfoResponses] + +export type GetLegacyObjectInfoByNodeClassData = { + body?: never + path: { + node_class: string + } + query?: never + url: '/api/object_info/{node_class}' +} -export type ReportPartnerUsageResponses = { +export type GetLegacyObjectInfoByNodeClassErrors = { /** - * Usage reported successfully + * Not Found — use /api/object_info instead */ - 200: PartnerUsageResponse + 404: unknown } -export type ReportPartnerUsageResponse = - ReportPartnerUsageResponses[keyof ReportPartnerUsageResponses] - -export type GetHistoryEventsData = { +export type GetPromptInfoData = { body?: never path?: never - query?: { - /** - * Target workspace. One of workspace_id or user_id is required; workspace_id wins when both are supplied. - */ - workspace_id?: string - /** - * Resolve the caller's personal workspace via converged identity when workspace_id is not given. One of workspace_id or user_id is required. - */ - user_id?: string - /** - * Optional exact event_type filter. - */ - event_type?: string - /** - * Inclusive lower bound on created_at (RFC3339). - */ - start_date?: string - /** - * Inclusive upper bound on created_at (RFC3339). - */ - end_date?: string - /** - * 1-indexed page number (defaults to 1). - */ - page?: number - /** - * Items per page (defaults to 10). - */ - limit?: number - } - url: '/admin/api/history-events' + query?: never + url: '/api/prompt' } -export type GetHistoryEventsErrors = { - /** - * Workspace not found - */ - 404: ErrorResponse +export type GetPromptInfoErrors = { /** - * Validation error - neither workspace_id nor user_id given, or a malformed date + * Unauthorized */ - 422: ErrorResponse + 401: ErrorResponse /** - * Internal error resolving the workspace or querying events + * Internal server error */ 500: ErrorResponse - /** - * Billing is disabled; the caller should fall back to legacy audit_logs - */ - 503: ErrorResponse } -export type GetHistoryEventsError = - GetHistoryEventsErrors[keyof GetHistoryEventsErrors] +export type GetPromptInfoError = GetPromptInfoErrors[keyof GetPromptInfoErrors] -export type GetHistoryEventsResponses = { +export type GetPromptInfoResponses = { /** - * Paginated cloud history events for the workspace + * Success */ - 200: BillingEventsResponse + 200: PromptInfo } -export type GetHistoryEventsResponse = - GetHistoryEventsResponses[keyof GetHistoryEventsResponses] +export type GetPromptInfoResponse = + GetPromptInfoResponses[keyof GetPromptInfoResponses] -export type ReportHistoryEventData = { - body: HistoryEventRequest +export type ExecutePromptData = { + body: PromptRequest path?: never query?: never - url: '/admin/api/history-event' + url: '/api/prompt' } -export type ReportHistoryEventErrors = { +export type ExecutePromptErrors = { /** - * Workspace not found + * Invalid prompt */ - 404: ErrorResponse + 400: PromptErrorResponse /** - * Validation error - missing or empty required fields + * Payment required - Insufficient credits */ - 422: ErrorResponse + 402: PromptErrorResponse + /** + * Workflow JSON too large + */ + 413: PromptErrorResponse + /** + * Payment required - User has not paid + */ + 429: PromptErrorResponse /** * Internal server error */ - 500: ErrorResponse + 500: PromptErrorResponse + /** + * Service unavailable + */ + 503: PromptErrorResponse } -export type ReportHistoryEventError = - ReportHistoryEventErrors[keyof ReportHistoryEventErrors] +export type ExecutePromptError = ExecutePromptErrors[keyof ExecutePromptErrors] -export type ReportHistoryEventResponses = { +export type ExecutePromptResponses = { /** - * History event recorded successfully + * Success - Prompt accepted */ - 200: PartnerUsageResponse + 200: PromptResponse } -export type ReportHistoryEventResponse = - ReportHistoryEventResponses[keyof ReportHistoryEventResponses] +export type ExecutePromptResponse = + ExecutePromptResponses[keyof ExecutePromptResponses] -export type UpdateSubscriptionCacheData = { - body: { - /** - * Firebase UID of the user whose cache should be updated. - */ - user_id: string - /** - * Whether the user currently has an active personal subscription. - * When false, any cached entry is cleared. - * - */ - is_active: boolean - /** - * Subscription tier (e.g. `PRO`, `CREATOR`). Required when - * `is_active=true`; ignored otherwise. Unknown values are treated as a - * no-op rather than cached, so a schema drift between services cannot - * poison the cache. - * - */ - tier?: string +export type GetLegacyPromptByIdData = { + body?: never + path: { + prompt_id: string } - path?: never query?: never - url: '/admin/api/update-subscription-cache' -} - -export type UpdateSubscriptionCacheErrors = { - /** - * Missing or invalid request body - */ - 400: ErrorResponse - /** - * Cache write failed (Redis unavailable, DEL/SET error, marshal error). - * Caller should retry — state on the ingest side is unchanged. - * - */ - 500: ErrorResponse + url: '/api/prompt/{prompt_id}' } -export type UpdateSubscriptionCacheError = - UpdateSubscriptionCacheErrors[keyof UpdateSubscriptionCacheErrors] - -export type UpdateSubscriptionCacheResponses = { +export type GetLegacyPromptByIdErrors = { /** - * Cache updated successfully + * Not Found — use /api/jobs/{prompt_id} instead */ - 200: { - /** - * One of `updated` (cache entry written), `cleared` (cache entry - * removed), or `skipped` (defensive no-op for missing / unknown tier). - * - */ - status?: string - } + 404: unknown } -export type UpdateSubscriptionCacheResponse = - UpdateSubscriptionCacheResponses[keyof UpdateSubscriptionCacheResponses] - -export type ListLinkedFirebaseUidsData = { - body: ListLinkedFirebaseUidsRequest +export type GetQueueInfoData = { + body?: never path?: never query?: never - url: '/admin/api/identity/linked-uids' + url: '/api/queue' } -export type ListLinkedFirebaseUidsErrors = { +export type GetQueueInfoErrors = { /** - * Malformed request or missing comfy_user_id + * Invalid request parameters */ 400: ErrorResponse /** - * Missing or invalid admin secret + * Unauthorized - Authentication required */ 401: ErrorResponse /** - * Internal error + * Invalid request parameters */ 500: ErrorResponse } -export type ListLinkedFirebaseUidsError = - ListLinkedFirebaseUidsErrors[keyof ListLinkedFirebaseUidsErrors] +export type GetQueueInfoError = GetQueueInfoErrors[keyof GetQueueInfoErrors] -export type ListLinkedFirebaseUidsResponses = { +export type GetQueueInfoResponses = { /** - * Linked Firebase UIDs (possibly empty list) + * Success */ - 200: ListLinkedFirebaseUidsResponse + 200: QueueInfo } -export type ListLinkedFirebaseUidsResponse2 = - ListLinkedFirebaseUidsResponses[keyof ListLinkedFirebaseUidsResponses] +export type GetQueueInfoResponse = + GetQueueInfoResponses[keyof GetQueueInfoResponses] -export type EnsureWorkspaceBillingProvisionedData = { - body: EnsureWorkspaceBillingProvisionedRequest +export type ManageQueueData = { + body: QueueManageRequest path?: never query?: never - url: '/admin/api/workspace/ensure-billing-provisioned' + url: '/api/queue' } -export type EnsureWorkspaceBillingProvisionedErrors = { +export type ManageQueueErrors = { /** - * Malformed request or missing user_id + * Invalid request parameters */ 400: ErrorResponse /** - * Missing or invalid admin secret + * Unauthorized */ 401: ErrorResponse /** - * Internal error + * Internal server error */ 500: ErrorResponse } -export type EnsureWorkspaceBillingProvisionedError = - EnsureWorkspaceBillingProvisionedErrors[keyof EnsureWorkspaceBillingProvisionedErrors] +export type ManageQueueError = ManageQueueErrors[keyof ManageQueueErrors] -export type EnsureWorkspaceBillingProvisionedResponses = { +export type ManageQueueResponses = { /** - * The workspace's provisioned billing identity + * Success */ - 200: EnsureWorkspaceBillingProvisionedResponse + 200: QueueManageResponse } -export type EnsureWorkspaceBillingProvisionedResponse2 = - EnsureWorkspaceBillingProvisionedResponses[keyof EnsureWorkspaceBillingProvisionedResponses] +export type ManageQueueResponse = + ManageQueueResponses[keyof ManageQueueResponses] -export type InsertDynamicConfigData = { - /** - * A valid dynamicconfig.Config JSON object. - */ - body: { - [key: string]: unknown - } +export type ListSecretsData = { + body?: never path?: never query?: never - url: '/admin/api/dynamic-config' + url: '/api/secrets' } -export type InsertDynamicConfigErrors = { +export type ListSecretsErrors = { /** - * Invalid or missing request body + * Unauthorized */ - 400: ErrorResponse + 401: ErrorResponse /** - * Database insert failed + * Internal server error */ 500: ErrorResponse + /** + * Service unavailable - feature is disabled + */ + 503: ErrorResponse } -export type InsertDynamicConfigError = - InsertDynamicConfigErrors[keyof InsertDynamicConfigErrors] +export type ListSecretsError = ListSecretsErrors[keyof ListSecretsErrors] -export type InsertDynamicConfigResponses = { +export type ListSecretsResponses = { /** - * Config inserted successfully + * Success */ - 201: { - /** - * The database ID of the newly inserted config row. - */ - id?: number - /** - * Human-readable success message. - */ - message?: string - } + 200: SecretListResponse } -export type InsertDynamicConfigResponse = - InsertDynamicConfigResponses[keyof InsertDynamicConfigResponses] +export type ListSecretsResponse = + ListSecretsResponses[keyof ListSecretsResponses] -export type SyncApiKeyData = { - body: SyncApiKeyRequest +export type CreateSecretData = { + body: CreateSecretRequest path?: never query?: never - url: '/admin/api/keys/sync' + url: '/api/secrets' } -export type SyncApiKeyErrors = { +export type CreateSecretErrors = { /** - * Malformed request or unsupported event + * Invalid request */ 400: ErrorResponse /** - * Missing or invalid admin secret + * Unauthorized */ 401: ErrorResponse /** - * Internal error + * Forbidden - workspace is not entitled to configure a secret for this provider + */ + 403: ErrorResponse + /** + * Conflict - secret with this name or provider already exists + */ + 409: ErrorResponse + /** + * Validation error + */ + 422: ErrorResponse + /** + * Internal server error */ 500: ErrorResponse + /** + * Service unavailable - secrets feature disabled + */ + 503: ErrorResponse } -export type SyncApiKeyError = SyncApiKeyErrors[keyof SyncApiKeyErrors] +export type CreateSecretError = CreateSecretErrors[keyof CreateSecretErrors] -export type SyncApiKeyResponses = { +export type CreateSecretResponses = { /** - * Sync processed — see `result` field + * Secret created successfully */ - 200: SyncApiKeyResponse + 201: SecretResponse } -export type SyncApiKeyResponse2 = SyncApiKeyResponses[keyof SyncApiKeyResponses] +export type CreateSecretResponse = + CreateSecretResponses[keyof CreateSecretResponses] -export type GetJobStatusData = { +export type DeleteSecretData = { body?: never path: { /** - * The unique ID of the job + * The UUID of the secret */ - job_id: string + id: string } query?: never - url: '/api/job/{job_id}/status' + url: '/api/secrets/{id}' } -export type GetJobStatusErrors = { +export type DeleteSecretErrors = { /** * Unauthorized */ 401: ErrorResponse /** - * Forbidden - job belongs to another user + * Forbidden - user does not own this secret */ 403: ErrorResponse /** - * Job not found + * Secret not found */ 404: ErrorResponse /** * Internal server error */ 500: ErrorResponse + /** + * Service unavailable - secrets feature disabled + */ + 503: ErrorResponse } -export type GetJobStatusError = GetJobStatusErrors[keyof GetJobStatusErrors] +export type DeleteSecretError = DeleteSecretErrors[keyof DeleteSecretErrors] -export type GetJobStatusResponses = { +export type DeleteSecretResponses = { /** - * Success - Job status returned + * Secret deleted successfully */ - 200: JobStatusResponse + 204: void } -export type GetJobStatusResponse = - GetJobStatusResponses[keyof GetJobStatusResponses] +export type DeleteSecretResponse = + DeleteSecretResponses[keyof DeleteSecretResponses] -export type ListTasksData = { +export type GetSecretData = { body?: never - path?: never - query?: { - /** - * Filter by task type name (exact match) - */ - task_name?: string - /** - * Filter by idempotency key (exact match). For best performance, specify task_name as well. - */ - idempotency_key?: string - /** - * Filter by one or more statuses (comma-separated) - */ - status?: string - /** - * Filter tasks created after this timestamp (RFC3339 format) - */ - created_after?: string - /** - * Filter tasks created before this timestamp (RFC3339 format) - */ - created_before?: string - /** - * Sort direction (asc = ascending, desc = descending by create_time) - */ - sort_order?: 'asc' | 'desc' - /** - * Pagination offset (0-based) - */ - offset?: number + path: { /** - * Maximum items per page (1-100) + * The UUID of the secret */ - limit?: number + id: string } - url: '/api/tasks' + query?: never + url: '/api/secrets/{id}' } -export type ListTasksErrors = { +export type GetSecretErrors = { /** - * Unauthorized - Authentication required + * Unauthorized */ 401: ErrorResponse /** - * Validation error - Invalid filter values + * Forbidden - user does not own this secret */ - 422: ErrorResponse + 403: ErrorResponse + /** + * Secret not found + */ + 404: ErrorResponse /** * Internal server error */ 500: ErrorResponse + /** + * Service unavailable - secrets feature disabled + */ + 503: ErrorResponse } -export type ListTasksError = ListTasksErrors[keyof ListTasksErrors] +export type GetSecretError = GetSecretErrors[keyof GetSecretErrors] -export type ListTasksResponses = { +export type GetSecretResponses = { /** - * Success - Tasks retrieved + * Success */ - 200: TasksListResponse + 200: SecretResponse } -export type ListTasksResponse = ListTasksResponses[keyof ListTasksResponses] +export type GetSecretResponse = GetSecretResponses[keyof GetSecretResponses] -export type GetTaskData = { - body?: never +export type UpdateSecretData = { + body: UpdateSecretRequest path: { /** - * Task identifier (UUID) + * The UUID of the secret */ - task_id: string + id: string } query?: never - url: '/api/tasks/{task_id}' + url: '/api/secrets/{id}' } -export type GetTaskErrors = { +export type UpdateSecretErrors = { /** - * Unauthorized - Authentication required + * Invalid request + */ + 400: ErrorResponse + /** + * Unauthorized */ 401: ErrorResponse /** - * Task not found (also returned for ownership failures to avoid leaking task existence) + * Forbidden - user does not own this secret + */ + 403: ErrorResponse + /** + * Secret not found */ 404: ErrorResponse + /** + * Conflict - a secret with this name already exists + */ + 409: ErrorResponse /** * Internal server error */ 500: ErrorResponse + /** + * Service unavailable - secrets feature disabled + */ + 503: ErrorResponse } -export type GetTaskError = GetTaskErrors[keyof GetTaskErrors] +export type UpdateSecretError = UpdateSecretErrors[keyof UpdateSecretErrors] -export type GetTaskResponses = { +export type UpdateSecretResponses = { /** - * Success - Task details retrieved + * Secret updated successfully */ - 200: TaskResponse + 200: SecretResponse } -export type GetTaskResponse = GetTaskResponses[keyof GetTaskResponses] +export type UpdateSecretResponse = + UpdateSecretResponses[keyof UpdateSecretResponses] -export type GetBillingStatusData = { +export type ListSecretProvidersData = { body?: never path?: never query?: never - url: '/api/billing/status' + url: '/api/secrets/providers' } -export type GetBillingStatusErrors = { +export type ListSecretProvidersErrors = { /** * Unauthorized */ 401: ErrorResponse /** - * Workspace not found - */ - 404: ErrorResponse - /** - * Internal server error + * Service unavailable - secrets feature disabled */ - 500: ErrorResponse + 503: ErrorResponse } -export type GetBillingStatusError = - GetBillingStatusErrors[keyof GetBillingStatusErrors] +export type ListSecretProvidersError = + ListSecretProvidersErrors[keyof ListSecretProvidersErrors] -export type GetBillingStatusResponses = { +export type ListSecretProvidersResponses = { /** - * Billing status + * Success */ - 200: BillingStatusResponse + 200: SecretProvidersResponse } -export type GetBillingStatusResponse = - GetBillingStatusResponses[keyof GetBillingStatusResponses] +export type ListSecretProvidersResponse = + ListSecretProvidersResponses[keyof ListSecretProvidersResponses] -export type GetBillingBalanceData = { +export type GetAllSettingsData = { body?: never path?: never query?: never - url: '/api/billing/balance' + url: '/api/settings' } -export type GetBillingBalanceErrors = { +export type GetAllSettingsErrors = { /** * Unauthorized */ 401: ErrorResponse +} + +export type GetAllSettingsError = + GetAllSettingsErrors[keyof GetAllSettingsErrors] + +export type GetAllSettingsResponses = { /** - * Internal server error + * User settings as key-value pairs */ - 500: ErrorResponse + 200: { + [key: string]: unknown + } } -export type GetBillingBalanceError = - GetBillingBalanceErrors[keyof GetBillingBalanceErrors] +export type GetAllSettingsResponse = + GetAllSettingsResponses[keyof GetAllSettingsResponses] -export type GetBillingBalanceResponses = { +export type UpdateMultipleSettingsData = { /** - * Credit balance + * Settings to update as key-value pairs */ - 200: BillingBalanceResponse + body: { + [key: string]: unknown + } + path?: never + query?: never + url: '/api/settings' } -export type GetBillingBalanceResponse = - GetBillingBalanceResponses[keyof GetBillingBalanceResponses] +export type UpdateMultipleSettingsErrors = { + /** + * Invalid request + */ + 400: ErrorResponse + /** + * Unauthorized + */ + 401: ErrorResponse +} -export type GetBillingEventsData = { +export type UpdateMultipleSettingsError = + UpdateMultipleSettingsErrors[keyof UpdateMultipleSettingsErrors] + +export type UpdateMultipleSettingsResponses = { + /** + * Updated user settings + */ + 200: { + [key: string]: unknown + } +} + +export type UpdateMultipleSettingsResponse = + UpdateMultipleSettingsResponses[keyof UpdateMultipleSettingsResponses] + +export type GetSettingByIdData = { body?: never - path?: never - query?: { - /** - * Page number (1-indexed) - */ - page?: number + path: { /** - * Number of events per page + * Setting id to retrieve */ - limit?: number + id: string } - url: '/api/billing/events' + query?: never + url: '/api/settings/{id}' } -export type GetBillingEventsErrors = { +export type GetSettingByIdErrors = { /** * Unauthorized */ 401: ErrorResponse /** - * Internal server error + * Setting not found */ - 500: ErrorResponse + 404: ErrorResponse } -export type GetBillingEventsError = - GetBillingEventsErrors[keyof GetBillingEventsErrors] +export type GetSettingByIdError = + GetSettingByIdErrors[keyof GetSettingByIdErrors] -export type GetBillingEventsResponses = { +export type GetSettingByIdResponses = { /** - * Paginated billing events + * Setting value response */ - 200: BillingEventsResponse + 200: { + /** + * The setting value + */ + value?: unknown + } } -export type GetBillingEventsResponse = - GetBillingEventsResponses[keyof GetBillingEventsResponses] +export type GetSettingByIdResponse = + GetSettingByIdResponses[keyof GetSettingByIdResponses] -export type GetBillingPlansData = { - body?: never - path?: never +export type UpdateSettingByIdData = { + /** + * New value for the setting + */ + body: unknown + path: { + /** + * Setting id to update + */ + id: string + } query?: never - url: '/api/billing/plans' + url: '/api/settings/{id}' } -export type GetBillingPlansErrors = { +export type UpdateSettingByIdErrors = { + /** + * Invalid request + */ + 400: ErrorResponse /** * Unauthorized */ 401: ErrorResponse +} + +export type UpdateSettingByIdError = + UpdateSettingByIdErrors[keyof UpdateSettingByIdErrors] + +export type UpdateSettingByIdResponses = { /** - * Internal server error + * Updated setting value response + */ + 200: { + /** + * The updated setting value + */ + value?: unknown + } +} + +export type UpdateSettingByIdResponse = + UpdateSettingByIdResponses[keyof UpdateSettingByIdResponses] + +export type GetSystemStatsData = { + body?: never + path?: never + query?: never + url: '/api/system_stats' +} + +export type GetSystemStatsErrors = { + /** + * Unauthorized */ - 500: ErrorResponse + 401: ErrorResponse } -export type GetBillingPlansError = - GetBillingPlansErrors[keyof GetBillingPlansErrors] +export type GetSystemStatsError = + GetSystemStatsErrors[keyof GetSystemStatsErrors] -export type GetBillingPlansResponses = { +export type GetSystemStatsResponses = { /** - * Available plans with pricing + * Success */ - 200: BillingPlansResponse + 200: SystemStatsResponse } -export type GetBillingPlansResponse = - GetBillingPlansResponses[keyof GetBillingPlansResponses] +export type GetSystemStatsResponse = + GetSystemStatsResponses[keyof GetSystemStatsResponses] -export type PreviewSubscribeData = { - body: PreviewSubscribeRequest +export type ListTagsData = { + body?: never path?: never - query?: never - url: '/api/billing/preview-subscribe' + query?: { + /** + * Filter tags by prefix + */ + prefix?: string + /** + * Maximum number of tags to return (1-1000) + */ + limit?: number + /** + * Number of tags to skip for pagination + */ + offset?: number + /** + * Sort order for tags + */ + order?: 'count_desc' | 'name_asc' + /** + * Include tags with zero usage count + */ + include_zero?: boolean + /** + * Whether to include public/shared assets when counting tags + */ + include_public?: boolean + } + url: '/api/tags' } -export type PreviewSubscribeErrors = { +export type ListTagsErrors = { /** - * Invalid request (e.g., invalid plan slug, seats below minimum) + * Invalid request parameters */ 400: ErrorResponse /** @@ -8914,97 +7304,148 @@ export type PreviewSubscribeErrors = { 500: ErrorResponse } -export type PreviewSubscribeError = - PreviewSubscribeErrors[keyof PreviewSubscribeErrors] +export type ListTagsError = ListTagsErrors[keyof ListTagsErrors] -export type PreviewSubscribeResponses = { +export type ListTagsResponses = { /** - * Subscription preview + * Tags retrieved successfully */ - 200: PreviewSubscribeResponse + 200: ListTagsResponse } -export type PreviewSubscribeResponse2 = - PreviewSubscribeResponses[keyof PreviewSubscribeResponses] +export type ListTagsResponse2 = ListTagsResponses[keyof ListTagsResponses] -export type SubscribeData = { - body: SubscribeRequest +export type ListTasksData = { + body?: never path?: never - query?: never - url: '/api/billing/subscribe' + query?: { + /** + * Filter by task type name (exact match) + */ + task_name?: string + /** + * Filter by idempotency key (exact match). For best performance, specify task_name as well. + */ + idempotency_key?: string + /** + * Filter by one or more statuses (comma-separated) + */ + status?: string + /** + * Filter tasks created after this timestamp (RFC3339 format) + */ + created_after?: string + /** + * Filter tasks created before this timestamp (RFC3339 format) + */ + created_before?: string + /** + * Sort direction (asc = ascending, desc = descending by create_time) + */ + sort_order?: 'asc' | 'desc' + /** + * Pagination offset (0-based) + */ + offset?: number + /** + * Maximum items per page (1-100) + */ + limit?: number + } + url: '/api/tasks' } -export type SubscribeErrors = { +export type ListTasksErrors = { /** - * Invalid request (e.g., invalid plan slug, incompatible plan) + * Unauthorized - Authentication required */ - 400: ErrorResponse + 401: ErrorResponse /** - * Unauthorized + * Validation error - Invalid filter values */ - 401: ErrorResponse + 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type SubscribeError = SubscribeErrors[keyof SubscribeErrors] +export type ListTasksError = ListTasksErrors[keyof ListTasksErrors] -export type SubscribeResponses = { +export type ListTasksResponses = { /** - * Subscription created or payment method needed + * Success - Tasks retrieved */ - 200: SubscribeResponse + 200: TasksListResponse } -export type SubscribeResponse2 = SubscribeResponses[keyof SubscribeResponses] +export type ListTasksResponse = ListTasksResponses[keyof ListTasksResponses] -export type CancelSubscriptionData = { - body: CancelSubscriptionRequest - path?: never +export type GetTaskData = { + body?: never + path: { + /** + * Task identifier (UUID) + */ + task_id: string + } query?: never - url: '/api/billing/subscription/cancel' + url: '/api/tasks/{task_id}' } -export type CancelSubscriptionErrors = { +export type GetTaskErrors = { /** - * Invalid request (e.g., no active subscription) + * Unauthorized - Authentication required */ - 400: ErrorResponse + 401: ErrorResponse /** - * Unauthorized + * Task not found (also returned for ownership failures to avoid leaking task existence) */ - 401: ErrorResponse + 404: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type CancelSubscriptionError = - CancelSubscriptionErrors[keyof CancelSubscriptionErrors] +export type GetTaskError = GetTaskErrors[keyof GetTaskErrors] -export type CancelSubscriptionResponses = { +export type GetTaskResponses = { /** - * Subscription cancellation scheduled + * Success - Task details retrieved */ - 200: CancelSubscriptionResponse + 200: TaskResponse } -export type CancelSubscriptionResponse2 = - CancelSubscriptionResponses[keyof CancelSubscriptionResponses] +export type GetTaskResponse = GetTaskResponses[keyof GetTaskResponses] -export type ResubscribeData = { - body: ResubscribeRequest +export type UploadImageData = { + body: { + /** + * The image file to upload + */ + image: Blob | File + /** + * Whether to overwrite existing file (true/false) + */ + overwrite?: string + /** + * Optional subfolder path + */ + subfolder?: string + /** + * Upload type (defaults to "output") + */ + type?: string + } path?: never query?: never - url: '/api/billing/subscription/resubscribe' + url: '/api/upload/image' } -export type ResubscribeErrors = { +export type UploadImageErrors = { /** - * Invalid request (e.g., no active subscription, not in cancellation grace period) + * Bad request */ 400: ErrorResponse /** @@ -9017,28 +7458,50 @@ export type ResubscribeErrors = { 500: ErrorResponse } -export type ResubscribeError = ResubscribeErrors[keyof ResubscribeErrors] +export type UploadImageError = UploadImageErrors[keyof UploadImageErrors] -export type ResubscribeResponses = { +export type UploadImageResponses = { /** - * Subscription resumed successfully + * Image uploaded successfully */ - 200: ResubscribeResponse + 200: { + /** + * Filename of the uploaded image + */ + name?: string + /** + * Subfolder path where image was saved + */ + subfolder?: string + /** + * Type of upload (e.g., "output") + */ + type?: string + } } -export type ResubscribeResponse2 = - ResubscribeResponses[keyof ResubscribeResponses] +export type UploadImageResponse = + UploadImageResponses[keyof UploadImageResponses] -export type GetPaymentPortalData = { - body?: PaymentPortalRequest +export type UploadMaskData = { + body: { + /** + * The mask image file to upload + */ + image: Blob | File + /** + * JSON string containing reference to the original image + */ + original_ref: string + } path?: never query?: never - url: '/api/billing/payment-portal' + url: '/api/upload/mask' } -export type GetPaymentPortalErrors = { +export type UploadMaskErrors = { /** - * Bad request (e.g., missing return_url) + * Bad request */ 400: ErrorResponse /** @@ -9051,273 +7514,321 @@ export type GetPaymentPortalErrors = { 500: ErrorResponse } -export type GetPaymentPortalError = - GetPaymentPortalErrors[keyof GetPaymentPortalErrors] +export type UploadMaskError = UploadMaskErrors[keyof UploadMaskErrors] -export type GetPaymentPortalResponses = { +export type UploadMaskResponses = { /** - * Success + * Mask uploaded successfully */ - 200: PaymentPortalResponse + 200: { + /** + * Filename of the uploaded mask + */ + name?: string + /** + * Subfolder path where mask was saved + */ + subfolder?: string + /** + * Type of upload (e.g., "output") + */ + type?: string + } } -export type GetPaymentPortalResponse = - GetPaymentPortalResponses[keyof GetPaymentPortalResponses] +export type UploadMaskResponse = UploadMaskResponses[keyof UploadMaskResponses] -export type CreateTopupData = { - body: CreateTopupRequest +export type GetUserData = { + body?: never path?: never query?: never - url: '/api/billing/topup' + url: '/api/user' } -export type CreateTopupErrors = { - /** - * Bad request (invalid amount, no payment method) - */ - 400: ErrorResponse +export type GetUserErrors = { /** * Unauthorized */ 401: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse } -export type CreateTopupError = CreateTopupErrors[keyof CreateTopupErrors] +export type GetUserError = GetUserErrors[keyof GetUserErrors] -export type CreateTopupResponses = { +export type GetUserResponses = { /** - * Top-up initiated successfully + * Success */ - 200: CreateTopupResponse + 200: UserResponse } -export type CreateTopupResponse2 = - CreateTopupResponses[keyof CreateTopupResponses] +export type GetUserResponse = GetUserResponses[keyof GetUserResponses] -export type GetBillingOpStatusData = { +export type GetUserdataData = { body?: never - path: { + path?: never + query?: { /** - * The billing operation ID + * The directory to list files from. */ - id: string + dir?: string + /** + * Whether to list files recursively. + */ + recurse?: boolean + /** + * Whether to split file information by type. + */ + split?: boolean + /** + * Whether to return full file metadata. + */ + full_info?: boolean } - query?: never - url: '/api/billing/ops/{id}' + url: '/api/userdata' } -export type GetBillingOpStatusErrors = { +export type GetUserdataErrors = { /** - * Unauthorized + * Bad request (e.g., invalid filename). */ - 401: ErrorResponse + 400: string /** - * Billing operation not found + * Unauthorized. */ - 404: ErrorResponse + 401: string /** - * Internal server error + * File not found or invalid path. */ - 500: ErrorResponse + 404: string + /** + * General error + */ + 500: string } -export type GetBillingOpStatusError = - GetBillingOpStatusErrors[keyof GetBillingOpStatusErrors] +export type GetUserdataError = GetUserdataErrors[keyof GetUserdataErrors] -export type GetBillingOpStatusResponses = { +export type GetUserdataResponses = { /** - * Billing operation status + * A list of user data files. */ - 200: BillingOpStatusResponse + 200: GetUserDataResponseFull } -export type GetBillingOpStatusResponse = - GetBillingOpStatusResponses[keyof GetBillingOpStatusResponses] +export type GetUserdataResponse = + GetUserdataResponses[keyof GetUserdataResponses] -export type ListWorkflowsData = { +export type DeleteUserdataFileData = { body?: never - path?: never - query?: { - limit?: number - offset?: number - /** - * Search workflows by name (case-insensitive substring match) - */ - name?: string - /** - * Filter by default view type - */ - default_view?: 'workflow' | 'app' - /** - * Sort field - */ - sort?: 'create_time' | 'update_time' | 'name' + path: { /** - * Sort order + * The file path to delete (URL encoded if necessary). */ - order?: 'asc' | 'desc' + file: string } - url: '/api/workflows' + query?: never + url: '/api/userdata/{file}' } -export type ListWorkflowsErrors = { +export type DeleteUserdataFileErrors = { /** - * Unauthorized + * Unauthorized. */ - 401: ErrorResponse + 401: string /** - * Internal server error + * File not found. */ - 500: ErrorResponse + 404: string + /** + * Internal server error. + */ + 500: string } -export type ListWorkflowsError = ListWorkflowsErrors[keyof ListWorkflowsErrors] +export type DeleteUserdataFileError = + DeleteUserdataFileErrors[keyof DeleteUserdataFileErrors] -export type ListWorkflowsResponses = { +export type DeleteUserdataFileResponses = { /** - * Success + * File deleted successfully (No Content). */ - 200: WorkflowListResponse + 204: void } -export type ListWorkflowsResponse = - ListWorkflowsResponses[keyof ListWorkflowsResponses] +export type DeleteUserdataFileResponse = + DeleteUserdataFileResponses[keyof DeleteUserdataFileResponses] -export type CreateWorkflowData = { - body: CreateWorkflowRequest - path?: never +export type GetUserdataFileData = { + body?: never + path: { + /** + * The filename of the user data to retrieve. + */ + file: string + } query?: never - url: '/api/workflows' + url: '/api/userdata/{file}' } -export type CreateWorkflowErrors = { +export type GetUserdataFileErrors = { /** - * Unauthorized + * Bad request (e.g., invalid filename). */ - 401: ErrorResponse + 400: string /** - * Validation error + * Unauthorized. */ - 422: ErrorResponse + 401: string /** - * Internal server error + * File not found or invalid path. */ - 500: ErrorResponse + 404: string + /** + * General error + */ + 500: string } -export type CreateWorkflowError = - CreateWorkflowErrors[keyof CreateWorkflowErrors] +export type GetUserdataFileError = + GetUserdataFileErrors[keyof GetUserdataFileErrors] -export type CreateWorkflowResponses = { +export type GetUserdataFileResponses = { /** - * Workflow created successfully + * Successfully retrieved the file. */ - 201: WorkflowResponse + 200: Blob | File } -export type CreateWorkflowResponse = - CreateWorkflowResponses[keyof CreateWorkflowResponses] +export type GetUserdataFileResponse = + GetUserdataFileResponses[keyof GetUserdataFileResponses] -export type DeleteWorkflowData = { - body?: never +export type PostUserdataFileData = { + body: Blob | File path: { /** - * The UUID of the workflow to delete. + * The target file path (URL encoded if necessary). */ - workflow_id: string + file: string } - query?: never - url: '/api/workflows/{workflow_id}' + query?: { + /** + * If "false", prevents overwriting existing files. Defaults to "true". + */ + overwrite?: 'true' | 'false' + /** + * If "true", returns detailed file info; if "false", returns only the relative path. + */ + full_info?: 'true' | 'false' + } + url: '/api/userdata/{file}' } -export type DeleteWorkflowErrors = { +export type PostUserdataFileErrors = { /** - * Unauthorized + * Missing or invalid 'file' parameter. */ - 401: ErrorResponse + 400: string /** - * Workflow not found + * Unauthorized. */ - 404: ErrorResponse + 401: string /** - * Internal server error + * The requested path is not allowed. */ - 500: ErrorResponse + 403: string + /** + * File already exists and overwrite is set to false. + */ + 409: string + /** + * General error + */ + 500: string } -export type DeleteWorkflowError = - DeleteWorkflowErrors[keyof DeleteWorkflowErrors] +export type PostUserdataFileError = + PostUserdataFileErrors[keyof PostUserdataFileErrors] -export type DeleteWorkflowResponses = { +export type PostUserdataFileResponses = { /** - * Workflow deleted successfully + * File uploaded successfully. */ - 204: void + 200: UserDataResponseFull } -export type DeleteWorkflowResponse = - DeleteWorkflowResponses[keyof DeleteWorkflowResponses] +export type PostUserdataFileResponse = + PostUserdataFileResponses[keyof PostUserdataFileResponses] -export type GetWorkflowData = { +export type MoveUserdataFileData = { body?: never path: { /** - * The UUID of the workflow. + * The source file path (URL encoded if necessary). */ - workflow_id: string + file: string + /** + * The destination file path (URL encoded if necessary). + */ + dest: string } - query?: never - url: '/api/workflows/{workflow_id}' + query?: { + /** + * If "false", prevents overwriting existing files. Defaults to "true". + */ + overwrite?: 'true' | 'false' + } + url: '/api/userdata/{file}/move/{dest}' } -export type GetWorkflowErrors = { +export type MoveUserdataFileErrors = { /** - * Unauthorized + * Missing or invalid parameters. */ - 401: ErrorResponse + 400: string /** - * Forbidden + * Unauthorized. */ - 403: ErrorResponse + 401: string /** - * Workflow not found + * Source file not found. */ - 404: ErrorResponse + 404: string /** - * Internal server error + * Destination file already exists and overwrite is set to false. */ - 500: ErrorResponse + 409: string + /** + * General error + */ + 500: string } -export type GetWorkflowError = GetWorkflowErrors[keyof GetWorkflowErrors] +export type MoveUserdataFileError = + MoveUserdataFileErrors[keyof MoveUserdataFileErrors] -export type GetWorkflowResponses = { +export type MoveUserdataFileResponses = { /** - * Success + * File moved successfully. */ - 200: WorkflowResponse + 200: UserDataResponseFull } -export type GetWorkflowResponse = - GetWorkflowResponses[keyof GetWorkflowResponses] +export type MoveUserdataFileResponse = + MoveUserdataFileResponses[keyof MoveUserdataFileResponses] -export type UpdateWorkflowData = { - body: UpdateWorkflowRequest +export type GetUserdataFilePublishData = { + body?: never path: { /** - * The UUID of the workflow to update. + * The workflow file path within the user's data directory (URL encoded if necessary). */ - workflow_id: string + file: string } query?: never - url: '/api/workflows/{workflow_id}' + url: '/api/userdata/{file}/publish' } -export type UpdateWorkflowErrors = { +export type GetUserdataFilePublishErrors = { /** * Unauthorized */ @@ -9326,266 +7837,310 @@ export type UpdateWorkflowErrors = { * Workflow not found */ 404: ErrorResponse - /** - * Validation error - */ - 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type UpdateWorkflowError = - UpdateWorkflowErrors[keyof UpdateWorkflowErrors] +export type GetUserdataFilePublishError = + GetUserdataFilePublishErrors[keyof GetUserdataFilePublishErrors] -export type UpdateWorkflowResponses = { +export type GetUserdataFilePublishResponses = { /** - * Success + * Publish info (publish_time is null if never published) */ - 200: WorkflowResponse + 200: WorkflowPublishInfo } -export type UpdateWorkflowResponse = - UpdateWorkflowResponses[keyof UpdateWorkflowResponses] +export type GetUserdataFilePublishResponse = + GetUserdataFilePublishResponses[keyof GetUserdataFilePublishResponses] -export type CreateWorkflowVersionData = { - body: CreateWorkflowVersionRequest +export type PostUserdataFilePublishData = { + body: PublishWorkflowAssetsRequest path: { /** - * The UUID of the workflow to create a new version for. + * The workflow file path within the user's data directory (URL encoded if necessary). */ - workflow_id: string + file: string } query?: never - url: '/api/workflows/{workflow_id}/versions' + url: '/api/userdata/{file}/publish' } -export type CreateWorkflowVersionErrors = { +export type PostUserdataFilePublishErrors = { /** - * Unauthorized + * Bad request */ - 401: ErrorResponse + 400: ErrorResponse /** - * Forbidden - not the workflow owner + * Unauthorized */ - 403: ErrorResponse + 401: ErrorResponse /** * Workflow not found */ 404: ErrorResponse - /** - * Version conflict - base_version does not match latest - */ - 409: ErrorResponse - /** - * Validation error - */ - 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type CreateWorkflowVersionError = - CreateWorkflowVersionErrors[keyof CreateWorkflowVersionErrors] +export type PostUserdataFilePublishError = + PostUserdataFilePublishErrors[keyof PostUserdataFilePublishErrors] -export type CreateWorkflowVersionResponses = { +export type PostUserdataFilePublishResponses = { /** - * Version created successfully + * Workflow published */ - 201: WorkflowVersionResponse + 200: WorkflowPublishInfo } -export type CreateWorkflowVersionResponse = - CreateWorkflowVersionResponses[keyof CreateWorkflowVersionResponses] +export type PostUserdataFilePublishResponse = + PostUserdataFilePublishResponses[keyof PostUserdataFilePublishResponses] -export type GetWorkflowContentData = { +export type GetUsersInfoData = { body?: never - path: { - /** - * The UUID of the workflow whose content should be retrieved. - */ - workflow_id: string - } + path?: never query?: never - url: '/api/workflows/{workflow_id}/content' + url: '/api/users' } -export type GetWorkflowContentErrors = { +export type GetUsersInfoErrors = { /** * Unauthorized */ 401: ErrorResponse +} + +export type GetUsersInfoError = GetUsersInfoErrors[keyof GetUsersInfoErrors] + +export type GetUsersInfoResponses = { /** - * Forbidden - */ - 403: ErrorResponse - /** - * Workflow not found - */ - 404: ErrorResponse - /** - * Internal server error + * Userdata storage information */ - 500: ErrorResponse + 200: { + /** + * Whether user data has been migrated (always true in cloud) + */ + migrated: boolean + /** + * Where user data is stored (always "server" in cloud) + */ + storage: string + } } -export type GetWorkflowContentError = - GetWorkflowContentErrors[keyof GetWorkflowContentErrors] +export type GetUsersInfoResponse = + GetUsersInfoResponses[keyof GetUsersInfoResponses] -export type GetWorkflowContentResponses = { +export type GetLegacyUserdataV2Data = { + body?: never + path?: never + query?: never + url: '/api/v2/userdata' +} + +export type GetLegacyUserdataV2Errors = { /** - * Success + * Not Found — use /api/userdata instead */ - 200: WorkflowVersionContentResponse + 404: unknown } -export type GetWorkflowContentResponse = - GetWorkflowContentResponses[keyof GetWorkflowContentResponses] - -export type ForkWorkflowData = { - body: ForkWorkflowRequest - path: { +export type GetVhsQueryVideoData = { + body?: never + path?: never + query: { /** - * The UUID of the source workflow to fork from. + * Name of the video file to query */ - workflow_id: string + filename: string } - query?: never - url: '/api/workflows/{workflow_id}/fork' + url: '/api/vhs/queryvideo' } -export type ForkWorkflowErrors = { - /** - * Unauthorized - */ - 401: ErrorResponse - /** - * Forbidden - */ - 403: ErrorResponse - /** - * Source workflow or version not found - */ - 404: ErrorResponse +export type GetVhsQueryVideoErrors = { /** - * Validation error + * Missing required query parameter. Produced by the oapi-codegen + * wrapper via echo.NewHTTPError; the custom Echo HTTPErrorHandler + * normalizes it to the standard ErrorResponse {code, message} shape + * (BE-1178). + * */ - 422: ErrorResponse + 400: ErrorResponse /** - * Internal server error + * Unauthorized */ - 500: ErrorResponse + 401: ErrorResponse } -export type ForkWorkflowError = ForkWorkflowErrors[keyof ForkWorkflowErrors] +export type GetVhsQueryVideoError = + GetVhsQueryVideoErrors[keyof GetVhsQueryVideoErrors] -export type ForkWorkflowResponses = { +export type GetVhsQueryVideoResponses = { /** - * Workflow forked successfully + * Video metadata */ - 201: WorkflowResponse + 200: { + /** + * Source video metadata + */ + source: { + /** + * Duration in seconds + */ + duration: number + /** + * Frames per second + */ + fps: number + /** + * Total frame count + */ + frames: number + /** + * [width, height] in pixels + */ + size: [number, number] + } + } } -export type ForkWorkflowResponse = - ForkWorkflowResponses[keyof ForkWorkflowResponses] +export type GetVhsQueryVideoResponse = + GetVhsQueryVideoResponses[keyof GetVhsQueryVideoResponses] -export type CreateHubProfileData = { - body: CreateHubProfileRequest +export type GetVhsViewAudioData = { + body?: never path?: never - query?: never - url: '/api/hub/profiles' + query: { + /** + * Name of the audio file to view + */ + filename: string + /** + * Type of file (e.g., output, input, temp) + */ + type?: string + /** + * Subfolder path where the file is located + */ + subfolder?: string + } + url: '/api/vhs/viewaudio' } -export type CreateHubProfileErrors = { - /** - * Bad request (e.g. invalid username) - */ - 400: ErrorResponse +export type GetVhsViewAudioErrors = { /** * Unauthorized */ - 401: ErrorResponse - /** - * Not found - */ - 404: ErrorResponse - /** - * Username already taken or profile already exists - */ - 409: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse + 401: unknown } -export type CreateHubProfileError = - CreateHubProfileErrors[keyof CreateHubProfileErrors] - -export type CreateHubProfileResponses = { +export type GetVhsViewAudioResponses = { /** - * Hub profile created + * Audio stream */ - 201: HubProfile + 200: unknown } -export type CreateHubProfileResponse = - CreateHubProfileResponses[keyof CreateHubProfileResponses] - -export type GetMyHubProfileData = { +export type GetVhsViewVideoData = { body?: never path?: never - query?: never - url: '/api/hub/profiles/me' + query: { + /** + * Name of the video file to view + */ + filename: string + /** + * Type of file (e.g., output, input, temp) + */ + type?: string + /** + * Subfolder path where the file is located + */ + subfolder?: string + } + url: '/api/vhs/viewvideo' } -export type GetMyHubProfileErrors = { +export type GetVhsViewVideoErrors = { /** * Unauthorized */ - 401: ErrorResponse - /** - * No hub profile exists - */ - 404: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse + 401: unknown } -export type GetMyHubProfileError = - GetMyHubProfileErrors[keyof GetMyHubProfileErrors] - -export type GetMyHubProfileResponses = { +export type GetVhsViewVideoResponses = { /** - * Hub profile + * Video stream */ - 200: HubProfile + 200: unknown } -export type GetMyHubProfileResponse = - GetMyHubProfileResponses[keyof GetMyHubProfileResponses] - -export type CheckHubUsernameData = { +export type ViewFileData = { body?: never path?: never query: { - username: string + /** + * Name of the file to view + */ + filename: string + /** + * Subfolder path where the file is located + */ + subfolder?: string + /** + * Type of file (e.g., output, input, temp) + */ + type?: string + /** + * Full path to the file (used for temp files) + */ + fullpath?: string + /** + * Format of the file + */ + format?: string + /** + * Frame rate for video files + */ + frame_rate?: number + /** + * Workflow identifier + */ + workflow?: string + /** + * Timestamp parameter + */ + timestamp?: number + /** + * Image channel to extract from PNG images. + * - 'rgb': Return only RGB channels (alpha set to fully opaque) + * - 'a' or 'alpha': Return alpha channel as grayscale image + * - If not specified, return original image unchanged via redirect + * + */ + channel?: string + /** + * Maximum dimension (width or height) to resize the image to, preserving aspect ratio. + * The image is fit within a res x res box. Returns a JPEG thumbnail. + * Only applies to raster image files (PNG, JPEG, WebP, GIF). + * + */ + res?: number } - url: '/api/hub/profiles/check' + url: '/api/view' } -export type CheckHubUsernameErrors = { +export type ViewFileErrors = { /** - * Unauthorized + * Invalid request parameters */ - 401: ErrorResponse + 400: ErrorResponse /** - * Not found + * File not found or unauthorized */ 404: ErrorResponse /** @@ -9594,210 +8149,225 @@ export type CheckHubUsernameErrors = { 500: ErrorResponse } -export type CheckHubUsernameError = - CheckHubUsernameErrors[keyof CheckHubUsernameErrors] +export type ViewFileError = ViewFileErrors[keyof ViewFileErrors] -export type CheckHubUsernameResponses = { +export type ViewFileResponses = { /** - * Username availability result + * Resized JPEG thumbnail (returned when res parameter is used) */ - 200: HubUsernameCheckResponse + 200: Blob | File } -export type CheckHubUsernameResponse = - CheckHubUsernameResponses[keyof CheckHubUsernameResponses] +export type ViewFileResponse = ViewFileResponses[keyof ViewFileResponses] -export type GetHubProfileByUsernameData = { +export type GetLegacyViewMetadataData = { body?: never path: { + folder_name: string + } + query?: never + url: '/api/view_metadata/{folder_name}' +} + +export type GetLegacyViewMetadataErrors = { + /** + * Not Found — use /api/experiment/models instead + */ + 404: unknown +} + +export type GetApiViewVideoAliasData = { + body?: never + path?: never + query: { /** - * The hub profile username. + * Name of the file to view (see `/api/view` for the full handler contract) */ - username: string + filename: string } - query?: never - url: '/api/hub/profiles/{username}' + url: '/api/viewvideo' } -export type GetHubProfileByUsernameErrors = { +export type GetApiViewVideoAliasErrors = { /** - * Profile not found + * Unauthorized */ - 404: ErrorResponse + 401: unknown +} + +export type GetApiViewVideoAliasResponses = { /** - * Internal server error + * File stream */ - 500: ErrorResponse + 200: unknown } -export type GetHubProfileByUsernameError = - GetHubProfileByUsernameErrors[keyof GetHubProfileByUsernameErrors] +export type GetWorkflowTemplatesData = { + body?: never + path?: never + query?: never + url: '/api/workflow_templates' +} -export type GetHubProfileByUsernameResponses = { +export type GetWorkflowTemplatesResponses = { /** - * Hub profile + * Empty object for workflow templates */ - 200: HubProfile + 200: { + [key: string]: unknown + } } -export type GetHubProfileByUsernameResponse = - GetHubProfileByUsernameResponses[keyof GetHubProfileByUsernameResponses] +export type GetWorkflowTemplatesResponse = + GetWorkflowTemplatesResponses[keyof GetWorkflowTemplatesResponses] -export type UpdateHubProfileData = { - body: UpdateHubProfileRequest - path: { +export type ListWorkflowsData = { + body?: never + path?: never + query?: { + limit?: number + offset?: number /** - * The hub profile username to update. + * Search workflows by name (case-insensitive substring match) */ - username: string + name?: string + /** + * Filter by default view type + */ + default_view?: 'workflow' | 'app' + /** + * Sort field + */ + sort?: 'create_time' | 'update_time' | 'name' + /** + * Sort order + */ + order?: 'asc' | 'desc' } - query?: never - url: '/api/hub/profiles/{username}' + url: '/api/workflows' } -export type UpdateHubProfileErrors = { - /** - * Bad request (e.g. missing body, invalid avatar token) - */ - 400: ErrorResponse +export type ListWorkflowsErrors = { /** * Unauthorized */ 401: ErrorResponse - /** - * No hub profile exists with this username - */ - 404: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type UpdateHubProfileError = - UpdateHubProfileErrors[keyof UpdateHubProfileErrors] +export type ListWorkflowsError = ListWorkflowsErrors[keyof ListWorkflowsErrors] -export type UpdateHubProfileResponses = { +export type ListWorkflowsResponses = { /** - * Hub profile updated + * Success */ - 200: HubProfile + 200: WorkflowListResponse } -export type UpdateHubProfileResponse = - UpdateHubProfileResponses[keyof UpdateHubProfileResponses] +export type ListWorkflowsResponse = + ListWorkflowsResponses[keyof ListWorkflowsResponses] -export type CreateHubAssetUploadUrlData = { - body: HubAssetUploadUrlRequest +export type CreateWorkflowData = { + body: CreateWorkflowRequest path?: never query?: never - url: '/api/hub/assets/upload-url' + url: '/api/workflows' } -export type CreateHubAssetUploadUrlErrors = { - /** - * Bad request (e.g. unsupported content type) - */ - 400: ErrorResponse +export type CreateWorkflowErrors = { /** * Unauthorized */ 401: ErrorResponse /** - * Not found + * Validation error */ - 404: ErrorResponse + 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type CreateHubAssetUploadUrlError = - CreateHubAssetUploadUrlErrors[keyof CreateHubAssetUploadUrlErrors] +export type CreateWorkflowError = + CreateWorkflowErrors[keyof CreateWorkflowErrors] -export type CreateHubAssetUploadUrlResponses = { +export type CreateWorkflowResponses = { /** - * Presigned upload URL and token + * Workflow created successfully */ - 200: HubAssetUploadUrlResponse + 201: WorkflowResponse } -export type CreateHubAssetUploadUrlResponse = - CreateHubAssetUploadUrlResponses[keyof CreateHubAssetUploadUrlResponses] +export type CreateWorkflowResponse = + CreateWorkflowResponses[keyof CreateWorkflowResponses] -export type ListHubLabelsData = { +export type DeleteWorkflowData = { body?: never - path?: never - query?: { + path: { /** - * Filter by label type. Omit to return all labels. + * The UUID of the workflow to delete. */ - type?: 'tag' | 'model' | 'custom_node' + workflow_id: string } - url: '/api/hub/labels' + query?: never + url: '/api/workflows/{workflow_id}' } -export type ListHubLabelsErrors = { +export type DeleteWorkflowErrors = { /** - * Bad request (e.g. invalid type parameter) + * Unauthorized */ - 400: ErrorResponse + 401: ErrorResponse + /** + * Workflow not found + */ + 404: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type ListHubLabelsError = ListHubLabelsErrors[keyof ListHubLabelsErrors] +export type DeleteWorkflowError = + DeleteWorkflowErrors[keyof DeleteWorkflowErrors] -export type ListHubLabelsResponses = { +export type DeleteWorkflowResponses = { /** - * List of labels + * Workflow deleted successfully */ - 200: HubLabelListResponse + 204: void } -export type ListHubLabelsResponse = - ListHubLabelsResponses[keyof ListHubLabelsResponses] +export type DeleteWorkflowResponse = + DeleteWorkflowResponses[keyof DeleteWorkflowResponses] -export type ListHubWorkflowsData = { +export type GetWorkflowData = { body?: never - path?: never - query?: { - cursor?: string - limit?: number - /** - * Search by workflow name - */ - search?: string - /** - * Filter by tag - */ - tag?: string - /** - * Filter by profile username - */ - username?: string - /** - * When true, returns full HubWorkflowDetail objects in the workflows array instead of summaries. Requires limit <= 20. - */ - detail?: boolean + path: { /** - * Filter by status (e.g. ?status=pending,approved). Defaults to approved if omitted. + * The UUID of the workflow. */ - status?: Array + workflow_id: string } - url: '/api/hub/workflows' + query?: never + url: '/api/workflows/{workflow_id}' } -export type ListHubWorkflowsErrors = { +export type GetWorkflowErrors = { /** - * Bad request (e.g. malformed pagination cursor) + * Unauthorized */ - 400: ErrorResponse + 401: ErrorResponse /** - * Profile not found (when filtering by username) + * Forbidden + */ + 403: ErrorResponse + /** + * Workflow not found */ 404: ErrorResponse /** @@ -9806,169 +8376,204 @@ export type ListHubWorkflowsErrors = { 500: ErrorResponse } -export type ListHubWorkflowsError = - ListHubWorkflowsErrors[keyof ListHubWorkflowsErrors] +export type GetWorkflowError = GetWorkflowErrors[keyof GetWorkflowErrors] -export type ListHubWorkflowsResponses = { +export type GetWorkflowResponses = { /** - * Paginated list of hub workflows + * Success */ - 200: HubWorkflowListResponse + 200: WorkflowResponse } -export type ListHubWorkflowsResponse = - ListHubWorkflowsResponses[keyof ListHubWorkflowsResponses] +export type GetWorkflowResponse = + GetWorkflowResponses[keyof GetWorkflowResponses] -export type PublishHubWorkflowData = { - body: PublishHubWorkflowRequest - path?: never +export type UpdateWorkflowData = { + body: UpdateWorkflowRequest + path: { + /** + * The UUID of the workflow to update. + */ + workflow_id: string + } query?: never - url: '/api/hub/workflows' + url: '/api/workflows/{workflow_id}' } -export type PublishHubWorkflowErrors = { - /** - * Bad request - */ - 400: ErrorResponse +export type UpdateWorkflowErrors = { /** * Unauthorized */ 401: ErrorResponse /** - * Workflow or profile not found + * Workflow not found */ 404: ErrorResponse + /** + * Validation error + */ + 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type PublishHubWorkflowError = - PublishHubWorkflowErrors[keyof PublishHubWorkflowErrors] +export type UpdateWorkflowError = + UpdateWorkflowErrors[keyof UpdateWorkflowErrors] -export type PublishHubWorkflowResponses = { +export type UpdateWorkflowResponses = { /** - * Workflow published to hub + * Success */ - 200: HubWorkflowDetail + 200: WorkflowResponse } -export type PublishHubWorkflowResponse = - PublishHubWorkflowResponses[keyof PublishHubWorkflowResponses] +export type UpdateWorkflowResponse = + UpdateWorkflowResponses[keyof UpdateWorkflowResponses] -export type ListHubWorkflowIndexData = { +export type GetWorkflowContentData = { body?: never - path?: never - query?: { + path: { /** - * Filter by status (e.g. ?status=pending,approved). Defaults to approved if omitted. + * The UUID of the workflow whose content should be retrieved. */ - status?: Array + workflow_id: string } - url: '/api/hub/workflows/index' + query?: never + url: '/api/workflows/{workflow_id}/content' } -export type ListHubWorkflowIndexErrors = { +export type GetWorkflowContentErrors = { + /** + * Unauthorized + */ + 401: ErrorResponse + /** + * Forbidden + */ + 403: ErrorResponse + /** + * Workflow not found + */ + 404: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type ListHubWorkflowIndexError = - ListHubWorkflowIndexErrors[keyof ListHubWorkflowIndexErrors] +export type GetWorkflowContentError = + GetWorkflowContentErrors[keyof GetWorkflowContentErrors] -export type ListHubWorkflowIndexResponses = { +export type GetWorkflowContentResponses = { /** - * List of hub workflow template entries + * Success */ - 200: Array + 200: WorkflowVersionContentResponse } -export type ListHubWorkflowIndexResponse = - ListHubWorkflowIndexResponses[keyof ListHubWorkflowIndexResponses] +export type GetWorkflowContentResponse = + GetWorkflowContentResponses[keyof GetWorkflowContentResponses] -export type DeleteHubWorkflowData = { - body?: never +export type ForkWorkflowData = { + body: ForkWorkflowRequest path: { /** - * The share ID of the hub workflow to unpublish. + * The UUID of the source workflow to fork from. */ - share_id: string + workflow_id: string } query?: never - url: '/api/hub/workflows/{share_id}' + url: '/api/workflows/{workflow_id}/fork' } -export type DeleteHubWorkflowErrors = { +export type ForkWorkflowErrors = { /** * Unauthorized */ 401: ErrorResponse /** - * Workflow not found + * Forbidden + */ + 403: ErrorResponse + /** + * Source workflow or version not found */ 404: ErrorResponse + /** + * Validation error + */ + 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type DeleteHubWorkflowError = - DeleteHubWorkflowErrors[keyof DeleteHubWorkflowErrors] +export type ForkWorkflowError = ForkWorkflowErrors[keyof ForkWorkflowErrors] -export type DeleteHubWorkflowResponses = { +export type ForkWorkflowResponses = { /** - * Successfully unpublished + * Workflow forked successfully */ - 204: void + 201: WorkflowResponse } -export type DeleteHubWorkflowResponse = - DeleteHubWorkflowResponses[keyof DeleteHubWorkflowResponses] +export type ForkWorkflowResponse = + ForkWorkflowResponses[keyof ForkWorkflowResponses] -export type GetHubWorkflowData = { - body?: never +export type CreateWorkflowVersionData = { + body: CreateWorkflowVersionRequest path: { /** - * The share ID of the hub workflow. + * The UUID of the workflow to create a new version for. */ - share_id: string + workflow_id: string } query?: never - url: '/api/hub/workflows/{share_id}' + url: '/api/workflows/{workflow_id}/versions' } -export type GetHubWorkflowErrors = { +export type CreateWorkflowVersionErrors = { + /** + * Unauthorized + */ + 401: ErrorResponse + /** + * Forbidden - not the workflow owner + */ + 403: ErrorResponse /** * Workflow not found */ 404: ErrorResponse /** - * Workflow JSON too large + * Version conflict - base_version does not match latest */ - 413: ErrorResponse + 409: ErrorResponse + /** + * Validation error + */ + 422: ErrorResponse /** * Internal server error */ 500: ErrorResponse } -export type GetHubWorkflowError = - GetHubWorkflowErrors[keyof GetHubWorkflowErrors] +export type CreateWorkflowVersionError = + CreateWorkflowVersionErrors[keyof CreateWorkflowVersionErrors] -export type GetHubWorkflowResponses = { +export type CreateWorkflowVersionResponses = { /** - * Hub workflow detail + * Version created successfully */ - 200: HubWorkflowDetail + 201: WorkflowVersionResponse } -export type GetHubWorkflowResponse = - GetHubWorkflowResponses[keyof GetHubWorkflowResponses] +export type CreateWorkflowVersionResponse = + CreateWorkflowVersionResponses[keyof CreateWorkflowVersionResponses] export type GetPublishedWorkflowData = { body?: never @@ -10014,1074 +8619,1075 @@ export type GetPublishedWorkflowResponses = { export type GetPublishedWorkflowResponse = GetPublishedWorkflowResponses[keyof GetPublishedWorkflowResponses] -export type GetExtensionsData = { +export type ListWorkspaceApiKeysData = { body?: never path?: never query?: never - url: '/api/extensions' + url: '/api/workspace/api-keys' } -export type GetExtensionsResponses = { +export type ListWorkspaceApiKeysErrors = { /** - * URL paths (relative to web root) of available extension JS files + * Unauthorized */ - 200: Array -} - -export type GetExtensionsResponse = - GetExtensionsResponses[keyof GetExtensionsResponses] - -export type GetNodeInfoSchemaData = { - body?: never - path?: never - query?: never - url: '/api/experiment/nodes' -} - -export type GetNodeInfoSchemaResponses = { + 401: ErrorResponse /** - * Full node schema JSON + * Forbidden */ - 200: unknown -} - -export type GetNodeByIdData = { - body?: never - path: { - /** - * Node class_type identifier - */ - id: string - } - query?: never - url: '/api/experiment/nodes/{id}' -} - -export type GetNodeByIdErrors = { + 403: ErrorResponse /** - * Node not found + * Internal server error */ - 404: unknown + 500: ErrorResponse } -export type GetNodeByIdResponses = { +export type ListWorkspaceApiKeysError = + ListWorkspaceApiKeysErrors[keyof ListWorkspaceApiKeysErrors] + +export type ListWorkspaceApiKeysResponses = { /** - * Node definition JSON + * List of API keys */ - 200: unknown + 200: ListWorkspaceApiKeysResponse } -export type GetVhsViewVideoData = { - body?: never +export type ListWorkspaceApiKeysResponse2 = + ListWorkspaceApiKeysResponses[keyof ListWorkspaceApiKeysResponses] + +export type CreateWorkspaceApiKeyData = { + body: CreateWorkspaceApiKeyRequest path?: never - query: { - /** - * Name of the video file to view - */ - filename: string - /** - * Type of file (e.g., output, input, temp) - */ - type?: string - /** - * Subfolder path where the file is located - */ - subfolder?: string - } - url: '/api/vhs/viewvideo' + query?: never + url: '/api/workspace/api-keys' } -export type GetVhsViewVideoErrors = { +export type CreateWorkspaceApiKeyErrors = { /** * Unauthorized */ - 401: unknown -} - -export type GetVhsViewVideoResponses = { + 401: ErrorResponse /** - * Video stream + * Not a workspace member */ - 200: unknown -} - -export type GetVhsViewAudioData = { - body?: never - path?: never - query: { - /** - * Name of the audio file to view - */ - filename: string - /** - * Type of file (e.g., output, input, temp) - */ - type?: string - /** - * Subfolder path where the file is located - */ - subfolder?: string - } - url: '/api/vhs/viewaudio' -} - -export type GetVhsViewAudioErrors = { + 403: ErrorResponse /** - * Unauthorized + * Workspace not found */ - 401: unknown -} - -export type GetVhsViewAudioResponses = { + 404: ErrorResponse /** - * Audio stream + * Validation error */ - 200: unknown -} - -export type GetVhsQueryVideoData = { - body?: never - path?: never - query: { - /** - * Name of the video file to query - */ - filename: string - } - url: '/api/vhs/queryvideo' -} - -export type GetVhsQueryVideoErrors = { + 422: ErrorResponse /** - * Missing required query parameter. Produced by the oapi-codegen - * wrapper via echo.NewHTTPError; the custom Echo HTTPErrorHandler - * normalizes it to the standard ErrorResponse {code, message} shape - * (BE-1178). - * + * Key limit reached */ - 400: ErrorResponse + 429: ErrorResponse /** - * Unauthorized + * Internal server error */ - 401: ErrorResponse + 500: ErrorResponse } -export type GetVhsQueryVideoError = - GetVhsQueryVideoErrors[keyof GetVhsQueryVideoErrors] +export type CreateWorkspaceApiKeyError = + CreateWorkspaceApiKeyErrors[keyof CreateWorkspaceApiKeyErrors] -export type GetVhsQueryVideoResponses = { +export type CreateWorkspaceApiKeyResponses = { /** - * Video metadata + * API key created (plaintext returned once) */ - 200: { - /** - * Source video metadata - */ - source: { - /** - * [width, height] in pixels - */ - size: [number, number] - /** - * Frames per second - */ - fps: number - /** - * Total frame count - */ - frames: number - /** - * Duration in seconds - */ - duration: number - } - } + 201: CreateWorkspaceApiKeyResponse } -export type GetVhsQueryVideoResponse = - GetVhsQueryVideoResponses[keyof GetVhsQueryVideoResponses] +export type CreateWorkspaceApiKeyResponse2 = + CreateWorkspaceApiKeyResponses[keyof CreateWorkspaceApiKeyResponses] -export type GetUsersInfoData = { +export type RevokeWorkspaceApiKeyData = { body?: never - path?: never + path: { + /** + * API key ID to revoke + */ + id: string + } query?: never - url: '/api/users' + url: '/api/workspace/api-keys/{id}' } -export type GetUsersInfoErrors = { +export type RevokeWorkspaceApiKeyErrors = { /** * Unauthorized */ 401: ErrorResponse + /** + * Not authorized to revoke this key + */ + 403: ErrorResponse + /** + * API key not found + */ + 404: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetUsersInfoError = GetUsersInfoErrors[keyof GetUsersInfoErrors] +export type RevokeWorkspaceApiKeyError = + RevokeWorkspaceApiKeyErrors[keyof RevokeWorkspaceApiKeyErrors] -export type GetUsersInfoResponses = { - /** - * Userdata storage information - */ - 200: { - /** - * Where user data is stored (always "server" in cloud) - */ - storage: string - /** - * Whether user data has been migrated (always true in cloud) - */ - migrated: boolean - } +export type RevokeWorkspaceApiKeyResponses = { + /** + * API key revoked + */ + 204: void } -export type GetUsersInfoResponse = - GetUsersInfoResponses[keyof GetUsersInfoResponses] +export type RevokeWorkspaceApiKeyResponse = + RevokeWorkspaceApiKeyResponses[keyof RevokeWorkspaceApiKeyResponses] -export type GetApiViewVideoAliasData = { +export type ListWorkspaceInvitesData = { body?: never path?: never - query: { - /** - * Name of the file to view (see `/api/view` for the full handler contract) - */ - filename: string - } - url: '/api/viewvideo' + query?: never + url: '/api/workspace/invites' } -export type GetApiViewVideoAliasErrors = { +export type ListWorkspaceInvitesErrors = { /** * Unauthorized */ - 401: unknown + 401: ErrorResponse + /** + * Owner role required + */ + 403: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetApiViewVideoAliasResponses = { +export type ListWorkspaceInvitesError = + ListWorkspaceInvitesErrors[keyof ListWorkspaceInvitesErrors] + +export type ListWorkspaceInvitesResponses = { /** - * File stream + * List of pending invites */ - 200: unknown + 200: ListInvitesResponse } -export type GetViewCompatAliasData = { - body?: never +export type ListWorkspaceInvitesResponse = + ListWorkspaceInvitesResponses[keyof ListWorkspaceInvitesResponses] + +export type CreateWorkspaceInviteData = { + body: CreateInviteRequest path?: never - query: { - /** - * Name of the file to view (see `/api/view` for the full handler contract) - */ - filename: string - } - url: '/view' + query?: never + url: '/api/workspace/invites' } -export type GetViewCompatAliasErrors = { +export type CreateWorkspaceInviteErrors = { /** * Unauthorized */ - 401: unknown -} - -export type GetViewCompatAliasResponses = { + 401: ErrorResponse /** - * File stream + * Owner role required or personal workspace (invites not allowed) */ - 200: unknown + 403: ErrorResponse + /** + * Workspace not found + */ + 404: ErrorResponse + /** + * Invite already exists + */ + 409: ErrorResponse + /** + * Validation error + */ + 422: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetWebsocketData = { - body?: never - path?: never - query?: { - /** - * Stable client identifier used to associate the WebSocket - * connection with the frontend session. If omitted, the server - * generates one. - * - */ - clientId?: string - } - url: '/ws' -} +export type CreateWorkspaceInviteError = + CreateWorkspaceInviteErrors[keyof CreateWorkspaceInviteErrors] -export type GetWebsocketErrors = { +export type CreateWorkspaceInviteResponses = { /** - * Unauthorized + * Invite created */ - 401: unknown + 201: PendingInvite } -export type GetTemplateProxyData = { +export type CreateWorkspaceInviteResponse = + CreateWorkspaceInviteResponses[keyof CreateWorkspaceInviteResponses] + +export type RevokeWorkspaceInviteData = { body?: never path: { /** - * Template subpath within the versioned GCS bucket. + * Invite ID to revoke */ - path: string + inviteId: string } query?: never - url: '/templates/{path}' + url: '/api/workspace/invites/{inviteId}' } -export type GetTemplateProxyErrors = { +export type RevokeWorkspaceInviteErrors = { /** - * Template not found. + * Unauthorized */ - 404: unknown + 401: ErrorResponse /** - * Workflow templates version not available. + * Owner role required */ - 503: unknown + 403: ErrorResponse + /** + * Workspace or invite not found + */ + 404: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetTemplateProxyResponses = { +export type RevokeWorkspaceInviteError = + RevokeWorkspaceInviteErrors[keyof RevokeWorkspaceInviteErrors] + +export type RevokeWorkspaceInviteResponses = { /** - * Template file content streamed from GCS. + * Invite revoked */ - 200: unknown + 204: void } -export type GetHealthData = { +export type RevokeWorkspaceInviteResponse = + RevokeWorkspaceInviteResponses[keyof RevokeWorkspaceInviteResponses] + +export type LeaveWorkspaceData = { body?: never path?: never query?: never - url: '/health' + url: '/api/workspace/leave' } -export type GetHealthErrors = { +export type LeaveWorkspaceErrors = { /** - * Service is unhealthy + * Unauthorized */ - 503: string + 401: ErrorResponse + /** + * Cannot leave as the only owner or cannot leave personal workspace + */ + 403: ErrorResponse + /** + * Workspace not found or not a member + */ + 404: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetHealthError = GetHealthErrors[keyof GetHealthErrors] +export type LeaveWorkspaceError = + LeaveWorkspaceErrors[keyof LeaveWorkspaceErrors] -export type GetHealthResponses = { +export type LeaveWorkspaceResponses = { /** - * Service is healthy + * Successfully left workspace */ - 200: string + 204: void } -export type GetHealthResponse = GetHealthResponses[keyof GetHealthResponses] +export type LeaveWorkspaceResponse = + LeaveWorkspaceResponses[keyof LeaveWorkspaceResponses] -export type GetMonitoringTasksData = { +export type ListWorkspaceMembersData = { body?: never path?: never - query?: never - url: '/monitoring/tasks' + query?: { + /** + * Pagination offset (0-based) + */ + offset?: number + /** + * Maximum number of members to return + */ + limit?: number + } + url: '/api/workspace/members' } -export type GetMonitoringTasksErrors = { +export type ListWorkspaceMembersErrors = { /** * Unauthorized */ - 401: unknown + 401: ErrorResponse /** - * Forbidden + * Not a member of this workspace */ - 403: unknown + 403: ErrorResponse + /** + * Workspace not found + */ + 404: ErrorResponse + /** + * Validation error + */ + 422: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetMonitoringTasksResponses = { +export type ListWorkspaceMembersError = + ListWorkspaceMembersErrors[keyof ListWorkspaceMembersErrors] + +export type ListWorkspaceMembersResponses = { /** - * HTML dashboard + * List of members */ - 200: unknown + 200: ListMembersResponse } -export type DeleteMonitoringTasksSubpathData = { +export type ListWorkspaceMembersResponse = + ListWorkspaceMembersResponses[keyof ListWorkspaceMembersResponses] + +export type BulkRevokeWorkspaceMemberApiKeysData = { body?: never path: { /** - * Asynqmon deletion subpath (e.g. delete task). + * Firebase UID of the member whose keys to revoke (must be non-empty) */ - path: string + user_id: string } query?: never - url: '/monitoring/tasks/{path}' + url: '/api/workspace/members/{user_id}/api-keys' } -export type DeleteMonitoringTasksSubpathErrors = { +export type BulkRevokeWorkspaceMemberApiKeysErrors = { /** * Unauthorized */ - 401: unknown + 401: ErrorResponse /** - * Forbidden + * Not authorized (must be workspace owner) */ - 403: unknown + 403: ErrorResponse + /** + * Validation error (e.g. empty user_id) + */ + 422: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type DeleteMonitoringTasksSubpathResponses = { +export type BulkRevokeWorkspaceMemberApiKeysError = + BulkRevokeWorkspaceMemberApiKeysErrors[keyof BulkRevokeWorkspaceMemberApiKeysErrors] + +export type BulkRevokeWorkspaceMemberApiKeysResponses = { /** - * Deletion result + * Keys revoked successfully */ - 200: unknown + 200: BulkRevokeApiKeysResponse } -export type GetMonitoringTasksSubpathData = { +export type BulkRevokeWorkspaceMemberApiKeysResponse = + BulkRevokeWorkspaceMemberApiKeysResponses[keyof BulkRevokeWorkspaceMemberApiKeysResponses] + +export type RemoveWorkspaceMemberData = { body?: never path: { /** - * Asynqmon UI subpath (HTML page, SPA XHR, or static asset). + * User ID to remove */ - path: string + userId: string } query?: never - url: '/monitoring/tasks/{path}' + url: '/api/workspace/members/{userId}' } -export type GetMonitoringTasksSubpathErrors = { +export type RemoveWorkspaceMemberErrors = { /** * Unauthorized */ - 401: unknown + 401: ErrorResponse /** - * Forbidden + * Owner role required or cannot remove yourself */ - 403: unknown + 403: ErrorResponse + /** + * Workspace or member not found + */ + 404: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetMonitoringTasksSubpathResponses = { +export type RemoveWorkspaceMemberError = + RemoveWorkspaceMemberErrors[keyof RemoveWorkspaceMemberErrors] + +export type RemoveWorkspaceMemberResponses = { /** - * Subpath response (asynqmon-determined content type) + * Member removed */ - 200: unknown + 204: void } -export type PostMonitoringTasksSubpathData = { - body?: never +export type RemoveWorkspaceMemberResponse = + RemoveWorkspaceMemberResponses[keyof RemoveWorkspaceMemberResponses] + +export type UpdateWorkspaceMemberRoleData = { + body: UpdateMemberRoleRequest path: { /** - * Asynqmon action subpath (e.g. retry, archive). + * User ID whose role is being changed */ - path: string + userId: string } query?: never - url: '/monitoring/tasks/{path}' + url: '/api/workspace/members/{userId}' } -export type PostMonitoringTasksSubpathErrors = { +export type UpdateWorkspaceMemberRoleErrors = { /** * Unauthorized */ - 401: unknown + 401: ErrorResponse /** - * Forbidden + * Owner role required, or the original owner cannot be demoted */ - 403: unknown -} - -export type PostMonitoringTasksSubpathResponses = { + 403: ErrorResponse /** - * Action result + * Workspace or member not found */ - 200: unknown + 404: ErrorResponse + /** + * Validation error + */ + 422: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetPprofData = { - body?: never - path: { - /** - * pprof endpoint name (e.g. heap, goroutine, allocs, block, mutex, threadcreate). - */ - path: string - } - query?: never - url: '/debug/pprof/{path}' -} +export type UpdateWorkspaceMemberRoleError = + UpdateWorkspaceMemberRoleErrors[keyof UpdateWorkspaceMemberRoleErrors] -export type GetPprofResponses = { +export type UpdateWorkspaceMemberRoleResponses = { /** - * Profile data + * Member role updated */ - 200: unknown + 200: Member } -export type GetPprofProfileData = { +export type UpdateWorkspaceMemberRoleResponse = + UpdateWorkspaceMemberRoleResponses[keyof UpdateWorkspaceMemberRoleResponses] + +export type ListWorkspacesData = { body?: never path?: never query?: never - url: '/debug/pprof/profile' + url: '/api/workspaces' } -export type GetPprofProfileResponses = { +export type ListWorkspacesErrors = { /** - * CPU profile data + * Unauthorized */ - 200: unknown + 401: ErrorResponse + /** + * Feature not enabled for user + */ + 404: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetPprofTraceData = { - body?: never - path?: never - query?: never - url: '/debug/pprof/trace' -} +export type ListWorkspacesError = + ListWorkspacesErrors[keyof ListWorkspacesErrors] -export type GetPprofTraceResponses = { +export type ListWorkspacesResponses = { /** - * Execution trace data + * List of workspaces */ - 200: unknown + 200: ListWorkspacesResponse } -export type PostPprofSymbolData = { - body?: never +export type ListWorkspacesResponse2 = + ListWorkspacesResponses[keyof ListWorkspacesResponses] + +export type CreateWorkspaceData = { + body: CreateWorkspaceRequest path?: never query?: never - url: '/debug/pprof/symbol' + url: '/api/workspaces' } -export type PostPprofSymbolResponses = { +export type CreateWorkspaceErrors = { /** - * Resolved symbols + * Unauthorized */ - 200: unknown -} - -export type GetStaticExtensionsData = { - body?: never - path: { - /** - * Extension file path relative to /static/extensions on disk. - */ - path: string - } - query?: never - url: '/extensions/{path}' -} - -export type GetStaticExtensionsErrors = { + 401: ErrorResponse /** - * File not found + * Feature not enabled for user */ - 404: unknown + 404: ErrorResponse + /** + * Validation error + */ + 422: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetStaticExtensionsResponses = { +export type CreateWorkspaceError = + CreateWorkspaceErrors[keyof CreateWorkspaceErrors] + +export type CreateWorkspaceResponses = { /** - * Static file + * Workspace created */ - 200: unknown + 201: Workspace } -export type GetCustomNodeProxyData = { +export type CreateWorkspaceResponse = + CreateWorkspaceResponses[keyof CreateWorkspaceResponses] + +export type DeleteWorkspaceData = { body?: never path: { /** - * Custom node HTTP endpoint path being proxied to the CPU-backed worker. + * Workspace ID (w-{uuid} format) */ - path: string + id: string } query?: never - url: '/__custom_node_proxy/{path}' + url: '/api/workspaces/{id}' } -export type GetCustomNodeProxyErrors = { +export type DeleteWorkspaceErrors = { /** * Unauthorized */ - 401: unknown + 401: ErrorResponse /** - * Path not in allowlist + * Owner role required or cannot delete personal workspace */ - 403: unknown + 403: ErrorResponse + /** + * Workspace not found + */ + 404: ErrorResponse + /** + * Internal server error + */ + 500: ErrorResponse } -export type GetCustomNodeProxyResponses = { +export type DeleteWorkspaceError = + DeleteWorkspaceErrors[keyof DeleteWorkspaceErrors] + +export type DeleteWorkspaceResponses = { /** - * Proxied response + * Workspace deleted */ - 200: unknown + 204: void } -export type PostCustomNodeProxyData = { +export type DeleteWorkspaceResponse = + DeleteWorkspaceResponses[keyof DeleteWorkspaceResponses] + +export type GetWorkspaceData = { body?: never path: { /** - * Custom node HTTP endpoint path being proxied to the CPU-backed worker. + * Workspace ID (w-{uuid} format) */ - path: string + id: string } query?: never - url: '/__custom_node_proxy/{path}' + url: '/api/workspaces/{id}' } -export type PostCustomNodeProxyErrors = { +export type GetWorkspaceErrors = { /** * Unauthorized */ - 401: unknown + 401: ErrorResponse /** - * Path not in allowlist + * Workspace not found or user not a member */ - 403: unknown -} - -export type PostCustomNodeProxyResponses = { + 404: ErrorResponse /** - * Proxied response + * Internal server error */ - 200: unknown + 500: ErrorResponse } -export type GetModelPreviewData = { - body?: never - path: { - /** - * The folder name containing the model. - */ - folder: string - /** - * The path index (usually 0 for cloud service). - */ - path_index: number - /** - * The model filename (with or without .webp extension). - */ - filename: string - } - query?: never - url: '/api/experiment/models/preview/{folder}/{path_index}/{filename}' -} +export type GetWorkspaceError = GetWorkspaceErrors[keyof GetWorkspaceErrors] -export type GetModelPreviewErrors = { +export type GetWorkspaceResponses = { /** - * Preview not available on Cloud + * Workspace details */ - 404: unknown + 200: Workspace } -export type ShortLinkRedirectData = { - body?: never +export type GetWorkspaceResponse = + GetWorkspaceResponses[keyof GetWorkspaceResponses] + +export type UpdateWorkspaceData = { + body: UpdateWorkspaceRequest path: { + /** + * Workspace ID (w-{uuid} format) + */ id: string } query?: never - url: '/api/s/{id}' + url: '/api/workspaces/{id}' } -export type ShortLinkRedirectErrors = { +export type UpdateWorkspaceErrors = { + /** + * Unauthorized + */ + 401: ErrorResponse + /** + * Owner role required + */ + 403: ErrorResponse + /** + * Workspace not found + */ + 404: ErrorResponse + /** + * Validation error + */ + 422: ErrorResponse /** - * Not Found — unknown, expired, revoked, or malformed short-link ID + * Internal server error */ - 404: unknown + 500: ErrorResponse } -export type GetLegacyPromptByIdData = { - body?: never - path: { - prompt_id: string - } - query?: never - url: '/api/prompt/{prompt_id}' -} +export type UpdateWorkspaceError = + UpdateWorkspaceErrors[keyof UpdateWorkspaceErrors] -export type GetLegacyPromptByIdErrors = { +export type UpdateWorkspaceResponses = { /** - * Not Found — use /api/jobs/{prompt_id} instead + * Workspace updated */ - 404: unknown + 200: Workspace } -export type GetLegacyHistoryByIdData = { +export type UpdateWorkspaceResponse = + UpdateWorkspaceResponses[keyof UpdateWorkspaceResponses] + +export type GetStaticExtensionsData = { body?: never path: { - prompt_id: string + /** + * Extension file path relative to /static/extensions on disk. + */ + path: string } query?: never - url: '/api/history/{prompt_id}' + url: '/extensions/{path}' } -export type GetLegacyHistoryByIdErrors = { +export type GetStaticExtensionsErrors = { /** - * Not Found — use /api/jobs/{prompt_id} instead + * File not found */ 404: unknown } -export type GetLegacyJobByIdData = { - body?: never - path: { - job_id: string - } - query?: never - url: '/api/job/{job_id}' -} - -export type GetLegacyJobByIdErrors = { +export type GetStaticExtensionsResponses = { /** - * Not Found — use /api/jobs/{job_id} instead + * Static file */ - 404: unknown + 200: unknown } -export type GetLegacyJobOutputsData = { +export type GetHealthData = { body?: never - path: { - job_id: string - } + path?: never query?: never - url: '/api/job/{job_id}/outputs' + url: '/health' } -export type GetLegacyJobOutputsErrors = { +export type GetHealthErrors = { /** - * Not Found — use /api/jobs/{job_id} instead + * Service is unhealthy */ - 404: unknown + 503: string } -export type GetLegacyModelsData = { - body?: never - path?: never - query?: never - url: '/api/models' -} +export type GetHealthError = GetHealthErrors[keyof GetHealthErrors] -export type GetLegacyModelsErrors = { +export type GetHealthResponses = { /** - * Not Found — use /api/experiment/models instead + * Service is healthy */ - 404: unknown + 200: string } -export type GetLegacyModelsByFolderData = { +export type GetHealthResponse = GetHealthResponses[keyof GetHealthResponses] + +export type GetInternalFolderPathsData = { body?: never - path: { - folder: string - } + path?: never query?: never - url: '/api/models/{folder}' + url: '/internal/folder_paths' } -export type GetLegacyModelsByFolderErrors = { +export type GetInternalFolderPathsResponses = { /** - * Not Found — use /api/experiment/models/{folder} instead + * Map of folder type name to list of path entries */ - 404: unknown + 200: { + [key: string]: Array> + } } -export type GetLegacyObjectInfoByNodeClassData = { +export type GetInternalFolderPathsResponse = + GetInternalFolderPathsResponses[keyof GetInternalFolderPathsResponses] + +export type GetInternalLogsData = { body?: never - path: { - node_class: string - } + path?: never query?: never - url: '/api/object_info/{node_class}' + url: '/internal/logs' } -export type GetLegacyObjectInfoByNodeClassErrors = { +export type GetInternalLogsResponses = { /** - * Not Found — use /api/object_info instead + * Log text */ - 404: unknown + 200: string } -export type GetLegacyUserdataV2Data = { +export type GetInternalLogsResponse = + GetInternalLogsResponses[keyof GetInternalLogsResponses] + +export type GetInternalLogsRawData = { body?: never path?: never query?: never - url: '/api/v2/userdata' + url: '/internal/logs/raw' } -export type GetLegacyUserdataV2Errors = { +export type GetInternalLogsRawResponses = { /** - * Not Found — use /api/userdata instead + * Structured log data */ - 404: unknown + 200: { + entries?: Array<{ + /** + * Message + */ + m?: string + /** + * Timestamp + */ + t?: number + }> + size?: { + cols?: number + rows?: number + } + } } -export type GetAssetContentData = { - body?: never - path: { +export type GetInternalLogsRawResponse = + GetInternalLogsRawResponses[keyof GetInternalLogsRawResponses] + +export type SubscribeToLogsData = { + body: { /** - * Asset ID + * WebSocket client ID */ - id: string - } - query?: { + clientId: string /** - * Content-Disposition for the response: `attachment` (download) or - * `inline` (render in browser). Defaults to `attachment`. - * + * Enable or disable log streaming for this client */ - disposition?: 'inline' | 'attachment' + enabled: boolean } - url: '/api/assets/{id}/content' -} - -export type GetAssetContentErrors = { - /** - * Asset not found - */ - 404: ErrorResponse - /** - * Internal server error - */ - 500: ErrorResponse + path?: never + query?: never + url: '/internal/logs/subscribe' } -export type GetAssetContentError = - GetAssetContentErrors[keyof GetAssetContentErrors] - -export type GetAssetContentResponses = { +export type SubscribeToLogsResponses = { /** - * Asset content stream (local runtime streams the bytes directly) + * Subscription updated */ - 200: Blob | File + 200: unknown } -export type GetAssetContentResponse = - GetAssetContentResponses[keyof GetAssetContentResponses] - -export type GetLegacyViewMetadataData = { +export type GetOAuthAuthorizeData = { body?: never - path: { - folder_name: string + path?: never + query?: { + response_type?: string + client_id?: string + redirect_uri?: string + scope?: string + /** + * RFC 6749 §10.12 marks `state` as RECOMMENDED. Our hardening makes + * it REQUIRED on the initial-entry path (omitted only on the resume + * path where `oauth_request_id` is supplied instead). This parameter + * is `required: false` at the spec level only because the operation + * is dual-mode (initial entry vs. resume); the runtime parser + * (services/ingest/server/implementation/oauth/protocol/request.go) + * rejects empty `state` on the initial-entry path with a stable + * `invalid_request` 400. + * + */ + state?: string + code_challenge?: string + code_challenge_method?: string + resource?: string + oauth_request_id?: string } - query?: never - url: '/api/view_metadata/{folder_name}' + url: '/oauth/authorize' } -export type GetLegacyViewMetadataErrors = { +export type GetOAuthAuthorizeErrors = { /** - * Not Found — use /api/experiment/models instead + * Invalid authorize request (pre-redirect failure — unknown client, redirect mismatch, malformed params). Content-negotiated; browser navigations (Accept includes text/html without application/json) receive a self-contained HTML error page instead of JSON. */ - 404: unknown -} - -export type GetEmbeddingsData = { - body?: never - path?: never - query?: never - url: '/api/embeddings' -} - -export type GetEmbeddingsResponses = { + 400: ErrorResponse /** - * Embedding names + * OAuth disabled */ - 200: Array -} - -export type GetEmbeddingsResponse = - GetEmbeddingsResponses[keyof GetEmbeddingsResponses] - -export type FreeMemoryData = { - body?: { - /** - * Unload all models from VRAM/RAM - */ - unload_models?: boolean - /** - * Run garbage collection and free cached memory - */ - free_memory?: boolean - } - path?: never - query?: never - url: '/api/free' + 404: ErrorResponse } -export type FreeMemoryResponses = { +export type GetOAuthAuthorizeError = + GetOAuthAuthorizeErrors[keyof GetOAuthAuthorizeErrors] + +export type GetOAuthAuthorizeResponses = { /** - * Memory freed + * Consent challenge payload (cookie present, email verified). Frontend renders the consent UI from this payload and POSTs back to /oauth/authorize. + * */ - 200: unknown + 200: OAuthConsentChallenge } -export type GetI18nData = { - body?: never +export type GetOAuthAuthorizeResponse = + GetOAuthAuthorizeResponses[keyof GetOAuthAuthorizeResponses] + +export type PostOAuthAuthorizeData = { + body: { + csrf_token: string + decision: 'allow' | 'deny' + oauth_request_id: string + workspace_id: string + } path?: never query?: never - url: '/api/i18n' + url: '/oauth/authorize' } -export type GetI18nResponses = { +export type PostOAuthAuthorizeErrors = { /** - * Nested map of locale to translation key-value pairs + * Bad request (CSRF mismatch, expired/consumed request, inaccessible workspace) */ - 200: { - [key: string]: unknown - } + 400: ErrorResponse + /** + * Scope broadening on consent re-grant — fresh consent flow required + */ + 403: ErrorResponse + /** + * OAuth disabled + */ + 404: ErrorResponse } -export type GetI18nResponse = GetI18nResponses[keyof GetI18nResponses] - -export type GetInternalFolderPathsData = { - body?: never - path?: never - query?: never - url: '/internal/folder_paths' -} +export type PostOAuthAuthorizeError = + PostOAuthAuthorizeErrors[keyof PostOAuthAuthorizeErrors] -export type GetInternalFolderPathsResponses = { +export type PostOAuthAuthorizeResponses = { /** - * Map of folder type name to list of path entries + * Redirect URL for the frontend to navigate to (allow → with code+state; deny → with error+state) */ - 200: { - [key: string]: Array> - } + 200: OAuthAuthorizeRedirectResponse } -export type GetInternalFolderPathsResponse = - GetInternalFolderPathsResponses[keyof GetInternalFolderPathsResponses] +export type PostOAuthAuthorizeResponse = + PostOAuthAuthorizeResponses[keyof PostOAuthAuthorizeResponses] -export type GetInternalLogsData = { - body?: never +export type PostOAuthRegisterData = { + body: OAuthRegisterRequest path?: never query?: never - url: '/internal/logs' + url: '/oauth/register' } -export type GetInternalLogsResponses = { +export type PostOAuthRegisterErrors = { /** - * Log text + * Bad request. Two shapes possible: `OAuthRegisterError` (RFC 7591 §3.2.2, emitted by the handler for invalid client metadata, reserved client_name, etc.) OR `ErrorResponse` (emitted by the strict-server binding layer when the request body fails OpenAPI-schema validation — malformed JSON, missing required fields, `additionalProperties: false` violations — normalized to the standard {code, message} shape by the custom Echo HTTPErrorHandler, BE-1178). + * */ - 200: string + 400: OAuthRegisterBadRequestResponse + /** + * OAuth disabled + */ + 404: ErrorResponse + /** + * No active MCP resource is configured — DCR cannot mint a usable client until ops seeds an active oauth_resources row. + */ + 503: ErrorResponse } -export type GetInternalLogsResponse = - GetInternalLogsResponses[keyof GetInternalLogsResponses] - -export type GetInternalLogsRawData = { - body?: never - path?: never - query?: never - url: '/internal/logs/raw' -} +export type PostOAuthRegisterError = + PostOAuthRegisterErrors[keyof PostOAuthRegisterErrors] -export type GetInternalLogsRawResponses = { +export type PostOAuthRegisterResponses = { /** - * Structured log data + * Registered. Body echoes the metadata RFC 7591 §3.2.1 requires. */ - 200: { - entries?: Array<{ - /** - * Timestamp - */ - t?: number - /** - * Message - */ - m?: string - }> - size?: { - cols?: number - rows?: number - } - } + 201: OAuthRegisterResponse } -export type GetInternalLogsRawResponse = - GetInternalLogsRawResponses[keyof GetInternalLogsRawResponses] +export type PostOAuthRegisterResponse = + PostOAuthRegisterResponses[keyof PostOAuthRegisterResponses] -export type SubscribeToLogsData = { +export type PostOAuthTokenData = { body: { - /** - * WebSocket client ID - */ - clientId: string - /** - * Enable or disable log streaming for this client - */ - enabled: boolean + client_id: string + client_secret?: string + code?: string + code_verifier?: string + grant_type: 'authorization_code' | 'refresh_token' + redirect_uri?: string + refresh_token?: string + scope?: string } path?: never query?: never - url: '/internal/logs/subscribe' + url: '/oauth/token' } -export type SubscribeToLogsResponses = { +export type PostOAuthTokenErrors = { /** - * Subscription updated + * RFC 6749 §5.2 error */ - 200: unknown + 400: OAuthTokenError + /** + * OAuth disabled + */ + 404: ErrorResponse } -export type PruneAssetsData = { - body?: never - path?: never - query?: never - url: '/api/assets/prune' -} +export type PostOAuthTokenError = + PostOAuthTokenErrors[keyof PostOAuthTokenErrors] -export type PruneAssetsResponses = { +export type PostOAuthTokenResponses = { /** - * Prune result + * New token pair */ - 200: { - status?: string - /** - * Number of assets marked as missing - */ - marked?: number - } + 200: OAuthTokenResponse } -export type PruneAssetsResponse = - PruneAssetsResponses[keyof PruneAssetsResponses] +export type PostOAuthTokenResponse = + PostOAuthTokenResponses[keyof PostOAuthTokenResponses] -export type SeedAssetsData = { - body?: { +export type GetTemplateProxyData = { + body?: never + path: { /** - * Root folder paths to scan (if omitted, scans all) + * Template subpath within the versioned GCS bucket. */ - roots?: Array + path: string } - path?: never query?: never - url: '/api/assets/seed' + url: '/templates/{path}' } -export type SeedAssetsResponses = { +export type GetTemplateProxyErrors = { /** - * Seed started + * Template not found. */ - 200: { - status?: string - } + 404: unknown + /** + * Workflow templates version not available. + */ + 503: unknown } -export type SeedAssetsResponse = SeedAssetsResponses[keyof SeedAssetsResponses] +export type GetTemplateProxyResponses = { + /** + * Template file content streamed from GCS. + */ + 200: unknown +} -export type GetAssetSeedStatusData = { +export type GetViewCompatAliasData = { body?: never path?: never - query?: never - url: '/api/assets/seed/status' + query: { + /** + * Name of the file to view (see `/api/view` for the full handler contract) + */ + filename: string + } + url: '/view' } -export type GetAssetSeedStatusResponses = { +export type GetViewCompatAliasErrors = { /** - * Scan progress details (files scanned, total, status, etc.) + * Unauthorized */ - 200: { - [key: string]: unknown - } + 401: unknown } -export type GetAssetSeedStatusResponse = - GetAssetSeedStatusResponses[keyof GetAssetSeedStatusResponses] +export type GetViewCompatAliasResponses = { + /** + * File stream + */ + 200: unknown +} -export type CancelAssetSeedData = { +export type GetWebsocketData = { body?: never path?: never - query?: never - url: '/api/assets/seed/cancel' + query?: { + /** + * Stable client identifier used to associate the WebSocket + * connection with the frontend session. If omitted, the server + * generates one. + * + */ + clientId?: string + } + url: '/ws' } -export type CancelAssetSeedResponses = { +export type GetWebsocketErrors = { /** - * Scan cancelled + * Unauthorized */ - 200: { - status?: string - } + 401: unknown } - -export type CancelAssetSeedResponse = - CancelAssetSeedResponses[keyof CancelAssetSeedResponses] diff --git a/packages/ingest-types/src/zod.gen.ts b/packages/ingest-types/src/zod.gen.ts index b39e7f0a1e9..b710e0501ef 100644 --- a/packages/ingest-types/src/zod.gen.ts +++ b/packages/ingest-types/src/zod.gen.ts @@ -3,76 +3,109 @@ import { z } from 'zod' /** - * Response indicating whether a Hub username is available. + * Subscription tier (uppercase to match comfy-api) */ -export const zHubUsernameCheckResponse = z.object({ - username: z.string(), - available: z.boolean(), - suggestions: z.array(z.string()).optional(), - validation_error: z.string().optional() -}) +export const zSubscriptionTier = z.enum([ + 'FREE', + 'STANDARD', + 'CREATOR', + 'PRO', + 'FOUNDERS_EDITION', + 'TEAM' +]) /** - * Response containing a signed upload URL and the target asset path. + * Workspace entity annotated with the requesting user's role. */ -export const zHubAssetUploadUrlResponse = z.object({ - upload_url: z.string(), - public_url: z.string(), - token: z.string() +export const zWorkspaceWithRole = z.object({ + created_at: z.string().datetime(), + id: z.string(), + joined_at: z.string().datetime(), + name: z.string(), + role: z.enum(['owner', 'member']), + subscription_tier: zSubscriptionTier.optional(), + type: z.enum(['personal', 'team']) }) /** - * Request body for requesting a signed upload URL for a Hub asset. + * Abbreviated workspace metadata used in list responses. */ -export const zHubAssetUploadUrlRequest = z.object({ - filename: z.string(), - content_type: z.string() +export const zWorkspaceSummary = z.object({ + id: z.string(), + name: z.string(), + type: z.enum(['personal', 'team']) }) /** - * Partial update for a published hub workflow (admin moderation). All fields are optional. Semantics match UpdateHubProfileRequest / avatar_token: - * - * * field omitted or null — leave unchanged - * * string field = "" — clear (for clearable string fields) - * * array field = [] — clear the list - * * any other value — set to the provided value - * - * Array fields use full-replacement (PUT) semantics when a value is supplied. The two single-value thumbnail token fields accept only upload tokens (not existing URLs) since omitting them already expresses "keep the current value". - * Backend note: cleared string columns are persisted as the empty string "" in the Ent schema (description, thumbnail_url, thumbnail_comparison_url, tutorial_url). thumbnail_type is the only true SQL-nullable column but is not clearable via this endpoint. - * + * Metadata for a workspace-scoped API key (secret is never returned). */ -export const zUpdateHubWorkflowRequest = z.object({ - name: z.string().min(1).nullish(), - description: z.string().nullish(), - tags: z.array(z.string()).nullish(), - models: z.array(z.string()).nullish(), - custom_nodes: z.array(z.string()).nullish(), - tutorial_url: z.string().nullish(), - thumbnail_type: z.enum(['image', 'video', 'image_comparison']).optional(), - thumbnail_token: z.string().nullish(), - thumbnail_comparison_token: z.string().nullish(), - sample_image_tokens_or_urls: z.array(z.string()).nullish(), - metadata: z.record(z.unknown()).nullish() +export const zWorkspaceApiKeyInfo = z.object({ + created_at: z.string().datetime(), + description: z.string().max(5000), + expires_at: z.string().datetime().optional(), + id: z.string().uuid(), + key_prefix: z.string(), + last_used_at: z.string().datetime().optional(), + name: z.string(), + revoked_at: z.string().datetime().optional(), + user_id: z.string(), + workspace_id: z.string() }) /** - * Request body for publishing or updating a workflow on the Hub. + * Full workspace entity with configuration and ownership details. */ -export const zPublishHubWorkflowRequest = z.object({ - username: z.string(), +export const zWorkspace = z.object({ + created_at: z.string().datetime(), + id: z.string(), name: z.string(), - workflow_filename: z.string(), - asset_ids: z.array(z.string()), + type: z.enum(['personal', 'team']) +}) + +/** + * Metadata for a single workflow version. + */ +export const zWorkflowVersionResponse = z.object({ + created_at: z.string().datetime(), + created_by: z.string(), + id: z.string(), + latest_version: z.number().int(), + version: z.number().int() +}) + +/** + * Full workflow version including the serialized workflow JSON. + */ +export const zWorkflowVersionContentResponse = z.object({ + created_at: z.string().datetime(), + created_by: z.string(), + dependency_asset_ids: z.array(z.string()).optional(), + id: z.string(), + version: z.number().int(), + workflow_json: z.record(z.unknown()) +}) + +/** + * Reference to the parent workflow from which this workflow was forked. + */ +export const zWorkflowForkedFrom = z.object({ + workflow_id: z.string().optional(), + workflow_version_id: z.string().optional() +}) + +/** + * Full workflow entity including metadata and version history. + */ +export const zWorkflowResponse = z.object({ + created_at: z.string().datetime(), + created_by: z.string(), + default_view: z.enum(['workflow', 'app']).optional(), description: z.string().optional(), - tags: z.array(z.string()).optional(), - models: z.array(z.string()).optional(), - custom_nodes: z.array(z.string()).optional(), - tutorial_url: z.string().optional(), - metadata: z.record(z.unknown()).optional(), - thumbnail_type: z.enum(['image', 'video', 'image_comparison']).optional(), - thumbnail_token_or_url: z.string().optional(), - thumbnail_comparison_token_or_url: z.string().optional(), - sample_image_tokens_or_urls: z.array(z.string()).optional() + forked_from: zWorkflowForkedFrom.optional(), + id: z.string(), + latest_version: z.number().int(), + name: z.string().optional(), + updated_at: z.string().datetime() }) /** @@ -80,153 +113,93 @@ export const zPublishHubWorkflowRequest = z.object({ */ export const zAssetInfo = z.object({ id: z.string(), + in_library: z.boolean(), + model: z.boolean(), name: z.string(), preview_url: z.string(), - storage_url: z.string(), - model: z.boolean(), public: z.boolean(), - in_library: z.boolean() + storage_url: z.string() }) /** - * Abbreviated Hub profile used in workflow listings. + * Publishing metadata for a workflow shared to the Hub. */ -export const zHubProfileSummary = z.object({ - username: z.string(), - display_name: z.string().optional(), - avatar_url: z.string().optional() +export const zWorkflowPublishInfo = z.object({ + assets: z.array(zAssetInfo), + listed: z.boolean(), + publish_time: z.string().datetime().nullish(), + share_id: z.string(), + workflow_id: z.string() }) /** - * Reference to a Hub label by ID. + * Pagination metadata included in list responses. Supports both legacy + * offset/limit pagination and cursor-based pagination. When cursor-based + * pagination is used, `next_cursor` is the primary pagination token and + * `offset`/`total` may be zero. + * */ -export const zLabelRef = z.object({ - name: z.string(), - display_name: z.string() +export const zPaginationInfo = z.object({ + has_more: z.boolean(), + limit: z.number().int().gte(1), + next_cursor: z.string().optional(), + offset: z.number().int().gte(0), + total: z.number().int().gte(0) }) /** - * Public workflow status. NULL in the database is represented as pending in API responses. + * Paginated list of saved workflows. */ -export const zHubWorkflowStatus = z.enum([ - 'pending', - 'approved', - 'rejected', - 'deprecated' -]) +export const zWorkflowListResponse = z.object({ + data: z.array(zWorkflowResponse), + pagination: zPaginationInfo +}) /** - * Full Hub workflow detail including versions, assets, and statistics. + * Response containing assets associated with a workflow. */ -export const zHubWorkflowDetail = z.object({ - share_id: z.string(), - workflow_id: z.string(), - name: z.string(), - status: zHubWorkflowStatus, - description: z.string().optional(), - tags: z.array(zLabelRef).optional(), - thumbnail_type: z.enum(['image', 'video', 'image_comparison']).optional(), - thumbnail_url: z.string().optional(), - thumbnail_comparison_url: z.string().optional(), - models: z.array(zLabelRef).optional(), - custom_nodes: z.array(zLabelRef).optional(), - tutorial_url: z.string().optional(), - metadata: z.record(z.unknown()).optional(), - sample_image_urls: z.array(z.string()).optional(), - publish_time: z.string().datetime().nullish(), - workflow_json: z.record(z.unknown()), - assets: z.array(zAssetInfo), - profile: zHubProfileSummary +export const zWorkflowApiAssetsResponse = z.object({ + assets: z.array(zAssetInfo) }) /** - * Abbreviated Hub workflow metadata used in search and listing results. + * Request body for querying assets associated with a workflow. */ -export const zHubWorkflowSummary = z.object({ - share_id: z.string(), - name: z.string(), - status: zHubWorkflowStatus, - description: z.string().optional(), - tags: z.array(zLabelRef).optional(), - models: z.array(zLabelRef).optional(), - custom_nodes: z.array(zLabelRef).optional(), - thumbnail_type: z.enum(['image', 'video', 'image_comparison']).optional(), - thumbnail_url: z.string().optional(), - thumbnail_comparison_url: z.string().optional(), - publish_time: z.string().datetime().nullish(), - profile: zHubProfileSummary, - metadata: z.record(z.unknown()).optional(), - tutorial_url: z.string().optional(), - sample_image_urls: z.array(z.string()).optional() +export const zWorkflowApiAssetsRequest = z.object({ + workflow_api_json: z.record(z.unknown()) }) /** - * Paginated list of Hub workflows matching search criteria. + * Details of a single validation error encountered during asset operations. */ -export const zHubWorkflowListResponse = z.object({ - workflows: z.array(z.union([zHubWorkflowSummary, zHubWorkflowDetail])), - next_cursor: z.string().optional() +export const zValidationError = z.object({ + code: z.string(), + field: z.string(), + message: z.string() }) /** - * Metadata for a single Hub label. + * Result of validating a set of asset operations. */ -export const zHubLabelInfo = z.object({ - name: z.string(), - display_name: z.string(), - description: z.string().optional(), - type: z.enum(['tag', 'model', 'custom_node']) +export const zValidationResult = z.object({ + errors: z.array(zValidationError).optional(), + is_valid: z.boolean(), + warnings: z.array(zValidationError).optional() }) /** - * List of available Hub labels for categorizing workflows. + * User information response */ -export const zHubLabelListResponse = z.object({ - labels: z.array(zHubLabelInfo) +export const zUserResponse = z.object({ + id: z.string(), + status: z.string() }) /** - * Entry in the curated workflow template gallery shown on the home page. + * User data listing entry with file metadata (path, size, modification time). */ -export const zHubWorkflowTemplateEntry = z.object({ - name: z.string(), - title: z.string(), - status: zHubWorkflowStatus, - description: z.string().optional(), - tags: z.array(z.string()).optional(), - models: z.array(z.string()).optional(), - requiresCustomNodes: z.array(z.string()).optional(), - thumbnailVariant: z.string().optional(), - mediaType: z.string().optional(), - mediaSubtype: z.string().optional(), - size: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }) - .optional(), - vram: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }) - .optional(), - usage: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }) - .optional(), - searchRank: z.coerce +export const zUserDataResponseFull = z.object({ + modified: z.coerce .bigint() .min(BigInt('-9223372036854775808'), { message: 'Invalid value: Expected int64 to be >= -9223372036854775808' @@ -235,376 +208,399 @@ export const zHubWorkflowTemplateEntry = z.object({ message: 'Invalid value: Expected int64 to be <= 9223372036854775807' }) .optional(), - isEssential: z.boolean().optional(), - openSource: z.boolean().optional(), - profile: zHubProfileSummary.optional(), - tutorialUrl: z.string().optional(), - logos: z.array(z.record(z.unknown())).optional(), - date: z.string().optional(), - io: z - .object({ - inputs: z.array(z.record(z.unknown())).optional(), - outputs: z.array(z.record(z.unknown())).optional() - }) - .optional(), - includeOnDistributions: z.array(z.string()).optional(), - thumbnailUrl: z.string().optional(), - thumbnailComparisonUrl: z.string().optional(), - shareId: z.string().optional(), - extendedDescription: z.string().optional(), - metaDescription: z.string().optional(), - howToUse: z.array(z.string()).optional(), - suggestedUseCases: z.array(z.string()).optional(), - faqItems: z - .array( - z.object({ - question: z.string(), - answer: z.string() - }) - ) - .optional(), - contentTemplate: z.string().optional() + path: z.string().optional(), + size: z.number().int().optional() }) /** - * Request body for updating an existing Hub profile. + * Request body for updating an existing workspace's settings. */ -export const zUpdateHubProfileRequest = z.object({ - display_name: z.string().optional(), - description: z.string().optional(), - avatar_token: z.string().nullish(), - website_urls: z.array(z.string()).optional() +export const zUpdateWorkspaceRequest = z.object({ + name: z.string().min(1).max(100).optional() }) /** - * Request body for creating a new Hub profile. + * Request body for updating an existing saved workflow. */ -export const zCreateHubProfileRequest = z.object({ - workspace_id: z.string(), - username: z.string(), - display_name: z.string().optional(), +export const zUpdateWorkflowRequest = z.object({ + default_view: z.enum(['workflow', 'app']).optional(), description: z.string().optional(), - avatar_token: z.string().optional(), - website_urls: z.array(z.string()).optional() + name: z.string().optional() }) /** - * Full public profile for a Hub creator. + * Request body for updating an existing user secret. */ -export const zHubProfile = z.object({ - username: z.string(), - display_name: z.string().optional(), - description: z.string().optional(), - avatar_url: z.string().optional(), - website_urls: z.array(z.string()).optional() +export const zUpdateSecretRequest = z.object({ + name: z.string().min(1).max(255).optional(), + secret_value: z.string().min(1).optional() }) /** - * Response after importing published workflow assets. + * Request body for changing a workspace member's role. */ -export const zImportPublishedAssetsResponse = z.object({ - assets: z.array(zAssetInfo) +export const zUpdateMemberRoleRequest = z.object({ + role: z.enum(['owner', 'member']) }) /** - * Request body for importing assets from a published workflow. + * Request body for updating an existing Hub profile. */ -export const zImportPublishedAssetsRequest = z.object({ - published_asset_ids: z.array(z.string()), - share_id: z.string().nullish() +export const zUpdateHubProfileRequest = z.object({ + avatar_token: z.string().nullish(), + description: z.string().optional(), + display_name: z.string().optional(), + website_urls: z.array(z.string()).optional() }) /** - * Full detail of a publicly published workflow on the Hub. + * Pre/post-discount price for a team credit stop, in cents. */ -export const zPublishedWorkflowDetail = z.object({ - share_id: z.string(), - workflow_id: z.string(), - name: z.string(), - listed: z.boolean(), - publish_time: z.string().datetime().nullish(), - workflow_json: z.record(z.unknown()), - assets: z.array(zAssetInfo) +export const zTeamCreditStopPrice = z.object({ + list_price_cents: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }), + price_cents: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }) }) /** - * Response containing assets associated with a workflow. + * A selectable preset on the team pricing slider. Echoed on subscribe via + * team_credit_stop_id; the backend owns the resolved amounts. credits is a + * RAW monthly credit count (not cents). Save% is derived by the FE as + * (list_price_cents - price_cents) / list_price_cents. + * */ -export const zWorkflowApiAssetsResponse = z.object({ - assets: z.array(zAssetInfo) +export const zTeamCreditStop = z.object({ + credits: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }), + id: z.string(), + monthly: zTeamCreditStopPrice, + yearly: zTeamCreditStopPrice }) /** - * Request body for querying assets associated with a workflow. + * Credit-stop ladder for the pricing slider (BE-1254). Returned by GET /api/billing/plans for every workspace regardless of the caller's token or workspace type (the personal/team distinction was removed); omitted only when the catalog defines no stops. */ -export const zWorkflowApiAssetsRequest = z.object({ - workflow_api_json: z.record(z.unknown()) +export const zTeamCreditStops = z.object({ + default_stop_index: z.number().int(), + stops: z.array(zTeamCreditStop) }) /** - * Request body for publishing workflow assets to the Hub. + * The team credit stop a workspace is currently subscribed to: the + * per-workspace slider choice recorded at subscribe time + * (workspace_subscriptions.team_credit_stop_id). Amounts are owned by the + * catalog, not the subscription row. Returned on GET /api/billing/status + * for per-credit Team plans (BE-1254). + * */ -export const zPublishWorkflowAssetsRequest = z.object({ - asset_ids: z.array(z.string()) +export const zTeamCreditStopSummary = z.object({ + credits_monthly: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }), + id: z.string(), + stop_usd: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }) }) /** - * Publishing metadata for a workflow shared to the Hub. + * Task data for list views */ -export const zWorkflowPublishInfo = z.object({ - workflow_id: z.string(), - share_id: z.string(), - publish_time: z.string().datetime().nullish(), - listed: z.boolean(), - assets: z.array(zAssetInfo) +export const zTaskEntry = z.object({ + completed_at: z.string().datetime().optional(), + create_time: z.string().datetime(), + id: z.string().uuid(), + started_at: z.string().datetime().optional(), + status: z.enum(['created', 'running', 'completed', 'failed']), + task_name: z.string() }) /** - * Request body for forking an existing workflow into the user's account. + * Paginated list of background tasks for the authenticated user. */ -export const zForkWorkflowRequest = z.object({ - source_version: z.number().int(), - name: z.string().optional() +export const zTasksListResponse = z.object({ + pagination: zPaginationInfo, + tasks: z.array(zTaskEntry) }) /** - * Full workflow version including the serialized workflow JSON. + * Full task details including payload and result */ -export const zWorkflowVersionContentResponse = z.object({ - id: z.string(), - version: z.number().int(), - workflow_json: z.record(z.unknown()), - created_by: z.string(), - created_at: z.string().datetime(), - dependency_asset_ids: z.array(z.string()).optional() +export const zTaskResponse = z.object({ + completed_at: z.string().datetime().optional(), + create_time: z.string().datetime(), + error_message: z.string().optional(), + id: z.string().uuid(), + idempotency_key: z.string(), + payload: z.record(z.unknown()), + result: z.record(z.unknown()).optional(), + started_at: z.string().datetime().optional(), + status: z.enum(['created', 'running', 'completed', 'failed']), + task_name: z.string(), + update_time: z.string().datetime() }) /** - * Metadata for a single workflow version. + * Response after adding, updating, or removing tags on an asset. */ -export const zWorkflowVersionResponse = z.object({ - id: z.string(), - version: z.number().int(), - latest_version: z.number().int(), - created_by: z.string(), - created_at: z.string().datetime() +export const zTagsModificationResponse = z.object({ + added: z.array(z.string()).optional(), + already_present: z.array(z.string()).optional(), + not_present: z.array(z.string()).optional(), + removed: z.array(z.string()).optional(), + total_tags: z.array(z.string()) }) /** - * Request body for creating a new version of a saved workflow. + * Metadata for a single tag that can be applied to assets. */ -export const zCreateWorkflowVersionRequest = z.object({ - base_version: z.number().int(), - workflow_json: z.record(z.unknown()) +export const zTagInfo = z.object({ + count: z.number().int(), + name: z.string() }) /** - * Pagination metadata included in list responses. Supports both legacy - * offset/limit pagination and cursor-based pagination. When cursor-based - * pagination is used, `next_cursor` is the primary pagination token and - * `offset`/`total` may be zero. - * + * System statistics response */ -export const zPaginationInfo = z.object({ - offset: z.number().int().gte(0), - limit: z.number().int().gte(1), - total: z.number().int().gte(0), - has_more: z.boolean(), - next_cursor: z.string().optional() +export const zSystemStatsResponse = z.object({ + devices: z.array( + z.object({ + name: z.string(), + type: z.string(), + vram_free: z.number().optional(), + vram_total: z.number().optional() + }) + ), + system: z.object({ + argv: z.array(z.string()), + cloud_version: z.string().optional(), + comfyui_frontend_version: z.string().optional(), + comfyui_version: z.string(), + deploy_environment: z.string().optional(), + embedded_python: z.boolean(), + os: z.string(), + python_version: z.string(), + pytorch_version: z.string(), + ram_free: z.number(), + ram_total: z.number(), + workflow_templates_version: z.string().optional() + }) }) /** - * Reference to the parent workflow from which this workflow was forked. + * Billing period (uppercase to match comfy-api) */ -export const zWorkflowForkedFrom = z.object({ - workflow_id: z.string().optional(), - workflow_version_id: z.string().optional() -}) +export const zSubscriptionDuration = z.enum(['MONTHLY', 'ANNUAL']) /** - * Full workflow entity including metadata and version history. + * Response after successfully subscribing to a billing plan. */ -export const zWorkflowResponse = z.object({ - id: z.string(), - name: z.string().optional(), - description: z.string().optional(), - default_view: z.enum(['workflow', 'app']).optional(), - latest_version: z.number().int(), - forked_from: zWorkflowForkedFrom.optional(), - created_by: z.string(), - created_at: z.string().datetime(), - updated_at: z.string().datetime() +export const zSubscribeResponse = z.object({ + billing_op_id: z.string(), + effective_at: z.string().datetime().optional(), + payment_method_url: z.string().optional(), + status: z.enum(['subscribed', 'needs_payment_method', 'pending_payment']) }) /** - * Paginated list of saved workflows. + * Request body for subscribing a workspace to a billing plan. */ -export const zWorkflowListResponse = z.object({ - data: z.array(zWorkflowResponse), - pagination: zPaginationInfo +export const zSubscribeRequest = z.object({ + billing_cycle: z.enum(['monthly', 'yearly']).optional(), + cancel_url: z.string().optional(), + idempotency_key: z.string().optional(), + plan_slug: z.string(), + return_url: z.string().optional(), + team_credit_stop_id: z.string().optional() }) /** - * Request body for updating an existing saved workflow. + * User secret metadata (the secret value itself is never returned after creation). */ -export const zUpdateWorkflowRequest = z.object({ - name: z.string().optional(), - description: z.string().optional(), - default_view: z.enum(['workflow', 'app']).optional() +export const zSecretResponse = z.object({ + created_at: z.string().datetime(), + id: z.string().uuid(), + last_used_at: z.string().datetime().optional(), + name: z.string(), + provider: z.string().optional(), + updated_at: z.string().datetime() }) /** - * Request body for creating a new saved workflow. + * A provider the user may configure a secret for. The shape is deliberately minimal (identifier only) and reserved for future per-provider fields such as sub-keys. */ -export const zCreateWorkflowRequest = z.object({ - name: z.string().optional(), - description: z.string().optional(), - default_view: z.enum(['workflow', 'app']).optional(), - workflow_json: z.record(z.unknown()), - forked_from_workflow_id: z.string().optional(), - forked_from_workflow_version_id: z.string().optional() +export const zSecretProvider = z.object({ + id: z.string() }) /** - * Request body for forwarding a comfy-api audit/history event. Identify the target workspace by either user_id (cloud resolves the user's personal workspace via the converged identity, BE-1047) or an explicit workspace_id. At least one must be provided; workspace_id wins when both are set. + * The providers available to the authenticated user in the current workspace. */ -export const zHistoryEventRequest = z.object({ - user_id: z.string().optional(), - workspace_id: z.string().optional(), - event_type: z.string().min(1), - event_id: z.string().min(1), - params: z.record(z.unknown()).optional(), - auth_method: z.enum(['api_key', 'bearer_token']).optional(), - customer_ref: z.string().optional(), - timestamp: z.string().datetime().optional() +export const zSecretProvidersResponse = z.object({ + data: z.array(zSecretProvider) }) /** - * Response after recording partner usage data. + * List of user secrets with metadata only. */ -export const zPartnerUsageResponse = z.object({ - status: z.string() +export const zSecretListResponse = z.object({ + data: z.array(zSecretResponse) }) /** - * Request body for reporting partner resource usage (admin endpoint). + * Response after accepting a resubscribe request. */ -export const zPartnerUsageRequest = z.object({ - workspace_id: z.string().min(1), - user_id: z.string().optional(), - transaction_id: z.string().min(1), - event_type: z.string().min(1), - timestamp: z.string().datetime().optional(), - properties: z.record(z.unknown()).optional() +export const zResubscribeResponse = z.object({ + billing_op_id: z.string(), + message: z.string().optional(), + status: z.enum(['active', 'pending']) }) /** - * Status of an asynchronous billing operation. + * Request body for reactivating a previously cancelled subscription. */ -export const zBillingOpStatusResponse = z.object({ - id: z.string(), - status: z.enum(['pending', 'succeeded', 'failed']), - error_message: z.string().optional(), - started_at: z.string().datetime(), - completed_at: z.string().datetime().optional() +export const zResubscribeRequest = z.object({ + idempotency_key: z.string().optional() }) /** - * Response after successfully purchasing a credit top-up. + * Response after a queue management action (delete or clear). */ -export const zCreateTopupResponse = z.object({ - billing_op_id: z.string(), - topup_id: z.string(), - status: z.enum(['pending', 'completed', 'failed']), - amount_cents: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }) +export const zQueueManageResponse = z.object({ + cleared: z.boolean().optional(), + deleted: z.array(z.string()).optional() }) /** - * Request body for purchasing a one-time credit top-up. + * Request to manage queue operations */ -export const zCreateTopupRequest = z.object({ - amount_cents: z.coerce - .bigint() - .gte(BigInt(500)) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }), - idempotency_key: z.string().optional() +export const zQueueManageRequest = z.object({ + clear: z.boolean().optional(), + delete: z.array(z.string()).optional() }) /** - * Response containing a redirect URL to the payment portal. + * Queue information with pending and running jobs */ -export const zPaymentPortalResponse = z.object({ - url: z.string() +export const zQueueInfo = z.object({ + queue_pending: z + .array( + z.tuple([z.unknown(), z.unknown(), z.unknown(), z.unknown(), z.unknown()]) + ) + .optional(), + queue_running: z + .array( + z.tuple([z.unknown(), z.unknown(), z.unknown(), z.unknown(), z.unknown()]) + ) + .optional() }) /** - * Request body for generating a payment portal session URL. + * Full detail of a publicly published workflow on the Hub. */ -export const zPaymentPortalRequest = z.object({ - return_url: z.string().optional() +export const zPublishedWorkflowDetail = z.object({ + assets: z.array(zAssetInfo), + listed: z.boolean(), + name: z.string(), + publish_time: z.string().datetime().nullish(), + share_id: z.string(), + workflow_id: z.string(), + workflow_json: z.record(z.unknown()) }) /** - * Response after accepting a resubscribe request. + * Request body for publishing workflow assets to the Hub. */ -export const zResubscribeResponse = z.object({ - billing_op_id: z.string(), - status: z.enum(['active', 'pending']), - message: z.string().optional() +export const zPublishWorkflowAssetsRequest = z.object({ + asset_ids: z.array(z.string()) }) /** - * Request body for reactivating a previously cancelled subscription. + * Request body for publishing or updating a workflow on the Hub. */ -export const zResubscribeRequest = z.object({ - idempotency_key: z.string().optional() +export const zPublishHubWorkflowRequest = z.object({ + asset_ids: z.array(z.string()), + custom_nodes: z.array(z.string()).optional(), + description: z.string().optional(), + metadata: z.record(z.unknown()).optional(), + models: z.array(z.string()).optional(), + name: z.string(), + sample_image_tokens_or_urls: z.array(z.string()).optional(), + tags: z.array(z.string()).optional(), + thumbnail_comparison_token_or_url: z.string().optional(), + thumbnail_token_or_url: z.string().optional(), + thumbnail_type: z.enum(['image', 'video', 'image_comparison']).optional(), + tutorial_url: z.string().optional(), + username: z.string(), + workflow_filename: z.string() }) /** - * Response after successfully cancelling a subscription. + * Response returned after successfully queuing a workflow prompt. */ -export const zCancelSubscriptionResponse = z.object({ - billing_op_id: z.string(), - cancel_at: z.string().datetime() +export const zPromptResponse = z.object({ + node_errors: z.record(z.unknown()).optional(), + number: z.number().optional(), + prompt_id: z.string().uuid().optional() }) /** - * Request body for cancelling the current subscription. + * Request body for submitting a ComfyUI workflow prompt for execution. */ -export const zCancelSubscriptionRequest = z.object({ - idempotency_key: z.string().optional() +export const zPromptRequest = z.object({ + extra_data: z.record(z.unknown()).optional(), + front: z.boolean().optional(), + number: z.number().optional(), + partial_execution_targets: z.array(z.string()).optional(), + prompt: z.record(z.unknown()), + workflow_id: z.string().optional(), + workflow_version_id: z.string().optional() }) /** - * Response after successfully subscribing to a billing plan. + * Metadata about the currently running and queued prompts. */ -export const zSubscribeResponse = z.object({ - billing_op_id: z.string(), - status: z.enum(['subscribed', 'needs_payment_method', 'pending_payment']), - effective_at: z.string().datetime().optional(), - payment_method_url: z.string().optional() +export const zPromptInfo = z.object({ + exec_info: z + .object({ + queue_remaining: z.number().int().optional() + }) + .optional() }) /** - * Request body for subscribing a workspace to a billing plan. + * Error response for ComfyUI prompt execution. */ -export const zSubscribeRequest = z.object({ - plan_slug: z.string(), - team_credit_stop_id: z.string().optional(), - billing_cycle: z.enum(['monthly', 'yearly']).optional(), - idempotency_key: z.string().optional(), - return_url: z.string().optional(), - cancel_url: z.string().optional() -}) +export const zPromptErrorResponse = z.record(z.unknown()) /** * Summary of seat costs based on current workspace members @@ -629,31 +625,11 @@ export const zPlanSeatSummary = z.object({ }) }) -/** - * Billing period (uppercase to match comfy-api) - */ -export const zSubscriptionDuration = z.enum(['MONTHLY', 'ANNUAL']) - -/** - * Subscription tier (uppercase to match comfy-api) - */ -export const zSubscriptionTier = z.enum([ - 'FREE', - 'STANDARD', - 'CREATOR', - 'PRO', - 'FOUNDERS_EDITION', - 'TEAM' -]) - /** * Plan information for preview display */ export const zPreviewPlanInfo = z.object({ - slug: z.string(), - tier: zSubscriptionTier, - duration: zSubscriptionDuration, - price_cents: z.coerce + credits_cents: z.coerce .bigint() .min(BigInt('-9223372036854775808'), { message: 'Invalid value: Expected int64 to be >= -9223372036854775808' @@ -661,7 +637,10 @@ export const zPreviewPlanInfo = z.object({ .max(BigInt('9223372036854775807'), { message: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), - credits_cents: z.coerce + duration: zSubscriptionDuration, + period_end: z.string().datetime().optional(), + period_start: z.string().datetime().optional(), + price_cents: z.coerce .bigint() .min(BigInt('-9223372036854775808'), { message: 'Invalid value: Expected int64 to be >= -9223372036854775808' @@ -670,8 +649,8 @@ export const zPreviewPlanInfo = z.object({ message: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), seat_summary: zPlanSeatSummary, - period_start: z.string().datetime().optional(), - period_end: z.string().datetime().optional() + slug: z.string(), + tier: zSubscriptionTier }) /** @@ -679,16 +658,7 @@ export const zPreviewPlanInfo = z.object({ */ export const zPreviewSubscribeResponse = z.object({ allowed: z.boolean(), - reason: z.string().optional(), - transition_type: z.enum([ - 'new_subscription', - 'upgrade', - 'downgrade', - 'duration_change' - ]), - effective_at: z.string().datetime(), - is_immediate: z.boolean(), - cost_today_cents: z.coerce + cost_next_period_cents: z.coerce .bigint() .min(BigInt('-9223372036854775808'), { message: 'Invalid value: Expected int64 to be >= -9223372036854775808' @@ -696,7 +666,7 @@ export const zPreviewSubscribeResponse = z.object({ .max(BigInt('9223372036854775807'), { message: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), - cost_next_period_cents: z.coerce + cost_today_cents: z.coerce .bigint() .min(BigInt('-9223372036854775808'), { message: 'Invalid value: Expected int64 to be >= -9223372036854775808' @@ -704,7 +674,7 @@ export const zPreviewSubscribeResponse = z.object({ .max(BigInt('9223372036854775807'), { message: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), - credits_today_cents: z.coerce + credits_next_period_cents: z.coerce .bigint() .min(BigInt('-9223372036854775808'), { message: 'Invalid value: Expected int64 to be >= -9223372036854775808' @@ -712,7 +682,7 @@ export const zPreviewSubscribeResponse = z.object({ .max(BigInt('9223372036854775807'), { message: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), - credits_next_period_cents: z.coerce + credits_today_cents: z.coerce .bigint() .min(BigInt('-9223372036854775808'), { message: 'Invalid value: Expected int64 to be >= -9223372036854775808' @@ -721,7 +691,16 @@ export const zPreviewSubscribeResponse = z.object({ message: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), current_plan: zPreviewPlanInfo.optional(), - new_plan: zPreviewPlanInfo + effective_at: z.string().datetime(), + is_immediate: z.boolean(), + new_plan: zPreviewPlanInfo, + reason: z.string().optional(), + transition_type: z.enum([ + 'new_subscription', + 'upgrade', + 'downgrade', + 'duration_change' + ]) }) /** @@ -732,10 +711,30 @@ export const zPreviewSubscribeRequest = z.object({ }) /** - * Pre/post-discount price for a team credit stop, in cents. + * Reason why a plan is unavailable */ -export const zTeamCreditStopPrice = z.object({ - list_price_cents: z.coerce +export const zPlanAvailabilityReason = z.enum([ + 'same_plan', + 'incompatible_transition', + 'requires_team', + 'requires_personal', + 'exceeds_max_seats' +]) + +/** + * Availability and eligibility information for a billing plan. + */ +export const zPlanAvailability = z.object({ + available: z.boolean(), + reason: zPlanAvailabilityReason.optional() +}) + +/** + * Billing plan details including pricing, limits, and features. + */ +export const zPlan = z.object({ + availability: zPlanAvailability, + credits_cents: z.coerce .bigint() .min(BigInt('-9223372036854775808'), { message: 'Invalid value: Expected int64 to be >= -9223372036854775808' @@ -743,88 +742,79 @@ export const zTeamCreditStopPrice = z.object({ .max(BigInt('9223372036854775807'), { message: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), - price_cents: z.coerce + duration: zSubscriptionDuration, + max_seats: z.coerce .bigint() .min(BigInt('-9223372036854775808'), { message: 'Invalid value: Expected int64 to be >= -9223372036854775808' }) .max(BigInt('9223372036854775807'), { message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }), + price_cents: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }), + seat_summary: zPlanSeatSummary, + slug: z.string(), + tier: zSubscriptionTier }) /** - * A selectable preset on the team pricing slider. Echoed on subscribe via - * team_credit_stop_id; the backend owns the resolved amounts. credits is a - * RAW monthly credit count (not cents). Save% is derived by the FE as - * (list_price_cents - price_cents) / list_price_cents. - * + * An outstanding workspace invitation that has not yet been accepted. */ -export const zTeamCreditStop = z.object({ +export const zPendingInvite = z.object({ + email: z.string().email(), + expires_at: z.string().datetime(), id: z.string(), - credits: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }), - monthly: zTeamCreditStopPrice, - yearly: zTeamCreditStopPrice + invited_at: z.string().datetime(), + token: z.string().optional() }) /** - * Credit-stop ladder for the pricing slider (BE-1254). Returned by GET /api/billing/plans for every workspace regardless of the caller's token or workspace type (the personal/team distinction was removed); omitted only when the catalog defines no stops. + * Response containing a redirect URL to the payment portal. */ -export const zTeamCreditStops = z.object({ - default_stop_index: z.number().int(), - stops: z.array(zTeamCreditStop) +export const zPaymentPortalResponse = z.object({ + url: z.string() }) /** - * Reason why a plan is unavailable + * Request body for generating a payment portal session URL. */ -export const zPlanAvailabilityReason = z.enum([ - 'same_plan', - 'incompatible_transition', - 'requires_team', - 'requires_personal', - 'exceeds_max_seats' -]) +export const zPaymentPortalRequest = z.object({ + return_url: z.string().optional() +}) /** - * Availability and eligibility information for a billing plan. + * RFC 6749 §5.1 successful token response. */ -export const zPlanAvailability = z.object({ - available: z.boolean(), - reason: zPlanAvailabilityReason.optional() +export const zOAuthTokenResponse = z.object({ + access_token: z.string(), + expires_in: z.number().int(), + refresh_token: z.string(), + scope: z.string(), + token_type: z.enum(['Bearer']) }) /** - * Billing plan details including pricing, limits, and features. + * RFC 6749 §5.2 error response. */ -export const zPlan = z.object({ - slug: z.string(), - tier: zSubscriptionTier, - duration: zSubscriptionDuration, - price_cents: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }), - credits_cents: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }), - max_seats: z.coerce +export const zOAuthTokenError = z.object({ + error: z.string(), + error_description: z.string().optional() +}) + +/** + * RFC 7591 §3.2.1 successful registration response. + */ +export const zOAuthRegisterResponse = z.object({ + application_type: z.enum(['native', 'web']), + client_id: z.string(), + client_id_issued_at: z.coerce .bigint() .min(BigInt('-9223372036854775808'), { message: 'Invalid value: Expected int64 to be >= -9223372036854775808' @@ -832,654 +822,806 @@ export const zPlan = z.object({ .max(BigInt('9223372036854775807'), { message: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), - availability: zPlanAvailability, - seat_summary: zPlanSeatSummary + client_name: z.string().optional(), + grant_types: z.array(z.string()), + redirect_uris: z.array(z.string()), + response_types: z.array(z.string()), + token_endpoint_auth_method: z.enum(['none']) }) /** - * List of available billing plans for subscription. + * RFC 7591 §2 client metadata document. Only the fields the server honors are listed; presence of `scope` or `resource_grants` in the request is rejected (`invalid_client_metadata`) because those are server-owned for dynamic clients. `additionalProperties: false` mirrors the runtime middleware that rejects any unknown metadata key. + * */ -export const zBillingPlansResponse = z.object({ - current_plan_slug: z.string().optional(), - plans: z.array(zPlan), - team_credit_stops: zTeamCreditStops.optional() +export const zOAuthRegisterRequest = z.object({ + application_type: z.enum(['native', 'web']).optional(), + client_name: z.string().max(100).optional(), + client_uri: z.string().nullish(), + contacts: z.array(z.string()).nullish(), + grant_types: z + .array(z.enum(['authorization_code', 'refresh_token'])) + .optional(), + jwks: z.record(z.unknown()).nullish(), + jwks_uri: z.string().nullish(), + logo_uri: z.string().nullish(), + policy_uri: z.string().nullish(), + redirect_uris: z.array(z.string()).min(1).max(5), + resource_grants: z.record(z.array(z.string())).nullish(), + response_types: z.array(z.enum(['code'])).optional(), + scope: z.string().nullish(), + software_id: z.string().nullish(), + software_version: z.string().nullish(), + token_endpoint_auth_method: z.enum(['none']).optional(), + tos_uri: z.string().nullish() }) /** - * The team credit stop a workspace is currently subscribed to: the - * per-workspace slider choice recorded at subscribe time - * (workspace_subscriptions.team_credit_stop_id). Amounts are owned by the - * catalog, not the subscription row. Returned on GET /api/billing/status - * for per-credit Team plans (BE-1254). - * + * RFC 7591 §3.2.2 error response. */ -export const zTeamCreditStopSummary = z.object({ - id: z.string(), - credits_monthly: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }), - stop_usd: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }) +export const zOAuthRegisterError = z.object({ + error: z.enum(['invalid_redirect_uri', 'invalid_client_metadata']), + error_description: z.string().nullish() }) /** - * A provider the user may configure a secret for. The shape is deliberately minimal (identifier only) and reserved for future per-provider fields such as sub-keys. + * Standard error response with a machine-readable code and human-readable message. */ -export const zSecretProvider = z.object({ - id: z.string() +export const zErrorResponse = z.object({ + code: z.string(), + details: z.record(z.unknown()).optional(), + message: z.string() }) /** - * The providers available to the authenticated user in the current workspace. + * Union of the two 400 shapes /oauth/register can emit. `OAuthRegisterError` is the handler-shaped RFC 7591 §3.2.2 error; `ErrorResponse` is the strict-server binding-layer error fired when the request body fails OpenAPI-schema validation before the handler runs, normalized to the standard {code, message} shape by the custom Echo HTTPErrorHandler (BE-1178). + * */ -export const zSecretProvidersResponse = z.object({ - data: z.array(zSecretProvider) -}) +export const zOAuthRegisterBadRequestResponse = z.union([ + zOAuthRegisterError, + zErrorResponse +]) /** - * User secret metadata (the secret value itself is never returned after creation). + * OAuth 2.1 protected-resource metadata (RFC 9728). */ -export const zSecretResponse = z.object({ - id: z.string().uuid(), - name: z.string(), - provider: z.string().optional(), - last_used_at: z.string().datetime().optional(), - created_at: z.string().datetime(), - updated_at: z.string().datetime() +export const zOAuthProtectedResourceMetadata = z.object({ + authorization_servers: z.array(z.string().url()), + bearer_methods_supported: z.array(z.string()).optional(), + resource: z.string().url(), + scopes_supported: z.array(z.string()) }) /** - * List of user secrets with metadata only. + * One workspace option presented in the OAuth consent challenge. Promoted to a named schema so the generated Go type is referenceable in handlers and tests rather than re-declared as an anonymous struct at every callsite. + * */ -export const zSecretListResponse = z.object({ - data: z.array(zSecretResponse) +export const zOAuthConsentChallengeWorkspace = z.object({ + id: z.string(), + name: z.string(), + role: z.enum(['owner', 'member']), + type: z.enum(['personal', 'team']) }) /** - * Request body for updating an existing user secret. + * Server-side state describing the OAuth consent decision the user is being asked to make. Returned by GET /oauth/authorize when a valid Cloud session exists; the frontend renders the consent UI from this payload and POSTs the decision back. Browser never sees the original OAuth params on resume. + * */ -export const zUpdateSecretRequest = z.object({ - name: z.string().min(1).max(255).optional(), - secret_value: z.string().min(1).optional() +export const zOAuthConsentChallenge = z.object({ + client_display_name: z.string(), + csrf_token: z.string(), + oauth_request_id: z.string().uuid(), + redirect_uri: z.string().url(), + resource_display_name: z.string(), + scopes: z.array(z.string()), + workspaces: z.array(zOAuthConsentChallengeWorkspace) }) /** - * Request body for creating a new user secret. + * Redirect target produced after a JSON consent submission. The frontend must navigate the browser to this URL so custom-scheme client callbacks work without relying on fetch-visible 302 headers. */ -export const zCreateSecretRequest = z.object({ - name: z.string().min(1).max(255), - provider: z.string().max(64).optional(), - secret_value: z.string().min(1) +export const zOAuthAuthorizeRedirectResponse = z.object({ + redirect_url: z.string().url() }) /** - * A single history event. The cloud history-events store is the single source of truth for both billing events (charges, credits, adjustments) and user-facing usage events. + * OAuth 2.1 authorization-server metadata (RFC 8414). */ -export const zBillingEvent = z.object({ - event_type: z.string(), - event_id: z.string(), - params: z.record(z.unknown()).optional(), - createdAt: z.string().datetime() +export const zOAuthAuthorizationServerMetadata = z.object({ + authorization_endpoint: z.string().url(), + code_challenge_methods_supported: z.array(z.string()), + grant_types_supported: z.array(z.string()), + issuer: z.string().url(), + jwks_uri: z.string().url(), + registration_endpoint: z.string().url().optional(), + response_types_supported: z.array(z.string()), + scopes_supported: z.array(z.string()).optional(), + token_endpoint: z.string().url(), + token_endpoint_auth_methods_supported: z.array(z.string()) }) /** - * Paginated list of billing events for a workspace. + * Metadata describing a single ComfyUI node type and its inputs/outputs. */ -export const zBillingEventsResponse = z.object({ - total: z.number().int(), - events: z.array(zBillingEvent), - page: z.number().int(), - limit: z.number().int(), - totalPages: z.number().int() +export const zNodeInfo = z.object({ + api_node: z.boolean().optional(), + category: z.string().optional(), + deprecated: z.boolean().optional(), + description: z.string().optional(), + display_name: z.string().optional(), + experimental: z.boolean().optional(), + input: z.record(z.unknown()).optional(), + input_order: z.record(z.array(z.string())).optional(), + name: z.string().optional(), + output: z.array(z.string()).optional(), + output_is_list: z.array(z.boolean()).optional(), + output_name: z.array(z.string()).optional(), + output_node: z.boolean().optional(), + output_tooltips: z.array(z.string()).optional(), + python_module: z.string().optional() }) /** - * Current credit balance and usage details for a workspace. + * Represents a folder containing models */ -export const zBillingBalanceResponse = z.object({ - amount_micros: z.number(), - prepaid_balance_micros: z.number().optional(), - cloud_credit_balance_micros: z.number().optional(), - pending_charges_micros: z.number().optional(), - effective_balance_micros: z.number().optional(), - currency: z.string() +export const zModelFolder = z.object({ + folders: z.array(z.string()), + name: z.string() }) /** - * Payment lifecycle status + * Represents a model file with metadata */ -export const zBillingStatus = z.enum([ - 'awaiting_payment_method', - 'pending_payment', - 'paid', - 'payment_failed', - 'inactive' -]) +export const zModelFile = z.object({ + name: z.string(), + pathIndex: z.number().int() +}) /** - * Current billing and subscription status for a workspace. - */ -export const zBillingStatusResponse = z.object({ - is_active: z.boolean(), - subscription_status: z.enum(['active', 'ended', 'canceled']).optional(), - subscription_tier: zSubscriptionTier.optional(), - subscription_duration: zSubscriptionDuration.optional(), - plan_slug: z.string().optional(), - billing_status: zBillingStatus.optional(), - has_funds: z.boolean(), - cancel_at: z.string().datetime().optional(), - renewal_date: z.string().datetime().optional(), - team_credit_stop: zTeamCreditStopSummary.nullable() -}) - -/** - * A single JSON Web Key entry within a JWKS response. - */ -export const zJwkKey = z.object({ - kty: z.string(), - crv: z.string(), - kid: z.string(), - use: z.string(), - alg: z.string(), - x: z.string(), - y: z.string() -}) - -/** - * RFC 6749 §5.2 error response. - */ -export const zOAuthTokenError = z.object({ - error: z.string(), - error_description: z.string().optional() -}) - -/** - * RFC 6749 §5.1 successful token response. - */ -export const zOAuthTokenResponse = z.object({ - access_token: z.string(), - token_type: z.enum(['Bearer']), - expires_in: z.number().int(), - refresh_token: z.string(), - scope: z.string() -}) - -/** - * One workspace option presented in the OAuth consent challenge. Promoted to a named schema so the generated Go type is referenceable in handlers and tests rather than re-declared as an anonymous struct at every callsite. - * + * Workspace member with profile and role information. */ -export const zOAuthConsentChallengeWorkspace = z.object({ +export const zMember = z.object({ + email: z.string().email(), id: z.string(), + is_original_owner: z.boolean(), + joined_at: z.string().datetime(), name: z.string(), - type: z.enum(['personal', 'team']), role: z.enum(['owner', 'member']) }) /** - * Redirect target produced after a JSON consent submission. The frontend must navigate the browser to this URL so custom-scheme client callbacks work without relying on fetch-visible 302 headers. + * Paginated list of workspaces the authenticated user belongs to. */ -export const zOAuthAuthorizeRedirectResponse = z.object({ - redirect_url: z.string().url() +export const zListWorkspacesResponse = z.object({ + workspaces: z.array(zWorkspaceWithRole) }) /** - * Server-side state describing the OAuth consent decision the user is being asked to make. Returned by GET /oauth/authorize when a valid Cloud session exists; the frontend renders the consent UI from this payload and POSTs the decision back. Browser never sees the original OAuth params on resume. - * + * List of API keys associated with the current workspace. */ -export const zOAuthConsentChallenge = z.object({ - oauth_request_id: z.string().uuid(), - csrf_token: z.string(), - client_display_name: z.string(), - resource_display_name: z.string(), - redirect_uri: z.string().url(), - scopes: z.array(z.string()), - workspaces: z.array(zOAuthConsentChallengeWorkspace) +export const zListWorkspaceApiKeysResponse = z.object({ + api_keys: z.array(zWorkspaceApiKeyInfo) }) /** - * OAuth 2.1 protected-resource metadata (RFC 9728). + * Paginated list of available asset tags. */ -export const zOAuthProtectedResourceMetadata = z.object({ - resource: z.string().url(), - authorization_servers: z.array(z.string().url()), - scopes_supported: z.array(z.string()), - bearer_methods_supported: z.array(z.string()).optional() +export const zListTagsResponse = z.object({ + has_more: z.boolean(), + tags: z.array(zTagInfo), + total: z.number().int() }) /** - * RFC 7591 §3.2.2 error response. + * List of members in the current workspace. */ -export const zOAuthRegisterError = z.object({ - error: z.enum(['invalid_redirect_uri', 'invalid_client_metadata']), - error_description: z.string().nullish() +export const zListMembersResponse = z.object({ + members: z.array(zMember), + pagination: zPaginationInfo }) /** - * Standard error response with a machine-readable code and human-readable message. + * List of pending invitations for the current workspace. */ -export const zErrorResponse = z.object({ - code: z.string(), - message: z.string(), - details: z.record(z.unknown()).optional() +export const zListInvitesResponse = z.object({ + invites: z.array(zPendingInvite) }) /** - * Union of the two 400 shapes /oauth/register can emit. `OAuthRegisterError` is the handler-shaped RFC 7591 §3.2.2 error; `ErrorResponse` is the strict-server binding-layer error fired when the request body fails OpenAPI-schema validation before the handler runs, normalized to the standard {code, message} shape by the custom Echo HTTPErrorHandler (BE-1178). - * - */ -export const zOAuthRegisterBadRequestResponse = z.union([ - zOAuthRegisterError, - zErrorResponse -]) - -/** - * RFC 7591 §3.2.1 successful registration response. + * Represents a user-owned asset (image, video, or other generated output). */ -export const zOAuthRegisterResponse = z.object({ - client_id: z.string(), - client_id_issued_at: z.coerce +export const zAsset = z.object({ + created_at: z.string().datetime(), + display_name: z.string().nullish(), + file_path: z.string().nullish(), + hash: z + .string() + .regex(/^blake3:[a-f0-9]{64}$/) + .optional(), + id: z.string().uuid(), + is_immutable: z.boolean().optional(), + job_id: z.string().uuid().nullish(), + last_access_time: z.string().datetime().optional(), + metadata: z.record(z.unknown()).readonly().optional(), + mime_type: z.string().optional(), + name: z.string(), + preview_id: z.string().uuid().nullish(), + preview_url: z.string().url().optional(), + short_url: z.string().nullish(), + size: z.coerce .bigint() .min(BigInt('-9223372036854775808'), { message: 'Invalid value: Expected int64 to be >= -9223372036854775808' }) .max(BigInt('9223372036854775807'), { message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }), - client_name: z.string().optional(), - redirect_uris: z.array(z.string()), - grant_types: z.array(z.string()), - response_types: z.array(z.string()), - token_endpoint_auth_method: z.enum(['none']), - application_type: z.enum(['native', 'web']) -}) - -/** - * RFC 7591 §2 client metadata document. Only the fields the server honors are listed; presence of `scope` or `resource_grants` in the request is rejected (`invalid_client_metadata`) because those are server-owned for dynamic clients. `additionalProperties: false` mirrors the runtime middleware that rejects any unknown metadata key. - * - */ -export const zOAuthRegisterRequest = z.object({ - redirect_uris: z.array(z.string()).min(1).max(5), - client_name: z.string().max(100).optional(), - application_type: z.enum(['native', 'web']).optional(), - token_endpoint_auth_method: z.enum(['none']).optional(), - grant_types: z - .array(z.enum(['authorization_code', 'refresh_token'])) + }) .optional(), - response_types: z.array(z.enum(['code'])).optional(), - scope: z.string().nullish(), - resource_grants: z.record(z.array(z.string())).nullish(), - client_uri: z.string().nullish(), - logo_uri: z.string().nullish(), - tos_uri: z.string().nullish(), - policy_uri: z.string().nullish(), - software_id: z.string().nullish(), - software_version: z.string().nullish(), - contacts: z.array(z.string()).nullish(), - jwks: z.record(z.unknown()).nullish(), - jwks_uri: z.string().nullish() + tags: z.array(z.string()).optional(), + updated_at: z.string().datetime(), + user_metadata: z.record(z.unknown()).optional() }) /** - * OAuth 2.1 authorization-server metadata (RFC 8414). + * Paginated list of assets belonging to the authenticated user. */ -export const zOAuthAuthorizationServerMetadata = z.object({ - issuer: z.string().url(), - authorization_endpoint: z.string().url(), - token_endpoint: z.string().url(), - jwks_uri: z.string().url(), - registration_endpoint: z.string().url().optional(), - response_types_supported: z.array(z.string()), - grant_types_supported: z.array(z.string()), - code_challenge_methods_supported: z.array(z.string()), - token_endpoint_auth_methods_supported: z.array(z.string()), - scopes_supported: z.array(z.string()).optional() +export const zListAssetsResponse = z.object({ + assets: z.array(zAsset), + has_more: z.boolean(), + next_cursor: z.string().optional(), + total: z.number().int() }) /** - * JSON Web Key Set containing the public keys used to verify Cloud JWTs. + * Reference to a Hub label by ID. */ -export const zJwksResponse = z.object({ - keys: z.array(zJwkKey) +export const zLabelRef = z.object({ + display_name: z.string(), + name: z.string() }) /** - * Response after synchronizing an API key into the local database. + * A single JSON Web Key entry within a JWKS response. */ -export const zSyncApiKeyResponse = z.object({ - result: z.enum(['revoked', 'already_revoked', 'no_op']) +export const zJwkKey = z.object({ + alg: z.string(), + crv: z.string(), + kid: z.string(), + kty: z.string(), + use: z.string(), + x: z.string(), + y: z.string() }) /** - * Request body for synchronizing an API key from the external registry. + * JSON Web Key Set containing the public keys used to verify Cloud JWTs. */ -export const zSyncApiKeyRequest = z.object({ - event: z.enum(['delete']), - key_hash: z.string().regex(/^[0-9a-fA-F]{64}$/), - customer_id: z.string().min(1) +export const zJwksResponse = z.object({ + keys: z.array(zJwkKey) }) /** - * The personal workspace's provisioned billing identity. + * Detailed execution error information from ComfyUI */ -export const zEnsureWorkspaceBillingProvisionedResponse = z.object({ - workspace_id: z.string(), - stripe_customer_id: z.string(), - metronome_customer_id: z.string(), - metronome_contract_id: z.string() +export const zExecutionError = z.object({ + current_inputs: z.record(z.unknown()), + current_outputs: z.record(z.unknown()), + exception_message: z.string(), + exception_type: z.string(), + node_id: z.string(), + node_type: z.string(), + traceback: z.array(z.string()) }) /** - * The caller's already-resolved legacy (comfy-api) customer identity. When - * present and carrying provider IDs, provisioning ATTACHES this identity to - * the personal workspace (sharing the existing balance and subscription) - * instead of minting a net-new empty customer. Omit (or send with no - * provider IDs) for a free user with nothing to attach — provisioning then - * creates net-new. This closes the create-new-before-attach gap: a caller - * that already knows the legacy identity hands it over so the very first - * provisioning is an attach. - * + * Lightweight job data for list views (workflow and full outputs excluded) */ -export const zEnsureWorkspaceBillingLegacySnapshot = z.object({ - stripe_customer_id: z.string().optional(), - metronome_customer_id: z.string().optional(), - metronome_contract_id: z.string().optional(), - has_funds: z.boolean().optional(), - subscription_tier: z.string().optional(), - legacy_stripe_subscription_id: z.string().optional(), - legacy_comfy_user_id: z.string().optional() +export const zJobEntry = z.object({ + create_time: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }), + execution_end_time: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }) + .optional(), + execution_error: zExecutionError.optional(), + execution_start_time: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }) + .optional(), + id: z.string().uuid(), + outputs_count: z.number().int().optional(), + preview_output: z.record(z.unknown()).optional(), + status: z.enum([ + 'pending', + 'in_progress', + 'completed', + 'failed', + 'cancelled' + ]), + workflow_id: z.string().optional() }) /** - * Request body for ensuring a user's personal workspace carries a fully - * provisioned billing identity. Sent by comfy-api's CreateCustomer (BE-1047) - * with the already canonical-resolved user identity. - * + * Paginated list of jobs for the authenticated user. */ -export const zEnsureWorkspaceBillingProvisionedRequest = z.object({ - user_id: z.string().min(1), - email: z.string().email().min(1), - snapshot: zEnsureWorkspaceBillingLegacySnapshot.optional() +export const zJobsListResponse = z.object({ + jobs: z.array(zJobEntry), + pagination: zPaginationInfo }) /** - * Firebase UIDs linked to the canonical comfy_user_id. Empty list when - * no mappings exist (not an error — callers can treat empty as "unknown - * canonical"). - * + * Response for POST /api/jobs/cancel. */ -export const zListLinkedFirebaseUidsResponse = z.object({ - firebase_uids: z.array(z.string()) +export const zJobsCancelResponse = z.object({ + cancelled: z.array(z.string()) }) /** - * Request body for reverse-looking-up Firebase UIDs linked to a canonical comfy_user_id. + * Request to cancel multiple jobs by ID. */ -export const zListLinkedFirebaseUidsRequest = z.object({ - comfy_user_id: z.string().min(1) +export const zJobsCancelRequest = z.object({ + job_ids: z.array(z.string().uuid()).min(1).max(100) }) /** - * Response confirming the validity and scope of a workspace API key. + * Job status information */ -export const zVerifyApiKeyResponse = z.object({ - user_id: z.string(), - email: z.string(), - name: z.string(), - is_admin: z.boolean(), - workspace_id: z.string(), - workspace_type: z.enum(['personal', 'team']), - role: z.enum(['owner', 'member']), - has_funds: z.boolean(), - is_active: z.boolean(), - permissions: z.array(z.string()) -}) - -/** - * Request body for verifying a workspace API key (admin endpoint). - */ -export const zVerifyApiKeyRequest = z.object({ - api_key: z.string() +export const zJobStatusResponse = z.object({ + assigned_inference: z.string().nullish(), + created_at: z.string().datetime(), + error_message: z.string().nullish(), + id: z.string().uuid(), + last_state_update: z.string().datetime().optional(), + status: z.enum([ + 'waiting_to_dispatch', + 'pending', + 'in_progress', + 'completed', + 'error', + 'cancelled' + ]), + updated_at: z.string().datetime() }) /** - * Response after bulk-revoking API keys for a workspace member. + * Full job details including workflow and outputs */ -export const zBulkRevokeApiKeysResponse = z.object({ - revoked_count: z.number().int().gte(0) +export const zJobDetailResponse = z.object({ + create_time: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }), + execution_error: zExecutionError.optional(), + execution_meta: z.record(z.unknown()).optional(), + execution_status: z.record(z.unknown()).optional(), + id: z.string().uuid(), + outputs: z.record(z.unknown()).optional(), + outputs_count: z.number().int().optional(), + preview_output: z.record(z.unknown()).optional(), + status: z.enum([ + 'pending', + 'in_progress', + 'completed', + 'failed', + 'cancelled' + ]), + update_time: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }), + workflow: z.record(z.unknown()).optional(), + workflow_id: z.string().optional() }) /** - * Metadata for a workspace-scoped API key (secret is never returned). + * Response for POST /api/jobs/{job_id}/cancel. Returned on both fresh cancels and idempotent no-ops. */ -export const zWorkspaceApiKeyInfo = z.object({ - id: z.string().uuid(), - workspace_id: z.string(), - user_id: z.string(), - name: z.string(), - description: z.string().max(5000), - key_prefix: z.string(), - expires_at: z.string().datetime().optional(), - last_used_at: z.string().datetime().optional(), - revoked_at: z.string().datetime().optional(), - created_at: z.string().datetime() +export const zJobCancelResponse = z.object({ + cancelled: z.boolean() }) /** - * List of API keys associated with the current workspace. + * Response after importing published workflow assets. */ -export const zListWorkspaceApiKeysResponse = z.object({ - api_keys: z.array(zWorkspaceApiKeyInfo) +export const zImportPublishedAssetsResponse = z.object({ + assets: z.array(zAssetInfo) }) /** - * Response containing the newly created workspace API key. + * Request body for importing assets from a published workflow. */ -export const zCreateWorkspaceApiKeyResponse = z.object({ - id: z.string().uuid(), - name: z.string(), - description: z.string().max(5000), - key: z.string(), - key_prefix: z.string(), - expires_at: z.string().datetime().optional(), - created_at: z.string().datetime() +export const zImportPublishedAssetsRequest = z.object({ + published_asset_ids: z.array(z.string()), + share_id: z.string().nullish() }) /** - * Request body for creating a new workspace-scoped API key. + * Public workflow status. NULL in the database is represented as pending in API responses. */ -export const zCreateWorkspaceApiKeyRequest = z.object({ - name: z.string(), - description: z.string().max(5000).optional(), - expires_at: z.string().datetime().optional() -}) +export const zHubWorkflowStatus = z.enum([ + 'pending', + 'approved', + 'rejected', + 'deprecated' +]) /** - * Response returned after successfully accepting a workspace invitation. + * Abbreviated Hub profile used in workflow listings. */ -export const zAcceptInviteResponse = z.object({ - workspace_id: z.string(), - workspace_name: z.string() +export const zHubProfileSummary = z.object({ + avatar_url: z.string().optional(), + display_name: z.string().optional(), + username: z.string() }) /** - * Request body for inviting a user to a workspace. + * Entry in the curated workflow template gallery shown on the home page. */ -export const zCreateInviteRequest = z.object({ - email: z.string().email() +export const zHubWorkflowTemplateEntry = z.object({ + contentTemplate: z.string().optional(), + date: z.string().optional(), + description: z.string().optional(), + extendedDescription: z.string().optional(), + faqItems: z + .array( + z.object({ + answer: z.string(), + question: z.string() + }) + ) + .optional(), + howToUse: z.array(z.string()).optional(), + includeOnDistributions: z.array(z.string()).optional(), + io: z + .object({ + inputs: z.array(z.record(z.unknown())).optional(), + outputs: z.array(z.record(z.unknown())).optional() + }) + .optional(), + isEssential: z.boolean().optional(), + logos: z.array(z.record(z.unknown())).optional(), + mediaSubtype: z.string().optional(), + mediaType: z.string().optional(), + metaDescription: z.string().optional(), + models: z.array(z.string()).optional(), + name: z.string(), + openSource: z.boolean().optional(), + profile: zHubProfileSummary.optional(), + requiresCustomNodes: z.array(z.string()).optional(), + searchRank: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }) + .optional(), + shareId: z.string().optional(), + size: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }) + .optional(), + status: zHubWorkflowStatus, + suggestedUseCases: z.array(z.string()).optional(), + tags: z.array(z.string()).optional(), + thumbnailComparisonUrl: z.string().optional(), + thumbnailUrl: z.string().optional(), + thumbnailVariant: z.string().optional(), + title: z.string(), + tutorialUrl: z.string().optional(), + usage: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }) + .optional(), + vram: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }) + .optional() }) /** - * An outstanding workspace invitation that has not yet been accepted. + * Abbreviated Hub workflow metadata used in search and listing results. */ -export const zPendingInvite = z.object({ - id: z.string(), - email: z.string().email(), - token: z.string().optional(), - invited_at: z.string().datetime(), - expires_at: z.string().datetime() +export const zHubWorkflowSummary = z.object({ + custom_nodes: z.array(zLabelRef).optional(), + description: z.string().optional(), + metadata: z.record(z.unknown()).optional(), + models: z.array(zLabelRef).optional(), + name: z.string(), + profile: zHubProfileSummary, + publish_time: z.string().datetime().nullish(), + sample_image_urls: z.array(z.string()).optional(), + share_id: z.string(), + status: zHubWorkflowStatus, + tags: z.array(zLabelRef).optional(), + thumbnail_comparison_url: z.string().optional(), + thumbnail_type: z.enum(['image', 'video', 'image_comparison']).optional(), + thumbnail_url: z.string().optional(), + tutorial_url: z.string().optional() }) /** - * List of pending invitations for the current workspace. + * Full Hub workflow detail including versions, assets, and statistics. */ -export const zListInvitesResponse = z.object({ - invites: z.array(zPendingInvite) +export const zHubWorkflowDetail = z.object({ + assets: z.array(zAssetInfo), + custom_nodes: z.array(zLabelRef).optional(), + description: z.string().optional(), + metadata: z.record(z.unknown()).optional(), + models: z.array(zLabelRef).optional(), + name: z.string(), + profile: zHubProfileSummary, + publish_time: z.string().datetime().nullish(), + sample_image_urls: z.array(z.string()).optional(), + share_id: z.string(), + status: zHubWorkflowStatus, + tags: z.array(zLabelRef).optional(), + thumbnail_comparison_url: z.string().optional(), + thumbnail_type: z.enum(['image', 'video', 'image_comparison']).optional(), + thumbnail_url: z.string().optional(), + tutorial_url: z.string().optional(), + workflow_id: z.string(), + workflow_json: z.record(z.unknown()) }) /** - * Workspace member with profile and role information. + * Paginated list of Hub workflows matching search criteria. */ -export const zMember = z.object({ - id: z.string(), - name: z.string(), - email: z.string().email(), - role: z.enum(['owner', 'member']), - joined_at: z.string().datetime(), - is_original_owner: z.boolean() +export const zHubWorkflowListResponse = z.object({ + next_cursor: z.string().optional(), + workflows: z.array(z.union([zHubWorkflowSummary, zHubWorkflowDetail])) }) /** - * List of members in the current workspace. + * Response indicating whether a Hub username is available. */ -export const zListMembersResponse = z.object({ - members: z.array(zMember), - pagination: zPaginationInfo +export const zHubUsernameCheckResponse = z.object({ + available: z.boolean(), + suggestions: z.array(z.string()).optional(), + username: z.string(), + validation_error: z.string().optional() }) /** - * Request body for changing a workspace member's role. + * Full public profile for a Hub creator. */ -export const zUpdateMemberRoleRequest = z.object({ - role: z.enum(['owner', 'member']) +export const zHubProfile = z.object({ + avatar_url: z.string().optional(), + description: z.string().optional(), + display_name: z.string().optional(), + username: z.string(), + website_urls: z.array(z.string()).optional() }) /** - * Request body for updating an existing workspace's settings. + * Metadata for a single Hub label. */ -export const zUpdateWorkspaceRequest = z.object({ - name: z.string().min(1).max(100).optional() +export const zHubLabelInfo = z.object({ + description: z.string().optional(), + display_name: z.string(), + name: z.string(), + type: z.enum(['tag', 'model', 'custom_node']) }) /** - * Request body for creating a new workspace. + * List of available Hub labels for categorizing workflows. */ -export const zCreateWorkspaceRequest = z.object({ - name: z.string().min(1).max(100) +export const zHubLabelListResponse = z.object({ + labels: z.array(zHubLabelInfo) }) /** - * Workspace entity annotated with the requesting user's role. + * Response containing a signed upload URL and the target asset path. */ -export const zWorkspaceWithRole = z.object({ - id: z.string(), - name: z.string(), - type: z.enum(['personal', 'team']), - role: z.enum(['owner', 'member']), - created_at: z.string().datetime(), - joined_at: z.string().datetime(), - subscription_tier: zSubscriptionTier.optional() +export const zHubAssetUploadUrlResponse = z.object({ + public_url: z.string(), + token: z.string(), + upload_url: z.string() }) /** - * Paginated list of workspaces the authenticated user belongs to. + * Request body for requesting a signed upload URL for a Hub asset. */ -export const zListWorkspacesResponse = z.object({ - workspaces: z.array(zWorkspaceWithRole) +export const zHubAssetUploadUrlRequest = z.object({ + content_type: z.string(), + filename: z.string() }) /** - * Full workspace entity with configuration and ownership details. + * History entry with prompt_id and execution data */ -export const zWorkspace = z.object({ - id: z.string(), - name: z.string(), - type: z.enum(['personal', 'team']), - created_at: z.string().datetime() +export const zHistoryEntry = z.object({ + create_time: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }) + .optional(), + meta: z.record(z.unknown()).optional(), + outputs: z.record(z.unknown()).optional(), + prompt: z + .object({ + extra_data: z.record(z.unknown()).optional(), + priority: z.number().optional(), + prompt_id: z.string().optional() + }) + .optional(), + prompt_id: z.string(), + status: z.record(z.unknown()).optional(), + workflow_id: z.string().optional() }) /** - * Exchange poll result. Pending until the code is redeemed in the browser. + * Execution history response with history array. + * Returns an object with a "history" key containing an array of history entries. + * Each entry includes prompt_id as a property along with execution data. + * */ -export const zDesktopLoginCodeExchangeResponse = z.object({ - status: z.enum(['pending', 'complete']), - custom_token: z.string().optional() +export const zHistoryResponse = z.object({ + history: z.array(zHistoryEntry) }) /** - * Request to exchange a redeemed login code for a custom token. + * Request to manage history operations */ -export const zDesktopLoginCodeExchangeRequest = z.object({ - code: z.string(), - code_verifier: z.string().min(43).max(128) +export const zHistoryManageRequest = z.object({ + clear: z.boolean().optional(), + delete: z.array(z.string()).optional() }) /** - * Result of redeeming a desktop login code. + * History entry with full prompt data */ -export const zDesktopLoginCodeRedeemResponse = z.object({ - status: z.enum(['redeemed']) +export const zHistoryDetailEntry = z.object({ + meta: z.record(z.unknown()).optional(), + outputs: z.record(z.unknown()).optional(), + prompt: z + .object({ + extra_data: z.record(z.unknown()).optional(), + outputs_to_execute: z.array(z.string()).optional(), + priority: z.number().optional(), + prompt: z.record(z.unknown()).optional(), + prompt_id: z.string().optional() + }) + .optional(), + status: z.record(z.unknown()).optional() }) /** - * Request to claim a desktop login code for the authenticated user. + * Detailed execution history response for a specific prompt. + * Returns a dictionary with prompt_id as key and full history data as value. + * */ -export const zDesktopLoginCodeRedeemRequest = z.object({ - code: z.string() +export const zHistoryDetailResponse = z.record(zHistoryDetailEntry) + +/** + * Metadata for a global subgraph blueprint (without full data) + */ +export const zGlobalSubgraphInfo = z.object({ + data: z.string().optional(), + info: z.object({ + node_pack: z.string() + }), + name: z.string(), + source: z.string() }) /** - * A freshly minted desktop login code and its polling parameters. + * Full data for a global subgraph blueprint */ -export const zDesktopLoginCodeCreateResponse = z.object({ - code: z.string(), - expires_in: z.number().int(), - poll_interval: z.number().int() +export const zGlobalSubgraphData = z.object({ + data: z.string(), + info: z.object({ + node_pack: z.string() + }), + name: z.string(), + source: z.string() }) /** - * Request to mint a desktop login code. + * Individual file entry within a full user data response. */ -export const zDesktopLoginCodeCreateRequest = z.object({ - installation_id: z - .string() - .min(8) - .max(128) - .regex(/^[A-Za-z0-9._-]+$/) +export const zGetUserDataResponseFullFile = z.object({ + modified: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' + }) + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }) .optional(), - platform: z.string().min(1).max(32), - app_version: z.string().min(1).max(64), - code_challenge: z.string().min(43).max(128) + path: z.string().optional(), + size: z.number().int().optional() }) /** - * Abbreviated workspace metadata used in list responses. + * List of user data file entries (each with path, size, and modification time) returned when full_info=true. */ -export const zWorkspaceSummary = z.object({ - id: z.string(), - name: z.string(), - type: z.enum(['personal', 'team']) +export const zGetUserDataResponseFull = z.array(zGetUserDataResponseFullFile) + +/** + * Request body for forking an existing workflow into the user's account. + */ +export const zForkWorkflowRequest = z.object({ + name: z.string().optional(), + source_version: z.number().int() +}) + +/** + * Response after submitting feedback + */ +export const zFeedbackResponse = z.record(z.unknown()) + +/** + * Request to submit user feedback + */ +export const zFeedbackRequest = z.object({ + content: z.string().optional(), + metadata: z.record(z.unknown()).optional(), + rating: z.number().int().gte(1).lte(5).optional(), + type: z.enum(['missing_nodes', 'general', 'missing_models']) +}) + +/** + * Response containing a signed download URL for an exported asset archive. + */ +export const zExportDownloadUrlResponse = z.object({ + expires_at: z.string().datetime().optional(), + url: z.string() }) /** * Response containing the issued Cloud JWT and its expiry. */ export const zExchangeTokenResponse = z.object({ - token: z.string(), expires_at: z.string().datetime(), - workspace: zWorkspaceSummary, + permissions: z.array(z.string()), role: z.enum(['owner', 'member']), - permissions: z.array(z.string()) + token: z.string(), + workspace: zWorkspaceSummary }) /** @@ -1493,155 +1635,120 @@ export const zExchangeTokenRequest = z.object({ }) /** - * Full task details including payload and result + * Result of redeeming a desktop login code. */ -export const zTaskResponse = z.object({ - id: z.string().uuid(), - idempotency_key: z.string(), - task_name: z.string(), - payload: z.record(z.unknown()), - status: z.enum(['created', 'running', 'completed', 'failed']), - result: z.record(z.unknown()).optional(), - error_message: z.string().optional(), - create_time: z.string().datetime(), - update_time: z.string().datetime(), - started_at: z.string().datetime().optional(), - completed_at: z.string().datetime().optional() +export const zDesktopLoginCodeRedeemResponse = z.object({ + status: z.enum(['redeemed']) }) /** - * Task data for list views + * Request to claim a desktop login code for the authenticated user. */ -export const zTaskEntry = z.object({ - id: z.string().uuid(), - task_name: z.string(), - status: z.enum(['created', 'running', 'completed', 'failed']), - create_time: z.string().datetime(), - started_at: z.string().datetime().optional(), - completed_at: z.string().datetime().optional() +export const zDesktopLoginCodeRedeemRequest = z.object({ + code: z.string() }) /** - * Paginated list of background tasks for the authenticated user. + * Exchange poll result. Pending until the code is redeemed in the browser. */ -export const zTasksListResponse = z.object({ - tasks: z.array(zTaskEntry), - pagination: zPaginationInfo +export const zDesktopLoginCodeExchangeResponse = z.object({ + custom_token: z.string().optional(), + status: z.enum(['pending', 'complete']) }) /** - * Result of authorizing a legal-hold release on a user's deletion. + * Request to exchange a redeemed login code for a custom token. */ -export const zReleaseHoldResponse = z.object({ - firebase_id: z.string(), - released: z.boolean(), - message: z.string() +export const zDesktopLoginCodeExchangeRequest = z.object({ + code: z.string(), + code_verifier: z.string().min(43).max(128) }) /** - * Current status of a user data deletion request. + * A freshly minted desktop login code and its polling parameters. */ -export const zDeletionStatus = z.object({ - status_name: z.string(), - status_details: z.string() +export const zDesktopLoginCodeCreateResponse = z.object({ + code: z.string(), + expires_in: z.number().int(), + poll_interval: z.number().int() }) /** - * Details of a pending or completed user data deletion request. + * Request to mint a desktop login code. */ -export const zDeletionRequest = z.object({ - id: z.string(), - firebase_id: z.string(), - create_time: z.string().datetime(), - deletion_status: z.array(zDeletionStatus) +export const zDesktopLoginCodeCreateRequest = z.object({ + app_version: z.string().min(1).max(64), + code_challenge: z.string().min(43).max(128), + installation_id: z + .string() + .min(8) + .max(128) + .regex(/^[A-Za-z0-9._-]+$/) + .optional(), + platform: z.string().min(1).max(32) }) /** - * Detailed execution error information from ComfyUI + * Response after deleting a session cookie */ -export const zExecutionError = z.object({ - node_id: z.string(), - node_type: z.string(), - exception_message: z.string(), - exception_type: z.string(), - traceback: z.array(z.string()), - current_inputs: z.record(z.unknown()), - current_outputs: z.record(z.unknown()) +export const zDeleteSessionResponse = z.object({ + success: z.boolean() }) /** - * Full job details including workflow and outputs + * Request body for creating a new workspace. */ -export const zJobDetailResponse = z.object({ +export const zCreateWorkspaceRequest = z.object({ + name: z.string().min(1).max(100) +}) + +/** + * Response containing the newly created workspace API key. + */ +export const zCreateWorkspaceApiKeyResponse = z.object({ + created_at: z.string().datetime(), + description: z.string().max(5000), + expires_at: z.string().datetime().optional(), id: z.string().uuid(), - status: z.enum([ - 'pending', - 'in_progress', - 'completed', - 'failed', - 'cancelled' - ]), - workflow: z.record(z.unknown()).optional(), - execution_error: zExecutionError.optional(), - create_time: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }), - update_time: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }), - outputs: z.record(z.unknown()).optional(), - preview_output: z.record(z.unknown()).optional(), - outputs_count: z.number().int().optional(), - workflow_id: z.string().optional(), - execution_status: z.record(z.unknown()).optional(), - execution_meta: z.record(z.unknown()).optional() + key: z.string(), + key_prefix: z.string(), + name: z.string() }) /** - * Response for POST /api/jobs/cancel. + * Request body for creating a new workspace-scoped API key. */ -export const zJobsCancelResponse = z.object({ - cancelled: z.array(z.string()) +export const zCreateWorkspaceApiKeyRequest = z.object({ + description: z.string().max(5000).optional(), + expires_at: z.string().datetime().optional(), + name: z.string() }) /** - * Request to cancel multiple jobs by ID. + * Request body for creating a new version of a saved workflow. */ -export const zJobsCancelRequest = z.object({ - job_ids: z.array(z.string().uuid()).min(1).max(100) +export const zCreateWorkflowVersionRequest = z.object({ + base_version: z.number().int(), + workflow_json: z.record(z.unknown()) }) /** - * Response for POST /api/jobs/{job_id}/cancel. Returned on both fresh cancels and idempotent no-ops. + * Request body for creating a new saved workflow. */ -export const zJobCancelResponse = z.object({ - cancelled: z.boolean() +export const zCreateWorkflowRequest = z.object({ + default_view: z.enum(['workflow', 'app']).optional(), + description: z.string().optional(), + forked_from_workflow_id: z.string().optional(), + forked_from_workflow_version_id: z.string().optional(), + name: z.string().optional(), + workflow_json: z.record(z.unknown()) }) /** - * Lightweight job data for list views (workflow and full outputs excluded) + * Response after successfully purchasing a credit top-up. */ -export const zJobEntry = z.object({ - id: z.string().uuid(), - status: z.enum([ - 'pending', - 'in_progress', - 'completed', - 'failed', - 'cancelled' - ]), - execution_error: zExecutionError.optional(), - create_time: z.coerce +export const zCreateTopupResponse = z.object({ + amount_cents: z.coerce .bigint() .min(BigInt('-9223372036854775808'), { message: 'Invalid value: Expected int64 to be >= -9223372036854775808' @@ -1649,1225 +1756,405 @@ export const zJobEntry = z.object({ .max(BigInt('9223372036854775807'), { message: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), - preview_output: z.record(z.unknown()).optional(), - outputs_count: z.number().int().optional(), - workflow_id: z.string().optional(), - execution_start_time: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }) - .optional(), - execution_end_time: z.coerce + billing_op_id: z.string(), + status: z.enum(['pending', 'completed', 'failed']), + topup_id: z.string() +}) + +/** + * Request body for purchasing a one-time credit top-up. + */ +export const zCreateTopupRequest = z.object({ + amount_cents: z.coerce .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) + .gte(BigInt(500)) .max(BigInt('9223372036854775807'), { message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }) - .optional() + }), + idempotency_key: z.string().optional() }) /** - * Paginated list of jobs for the authenticated user. + * Response after creating a session cookie */ -export const zJobsListResponse = z.object({ - jobs: z.array(zJobEntry), - pagination: zPaginationInfo +export const zCreateSessionResponse = z.object({ + expiresIn: z.number().int().optional(), + success: z.boolean() }) /** - * Response after adding, updating, or removing tags on an asset. + * Request body for creating a new user secret. */ -export const zTagsModificationResponse = z.object({ - added: z.array(z.string()).optional(), - removed: z.array(z.string()).optional(), - already_present: z.array(z.string()).optional(), - not_present: z.array(z.string()).optional(), - total_tags: z.array(z.string()) +export const zCreateSecretRequest = z.object({ + name: z.string().min(1).max(255), + provider: z.string().max(64).optional(), + secret_value: z.string().min(1) }) /** - * Details of a single validation error encountered during asset operations. + * Request body for inviting a user to a workspace. */ -export const zValidationError = z.object({ - code: z.string(), - message: z.string(), - field: z.string() +export const zCreateInviteRequest = z.object({ + email: z.string().email() }) /** - * Result of validating a set of asset operations. + * Request body for creating a new Hub profile. */ -export const zValidationResult = z.object({ - is_valid: z.boolean(), - errors: z.array(zValidationError).optional(), - warnings: z.array(zValidationError).optional() +export const zCreateHubProfileRequest = z.object({ + avatar_token: z.string().optional(), + description: z.string().optional(), + display_name: z.string().optional(), + username: z.string(), + website_urls: z.array(z.string()).optional(), + workspace_id: z.string() }) /** - * Acknowledgement of an async asset download task; clients poll GET /api/tasks/{task_id} for status. + * Response after successfully cancelling a subscription. */ -export const zAssetDownloadResponse = z.object({ - task_id: z.string().uuid(), - status: z.enum(['created', 'running', 'completed', 'failed']), - message: z.string().optional() +export const zCancelSubscriptionResponse = z.object({ + billing_op_id: z.string(), + cancel_at: z.string().datetime() }) /** - * Metadata for a remotely hosted asset resolved by URL. + * Request body for cancelling the current subscription. */ -export const zAssetMetadataResponse = z.object({ - content_length: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }), - content_type: z.string().optional(), - filename: z.string().optional(), - name: z.string().optional(), - tags: z.array(z.string()).optional(), - preview_image: z.string().optional(), - validation: zValidationResult.optional() +export const zCancelSubscriptionRequest = z.object({ + idempotency_key: z.string().optional() }) /** - * Histogram of tag counts used for refining asset search results. + * Response after bulk-revoking API keys for a workspace member. */ -export const zAssetTagHistogramResponse = z.object({ - tag_counts: z.record(z.number().int()) +export const zBulkRevokeApiKeysResponse = z.object({ + revoked_count: z.number().int().gte(0) }) /** - * Metadata for a single tag that can be applied to assets. + * Payment lifecycle status */ -export const zTagInfo = z.object({ - name: z.string(), - count: z.number().int() +export const zBillingStatus = z.enum([ + 'awaiting_payment_method', + 'pending_payment', + 'paid', + 'payment_failed', + 'inactive' +]) + +/** + * Current billing and subscription status for a workspace. + */ +export const zBillingStatusResponse = z.object({ + billing_status: zBillingStatus.optional(), + cancel_at: z.string().datetime().optional(), + has_funds: z.boolean(), + is_active: z.boolean(), + plan_slug: z.string().optional(), + renewal_date: z.string().datetime().optional(), + subscription_duration: zSubscriptionDuration.optional(), + subscription_status: z.enum(['active', 'ended', 'canceled']).optional(), + subscription_tier: zSubscriptionTier.optional(), + team_credit_stop: zTeamCreditStopSummary.nullable() }) /** - * Paginated list of available asset tags. + * List of available billing plans for subscription. */ -export const zListTagsResponse = z.object({ - tags: z.array(zTagInfo), - total: z.number().int(), - has_more: z.boolean() +export const zBillingPlansResponse = z.object({ + current_plan_slug: z.string().optional(), + plans: z.array(zPlan), + team_credit_stops: zTeamCreditStops.optional() }) /** - * Represents a user-owned asset (image, video, or other generated output). + * Status of an asynchronous billing operation. */ -export const zAsset = z.object({ - id: z.string().uuid(), - name: z.string(), - display_name: z.string().nullish(), - hash: z - .string() - .regex(/^blake3:[a-f0-9]{64}$/) - .optional(), - size: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }) - .optional(), - mime_type: z.string().optional(), - tags: z.array(z.string()).optional(), - user_metadata: z.record(z.unknown()).optional(), - metadata: z.record(z.unknown()).readonly().optional(), - preview_url: z.string().url().optional(), - short_url: z.string().nullish(), - preview_id: z.string().uuid().nullish(), - job_id: z.string().uuid().nullish(), - created_at: z.string().datetime(), - updated_at: z.string().datetime(), - last_access_time: z.string().datetime().optional(), - is_immutable: z.boolean().optional(), - file_path: z.string().nullish() +export const zBillingOpStatusResponse = z.object({ + completed_at: z.string().datetime().optional(), + error_message: z.string().optional(), + id: z.string(), + started_at: z.string().datetime(), + status: z.enum(['pending', 'succeeded', 'failed']) }) /** - * Paginated list of assets belonging to the authenticated user. + * A single history event. The cloud history-events store is the single source of truth for both billing events (charges, credits, adjustments) and user-facing usage events. */ -export const zListAssetsResponse = z.object({ - assets: z.array(zAsset), +export const zBillingEvent = z.object({ + createdAt: z.string().datetime(), + event_id: z.string(), + event_type: z.string(), + params: z.record(z.unknown()).optional() +}) + +/** + * Paginated list of billing events for a workspace. + */ +export const zBillingEventsResponse = z.object({ + events: z.array(zBillingEvent), + limit: z.number().int(), + page: z.number().int(), total: z.number().int(), - has_more: z.boolean(), - next_cursor: z.string().optional() + totalPages: z.number().int() +}) + +/** + * Current credit balance and usage details for a workspace. + */ +export const zBillingBalanceResponse = z.object({ + amount_micros: z.number(), + cloud_credit_balance_micros: z.number().optional(), + currency: z.string(), + effective_balance_micros: z.number().optional(), + pending_charges_micros: z.number().optional(), + prepaid_balance_micros: z.number().optional() }) /** * Response returned when an existing asset is successfully updated. */ export const zAssetUpdated = z.object({ - id: z.string().uuid(), - name: z.string().optional(), display_name: z.string().nullish(), + file_path: z.string().nullish(), hash: z .string() .regex(/^blake3:[a-f0-9]{64}$/) .optional(), - tags: z.array(z.string()).optional(), - mime_type: z.string().optional(), - user_metadata: z.record(z.unknown()).optional(), + id: z.string().uuid(), job_id: z.string().uuid().nullish(), + mime_type: z.string().optional(), + name: z.string().optional(), + tags: z.array(z.string()).optional(), updated_at: z.string().datetime(), - file_path: z.string().nullish() + user_metadata: z.record(z.unknown()).optional() }) /** - * Response returned when a new asset is successfully created. - */ -export const zAssetCreated = zAsset.and( - z.object({ - created_new: z.boolean() - }) -) - -/** - * Response after updating the review status of a Hub workflow. - */ -export const zSetReviewStatusResponse = z.object({ - share_ids: z.array(z.string()), - status: z.enum(['approved', 'rejected']) -}) - -/** - * Request body for setting the review status of a Hub workflow. - */ -export const zSetReviewStatusRequest = z.object({ - share_ids: z.array(z.string()).min(1), - status: z.enum(['approved', 'rejected']) -}) - -/** - * Response after deleting a session cookie - */ -export const zDeleteSessionResponse = z.object({ - success: z.boolean() -}) - -/** - * Response after creating a session cookie - */ -export const zCreateSessionResponse = z.object({ - success: z.boolean(), - expiresIn: z.number().int().optional() -}) - -/** - * User information response - */ -export const zUserResponse = z.object({ - id: z.string(), - status: z.string() -}) - -/** - * System statistics response - */ -export const zSystemStatsResponse = z.object({ - system: z.object({ - os: z.string(), - python_version: z.string(), - embedded_python: z.boolean(), - comfyui_version: z.string(), - deploy_environment: z.string().optional(), - comfyui_frontend_version: z.string().optional(), - workflow_templates_version: z.string().optional(), - cloud_version: z.string().optional(), - pytorch_version: z.string(), - argv: z.array(z.string()), - ram_total: z.number(), - ram_free: z.number() - }), - devices: z.array( - z.object({ - name: z.string(), - type: z.string(), - vram_total: z.number().optional(), - vram_free: z.number().optional() - }) - ) -}) - -/** - * System logs response - */ -export const zLogsResponse = z.array( - z.object({ - timestamp: z.string().datetime().optional(), - level: z.enum(['debug', 'info', 'warn', 'error']).optional(), - message: z.string().optional(), - source: z.string().optional(), - metadata: z.record(z.unknown()).optional() - }) -) - -/** - * Response after submitting feedback - */ -export const zFeedbackResponse = z.record(z.unknown()) - -/** - * Request to submit user feedback - */ -export const zFeedbackRequest = z.object({ - type: z.enum(['missing_nodes', 'general', 'missing_models']), - content: z.string().optional(), - rating: z.number().int().gte(1).lte(5).optional(), - metadata: z.record(z.unknown()).optional() -}) - -/** - * Represents a model file with metadata - */ -export const zModelFile = z.object({ - name: z.string(), - pathIndex: z.number().int() -}) - -/** - * Represents a folder containing models - */ -export const zModelFolder = z.object({ - name: z.string(), - folders: z.array(z.string()) -}) - -/** - * Error response for ComfyUI prompt execution. - */ -export const zPromptErrorResponse = z.record(z.unknown()) - -/** - * Individual file entry within a full user data response. + * Histogram of tag counts used for refining asset search results. */ -export const zGetUserDataResponseFullFile = z.object({ - path: z.string().optional(), - size: z.number().int().optional(), - modified: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }) - .optional() +export const zAssetTagHistogramResponse = z.object({ + tag_counts: z.record(z.number().int()) }) /** - * List of user data file entries (each with path, size, and modification time) returned when full_info=true. - */ -export const zGetUserDataResponseFull = z.array(zGetUserDataResponseFullFile) - -/** - * User data listing entry with file metadata (path, size, modification time). + * Metadata for a remotely hosted asset resolved by URL. */ -export const zUserDataResponseFull = z.object({ - path: z.string().optional(), - size: z.number().int().optional(), - modified: z.coerce +export const zAssetMetadataResponse = z.object({ + content_length: z.coerce .bigint() .min(BigInt('-9223372036854775808'), { message: 'Invalid value: Expected int64 to be >= -9223372036854775808' }) .max(BigInt('9223372036854775807'), { message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }) - .optional() -}) - -/** - * Request to manage history operations - */ -export const zHistoryManageRequest = z.object({ - delete: z.array(z.string()).optional(), - clear: z.boolean().optional() -}) - -/** - * Job status information - */ -export const zJobStatusResponse = z.object({ - id: z.string().uuid(), - status: z.enum([ - 'waiting_to_dispatch', - 'pending', - 'in_progress', - 'completed', - 'error', - 'cancelled' - ]), - created_at: z.string().datetime(), - updated_at: z.string().datetime(), - last_state_update: z.string().datetime().optional(), - assigned_inference: z.string().nullish(), - error_message: z.string().nullish() -}) - -/** - * Response after a queue management action (delete or clear). - */ -export const zQueueManageResponse = z.object({ - deleted: z.array(z.string()).optional(), - cleared: z.boolean().optional() + }), + content_type: z.string().optional(), + filename: z.string().optional(), + name: z.string().optional(), + preview_image: z.string().optional(), + tags: z.array(z.string()).optional(), + validation: zValidationResult.optional() }) /** - * Request to manage queue operations + * Acknowledgement of an async asset download task; clients poll GET /api/tasks/{task_id} for status. */ -export const zQueueManageRequest = z.object({ - delete: z.array(z.string()).optional(), - clear: z.boolean().optional() +export const zAssetDownloadResponse = z.object({ + message: z.string().optional(), + status: z.enum(['created', 'running', 'completed', 'failed']), + task_id: z.string().uuid() }) /** - * Queue information with pending and running jobs + * Response returned when a new asset is successfully created. */ -export const zQueueInfo = z.object({ - queue_running: z - .array( - z.tuple([z.unknown(), z.unknown(), z.unknown(), z.unknown(), z.unknown()]) - ) - .optional(), - queue_pending: z - .array( - z.tuple([z.unknown(), z.unknown(), z.unknown(), z.unknown(), z.unknown()]) - ) - .optional() -}) +export const zAssetCreated = zAsset.and( + z.object({ + created_new: z.boolean() + }) +) /** - * History entry with full prompt data + * Response returned after successfully accepting a workspace invitation. */ -export const zHistoryDetailEntry = z.object({ - prompt: z - .object({ - priority: z.number().optional(), - prompt_id: z.string().optional(), - prompt: z.record(z.unknown()).optional(), - extra_data: z.record(z.unknown()).optional(), - outputs_to_execute: z.array(z.string()).optional() - }) - .optional(), - outputs: z.record(z.unknown()).optional(), - status: z.record(z.unknown()).optional(), - meta: z.record(z.unknown()).optional() +export const zAcceptInviteResponse = z.object({ + workspace_id: z.string(), + workspace_name: z.string() }) /** - * Detailed execution history response for a specific prompt. - * Returns a dictionary with prompt_id as key and full history data as value. - * - */ -export const zHistoryDetailResponse = z.record(zHistoryDetailEntry) - -/** - * History entry with prompt_id and execution data + * Represents a user-owned asset (image, video, or other generated output). */ -export const zHistoryEntry = z.object({ - prompt_id: z.string(), - create_time: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }) - .optional(), - workflow_id: z.string().optional(), - prompt: z - .object({ - priority: z.number().optional(), - prompt_id: z.string().optional(), - extra_data: z.record(z.unknown()).optional() - }) +export const zAssetWritable = z.object({ + created_at: z.string().datetime(), + display_name: z.string().nullish(), + file_path: z.string().nullish(), + hash: z + .string() + .regex(/^blake3:[a-f0-9]{64}$/) .optional(), - outputs: z.record(z.unknown()).optional(), - status: z.record(z.unknown()).optional(), - meta: z.record(z.unknown()).optional() -}) - -/** - * Execution history response with history array. - * Returns an object with a "history" key containing an array of history entries. - * Each entry includes prompt_id as a property along with execution data. - * - */ -export const zHistoryResponse = z.object({ - history: z.array(zHistoryEntry) -}) - -/** - * Full data for a global subgraph blueprint - */ -export const zGlobalSubgraphData = z.object({ - source: z.string(), - name: z.string(), - info: z.object({ - node_pack: z.string() - }), - data: z.string() -}) - -/** - * Metadata for a global subgraph blueprint (without full data) - */ -export const zGlobalSubgraphInfo = z.object({ - source: z.string(), - name: z.string(), - info: z.object({ - node_pack: z.string() - }), - data: z.string().optional() -}) - -/** - * Metadata describing a single ComfyUI node type and its inputs/outputs. - */ -export const zNodeInfo = z.object({ - input: z.record(z.unknown()).optional(), - input_order: z.record(z.array(z.string())).optional(), - output: z.array(z.string()).optional(), - output_is_list: z.array(z.boolean()).optional(), - output_name: z.array(z.string()).optional(), - name: z.string().optional(), - display_name: z.string().optional(), - description: z.string().optional(), - python_module: z.string().optional(), - category: z.string().optional(), - output_node: z.boolean().optional(), - output_tooltips: z.array(z.string()).optional(), - deprecated: z.boolean().optional(), - experimental: z.boolean().optional(), - api_node: z.boolean().optional() -}) - -/** - * Metadata about the currently running and queued prompts. - */ -export const zPromptInfo = z.object({ - exec_info: z - .object({ - queue_remaining: z.number().int().optional() - }) - .optional() -}) - -/** - * Response containing a signed download URL for an exported asset archive. - */ -export const zExportDownloadUrlResponse = z.object({ - url: z.string(), - expires_at: z.string().datetime().optional() -}) - -/** - * Response returned after successfully queuing a workflow prompt. - */ -export const zPromptResponse = z.object({ - prompt_id: z.string().uuid().optional(), - number: z.number().optional(), - node_errors: z.record(z.unknown()).optional() -}) - -/** - * Request body for submitting a ComfyUI workflow prompt for execution. - */ -export const zPromptRequest = z.object({ - prompt: z.record(z.unknown()), - number: z.number().optional(), - front: z.boolean().optional(), - extra_data: z.record(z.unknown()).optional(), - partial_execution_targets: z.array(z.string()).optional(), - workflow_id: z.string().optional(), - workflow_version_id: z.string().optional() -}) - -/** - * Represents a user-owned asset (image, video, or other generated output). - */ -export const zAssetWritable = z.object({ id: z.string().uuid(), - name: z.string(), - display_name: z.string().nullish(), - hash: z - .string() - .regex(/^blake3:[a-f0-9]{64}$/) - .optional(), - size: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }) - .optional(), - mime_type: z.string().optional(), - tags: z.array(z.string()).optional(), - user_metadata: z.record(z.unknown()).optional(), - preview_url: z.string().url().optional(), - short_url: z.string().nullish(), - preview_id: z.string().uuid().nullish(), + is_immutable: z.boolean().optional(), job_id: z.string().uuid().nullish(), - created_at: z.string().datetime(), - updated_at: z.string().datetime(), last_access_time: z.string().datetime().optional(), - is_immutable: z.boolean().optional(), - file_path: z.string().nullish() -}) - -/** - * Paginated list of assets belonging to the authenticated user. - */ -export const zListAssetsResponseWritable = z.object({ - assets: z.array(zAssetWritable), - total: z.number().int(), - has_more: z.boolean(), - next_cursor: z.string().optional() -}) - -/** - * Response returned when a new asset is successfully created. - */ -export const zAssetCreatedWritable = zAssetWritable.and( - z.object({ - created_new: z.boolean() - }) -) - -/** - * Response after submitting feedback - */ -export const zFeedbackResponseWritable = z.record(z.unknown()) - -export const zGetPromptInfoData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z.never().optional() -}) - -/** - * Success - */ -export const zGetPromptInfoResponse = zPromptInfo - -export const zExecutePromptData = z.object({ - body: zPromptRequest, - path: z.never().optional(), - query: z.never().optional() -}) - -/** - * Success - Prompt accepted - */ -export const zExecutePromptResponse = zPromptResponse - -export const zGetNodeInfoData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z.never().optional() -}) - -/** - * Success - */ -export const zGetNodeInfoResponse = z.record(zNodeInfo) - -export const zGetFeaturesData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z.never().optional() -}) - -/** - * Success - */ -export const zGetFeaturesResponse = z.object({ - supports_preview_metadata: z.boolean().optional(), - max_upload_size: z.number().int().optional() -}) - -export const zGetNodeReplacementsData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z.never().optional() -}) - -/** - * Success - Node replacement mappings - */ -export const zGetNodeReplacementsResponse = z.record(z.unknown()) - -export const zGetWorkflowTemplatesData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z.never().optional() -}) - -/** - * Empty object for workflow templates - */ -export const zGetWorkflowTemplatesResponse = z.record(z.unknown()) - -export const zGetGlobalSubgraphsData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z.never().optional() -}) - -/** - * Success - Map of subgraph IDs to their metadata - */ -export const zGetGlobalSubgraphsResponse = z.record(zGlobalSubgraphInfo) - -export const zGetGlobalSubgraphData = z.object({ - body: z.never().optional(), - path: z.object({ - id: z.string() - }), - query: z.never().optional() -}) - -/** - * Success - Full subgraph data - */ -export const zGetGlobalSubgraphResponse = zGlobalSubgraphData - -export const zGetModelFoldersData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z.never().optional() -}) - -/** - * Success - List of model folders - */ -export const zGetModelFoldersResponse = z.array(zModelFolder) - -export const zGetModelsInFolderData = z.object({ - body: z.never().optional(), - path: z.object({ - folder: z.string() - }), - query: z.never().optional() -}) - -/** - * Success - List of models in the folder - */ -export const zGetModelsInFolderResponse = z.array(zModelFile) - -export const zGetLegacyHistoryData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z.never().optional() -}) - -export const zManageHistoryData = z.object({ - body: zHistoryManageRequest, - path: z.never().optional(), - query: z.never().optional() -}) - -export const zGetHistoryData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z - .object({ - max_items: z.number().int().optional(), - offset: z.number().int().optional().default(0) - }) - .optional() -}) - -/** - * Success - Execution history retrieved - */ -export const zGetHistoryResponse = zHistoryResponse - -export const zGetHistoryForPromptData = z.object({ - body: z.never().optional(), - path: z.object({ - prompt_id: z.string() - }), - query: z.never().optional() -}) - -/** - * Success - History for prompt retrieved - */ -export const zGetHistoryForPromptResponse = zHistoryDetailResponse - -export const zListJobsData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z - .object({ - status: z.string().optional(), - workflow_id: z.string().optional(), - output_type: z.enum(['image', 'video', 'audio', '3d']).optional(), - sort_by: z.enum(['create_time', 'execution_time']).optional(), - sort_order: z.enum(['asc', 'desc']).optional(), - after: z.string().optional(), - offset: z.number().int().gte(0).optional().default(0), - limit: z.number().int().gte(1).lte(1000).optional().default(100) - }) - .optional() -}) - -/** - * Success - Jobs retrieved - */ -export const zListJobsResponse = zJobsListResponse - -export const zGetJobDetailData = z.object({ - body: z.never().optional(), - path: z.object({ - job_id: z.string().uuid() - }), - query: z - .object({ - short_link: z.enum(['ephemeral_tool_chain', 'default']).optional() - }) - .optional() -}) - -/** - * Success - Job details retrieved - */ -export const zGetJobDetailResponse = zJobDetailResponse - -export const zCancelJobData = z.object({ - body: z.never().optional(), - path: z.object({ - job_id: z.string().uuid() - }), - query: z.never().optional() -}) - -/** - * Success - Cancel request accepted (or job was already terminal) - */ -export const zCancelJobResponse = zJobCancelResponse - -export const zCancelJobsData = z.object({ - body: zJobsCancelRequest, - path: z.never().optional(), - query: z.never().optional() -}) - -/** - * Success - cancel requests dispatched (or jobs were already terminal) - */ -export const zCancelJobsResponse = zJobsCancelResponse - -export const zViewFileData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z.object({ - filename: z.string(), - subfolder: z.string().optional(), - type: z.string().optional(), - fullpath: z.string().optional(), - format: z.string().optional(), - frame_rate: z.number().int().optional(), - workflow: z.string().optional(), - timestamp: z.number().int().optional(), - channel: z.string().optional(), - res: z.number().int().gte(64).lte(1024).optional() - }) -}) - -/** - * Processed PNG image with extracted channel - */ -export const zViewFileResponse = z.string() - -export const zGetMaskLayersData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z.object({ - filename: z.string() - }) -}) - -/** - * Success - Related mask layers returned - */ -export const zGetMaskLayersResponse = z.object({ - mask: z.string().nullish(), - paint: z.string().nullish(), - painted: z.string().nullish(), - painted_masked: z.string().nullish() -}) - -export const zGetFilesData = z.object({ - body: z.never().optional(), - path: z.object({ - directory_type: z.enum(['output', 'input', 'temp']) - }), - query: z.never().optional() -}) - -/** - * Array of file names sorted by modification time (newest first) - */ -export const zGetFilesResponse = z.array(z.string()) - -export const zListAssetsData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z - .object({ - include_tags: z.array(z.string()).optional(), - exclude_tags: z.array(z.string()).optional(), - name_contains: z.string().optional(), - metadata_filter: z.string().optional(), - limit: z.number().int().gte(1).lte(500).optional().default(20), - offset: z.number().int().gte(0).optional().default(0), - sort: z - .enum(['name', 'created_at', 'updated_at', 'size', 'last_access_time']) - .optional(), - order: z.enum(['asc', 'desc']).optional(), - include_public: z.boolean().optional().default(true), - hash: z.string().optional(), - after: z.string().optional() - }) - .optional() -}) - -/** - * Success - Assets returned - */ -export const zListAssetsResponse2 = zListAssetsResponse - -export const zCreateAssetData = z.object({ - body: z.object({ - file: z.string(), - hash: z - .string() - .regex(/^(blake3|sha256):[a-f0-9]{64}$/) - .optional(), - tags: z.string().optional(), - id: z.string().uuid().optional(), - preview_id: z.string().uuid().optional(), - name: z.string().optional(), - mime_type: z.string().optional(), - user_metadata: z.string().optional() - }), - path: z.never().optional(), - query: z.never().optional() -}) - -/** - * Asset already existed for this user (deduplicated by content hash); the - * existing asset is returned with created_new=false. - * - */ -export const zCreateAssetResponse = zAssetCreated - -export const zCreateAssetFromHashData = z.object({ - body: z.object({ - hash: z.string().regex(/^blake3:[a-f0-9]{64}$/), - name: z.string().optional(), - tags: z.array(z.string()).min(1), - mime_type: z.string().optional(), - user_metadata: z.record(z.unknown()).optional() - }), - path: z.never().optional(), - query: z.never().optional() -}) - -/** - * Asset reference already existed for this user (deduplicated by content - * hash); the existing asset is returned with created_new=false. - * - */ -export const zCreateAssetFromHashResponse = zAssetCreated - -export const zGetRemoteAssetMetadataData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z.object({ - url: z.string().url() - }) -}) - -/** - * Metadata retrieved successfully - */ -export const zGetRemoteAssetMetadataResponse = zAssetMetadataResponse - -export const zCreateAssetDownloadData = z.object({ - body: z.object({ - source_url: z.string().url(), - tags: z.array(z.string()).optional(), - user_metadata: z.record(z.unknown()).optional(), - preview_id: z.string().uuid().optional() - }), - path: z.never().optional(), - query: z.never().optional() -}) - -export const zCreateAssetDownloadResponse = z.union([ - zAssetCreated, - zAssetDownloadResponse -]) - -export const zCreateAssetExportData = z.object({ - body: z.object({ - job_ids: z.array(z.string()).optional(), - asset_ids: z.array(z.string()).optional(), - naming_strategy: z - .enum(['group_by_job_id', 'preserve', 'asset_id', 'group_by_job_time']) - .optional(), - job_asset_name_filters: z.record(z.array(z.string()).min(1)).optional(), - include_previews: z.boolean().optional().default(false) - }), - path: z.never().optional(), - query: z.never().optional() -}) - -/** - * Accepted - Export task created and processing in background - */ -export const zCreateAssetExportResponse = zAssetDownloadResponse - -export const zDownloadExportData = z.object({ - body: z.never().optional(), - path: z.object({ - exportName: z.string().regex(/^[a-zA-Z0-9_-]+\.zip$/) - }), - query: z.never().optional() -}) - -/** - * Signed URL for downloading the export - */ -export const zDownloadExportResponse = zExportDownloadUrlResponse - -export const zDeleteAssetData = z.object({ - body: z.never().optional(), - path: z.object({ - id: z.string().uuid() - }), - query: z.never().optional() -}) - -/** - * Asset record deleted successfully - */ -export const zDeleteAssetResponse = z.void() - -export const zGetAssetByIdData = z.object({ - body: z.never().optional(), - path: z.object({ - id: z.string().uuid() - }), - query: z.never().optional() -}) - -/** - * Asset details retrieved successfully - */ -export const zGetAssetByIdResponse = zAsset - -export const zUpdateAssetData = z.object({ - body: z.object({ - name: z.string().optional(), - mime_type: z.string().optional(), - preview_id: z.string().uuid().optional(), - user_metadata: z.record(z.unknown()).optional() - }), - path: z.object({ - id: z.string().uuid() - }), - query: z.never().optional() -}) - -/** - * Asset updated successfully - */ -export const zUpdateAssetResponse = zAssetUpdated - -export const zRemoveAssetTagsData = z.object({ - body: z.object({ - tags: z.array(z.string()).min(1) - }), - path: z.object({ - id: z.string().uuid() - }), - query: z.never().optional() -}) - -/** - * Tags removed successfully - */ -export const zRemoveAssetTagsResponse = zTagsModificationResponse - -export const zAddAssetTagsData = z.object({ - body: z.object({ - tags: z.array(z.string()).min(1) - }), - path: z.object({ - id: z.string().uuid() - }), - query: z.never().optional() -}) - -/** - * Tags added successfully - */ -export const zAddAssetTagsResponse = zTagsModificationResponse - -export const zListTagsData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z - .object({ - prefix: z.string().optional(), - limit: z.number().int().gte(1).lte(1000).optional().default(100), - offset: z.number().int().gte(0).optional().default(0), - order: z.enum(['count_desc', 'name_asc']).optional(), - include_zero: z.boolean().optional().default(false), - include_public: z.boolean().optional().default(true) + mime_type: z.string().optional(), + name: z.string(), + preview_id: z.string().uuid().nullish(), + preview_url: z.string().url().optional(), + short_url: z.string().nullish(), + size: z.coerce + .bigint() + .min(BigInt('-9223372036854775808'), { + message: 'Invalid value: Expected int64 to be >= -9223372036854775808' }) - .optional() + .max(BigInt('9223372036854775807'), { + message: 'Invalid value: Expected int64 to be <= 9223372036854775807' + }) + .optional(), + tags: z.array(z.string()).optional(), + updated_at: z.string().datetime(), + user_metadata: z.record(z.unknown()).optional() }) /** - * Tags retrieved successfully + * Paginated list of assets belonging to the authenticated user. */ -export const zListTagsResponse2 = zListTagsResponse - -export const zGetAssetTagHistogramData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z - .object({ - include_tags: z.array(z.string()).optional(), - exclude_tags: z.array(z.string()).optional(), - name_contains: z.string().optional(), - metadata_filter: z.string().optional(), - limit: z.number().int().gte(1).lte(1000).optional().default(100), - include_public: z.boolean().optional().default(true) - }) - .optional() +export const zListAssetsResponseWritable = z.object({ + assets: z.array(zAssetWritable), + has_more: z.boolean(), + next_cursor: z.string().optional(), + total: z.number().int() }) /** - * Success - Tag histogram returned + * Response returned when a new asset is successfully created. */ -export const zGetAssetTagHistogramResponse = zAssetTagHistogramResponse +export const zAssetCreatedWritable = zAssetWritable.and( + z.object({ + created_new: z.boolean() + }) +) -export const zCheckAssetByHashData = z.object({ +export const zGetJwksData = z.object({ body: z.never().optional(), - path: z.object({ - hash: z.string().regex(/^blake3:[a-f0-9]{64}$/) - }), - query: z.never().optional() -}) - -export const zPostAssetsFromWorkflowData = z.object({ - body: zWorkflowApiAssetsRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Success + * JWKS response */ -export const zPostAssetsFromWorkflowResponse = zWorkflowApiAssetsResponse +export const zGetJwksResponse = zJwksResponse -export const zImportPublishedAssetsData = z.object({ - body: zImportPublishedAssetsRequest, +export const zGetOAuthAuthorizationServerData = z.object({ + body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * Successfully imported assets + * Authorization-server metadata */ -export const zImportPublishedAssetsResponse2 = zImportPublishedAssetsResponse +export const zGetOAuthAuthorizationServerResponse = + zOAuthAuthorizationServerMetadata -export const zGetQueueInfoData = z.object({ +export const zGetOAuthProtectedResourceData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * Success + * Protected-resource metadata */ -export const zGetQueueInfoResponse = zQueueInfo +export const zGetOAuthProtectedResourceResponse = + zOAuthProtectedResourceMetadata -export const zManageQueueData = z.object({ - body: zQueueManageRequest, - path: z.never().optional(), +export const zGetOAuthProtectedResourceByPathData = z.object({ + body: z.never().optional(), + path: z.object({ + resourcePath: z.string().regex(/^[a-zA-Z0-9._-]+$/) + }), query: z.never().optional() }) /** - * Success + * Protected-resource metadata */ -export const zManageQueueResponse = zQueueManageResponse +export const zGetOAuthProtectedResourceByPathResponse = + zOAuthProtectedResourceMetadata -export const zInterruptJobData = z.object({ +export const zGetCustomNodeProxyData = z.object({ body: z.never().optional(), - path: z.never().optional(), + path: z.object({ + path: z.string() + }), query: z.never().optional() }) -export const zListSecretsData = z.object({ +export const zPostCustomNodeProxyData = z.object({ body: z.never().optional(), - path: z.never().optional(), + path: z.object({ + path: z.string() + }), query: z.never().optional() }) -/** - * Success - */ -export const zListSecretsResponse = zSecretListResponse - -export const zCreateSecretData = z.object({ - body: zCreateSecretRequest, +export const zListAssetsData = z.object({ + body: z.never().optional(), path: z.never().optional(), - query: z.never().optional() + query: z + .object({ + include_tags: z.array(z.string()).optional(), + exclude_tags: z.array(z.string()).optional(), + name_contains: z.string().optional(), + metadata_filter: z.string().optional(), + limit: z.number().int().gte(1).lte(500).optional().default(20), + offset: z.number().int().gte(0).optional().default(0), + sort: z + .enum(['name', 'created_at', 'updated_at', 'size', 'last_access_time']) + .optional(), + order: z.enum(['asc', 'desc']).optional(), + include_public: z.boolean().optional().default(true), + hash: z.string().optional(), + after: z.string().optional() + }) + .optional() }) /** - * Secret created successfully + * Success - Assets returned */ -export const zCreateSecretResponse = zSecretResponse +export const zListAssetsResponse2 = zListAssetsResponse -export const zListSecretProvidersData = z.object({ - body: z.never().optional(), +export const zCreateAssetData = z.object({ + body: z.object({ + file: z.string(), + hash: z + .string() + .regex(/^(blake3|sha256):[a-f0-9]{64}$/) + .optional(), + id: z.string().uuid().optional(), + mime_type: z.string().optional(), + name: z.string().optional(), + preview_id: z.string().uuid().optional(), + tags: z.string().optional(), + user_metadata: z.string().optional() + }), path: z.never().optional(), query: z.never().optional() }) /** - * Success + * Asset already existed for this user (deduplicated by content hash); the + * existing asset is returned with created_new=false. + * */ -export const zListSecretProvidersResponse = zSecretProvidersResponse +export const zCreateAssetResponse = zAssetCreated -export const zDeleteSecretData = z.object({ +export const zDeleteAssetData = z.object({ body: z.never().optional(), path: z.object({ id: z.string().uuid() @@ -2876,11 +2163,11 @@ export const zDeleteSecretData = z.object({ }) /** - * Secret deleted successfully + * Asset record deleted successfully */ -export const zDeleteSecretResponse = z.void() +export const zDeleteAssetResponse = z.void() -export const zGetSecretData = z.object({ +export const zGetAssetByIdData = z.object({ body: z.never().optional(), path: z.object({ id: z.string().uuid() @@ -2889,12 +2176,17 @@ export const zGetSecretData = z.object({ }) /** - * Success + * Asset details retrieved successfully */ -export const zGetSecretResponse = zSecretResponse +export const zGetAssetByIdResponse = zAsset -export const zUpdateSecretData = z.object({ - body: zUpdateSecretRequest, +export const zUpdateAssetData = z.object({ + body: z.object({ + mime_type: z.string().optional(), + name: z.string().optional(), + preview_id: z.string().uuid().optional(), + user_metadata: z.record(z.unknown()).optional() + }), path: z.object({ id: z.string().uuid() }), @@ -2902,238 +2194,275 @@ export const zUpdateSecretData = z.object({ }) /** - * Secret updated successfully + * Asset updated successfully */ -export const zUpdateSecretResponse = zSecretResponse +export const zUpdateAssetResponse = zAssetUpdated -export const zGetAllSettingsData = z.object({ +export const zGetAssetContentData = z.object({ body: z.never().optional(), - path: z.never().optional(), - query: z.never().optional() + path: z.object({ + id: z.string() + }), + query: z + .object({ + disposition: z.enum(['inline', 'attachment']).optional() + }) + .optional() }) /** - * User settings as key-value pairs + * Asset content stream (local runtime streams the bytes directly) */ -export const zGetAllSettingsResponse = z.record(z.unknown()) +export const zGetAssetContentResponse = z.string() -export const zUpdateMultipleSettingsData = z.object({ - body: z.record(z.unknown()), - path: z.never().optional(), +export const zRemoveAssetTagsData = z.object({ + body: z.object({ + tags: z.array(z.string()).min(1) + }), + path: z.object({ + id: z.string().uuid() + }), query: z.never().optional() }) /** - * Updated user settings + * Tags removed successfully */ -export const zUpdateMultipleSettingsResponse = z.record(z.unknown()) +export const zRemoveAssetTagsResponse = zTagsModificationResponse -export const zGetSettingByIdData = z.object({ - body: z.never().optional(), +export const zAddAssetTagsData = z.object({ + body: z.object({ + tags: z.array(z.string()).min(1) + }), path: z.object({ - id: z.string() + id: z.string().uuid() }), query: z.never().optional() }) /** - * Setting value response + * Tags added successfully */ -export const zGetSettingByIdResponse = z.object({ - value: z.unknown().optional() +export const zAddAssetTagsResponse = zTagsModificationResponse + +export const zCreateAssetDownloadData = z.object({ + body: z.object({ + preview_id: z.string().uuid().optional(), + source_url: z.string().url(), + tags: z.array(z.string()).optional(), + user_metadata: z.record(z.unknown()).optional() + }), + path: z.never().optional(), + query: z.never().optional() }) -export const zUpdateSettingByIdData = z.object({ - body: z.unknown(), - path: z.object({ - id: z.string() +export const zCreateAssetDownloadResponse = z.union([ + zAssetCreated, + zAssetDownloadResponse +]) + +export const zCreateAssetExportData = z.object({ + body: z.object({ + asset_ids: z.array(z.string()).optional(), + include_previews: z.boolean().optional().default(false), + job_asset_name_filters: z.record(z.array(z.string()).min(1)).optional(), + job_ids: z.array(z.string()).optional(), + naming_strategy: z + .enum(['group_by_job_id', 'preserve', 'asset_id', 'group_by_job_time']) + .optional() }), + path: z.never().optional(), query: z.never().optional() }) /** - * Updated setting value response + * Accepted - Export task created and processing in background */ -export const zUpdateSettingByIdResponse = z.object({ - value: z.unknown().optional() +export const zCreateAssetExportResponse = zAssetDownloadResponse + +export const zDownloadExportData = z.object({ + body: z.never().optional(), + path: z.object({ + exportName: z.string().regex(/^[a-zA-Z0-9_-]+\.zip$/) + }), + query: z.never().optional() }) -export const zSubmitFeedbackData = z.object({ - body: zFeedbackRequest, +/** + * Signed URL for downloading the export + */ +export const zDownloadExportResponse = zExportDownloadUrlResponse + +export const zCreateAssetFromHashData = z.object({ + body: z.object({ + hash: z.string().regex(/^blake3:[a-f0-9]{64}$/), + mime_type: z.string().optional(), + name: z.string().optional(), + tags: z.array(z.string()).min(1), + user_metadata: z.record(z.unknown()).optional() + }), path: z.never().optional(), query: z.never().optional() }) /** - * Feedback submitted successfully + * Asset reference already existed for this user (deduplicated by content + * hash); the existing asset is returned with created_new=false. + * */ -export const zSubmitFeedbackResponse = zFeedbackResponse +export const zCreateAssetFromHashResponse = zAssetCreated -export const zGetUserdataData = z.object({ - body: z.never().optional(), +export const zPostAssetsFromWorkflowData = z.object({ + body: zWorkflowApiAssetsRequest, path: z.never().optional(), - query: z - .object({ - dir: z.string().optional(), - recurse: z.boolean().optional().default(false), - split: z.boolean().optional().default(false), - full_info: z.boolean().optional().default(false) - }) - .optional() + query: z.never().optional() }) /** - * A list of user data files. + * Success */ -export const zGetUserdataResponse = zGetUserDataResponseFull +export const zPostAssetsFromWorkflowResponse = zWorkflowApiAssetsResponse -export const zGetUserdataFilePublishData = z.object({ +export const zCheckAssetByHashData = z.object({ body: z.never().optional(), path: z.object({ - file: z.string() + hash: z.string().regex(/^blake3:[a-f0-9]{64}$/) }), query: z.never().optional() }) -/** - * Publish info (publish_time is null if never published) - */ -export const zGetUserdataFilePublishResponse = zWorkflowPublishInfo - -export const zPostUserdataFilePublishData = z.object({ - body: zPublishWorkflowAssetsRequest, - path: z.object({ - file: z.string() - }), +export const zImportPublishedAssetsData = z.object({ + body: zImportPublishedAssetsRequest, + path: z.never().optional(), query: z.never().optional() }) /** - * Workflow published + * Successfully imported assets */ -export const zPostUserdataFilePublishResponse = zWorkflowPublishInfo +export const zImportPublishedAssetsResponse2 = zImportPublishedAssetsResponse -export const zDeleteUserdataFileData = z.object({ +export const zPruneAssetsData = z.object({ body: z.never().optional(), - path: z.object({ - file: z.string() - }), + path: z.never().optional(), query: z.never().optional() }) /** - * File deleted successfully (No Content). + * Prune result */ -export const zDeleteUserdataFileResponse = z.void() +export const zPruneAssetsResponse = z.object({ + marked: z.number().int().optional(), + status: z.string().optional() +}) -export const zGetUserdataFileData = z.object({ +export const zGetRemoteAssetMetadataData = z.object({ body: z.never().optional(), - path: z.object({ - file: z.string() - }), - query: z.never().optional() + path: z.never().optional(), + query: z.object({ + url: z.string().url() + }) }) /** - * Successfully retrieved the file. + * Metadata retrieved successfully */ -export const zGetUserdataFileResponse = z.string() +export const zGetRemoteAssetMetadataResponse = zAssetMetadataResponse -export const zPostUserdataFileData = z.object({ - body: z.string(), - path: z.object({ - file: z.string() - }), - query: z +export const zSeedAssetsData = z.object({ + body: z .object({ - overwrite: z.enum(['true', 'false']).optional(), - full_info: z.enum(['true', 'false']).optional() + roots: z.array(z.string()).optional() }) - .optional() + .optional(), + path: z.never().optional(), + query: z.never().optional() }) /** - * File uploaded successfully. + * Seed started */ -export const zPostUserdataFileResponse = zUserDataResponseFull +export const zSeedAssetsResponse = z.object({ + status: z.string().optional() +}) -export const zMoveUserdataFileData = z.object({ +export const zCancelAssetSeedData = z.object({ body: z.never().optional(), - path: z.object({ - file: z.string(), - dest: z.string() - }), - query: z - .object({ - overwrite: z.enum(['true', 'false']).optional() - }) - .optional() + path: z.never().optional(), + query: z.never().optional() }) /** - * File moved successfully. + * Scan cancelled */ -export const zMoveUserdataFileResponse = zUserDataResponseFull +export const zCancelAssetSeedResponse = z.object({ + status: z.string().optional() +}) -export const zUploadImageData = z.object({ - body: z.object({ - image: z.string(), - overwrite: z.string().optional(), - subfolder: z.string().optional(), - type: z.string().optional() - }), +export const zGetAssetSeedStatusData = z.object({ + body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * Image uploaded successfully + * Scan progress details (files scanned, total, status, etc.) */ -export const zUploadImageResponse = z.object({ - name: z.string().optional(), - subfolder: z.string().optional(), - type: z.string().optional() +export const zGetAssetSeedStatusResponse = z.record(z.unknown()) + +export const zGetAssetTagHistogramData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z + .object({ + include_tags: z.array(z.string()).optional(), + exclude_tags: z.array(z.string()).optional(), + name_contains: z.string().optional(), + metadata_filter: z.string().optional(), + limit: z.number().int().gte(1).lte(1000).optional().default(100), + include_public: z.boolean().optional().default(true) + }) + .optional() }) -export const zUploadMaskData = z.object({ - body: z.object({ - image: z.string(), - original_ref: z.string() - }), +/** + * Success - Tag histogram returned + */ +export const zGetAssetTagHistogramResponse = zAssetTagHistogramResponse + +export const zCreateDesktopLoginCodeData = z.object({ + body: zDesktopLoginCodeCreateRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Mask uploaded successfully + * Login code created */ -export const zUploadMaskResponse = z.object({ - name: z.string().optional(), - subfolder: z.string().optional(), - type: z.string().optional() -}) +export const zCreateDesktopLoginCodeResponse = zDesktopLoginCodeCreateResponse -export const zGetLogsData = z.object({ - body: z.never().optional(), +export const zExchangeDesktopLoginCodeData = z.object({ + body: zDesktopLoginCodeExchangeRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Success + * Pending (not yet redeemed) or complete with a custom token */ -export const zGetLogsResponse = zLogsResponse +export const zExchangeDesktopLoginCodeResponse = + zDesktopLoginCodeExchangeResponse -export const zGetSystemStatsData = z.object({ - body: z.never().optional(), +export const zRedeemDesktopLoginCodeData = z.object({ + body: zDesktopLoginCodeRedeemRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Success + * Code redeemed (or already redeemed by the same user) */ -export const zGetSystemStatsResponse = zSystemStatsResponse +export const zRedeemDesktopLoginCodeResponse = zDesktopLoginCodeRedeemResponse export const zDeleteSessionData = z.object({ body: z.never().optional(), @@ -3168,590 +2497,536 @@ export const zExchangeTokenData = z.object({ */ export const zExchangeTokenResponse2 = zExchangeTokenResponse -export const zCreateDesktopLoginCodeData = z.object({ - body: zDesktopLoginCodeCreateRequest, +export const zGetBillingBalanceData = z.object({ + body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * Login code created + * Credit balance */ -export const zCreateDesktopLoginCodeResponse = zDesktopLoginCodeCreateResponse +export const zGetBillingBalanceResponse = zBillingBalanceResponse -export const zRedeemDesktopLoginCodeData = z.object({ - body: zDesktopLoginCodeRedeemRequest, +export const zGetBillingEventsData = z.object({ + body: z.never().optional(), path: z.never().optional(), - query: z.never().optional() + query: z + .object({ + page: z.number().int().gte(1).optional().default(1), + limit: z.number().int().gte(1).lte(100).optional().default(20) + }) + .optional() }) /** - * Code redeemed (or already redeemed by the same user) + * Paginated billing events */ -export const zRedeemDesktopLoginCodeResponse = zDesktopLoginCodeRedeemResponse +export const zGetBillingEventsResponse = zBillingEventsResponse -export const zExchangeDesktopLoginCodeData = z.object({ - body: zDesktopLoginCodeExchangeRequest, - path: z.never().optional(), +export const zGetBillingOpStatusData = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.string() + }), query: z.never().optional() }) /** - * Pending (not yet redeemed) or complete with a custom token + * Billing operation status */ -export const zExchangeDesktopLoginCodeResponse = - zDesktopLoginCodeExchangeResponse +export const zGetBillingOpStatusResponse = zBillingOpStatusResponse -export const zGetJwksData = z.object({ - body: z.never().optional(), +export const zGetPaymentPortalData = z.object({ + body: zPaymentPortalRequest.optional(), path: z.never().optional(), query: z.never().optional() }) /** - * JWKS response + * Success */ -export const zGetJwksResponse = zJwksResponse +export const zGetPaymentPortalResponse = zPaymentPortalResponse -export const zGetOAuthAuthorizationServerData = z.object({ +export const zGetBillingPlansData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * Authorization-server metadata + * Available plans with pricing */ -export const zGetOAuthAuthorizationServerResponse = - zOAuthAuthorizationServerMetadata +export const zGetBillingPlansResponse = zBillingPlansResponse -export const zGetOAuthProtectedResourceData = z.object({ - body: z.never().optional(), +export const zPreviewSubscribeData = z.object({ + body: zPreviewSubscribeRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Protected-resource metadata + * Subscription preview */ -export const zGetOAuthProtectedResourceResponse = - zOAuthProtectedResourceMetadata +export const zPreviewSubscribeResponse2 = zPreviewSubscribeResponse -export const zGetOAuthProtectedResourceByPathData = z.object({ +export const zGetBillingStatusData = z.object({ body: z.never().optional(), - path: z.object({ - resourcePath: z.string().regex(/^[a-zA-Z0-9._-]+$/) - }), + path: z.never().optional(), query: z.never().optional() }) /** - * Protected-resource metadata + * Billing status */ -export const zGetOAuthProtectedResourceByPathResponse = - zOAuthProtectedResourceMetadata +export const zGetBillingStatusResponse = zBillingStatusResponse -export const zGetOAuthAuthorizeData = z.object({ - body: z.never().optional(), +export const zSubscribeData = z.object({ + body: zSubscribeRequest, path: z.never().optional(), - query: z - .object({ - response_type: z.string().optional(), - client_id: z.string().optional(), - redirect_uri: z.string().optional(), - scope: z.string().optional(), - state: z.string().optional(), - code_challenge: z.string().optional(), - code_challenge_method: z.string().optional(), - resource: z.string().optional(), - oauth_request_id: z.string().optional() - }) - .optional() + query: z.never().optional() }) /** - * Consent challenge payload (cookie present, email verified). Frontend renders the consent UI from this payload and POSTs back to /oauth/authorize. - * + * Subscription created or payment method needed */ -export const zGetOAuthAuthorizeResponse = zOAuthConsentChallenge +export const zSubscribeResponse2 = zSubscribeResponse -export const zPostOAuthAuthorizeData = z.object({ - body: z.object({ - oauth_request_id: z.string().uuid(), - csrf_token: z.string(), - decision: z.enum(['allow', 'deny']), - workspace_id: z.string() - }), +export const zCancelSubscriptionData = z.object({ + body: zCancelSubscriptionRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Redirect URL for the frontend to navigate to (allow → with code+state; deny → with error+state) + * Subscription cancellation scheduled */ -export const zPostOAuthAuthorizeResponse = zOAuthAuthorizeRedirectResponse +export const zCancelSubscriptionResponse2 = zCancelSubscriptionResponse -export const zPostOAuthTokenData = z.object({ - body: z.object({ - grant_type: z.enum(['authorization_code', 'refresh_token']), - client_id: z.string(), - code: z.string().optional(), - redirect_uri: z.string().optional(), - code_verifier: z.string().optional(), - refresh_token: z.string().optional(), - scope: z.string().optional(), - client_secret: z.string().optional() - }), +export const zResubscribeData = z.object({ + body: zResubscribeRequest, path: z.never().optional(), query: z.never().optional() }) /** - * New token pair + * Subscription resumed successfully */ -export const zPostOAuthTokenResponse = zOAuthTokenResponse +export const zResubscribeResponse2 = zResubscribeResponse -export const zPostOAuthRegisterData = z.object({ - body: zOAuthRegisterRequest, +export const zCreateTopupData = z.object({ + body: zCreateTopupRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Registered. Body echoes the metadata RFC 7591 §3.2.1 requires. + * Top-up initiated successfully */ -export const zPostOAuthRegisterResponse = zOAuthRegisterResponse +export const zCreateTopupResponse2 = zCreateTopupResponse -export const zListWorkspacesData = z.object({ +export const zGetEmbeddingsData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * List of workspaces + * Embedding names */ -export const zListWorkspacesResponse2 = zListWorkspacesResponse +export const zGetEmbeddingsResponse = z.array(z.string()) -export const zCreateWorkspaceData = z.object({ - body: zCreateWorkspaceRequest, +export const zGetModelFoldersData = z.object({ + body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * Workspace created + * Success - List of model folders */ -export const zCreateWorkspaceResponse = zWorkspace +export const zGetModelFoldersResponse = z.array(zModelFolder) -export const zDeleteWorkspaceData = z.object({ +export const zGetModelsInFolderData = z.object({ body: z.never().optional(), path: z.object({ - id: z.string() + folder: z.string() }), query: z.never().optional() }) /** - * Workspace deleted + * Success - List of models in the folder */ -export const zDeleteWorkspaceResponse = z.void() +export const zGetModelsInFolderResponse = z.array(zModelFile) -export const zGetWorkspaceData = z.object({ +export const zGetModelPreviewData = z.object({ body: z.never().optional(), path: z.object({ - id: z.string() + folder: z.string(), + path_index: z.number().int(), + filename: z.string() }), query: z.never().optional() }) -/** - * Workspace details - */ -export const zGetWorkspaceResponse = zWorkspace +export const zGetNodeInfoSchemaData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() +}) -export const zUpdateWorkspaceData = z.object({ - body: zUpdateWorkspaceRequest, +export const zGetNodeByIdData = z.object({ + body: z.never().optional(), path: z.object({ id: z.string() }), query: z.never().optional() }) -/** - * Workspace updated - */ -export const zUpdateWorkspaceResponse = zWorkspace - -export const zListWorkspaceMembersData = z.object({ +export const zGetExtensionsData = z.object({ body: z.never().optional(), path: z.never().optional(), - query: z - .object({ - offset: z.number().int().gte(0).optional().default(0), - limit: z.number().int().gte(1).lte(100).optional().default(20) - }) - .optional() + query: z.never().optional() }) /** - * List of members + * URL paths (relative to web root) of available extension JS files */ -export const zListWorkspaceMembersResponse = zListMembersResponse +export const zGetExtensionsResponse = z.array(z.string()) -export const zListWorkspaceInvitesData = z.object({ +export const zGetFeaturesData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * List of pending invites + * Success */ -export const zListWorkspaceInvitesResponse = zListInvitesResponse +export const zGetFeaturesResponse = z.object({ + max_upload_size: z.number().int().optional(), + supports_preview_metadata: z.boolean().optional() +}) -export const zCreateWorkspaceInviteData = z.object({ - body: zCreateInviteRequest, +export const zSubmitFeedbackData = z.object({ + body: zFeedbackRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Invite created + * Feedback submitted successfully */ -export const zCreateWorkspaceInviteResponse = zPendingInvite +export const zSubmitFeedbackResponse = zFeedbackResponse -export const zAcceptWorkspaceInviteData = z.object({ +export const zGetMaskLayersData = z.object({ body: z.never().optional(), - path: z.object({ - token: z.string() - }), - query: z.never().optional() + path: z.never().optional(), + query: z.object({ + filename: z.string() + }) }) /** - * Invite accepted, user is now a member + * Success - Related mask layers returned */ -export const zAcceptWorkspaceInviteResponse = zAcceptInviteResponse +export const zGetMaskLayersResponse = z.object({ + mask: z.string().nullish(), + paint: z.string().nullish(), + painted: z.string().nullish(), + painted_masked: z.string().nullish() +}) -export const zLeaveWorkspaceData = z.object({ - body: z.never().optional(), +export const zFreeMemoryData = z.object({ + body: z + .object({ + free_memory: z.boolean().optional(), + unload_models: z.boolean().optional() + }) + .optional(), path: z.never().optional(), query: z.never().optional() }) -/** - * Successfully left workspace - */ -export const zLeaveWorkspaceResponse = z.void() - -export const zRevokeWorkspaceInviteData = z.object({ +export const zGetGlobalSubgraphsData = z.object({ body: z.never().optional(), - path: z.object({ - inviteId: z.string() - }), + path: z.never().optional(), query: z.never().optional() }) /** - * Invite revoked + * Success - Map of subgraph IDs to their metadata */ -export const zRevokeWorkspaceInviteResponse = z.void() +export const zGetGlobalSubgraphsResponse = z.record(zGlobalSubgraphInfo) -export const zRemoveWorkspaceMemberData = z.object({ +export const zGetGlobalSubgraphData = z.object({ body: z.never().optional(), path: z.object({ - userId: z.string() - }), - query: z.never().optional() -}) - -/** - * Member removed - */ -export const zRemoveWorkspaceMemberResponse = z.void() - -export const zUpdateWorkspaceMemberRoleData = z.object({ - body: zUpdateMemberRoleRequest, - path: z.object({ - userId: z.string() + id: z.string() }), query: z.never().optional() }) /** - * Member role updated + * Success - Full subgraph data */ -export const zUpdateWorkspaceMemberRoleResponse = zMember +export const zGetGlobalSubgraphResponse = zGlobalSubgraphData -export const zListWorkspaceApiKeysData = z.object({ +export const zGetLegacyHistoryData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) -/** - * List of API keys - */ -export const zListWorkspaceApiKeysResponse2 = zListWorkspaceApiKeysResponse - -export const zCreateWorkspaceApiKeyData = z.object({ - body: zCreateWorkspaceApiKeyRequest, +export const zManageHistoryData = z.object({ + body: zHistoryManageRequest, path: z.never().optional(), query: z.never().optional() }) -/** - * API key created (plaintext returned once) - */ -export const zCreateWorkspaceApiKeyResponse2 = zCreateWorkspaceApiKeyResponse - -export const zRevokeWorkspaceApiKeyData = z.object({ +export const zGetLegacyHistoryByIdData = z.object({ body: z.never().optional(), path: z.object({ - id: z.string().uuid() + prompt_id: z.string() }), query: z.never().optional() }) +export const zGetHistoryData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z + .object({ + max_items: z.number().int().optional(), + offset: z.number().int().optional().default(0) + }) + .optional() +}) + /** - * API key revoked + * Success - Execution history retrieved */ -export const zRevokeWorkspaceApiKeyResponse = z.void() +export const zGetHistoryResponse = zHistoryResponse -export const zBulkRevokeWorkspaceMemberApiKeysData = z.object({ +export const zGetHistoryForPromptData = z.object({ body: z.never().optional(), path: z.object({ - user_id: z.string().min(1) + prompt_id: z.string() }), query: z.never().optional() }) /** - * Keys revoked successfully + * Success - History for prompt retrieved */ -export const zBulkRevokeWorkspaceMemberApiKeysResponse = - zBulkRevokeApiKeysResponse +export const zGetHistoryForPromptResponse = zHistoryDetailResponse -export const zVerifyWorkspaceApiKeyData = z.object({ - body: zVerifyApiKeyRequest, +export const zCreateHubAssetUploadUrlData = z.object({ + body: zHubAssetUploadUrlRequest, path: z.never().optional(), - query: z - .object({ - include_billing: z.boolean().optional().default(false) - }) - .optional() + query: z.never().optional() }) /** - * Key is valid + * Presigned upload URL and token */ -export const zVerifyWorkspaceApiKeyResponse = zVerifyApiKeyResponse +export const zCreateHubAssetUploadUrlResponse = zHubAssetUploadUrlResponse -export const zGetUserData = z.object({ +export const zListHubLabelsData = z.object({ body: z.never().optional(), path: z.never().optional(), - query: z.never().optional() + query: z + .object({ + type: z.enum(['tag', 'model', 'custom_node']).optional() + }) + .optional() }) /** - * Success + * List of labels */ -export const zGetUserResponse = zUserResponse +export const zListHubLabelsResponse = zHubLabelListResponse -export const zSetReviewStatusData = z.object({ - body: zSetReviewStatusRequest, +export const zCreateHubProfileData = z.object({ + body: zCreateHubProfileRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Status updated successfully + * Hub profile created */ -export const zSetReviewStatusResponse2 = zSetReviewStatusResponse +export const zCreateHubProfileResponse = zHubProfile -export const zAdminDeleteHubWorkflowData = z.object({ +export const zGetHubProfileByUsernameData = z.object({ body: z.never().optional(), path: z.object({ - share_id: z.string() + username: z.string() }), query: z.never().optional() }) /** - * Successfully deleted + * Hub profile */ -export const zAdminDeleteHubWorkflowResponse = z.void() +export const zGetHubProfileByUsernameResponse = zHubProfile -export const zUpdateHubWorkflowData = z.object({ - body: zUpdateHubWorkflowRequest, +export const zUpdateHubProfileData = z.object({ + body: zUpdateHubProfileRequest, path: z.object({ - share_id: z.string() + username: z.string() }), query: z.never().optional() }) /** - * Updated hub workflow detail + * Hub profile updated */ -export const zUpdateHubWorkflowResponse = zHubWorkflowDetail +export const zUpdateHubProfileResponse = zHubProfile -export const zGetDeletionRequestData = z.object({ +export const zCheckHubUsernameData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.object({ - firebase_id: z.string() + username: z.string() }) }) /** - * Success - deletion request found + * Username availability result */ -export const zGetDeletionRequestResponse = z.array(zDeletionRequest) +export const zCheckHubUsernameResponse = zHubUsernameCheckResponse -export const zCreateDeletionRequestData = z.object({ - body: z.object({ - firebase_id: z.string() - }), +export const zGetMyHubProfileData = z.object({ + body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * Created - deletion request created or already exists + * Hub profile */ -export const zCreateDeletionRequestResponse = z.object({ - user_found_in_cloud: z.boolean() -}) +export const zGetMyHubProfileResponse = zHubProfile -export const zReleaseDeletionHoldData = z.object({ - body: z.object({ - firebase_id: z.string() - }), +export const zListHubWorkflowsData = z.object({ + body: z.never().optional(), path: z.never().optional(), - query: z.never().optional() + query: z + .object({ + cursor: z.string().optional(), + limit: z.number().int().gte(1).lte(100).optional().default(20), + search: z.string().optional(), + tag: z.string().optional(), + username: z.string().optional(), + detail: z.boolean().optional().default(false), + status: z.array(zHubWorkflowStatus).optional() + }) + .optional() }) /** - * Release authorized; the deletion workflow will proceed + * Paginated list of hub workflows */ -export const zReleaseDeletionHoldResponse = zReleaseHoldResponse +export const zListHubWorkflowsResponse = zHubWorkflowListResponse -export const zReportPartnerUsageData = z.object({ - body: zPartnerUsageRequest, +export const zPublishHubWorkflowData = z.object({ + body: zPublishHubWorkflowRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Usage reported successfully + * Workflow published to hub */ -export const zReportPartnerUsageResponse = zPartnerUsageResponse +export const zPublishHubWorkflowResponse = zHubWorkflowDetail -export const zGetHistoryEventsData = z.object({ +export const zDeleteHubWorkflowData = z.object({ body: z.never().optional(), - path: z.never().optional(), - query: z - .object({ - workspace_id: z.string().optional(), - user_id: z.string().optional(), - event_type: z.string().optional(), - start_date: z.string().datetime().optional(), - end_date: z.string().datetime().optional(), - page: z.number().int().optional(), - limit: z.number().int().optional() - }) - .optional() + path: z.object({ + share_id: z.string() + }), + query: z.never().optional() }) /** - * Paginated cloud history events for the workspace + * Successfully unpublished */ -export const zGetHistoryEventsResponse = zBillingEventsResponse +export const zDeleteHubWorkflowResponse = z.void() -export const zReportHistoryEventData = z.object({ - body: zHistoryEventRequest, - path: z.never().optional(), +export const zGetHubWorkflowData = z.object({ + body: z.never().optional(), + path: z.object({ + share_id: z.string() + }), query: z.never().optional() }) /** - * History event recorded successfully + * Hub workflow detail */ -export const zReportHistoryEventResponse = zPartnerUsageResponse +export const zGetHubWorkflowResponse = zHubWorkflowDetail -export const zUpdateSubscriptionCacheData = z.object({ - body: z.object({ - user_id: z.string(), - is_active: z.boolean(), - tier: z.string().optional() - }), +export const zListHubWorkflowIndexData = z.object({ + body: z.never().optional(), path: z.never().optional(), - query: z.never().optional() + query: z + .object({ + status: z.array(zHubWorkflowStatus).optional() + }) + .optional() }) /** - * Cache updated successfully + * List of hub workflow template entries */ -export const zUpdateSubscriptionCacheResponse = z.object({ - status: z.string().optional() -}) +export const zListHubWorkflowIndexResponse = z.array(zHubWorkflowTemplateEntry) -export const zListLinkedFirebaseUidsData = z.object({ - body: zListLinkedFirebaseUidsRequest, +export const zGetI18nData = z.object({ + body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * Linked Firebase UIDs (possibly empty list) + * Nested map of locale to translation key-value pairs */ -export const zListLinkedFirebaseUidsResponse2 = zListLinkedFirebaseUidsResponse +export const zGetI18nResponse = z.record(z.unknown()) -export const zEnsureWorkspaceBillingProvisionedData = z.object({ - body: zEnsureWorkspaceBillingProvisionedRequest, +export const zInterruptJobData = z.object({ + body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) -/** - * The workspace's provisioned billing identity - */ -export const zEnsureWorkspaceBillingProvisionedResponse2 = - zEnsureWorkspaceBillingProvisionedResponse - -export const zInsertDynamicConfigData = z.object({ - body: z.record(z.unknown()), - path: z.never().optional(), +export const zAcceptWorkspaceInviteData = z.object({ + body: z.never().optional(), + path: z.object({ + token: z.string() + }), query: z.never().optional() }) /** - * Config inserted successfully + * Invite accepted, user is now a member */ -export const zInsertDynamicConfigResponse = z.object({ - id: z.coerce - .bigint() - .min(BigInt('-9223372036854775808'), { - message: 'Invalid value: Expected int64 to be >= -9223372036854775808' - }) - .max(BigInt('9223372036854775807'), { - message: 'Invalid value: Expected int64 to be <= 9223372036854775807' - }) - .optional(), - message: z.string().optional() -}) +export const zAcceptWorkspaceInviteResponse = zAcceptInviteResponse -export const zSyncApiKeyData = z.object({ - body: zSyncApiKeyRequest, - path: z.never().optional(), +export const zGetLegacyJobByIdData = z.object({ + body: z.never().optional(), + path: z.object({ + job_id: z.string() + }), query: z.never().optional() }) -/** - * Sync processed — see `result` field - */ -export const zSyncApiKeyResponse2 = zSyncApiKeyResponse +export const zGetLegacyJobOutputsData = z.object({ + body: z.never().optional(), + path: z.object({ + job_id: z.string() + }), + query: z.never().optional() +}) export const zGetJobStatusData = z.object({ body: z.never().optional(), @@ -3766,136 +3041,167 @@ export const zGetJobStatusData = z.object({ */ export const zGetJobStatusResponse = zJobStatusResponse -export const zListTasksData = z.object({ +export const zListJobsData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z .object({ - task_name: z.string().optional(), - idempotency_key: z.string().optional(), status: z.string().optional(), - created_after: z.string().datetime().optional(), - created_before: z.string().datetime().optional(), + workflow_id: z.string().optional(), + output_type: z.enum(['image', 'video', 'audio', '3d']).optional(), + sort_by: z.enum(['create_time', 'execution_time']).optional(), sort_order: z.enum(['asc', 'desc']).optional(), + after: z.string().optional(), offset: z.number().int().gte(0).optional().default(0), - limit: z.number().int().gte(1).lte(100).optional().default(20) + limit: z.number().int().gte(1).lte(1000).optional().default(100) }) .optional() }) /** - * Success - Tasks retrieved + * Success - Jobs retrieved */ -export const zListTasksResponse = zTasksListResponse +export const zListJobsResponse = zJobsListResponse -export const zGetTaskData = z.object({ +export const zGetJobDetailData = z.object({ body: z.never().optional(), path: z.object({ - task_id: z.string().uuid() + job_id: z.string().uuid() }), - query: z.never().optional() + query: z + .object({ + short_link: z.enum(['ephemeral_tool_chain', 'default']).optional() + }) + .optional() }) /** - * Success - Task details retrieved + * Success - Job details retrieved */ -export const zGetTaskResponse = zTaskResponse +export const zGetJobDetailResponse = zJobDetailResponse -export const zGetBillingStatusData = z.object({ +export const zCancelJobData = z.object({ body: z.never().optional(), - path: z.never().optional(), + path: z.object({ + job_id: z.string().uuid() + }), query: z.never().optional() }) /** - * Billing status + * Success - Cancel request accepted (or job was already terminal) */ -export const zGetBillingStatusResponse = zBillingStatusResponse +export const zCancelJobResponse = zJobCancelResponse -export const zGetBillingBalanceData = z.object({ - body: z.never().optional(), +export const zCancelJobsData = z.object({ + body: zJobsCancelRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Credit balance + * Success - cancel requests dispatched (or jobs were already terminal) */ -export const zGetBillingBalanceResponse = zBillingBalanceResponse +export const zCancelJobsResponse = zJobsCancelResponse -export const zGetBillingEventsData = z.object({ +export const zGetLegacyModelsData = z.object({ body: z.never().optional(), path: z.never().optional(), - query: z - .object({ - page: z.number().int().gte(1).optional().default(1), - limit: z.number().int().gte(1).lte(100).optional().default(20) - }) - .optional() + query: z.never().optional() +}) + +export const zGetLegacyModelsByFolderData = z.object({ + body: z.never().optional(), + path: z.object({ + folder: z.string() + }), + query: z.never().optional() +}) + +export const zGetNodeReplacementsData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }) /** - * Paginated billing events + * Success - Node replacement mappings */ -export const zGetBillingEventsResponse = zBillingEventsResponse +export const zGetNodeReplacementsResponse = z.record(z.unknown()) -export const zGetBillingPlansData = z.object({ +export const zGetNodeInfoData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * Available plans with pricing + * Success */ -export const zGetBillingPlansResponse = zBillingPlansResponse +export const zGetNodeInfoResponse = z.record(zNodeInfo) -export const zPreviewSubscribeData = z.object({ - body: zPreviewSubscribeRequest, +export const zGetLegacyObjectInfoByNodeClassData = z.object({ + body: z.never().optional(), + path: z.object({ + node_class: z.string() + }), + query: z.never().optional() +}) + +export const zGetPromptInfoData = z.object({ + body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * Subscription preview + * Success */ -export const zPreviewSubscribeResponse2 = zPreviewSubscribeResponse +export const zGetPromptInfoResponse = zPromptInfo -export const zSubscribeData = z.object({ - body: zSubscribeRequest, +export const zExecutePromptData = z.object({ + body: zPromptRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Subscription created or payment method needed + * Success - Prompt accepted */ -export const zSubscribeResponse2 = zSubscribeResponse +export const zExecutePromptResponse = zPromptResponse -export const zCancelSubscriptionData = z.object({ - body: zCancelSubscriptionRequest, +export const zGetLegacyPromptByIdData = z.object({ + body: z.never().optional(), + path: z.object({ + prompt_id: z.string() + }), + query: z.never().optional() +}) + +export const zGetQueueInfoData = z.object({ + body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * Subscription cancellation scheduled + * Success */ -export const zCancelSubscriptionResponse2 = zCancelSubscriptionResponse +export const zGetQueueInfoResponse = zQueueInfo -export const zResubscribeData = z.object({ - body: zResubscribeRequest, +export const zManageQueueData = z.object({ + body: zQueueManageRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Subscription resumed successfully + * Success */ -export const zResubscribeResponse2 = zResubscribeResponse +export const zManageQueueResponse = zQueueManageResponse -export const zGetPaymentPortalData = z.object({ - body: zPaymentPortalRequest.optional(), +export const zListSecretsData = z.object({ + body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) @@ -3903,340 +3209,383 @@ export const zGetPaymentPortalData = z.object({ /** * Success */ -export const zGetPaymentPortalResponse = zPaymentPortalResponse +export const zListSecretsResponse = zSecretListResponse -export const zCreateTopupData = z.object({ - body: zCreateTopupRequest, +export const zCreateSecretData = z.object({ + body: zCreateSecretRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Top-up initiated successfully + * Secret created successfully */ -export const zCreateTopupResponse2 = zCreateTopupResponse +export const zCreateSecretResponse = zSecretResponse -export const zGetBillingOpStatusData = z.object({ +export const zDeleteSecretData = z.object({ body: z.never().optional(), path: z.object({ - id: z.string() + id: z.string().uuid() }), query: z.never().optional() }) /** - * Billing operation status + * Secret deleted successfully */ -export const zGetBillingOpStatusResponse = zBillingOpStatusResponse +export const zDeleteSecretResponse = z.void() -export const zListWorkflowsData = z.object({ +export const zGetSecretData = z.object({ body: z.never().optional(), - path: z.never().optional(), - query: z - .object({ - limit: z.number().int().lte(100).optional().default(20), - offset: z.number().int().optional().default(0), - name: z.string().optional(), - default_view: z.enum(['workflow', 'app']).optional(), - sort: z.enum(['create_time', 'update_time', 'name']).optional(), - order: z.enum(['asc', 'desc']).optional() - }) - .optional() -}) - -/** - * Success - */ -export const zListWorkflowsResponse = zWorkflowListResponse - -export const zCreateWorkflowData = z.object({ - body: zCreateWorkflowRequest, - path: z.never().optional(), + path: z.object({ + id: z.string().uuid() + }), query: z.never().optional() }) /** - * Workflow created successfully + * Success */ -export const zCreateWorkflowResponse = zWorkflowResponse +export const zGetSecretResponse = zSecretResponse -export const zDeleteWorkflowData = z.object({ - body: z.never().optional(), +export const zUpdateSecretData = z.object({ + body: zUpdateSecretRequest, path: z.object({ - workflow_id: z.string() + id: z.string().uuid() }), query: z.never().optional() }) /** - * Workflow deleted successfully + * Secret updated successfully */ -export const zDeleteWorkflowResponse = z.void() +export const zUpdateSecretResponse = zSecretResponse -export const zGetWorkflowData = z.object({ +export const zListSecretProvidersData = z.object({ body: z.never().optional(), - path: z.object({ - workflow_id: z.string() - }), + path: z.never().optional(), query: z.never().optional() }) /** * Success */ -export const zGetWorkflowResponse = zWorkflowResponse +export const zListSecretProvidersResponse = zSecretProvidersResponse -export const zUpdateWorkflowData = z.object({ - body: zUpdateWorkflowRequest, - path: z.object({ - workflow_id: z.string() - }), +export const zGetAllSettingsData = z.object({ + body: z.never().optional(), + path: z.never().optional(), query: z.never().optional() }) /** - * Success + * User settings as key-value pairs */ -export const zUpdateWorkflowResponse = zWorkflowResponse +export const zGetAllSettingsResponse = z.record(z.unknown()) -export const zCreateWorkflowVersionData = z.object({ - body: zCreateWorkflowVersionRequest, - path: z.object({ - workflow_id: z.string() - }), +export const zUpdateMultipleSettingsData = z.object({ + body: z.record(z.unknown()), + path: z.never().optional(), query: z.never().optional() }) /** - * Version created successfully + * Updated user settings */ -export const zCreateWorkflowVersionResponse = zWorkflowVersionResponse +export const zUpdateMultipleSettingsResponse = z.record(z.unknown()) -export const zGetWorkflowContentData = z.object({ +export const zGetSettingByIdData = z.object({ body: z.never().optional(), path: z.object({ - workflow_id: z.string() + id: z.string() }), query: z.never().optional() }) /** - * Success + * Setting value response */ -export const zGetWorkflowContentResponse = zWorkflowVersionContentResponse +export const zGetSettingByIdResponse = z.object({ + value: z.unknown().optional() +}) -export const zForkWorkflowData = z.object({ - body: zForkWorkflowRequest, +export const zUpdateSettingByIdData = z.object({ + body: z.unknown(), path: z.object({ - workflow_id: z.string() + id: z.string() }), query: z.never().optional() }) /** - * Workflow forked successfully + * Updated setting value response */ -export const zForkWorkflowResponse = zWorkflowResponse +export const zUpdateSettingByIdResponse = z.object({ + value: z.unknown().optional() +}) -export const zCreateHubProfileData = z.object({ - body: zCreateHubProfileRequest, +export const zGetSystemStatsData = z.object({ + body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * Hub profile created + * Success */ -export const zCreateHubProfileResponse = zHubProfile +export const zGetSystemStatsResponse = zSystemStatsResponse -export const zGetMyHubProfileData = z.object({ +export const zListTagsData = z.object({ body: z.never().optional(), path: z.never().optional(), - query: z.never().optional() + query: z + .object({ + prefix: z.string().optional(), + limit: z.number().int().gte(1).lte(1000).optional().default(100), + offset: z.number().int().gte(0).optional().default(0), + order: z.enum(['count_desc', 'name_asc']).optional(), + include_zero: z.boolean().optional().default(false), + include_public: z.boolean().optional().default(true) + }) + .optional() }) /** - * Hub profile + * Tags retrieved successfully */ -export const zGetMyHubProfileResponse = zHubProfile +export const zListTagsResponse2 = zListTagsResponse -export const zCheckHubUsernameData = z.object({ +export const zListTasksData = z.object({ body: z.never().optional(), path: z.never().optional(), - query: z.object({ - username: z.string() - }) + query: z + .object({ + task_name: z.string().optional(), + idempotency_key: z.string().optional(), + status: z.string().optional(), + created_after: z.string().datetime().optional(), + created_before: z.string().datetime().optional(), + sort_order: z.enum(['asc', 'desc']).optional(), + offset: z.number().int().gte(0).optional().default(0), + limit: z.number().int().gte(1).lte(100).optional().default(20) + }) + .optional() }) /** - * Username availability result + * Success - Tasks retrieved */ -export const zCheckHubUsernameResponse = zHubUsernameCheckResponse +export const zListTasksResponse = zTasksListResponse -export const zGetHubProfileByUsernameData = z.object({ +export const zGetTaskData = z.object({ body: z.never().optional(), path: z.object({ - username: z.string() + task_id: z.string().uuid() }), query: z.never().optional() }) /** - * Hub profile + * Success - Task details retrieved */ -export const zGetHubProfileByUsernameResponse = zHubProfile +export const zGetTaskResponse = zTaskResponse -export const zUpdateHubProfileData = z.object({ - body: zUpdateHubProfileRequest, - path: z.object({ - username: z.string() +export const zUploadImageData = z.object({ + body: z.object({ + image: z.string(), + overwrite: z.string().optional(), + subfolder: z.string().optional(), + type: z.string().optional() }), + path: z.never().optional(), query: z.never().optional() }) /** - * Hub profile updated + * Image uploaded successfully */ -export const zUpdateHubProfileResponse = zHubProfile +export const zUploadImageResponse = z.object({ + name: z.string().optional(), + subfolder: z.string().optional(), + type: z.string().optional() +}) -export const zCreateHubAssetUploadUrlData = z.object({ - body: zHubAssetUploadUrlRequest, +export const zUploadMaskData = z.object({ + body: z.object({ + image: z.string(), + original_ref: z.string() + }), path: z.never().optional(), query: z.never().optional() }) /** - * Presigned upload URL and token + * Mask uploaded successfully */ -export const zCreateHubAssetUploadUrlResponse = zHubAssetUploadUrlResponse +export const zUploadMaskResponse = z.object({ + name: z.string().optional(), + subfolder: z.string().optional(), + type: z.string().optional() +}) -export const zListHubLabelsData = z.object({ +export const zGetUserData = z.object({ body: z.never().optional(), path: z.never().optional(), - query: z - .object({ - type: z.enum(['tag', 'model', 'custom_node']).optional() - }) - .optional() + query: z.never().optional() }) /** - * List of labels + * Success */ -export const zListHubLabelsResponse = zHubLabelListResponse +export const zGetUserResponse = zUserResponse -export const zListHubWorkflowsData = z.object({ +export const zGetUserdataData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z .object({ - cursor: z.string().optional(), - limit: z.number().int().gte(1).lte(100).optional().default(20), - search: z.string().optional(), - tag: z.string().optional(), - username: z.string().optional(), - detail: z.boolean().optional().default(false), - status: z.array(zHubWorkflowStatus).optional() + dir: z.string().optional(), + recurse: z.boolean().optional().default(false), + split: z.boolean().optional().default(false), + full_info: z.boolean().optional().default(false) }) .optional() }) /** - * Paginated list of hub workflows + * A list of user data files. */ -export const zListHubWorkflowsResponse = zHubWorkflowListResponse +export const zGetUserdataResponse = zGetUserDataResponseFull -export const zPublishHubWorkflowData = z.object({ - body: zPublishHubWorkflowRequest, - path: z.never().optional(), +export const zDeleteUserdataFileData = z.object({ + body: z.never().optional(), + path: z.object({ + file: z.string() + }), + query: z.never().optional() +}) + +/** + * File deleted successfully (No Content). + */ +export const zDeleteUserdataFileResponse = z.void() + +export const zGetUserdataFileData = z.object({ + body: z.never().optional(), + path: z.object({ + file: z.string() + }), query: z.never().optional() }) /** - * Workflow published to hub + * Successfully retrieved the file. */ -export const zPublishHubWorkflowResponse = zHubWorkflowDetail +export const zGetUserdataFileResponse = z.string() -export const zListHubWorkflowIndexData = z.object({ - body: z.never().optional(), - path: z.never().optional(), +export const zPostUserdataFileData = z.object({ + body: z.string(), + path: z.object({ + file: z.string() + }), query: z .object({ - status: z.array(zHubWorkflowStatus).optional() + overwrite: z.enum(['true', 'false']).optional(), + full_info: z.enum(['true', 'false']).optional() }) .optional() }) /** - * List of hub workflow template entries + * File uploaded successfully. */ -export const zListHubWorkflowIndexResponse = z.array(zHubWorkflowTemplateEntry) +export const zPostUserdataFileResponse = zUserDataResponseFull -export const zDeleteHubWorkflowData = z.object({ +export const zMoveUserdataFileData = z.object({ body: z.never().optional(), path: z.object({ - share_id: z.string() + file: z.string(), + dest: z.string() }), - query: z.never().optional() + query: z + .object({ + overwrite: z.enum(['true', 'false']).optional() + }) + .optional() }) /** - * Successfully unpublished + * File moved successfully. */ -export const zDeleteHubWorkflowResponse = z.void() +export const zMoveUserdataFileResponse = zUserDataResponseFull -export const zGetHubWorkflowData = z.object({ +export const zGetUserdataFilePublishData = z.object({ body: z.never().optional(), path: z.object({ - share_id: z.string() + file: z.string() }), query: z.never().optional() }) /** - * Hub workflow detail + * Publish info (publish_time is null if never published) */ -export const zGetHubWorkflowResponse = zHubWorkflowDetail +export const zGetUserdataFilePublishResponse = zWorkflowPublishInfo -export const zGetPublishedWorkflowData = z.object({ - body: z.never().optional(), +export const zPostUserdataFilePublishData = z.object({ + body: zPublishWorkflowAssetsRequest, path: z.object({ - share_id: z.string() + file: z.string() }), query: z.never().optional() }) /** - * Published workflow details with asset statuses + * Workflow published */ -export const zGetPublishedWorkflowResponse = zPublishedWorkflowDetail +export const zPostUserdataFilePublishResponse = zWorkflowPublishInfo -export const zGetExtensionsData = z.object({ +export const zGetUsersInfoData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * URL paths (relative to web root) of available extension JS files + * Userdata storage information */ -export const zGetExtensionsResponse = z.array(z.string()) +export const zGetUsersInfoResponse = z.object({ + migrated: z.boolean(), + storage: z.string() +}) -export const zGetNodeInfoSchemaData = z.object({ +export const zGetLegacyUserdataV2Data = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) -export const zGetNodeByIdData = z.object({ +export const zGetVhsQueryVideoData = z.object({ body: z.never().optional(), - path: z.object({ - id: z.string() - }), - query: z.never().optional() + path: z.never().optional(), + query: z.object({ + filename: z.string() + }) }) -export const zGetVhsViewVideoData = z.object({ +/** + * Video metadata + */ +export const zGetVhsQueryVideoResponse = z.object({ + source: z.object({ + duration: z.number(), + fps: z.number(), + frames: z.number().int(), + size: z.tuple([z.number().int(), z.number().int()]) + }) +}) + +export const zGetVhsViewAudioData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.object({ @@ -4246,7 +3595,7 @@ export const zGetVhsViewVideoData = z.object({ }) }) -export const zGetVhsViewAudioData = z.object({ +export const zGetVhsViewVideoData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.object({ @@ -4256,40 +3605,36 @@ export const zGetVhsViewAudioData = z.object({ }) }) -export const zGetVhsQueryVideoData = z.object({ +export const zViewFileData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.object({ - filename: z.string() + filename: z.string(), + subfolder: z.string().optional(), + type: z.string().optional(), + fullpath: z.string().optional(), + format: z.string().optional(), + frame_rate: z.number().int().optional(), + workflow: z.string().optional(), + timestamp: z.number().int().optional(), + channel: z.string().optional(), + res: z.number().int().gte(64).lte(1024).optional() }) }) /** - * Video metadata + * Resized JPEG thumbnail (returned when res parameter is used) */ -export const zGetVhsQueryVideoResponse = z.object({ - source: z.object({ - size: z.tuple([z.number().int(), z.number().int()]), - fps: z.number(), - frames: z.number().int(), - duration: z.number() - }) -}) +export const zViewFileResponse = z.string() -export const zGetUsersInfoData = z.object({ +export const zGetLegacyViewMetadataData = z.object({ body: z.never().optional(), - path: z.never().optional(), + path: z.object({ + folder_name: z.string() + }), query: z.never().optional() }) -/** - * Userdata storage information - */ -export const zGetUsersInfoResponse = z.object({ - storage: z.string(), - migrated: z.boolean() -}) - export const zGetApiViewVideoAliasData = z.object({ body: z.never().optional(), path: z.never().optional(), @@ -4298,258 +3643,355 @@ export const zGetApiViewVideoAliasData = z.object({ }) }) -export const zGetViewCompatAliasData = z.object({ +export const zGetWorkflowTemplatesData = z.object({ body: z.never().optional(), path: z.never().optional(), - query: z.object({ - filename: z.string() - }) + query: z.never().optional() }) -export const zGetWebsocketData = z.object({ +/** + * Empty object for workflow templates + */ +export const zGetWorkflowTemplatesResponse = z.record(z.unknown()) + +export const zListWorkflowsData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z .object({ - clientId: z.string().optional() + limit: z.number().int().lte(100).optional().default(20), + offset: z.number().int().optional().default(0), + name: z.string().optional(), + default_view: z.enum(['workflow', 'app']).optional(), + sort: z.enum(['create_time', 'update_time', 'name']).optional(), + order: z.enum(['asc', 'desc']).optional() }) .optional() }) -export const zGetTemplateProxyData = z.object({ - body: z.never().optional(), - path: z.object({ - path: z.string() - }), +/** + * Success + */ +export const zListWorkflowsResponse = zWorkflowListResponse + +export const zCreateWorkflowData = z.object({ + body: zCreateWorkflowRequest, + path: z.never().optional(), query: z.never().optional() }) -export const zGetHealthData = z.object({ +/** + * Workflow created successfully + */ +export const zCreateWorkflowResponse = zWorkflowResponse + +export const zDeleteWorkflowData = z.object({ body: z.never().optional(), - path: z.never().optional(), + path: z.object({ + workflow_id: z.string() + }), query: z.never().optional() }) /** - * Service is healthy + * Workflow deleted successfully */ -export const zGetHealthResponse = z.string() +export const zDeleteWorkflowResponse = z.void() -export const zGetMonitoringTasksData = z.object({ +export const zGetWorkflowData = z.object({ body: z.never().optional(), - path: z.never().optional(), + path: z.object({ + workflow_id: z.string() + }), query: z.never().optional() }) -export const zDeleteMonitoringTasksSubpathData = z.object({ - body: z.never().optional(), +/** + * Success + */ +export const zGetWorkflowResponse = zWorkflowResponse + +export const zUpdateWorkflowData = z.object({ + body: zUpdateWorkflowRequest, path: z.object({ - path: z.string() + workflow_id: z.string() }), query: z.never().optional() }) -export const zGetMonitoringTasksSubpathData = z.object({ +/** + * Success + */ +export const zUpdateWorkflowResponse = zWorkflowResponse + +export const zGetWorkflowContentData = z.object({ body: z.never().optional(), path: z.object({ - path: z.string() + workflow_id: z.string() }), query: z.never().optional() }) -export const zPostMonitoringTasksSubpathData = z.object({ - body: z.never().optional(), +/** + * Success + */ +export const zGetWorkflowContentResponse = zWorkflowVersionContentResponse + +export const zForkWorkflowData = z.object({ + body: zForkWorkflowRequest, path: z.object({ - path: z.string() + workflow_id: z.string() }), query: z.never().optional() }) -export const zGetPprofData = z.object({ - body: z.never().optional(), +/** + * Workflow forked successfully + */ +export const zForkWorkflowResponse = zWorkflowResponse + +export const zCreateWorkflowVersionData = z.object({ + body: zCreateWorkflowVersionRequest, path: z.object({ - path: z.string() + workflow_id: z.string() }), query: z.never().optional() }) -export const zGetPprofProfileData = z.object({ +/** + * Version created successfully + */ +export const zCreateWorkflowVersionResponse = zWorkflowVersionResponse + +export const zGetPublishedWorkflowData = z.object({ body: z.never().optional(), - path: z.never().optional(), + path: z.object({ + share_id: z.string() + }), query: z.never().optional() }) -export const zGetPprofTraceData = z.object({ +/** + * Published workflow details with asset statuses + */ +export const zGetPublishedWorkflowResponse = zPublishedWorkflowDetail + +export const zListWorkspaceApiKeysData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) -export const zPostPprofSymbolData = z.object({ - body: z.never().optional(), +/** + * List of API keys + */ +export const zListWorkspaceApiKeysResponse2 = zListWorkspaceApiKeysResponse + +export const zCreateWorkspaceApiKeyData = z.object({ + body: zCreateWorkspaceApiKeyRequest, path: z.never().optional(), query: z.never().optional() }) -export const zGetStaticExtensionsData = z.object({ +/** + * API key created (plaintext returned once) + */ +export const zCreateWorkspaceApiKeyResponse2 = zCreateWorkspaceApiKeyResponse + +export const zRevokeWorkspaceApiKeyData = z.object({ body: z.never().optional(), path: z.object({ - path: z.string() + id: z.string().uuid() }), query: z.never().optional() }) -export const zGetCustomNodeProxyData = z.object({ +/** + * API key revoked + */ +export const zRevokeWorkspaceApiKeyResponse = z.void() + +export const zListWorkspaceInvitesData = z.object({ body: z.never().optional(), - path: z.object({ - path: z.string() - }), + path: z.never().optional(), query: z.never().optional() }) -export const zPostCustomNodeProxyData = z.object({ - body: z.never().optional(), - path: z.object({ - path: z.string() - }), +/** + * List of pending invites + */ +export const zListWorkspaceInvitesResponse = zListInvitesResponse + +export const zCreateWorkspaceInviteData = z.object({ + body: zCreateInviteRequest, + path: z.never().optional(), query: z.never().optional() }) -export const zGetModelPreviewData = z.object({ +/** + * Invite created + */ +export const zCreateWorkspaceInviteResponse = zPendingInvite + +export const zRevokeWorkspaceInviteData = z.object({ body: z.never().optional(), path: z.object({ - folder: z.string(), - path_index: z.number().int(), - filename: z.string() + inviteId: z.string() }), query: z.never().optional() }) -export const zShortLinkRedirectData = z.object({ +/** + * Invite revoked + */ +export const zRevokeWorkspaceInviteResponse = z.void() + +export const zLeaveWorkspaceData = z.object({ body: z.never().optional(), - path: z.object({ - id: z.string() - }), + path: z.never().optional(), query: z.never().optional() }) -export const zGetLegacyPromptByIdData = z.object({ +/** + * Successfully left workspace + */ +export const zLeaveWorkspaceResponse = z.void() + +export const zListWorkspaceMembersData = z.object({ body: z.never().optional(), - path: z.object({ - prompt_id: z.string() - }), - query: z.never().optional() + path: z.never().optional(), + query: z + .object({ + offset: z.number().int().gte(0).optional().default(0), + limit: z.number().int().gte(1).lte(100).optional().default(20) + }) + .optional() }) -export const zGetLegacyHistoryByIdData = z.object({ +/** + * List of members + */ +export const zListWorkspaceMembersResponse = zListMembersResponse + +export const zBulkRevokeWorkspaceMemberApiKeysData = z.object({ body: z.never().optional(), path: z.object({ - prompt_id: z.string() + user_id: z.string().min(1) }), query: z.never().optional() }) -export const zGetLegacyJobByIdData = z.object({ +/** + * Keys revoked successfully + */ +export const zBulkRevokeWorkspaceMemberApiKeysResponse = + zBulkRevokeApiKeysResponse + +export const zRemoveWorkspaceMemberData = z.object({ body: z.never().optional(), path: z.object({ - job_id: z.string() + userId: z.string() }), query: z.never().optional() }) -export const zGetLegacyJobOutputsData = z.object({ - body: z.never().optional(), +/** + * Member removed + */ +export const zRemoveWorkspaceMemberResponse = z.void() + +export const zUpdateWorkspaceMemberRoleData = z.object({ + body: zUpdateMemberRoleRequest, path: z.object({ - job_id: z.string() + userId: z.string() }), query: z.never().optional() }) -export const zGetLegacyModelsData = z.object({ +/** + * Member role updated + */ +export const zUpdateWorkspaceMemberRoleResponse = zMember + +export const zListWorkspacesData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) -export const zGetLegacyModelsByFolderData = z.object({ - body: z.never().optional(), - path: z.object({ - folder: z.string() - }), +/** + * List of workspaces + */ +export const zListWorkspacesResponse2 = zListWorkspacesResponse + +export const zCreateWorkspaceData = z.object({ + body: zCreateWorkspaceRequest, + path: z.never().optional(), query: z.never().optional() }) -export const zGetLegacyObjectInfoByNodeClassData = z.object({ +/** + * Workspace created + */ +export const zCreateWorkspaceResponse = zWorkspace + +export const zDeleteWorkspaceData = z.object({ body: z.never().optional(), path: z.object({ - node_class: z.string() + id: z.string() }), query: z.never().optional() }) -export const zGetLegacyUserdataV2Data = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z.never().optional() -}) +/** + * Workspace deleted + */ +export const zDeleteWorkspaceResponse = z.void() -export const zGetAssetContentData = z.object({ +export const zGetWorkspaceData = z.object({ body: z.never().optional(), path: z.object({ id: z.string() }), - query: z - .object({ - disposition: z.enum(['inline', 'attachment']).optional() - }) - .optional() + query: z.never().optional() }) /** - * Asset content stream (local runtime streams the bytes directly) + * Workspace details */ -export const zGetAssetContentResponse = z.string() +export const zGetWorkspaceResponse = zWorkspace -export const zGetLegacyViewMetadataData = z.object({ - body: z.never().optional(), +export const zUpdateWorkspaceData = z.object({ + body: zUpdateWorkspaceRequest, path: z.object({ - folder_name: z.string() + id: z.string() }), query: z.never().optional() }) -export const zGetEmbeddingsData = z.object({ - body: z.never().optional(), - path: z.never().optional(), - query: z.never().optional() -}) - /** - * Embedding names + * Workspace updated */ -export const zGetEmbeddingsResponse = z.array(z.string()) +export const zUpdateWorkspaceResponse = zWorkspace -export const zFreeMemoryData = z.object({ - body: z - .object({ - unload_models: z.boolean().optional(), - free_memory: z.boolean().optional() - }) - .optional(), - path: z.never().optional(), +export const zGetStaticExtensionsData = z.object({ + body: z.never().optional(), + path: z.object({ + path: z.string() + }), query: z.never().optional() }) -export const zGetI18nData = z.object({ +export const zGetHealthData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.never().optional() }) /** - * Nested map of locale to translation key-value pairs + * Service is healthy */ -export const zGetI18nResponse = z.record(z.unknown()) +export const zGetHealthResponse = z.string() export const zGetInternalFolderPathsData = z.object({ body: z.never().optional(), @@ -4588,8 +4030,8 @@ export const zGetInternalLogsRawResponse = z.object({ entries: z .array( z.object({ - t: z.number().optional(), - m: z.string().optional() + m: z.string().optional(), + t: z.number().optional() }) ) .optional(), @@ -4610,57 +4052,99 @@ export const zSubscribeToLogsData = z.object({ query: z.never().optional() }) -export const zPruneAssetsData = z.object({ +export const zGetOAuthAuthorizeData = z.object({ body: z.never().optional(), path: z.never().optional(), - query: z.never().optional() + query: z + .object({ + response_type: z.string().optional(), + client_id: z.string().optional(), + redirect_uri: z.string().optional(), + scope: z.string().optional(), + state: z.string().optional(), + code_challenge: z.string().optional(), + code_challenge_method: z.string().optional(), + resource: z.string().optional(), + oauth_request_id: z.string().optional() + }) + .optional() }) /** - * Prune result + * Consent challenge payload (cookie present, email verified). Frontend renders the consent UI from this payload and POSTs back to /oauth/authorize. + * */ -export const zPruneAssetsResponse = z.object({ - status: z.string().optional(), - marked: z.number().int().optional() -}) +export const zGetOAuthAuthorizeResponse = zOAuthConsentChallenge -export const zSeedAssetsData = z.object({ - body: z - .object({ - roots: z.array(z.string()).optional() - }) - .optional(), +export const zPostOAuthAuthorizeData = z.object({ + body: z.object({ + csrf_token: z.string(), + decision: z.enum(['allow', 'deny']), + oauth_request_id: z.string().uuid(), + workspace_id: z.string() + }), path: z.never().optional(), query: z.never().optional() }) /** - * Seed started + * Redirect URL for the frontend to navigate to (allow → with code+state; deny → with error+state) */ -export const zSeedAssetsResponse = z.object({ - status: z.string().optional() -}) +export const zPostOAuthAuthorizeResponse = zOAuthAuthorizeRedirectResponse -export const zGetAssetSeedStatusData = z.object({ - body: z.never().optional(), +export const zPostOAuthRegisterData = z.object({ + body: zOAuthRegisterRequest, path: z.never().optional(), query: z.never().optional() }) /** - * Scan progress details (files scanned, total, status, etc.) + * Registered. Body echoes the metadata RFC 7591 §3.2.1 requires. */ -export const zGetAssetSeedStatusResponse = z.record(z.unknown()) +export const zPostOAuthRegisterResponse = zOAuthRegisterResponse -export const zCancelAssetSeedData = z.object({ - body: z.never().optional(), +export const zPostOAuthTokenData = z.object({ + body: z.object({ + client_id: z.string(), + client_secret: z.string().optional(), + code: z.string().optional(), + code_verifier: z.string().optional(), + grant_type: z.enum(['authorization_code', 'refresh_token']), + redirect_uri: z.string().optional(), + refresh_token: z.string().optional(), + scope: z.string().optional() + }), path: z.never().optional(), query: z.never().optional() }) /** - * Scan cancelled + * New token pair */ -export const zCancelAssetSeedResponse = z.object({ - status: z.string().optional() +export const zPostOAuthTokenResponse = zOAuthTokenResponse + +export const zGetTemplateProxyData = z.object({ + body: z.never().optional(), + path: z.object({ + path: z.string() + }), + query: z.never().optional() +}) + +export const zGetViewCompatAliasData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + filename: z.string() + }) +}) + +export const zGetWebsocketData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z + .object({ + clientId: z.string().optional() + }) + .optional() })