Compare commits

..

2 Commits

Author SHA1 Message Date
GitHub Action
012bebdd2a [automated] Apply ESLint and Oxfmt fixes 2026-04-16 01:04:39 +00:00
MillerMedia
b4a1f552b9 [chore] Update Ingest API types from cloud@4be4a08 2026-04-16 01:01:37 +00:00
4 changed files with 954 additions and 330 deletions

View File

@@ -71,50 +71,3 @@ jobs:
flags: e2e
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
- name: Generate HTML coverage report
run: |
if [ ! -s coverage/playwright/coverage.lcov ]; then
echo "No coverage data; generating placeholder report."
mkdir -p coverage/html
echo '<html><body><h1>No E2E coverage data available for this run.</h1></body></html>' > coverage/html/index.html
exit 0
fi
genhtml coverage/playwright/coverage.lcov \
-o coverage/html \
--title "ComfyUI E2E Coverage" \
--no-function-coverage \
--precision 1
- name: Upload HTML report artifact
uses: actions/upload-artifact@v6
with:
name: e2e-coverage-html
path: coverage/html/
retention-days: 30
deploy:
needs: merge
if: github.event.workflow_run.head_branch == 'main'
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Download HTML report
uses: actions/download-artifact@v7
with:
name: e2e-coverage-html
path: coverage/html
- name: Upload to GitHub Pages
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1
with:
path: coverage/html
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5

View File

@@ -28,6 +28,7 @@ export type {
BillingPlansResponse,
BillingStatus,
BillingStatusResponse,
BindingErrorResponse,
CancelSubscriptionData,
CancelSubscriptionError,
CancelSubscriptionErrors,
@@ -44,11 +45,6 @@ export type {
CheckHubUsernameErrors,
CheckHubUsernameResponse,
CheckHubUsernameResponses,
ClaimInviteCodeData,
ClaimInviteCodeError,
ClaimInviteCodeErrors,
ClaimInviteCodeResponse,
ClaimInviteCodeResponses,
ClientOptions,
CreateAssetDownloadData,
CreateAssetDownloadError,
@@ -113,6 +109,13 @@ export type {
CreateWorkflowVersionRequest,
CreateWorkflowVersionResponse,
CreateWorkflowVersionResponses,
CreateWorkspaceApiKeyData,
CreateWorkspaceApiKeyError,
CreateWorkspaceApiKeyErrors,
CreateWorkspaceApiKeyRequest,
CreateWorkspaceApiKeyResponse,
CreateWorkspaceApiKeyResponse2,
CreateWorkspaceApiKeyResponses,
CreateWorkspaceData,
CreateWorkspaceError,
CreateWorkspaceErrors,
@@ -237,12 +240,16 @@ export type {
GetBillingStatusErrors,
GetBillingStatusResponse,
GetBillingStatusResponses,
GetCustomNodeProxyData,
GetCustomNodeProxyErrors,
GetCustomNodeProxyResponses,
GetDeletionRequestData,
GetDeletionRequestError,
GetDeletionRequestErrors,
GetDeletionRequestResponse,
GetDeletionRequestResponses,
GetExtensionsData,
GetExtensionsResponse,
GetExtensionsResponses,
GetFeaturesData,
GetFeaturesResponse,
@@ -263,7 +270,9 @@ export type {
GetGlobalSubgraphsResponse,
GetGlobalSubgraphsResponses,
GetHealthData,
GetHealthError,
GetHealthErrors,
GetHealthResponse,
GetHealthResponses,
GetHistoryData,
GetHistoryError,
@@ -285,11 +294,6 @@ export type {
GetHubWorkflowErrors,
GetHubWorkflowResponse,
GetHubWorkflowResponses,
GetInviteCodeStatusData,
GetInviteCodeStatusError,
GetInviteCodeStatusErrors,
GetInviteCodeStatusResponse,
GetInviteCodeStatusResponses,
GetJobDetailData,
GetJobDetailError,
GetJobDetailErrors,
@@ -339,9 +343,19 @@ export type {
GetMyHubProfileErrors,
GetMyHubProfileResponse,
GetMyHubProfileResponses,
GetNodeByIdData,
GetNodeByIdErrors,
GetNodeByIdResponses,
GetNodeInfoData,
GetNodeInfoResponse,
GetNodeInfoResponses,
GetNodeInfoSchemaData,
GetNodeInfoSchemaResponses,
GetNodeReplacementsData,
GetNodeReplacementsError,
GetNodeReplacementsErrors,
GetNodeReplacementsResponse,
GetNodeReplacementsResponses,
GetOpenapiSpecData,
GetOpenapiSpecResponses,
GetPaymentPortalData,
@@ -422,11 +436,15 @@ export type {
GetUserErrors,
GetUserResponse,
GetUserResponses,
GetUsersRawData,
GetUsersRawErrors,
GetUsersRawResponses,
GetUsersInfoData,
GetUsersInfoError,
GetUsersInfoErrors,
GetUsersInfoResponse,
GetUsersInfoResponses,
GetVhsQueryVideoData,
GetVhsQueryVideoError,
GetVhsQueryVideoErrors,
GetVhsQueryVideoResponse,
GetVhsQueryVideoResponses,
GetVhsViewAudioData,
GetVhsViewAudioErrors,
@@ -487,8 +505,6 @@ export type {
InterruptJobError,
InterruptJobErrors,
InterruptJobResponses,
InviteCodeClaimResponse,
InviteCodeStatusResponse,
JobDetailResponse,
JobEntry,
JobsListResponse,
@@ -551,6 +567,12 @@ export type {
ListWorkflowsErrors,
ListWorkflowsResponse,
ListWorkflowsResponses,
ListWorkspaceApiKeysData,
ListWorkspaceApiKeysError,
ListWorkspaceApiKeysErrors,
ListWorkspaceApiKeysResponse,
ListWorkspaceApiKeysResponse2,
ListWorkspaceApiKeysResponses,
ListWorkspaceInvitesData,
ListWorkspaceInvitesError,
ListWorkspaceInvitesErrors,
@@ -601,6 +623,9 @@ export type {
PostAssetsFromWorkflowErrors,
PostAssetsFromWorkflowResponse,
PostAssetsFromWorkflowResponses,
PostCustomNodeProxyData,
PostCustomNodeProxyErrors,
PostCustomNodeProxyResponses,
PostMonitoringTasksSubpathData,
PostMonitoringTasksSubpathErrors,
PostMonitoringTasksSubpathResponses,
@@ -661,6 +686,11 @@ export type {
ResubscribeResponse,
ResubscribeResponse2,
ResubscribeResponses,
RevokeWorkspaceApiKeyData,
RevokeWorkspaceApiKeyError,
RevokeWorkspaceApiKeyErrors,
RevokeWorkspaceApiKeyResponse,
RevokeWorkspaceApiKeyResponses,
RevokeWorkspaceInviteData,
RevokeWorkspaceInviteError,
RevokeWorkspaceInviteErrors,
@@ -668,13 +698,6 @@ export type {
RevokeWorkspaceInviteResponses,
SecretListResponse,
SecretResponse,
SendUserInviteEmailData,
SendUserInviteEmailError,
SendUserInviteEmailErrors,
SendUserInviteEmailRequest,
SendUserInviteEmailResponse,
SendUserInviteEmailResponse2,
SendUserInviteEmailResponses,
SetReviewStatusData,
SetReviewStatusError,
SetReviewStatusErrors,
@@ -718,6 +741,12 @@ export type {
UpdateHubProfileRequest,
UpdateHubProfileResponse,
UpdateHubProfileResponses,
UpdateHubWorkflowData,
UpdateHubWorkflowError,
UpdateHubWorkflowErrors,
UpdateHubWorkflowRequest,
UpdateHubWorkflowResponse,
UpdateHubWorkflowResponses,
UpdateMultipleSettingsData,
UpdateMultipleSettingsError,
UpdateMultipleSettingsErrors,
@@ -765,6 +794,13 @@ export type {
UserResponse,
ValidationError,
ValidationResult,
VerifyApiKeyRequest,
VerifyApiKeyResponse,
VerifyWorkspaceApiKeyData,
VerifyWorkspaceApiKeyError,
VerifyWorkspaceApiKeyErrors,
VerifyWorkspaceApiKeyResponse,
VerifyWorkspaceApiKeyResponses,
ViewFileData,
ViewFileError,
ViewFileErrors,
@@ -779,6 +815,7 @@ export type {
WorkflowVersionContentResponse,
WorkflowVersionResponse,
Workspace,
WorkspaceApiKeyInfo,
WorkspaceSummary,
WorkspaceWithRole
} from './types.gen'

View File

@@ -50,6 +50,72 @@ export type HubAssetUploadUrlRequest = {
content_type: string
}
/**
* 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.
*
*/
export type UpdateHubWorkflowRequest = {
/**
* Display name. Not clearable. Null/omit leaves unchanged; empty string is invalid.
*/
name?: string | null
/**
* Workflow description. Send "" to clear. Null/omit leaves unchanged.
*/
description?: string | null
/**
* Full replacement of tag slugs. Must exist in hub_labels. Send [] to clear. Null/omit leaves unchanged.
*/
tags?: Array<string> | null
/**
* Full replacement of model slugs. Must exist in hub_labels. Send [] to clear. Null/omit leaves unchanged.
*/
models?: Array<string> | null
/**
* Full replacement of custom_node slugs. Must exist in hub_labels. Send [] to clear. Null/omit leaves unchanged.
*/
custom_nodes?: Array<string> | null
/**
* Tutorial URL. Send "" to clear. Null/omit leaves unchanged.
*/
tutorial_url?: string | null
/**
* 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).
*
*/
thumbnail_type?: 'image' | 'video' | 'image_comparison'
/**
* 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.)
*
*/
thumbnail_token?: string | null
/**
* 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.)
*
*/
thumbnail_comparison_token?: string | null
/**
* 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.
*
*/
sample_image_tokens_or_urls?: Array<string> | null
/**
* 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.).
*
*/
metadata?: {
[key: string]: unknown
} | null
}
export type PublishHubWorkflowRequest = {
/**
* Username of the hub profile to publish under. The authenticated user must belong to the workspace that owns this profile.
@@ -264,8 +330,26 @@ export type HubWorkflowTemplateEntry = {
thumbnailVariant?: string
mediaType?: string
mediaSubtype?: string
/**
* Workflow asset size in bytes.
*/
size?: number
/**
* Approximate VRAM requirement in bytes.
*/
vram?: number
/**
* Usage count reported upstream.
*/
usage?: number
/**
* Search ranking score reported upstream.
*/
searchRank?: number
/**
* Whether the template belongs to a module marked as essential.
*/
isEssential?: boolean
openSource?: boolean
profile?: HubProfileSummary
tutorialUrl?: string
@@ -1109,6 +1193,143 @@ export type JwksResponse = {
keys: Array<JwkKey>
}
export type VerifyApiKeyResponse = {
/**
* Firebase UID of the key creator
*/
user_id: string
/**
* User's email address
*/
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<string>
}
export type VerifyApiKeyRequest = {
/**
* The full plaintext API key to verify
*/
api_key: string
}
export type ListWorkspaceApiKeysResponse = {
api_keys: Array<WorkspaceApiKeyInfo>
}
export type WorkspaceApiKeyInfo = {
/**
* API key ID
*/
id: string
/**
* Workspace this key belongs to
*/
workspace_id: string
/**
* User who created this key
*/
user_id: string
/**
* User-provided label
*/
name: string
/**
* First 8 chars after prefix for display
*/
key_prefix: string
/**
* When the key expires (if set)
*/
expires_at?: string
/**
* Last time the key was used
*/
last_used_at?: string
/**
* When the key was revoked (if revoked)
*/
revoked_at?: string
/**
* When the key was created
*/
created_at: string
}
export type CreateWorkspaceApiKeyResponse = {
/**
* API key ID
*/
id: string
/**
* User-provided label
*/
name: string
/**
* The full plaintext API key (only shown once)
*/
key: string
/**
* First 8 chars after prefix for display
*/
key_prefix: string
/**
* When the key expires (if set)
*/
expires_at?: string
/**
* When the key was created
*/
created_at: string
}
export type CreateWorkspaceApiKeyRequest = {
/**
* User-provided label for the key
*/
name: string
/**
* Optional expiration timestamp
*/
expires_at?: string
}
export type AcceptInviteResponse = {
/**
* ID of the workspace joined
@@ -1434,6 +1655,9 @@ export type JobDetailResponse = {
workflow?: {
[key: string]: unknown
}
/**
* Detailed execution error from ComfyUI (only for failed jobs with structured error data)
*/
execution_error?: ExecutionError
/**
* Job creation timestamp (Unix timestamp in milliseconds)
@@ -1489,6 +1713,9 @@ export type JobEntry = {
* User-friendly job status
*/
status: 'pending' | 'in_progress' | 'completed' | 'failed' | 'cancelled'
/**
* Detailed execution error from ComfyUI (only for failed jobs with structured error data)
*/
execution_error?: ExecutionError
/**
* Job creation timestamp (Unix timestamp in milliseconds)
@@ -1619,6 +1846,9 @@ export type AssetMetadataResponse = {
* Preview image as base64-encoded data URL
*/
preview_image?: string
/**
* Validation results for the file
*/
validation?: ValidationResult
}
@@ -1779,34 +2009,6 @@ export type AssetCreated = Asset & {
created_new: boolean
}
/**
* Response after sending an invite email
*/
export type SendUserInviteEmailResponse = {
/**
* Whether the email was sent successfully
*/
success: boolean
/**
* A message describing the result
*/
message: string
}
/**
* Request to send an invite email to a user
*/
export type SendUserInviteEmailRequest = {
/**
* The email address to send the invitation to
*/
email: string
/**
* Whether to force send the invite even if user already exists or has been invited
*/
force?: boolean
}
export type SetReviewStatusResponse = {
/**
* The share IDs that were submitted for review
@@ -1829,34 +2031,6 @@ export type SetReviewStatusRequest = {
status: 'approved' | 'rejected'
}
/**
* Response after successfully claiming an invite code
*/
export type InviteCodeClaimResponse = {
/**
* Whether the claim was successful
*/
success: boolean
/**
* Success message
*/
message: string
}
/**
* Invite code status response
*/
export type InviteCodeStatusResponse = {
/**
* Whether the code has been claimed
*/
claimed: boolean
/**
* Whether the code has expired
*/
expired: boolean
}
/**
* Response after deleting a session cookie
*/
@@ -1886,7 +2060,7 @@ export type CreateSessionResponse = {
*/
export type UserResponse = {
/**
* User status (active or waitlisted)
* User status (always "active" for authenticated users)
*/
status: string
}
@@ -2167,11 +2341,11 @@ export type QueueInfo = {
/**
* Array of currently running job items
*/
queue_running?: Array<Array<unknown>>
queue_running?: Array<[unknown, unknown, unknown, unknown, unknown]>
/**
* Array of pending job items (ordered by creation time, oldest first)
*/
queue_pending?: Array<Array<unknown>>
queue_pending?: Array<[unknown, unknown, unknown, unknown, unknown]>
}
/**
@@ -2445,6 +2619,10 @@ export type ExportDownloadUrlResponse = {
expires_at?: string
}
export type BindingErrorResponse = {
message: string
}
export type ErrorResponse = {
code: string
message: string
@@ -2710,6 +2888,35 @@ export type GetFeaturesResponses = {
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
@@ -3185,7 +3392,7 @@ export type ViewFileError = ViewFileErrors[keyof ViewFileErrors]
export type ViewFileResponses = {
/**
* Success - File content returned (used when channel or res parameter is present)
* Processed PNG image with extracted channel
*/
200: Blob | File
}
@@ -5919,6 +6126,168 @@ export type RemoveWorkspaceMemberResponses = {
export type RemoveWorkspaceMemberResponse =
RemoveWorkspaceMemberResponses[keyof RemoveWorkspaceMemberResponses]
export type ListWorkspaceApiKeysData = {
body?: never
path?: never
query?: never
url: '/api/workspace/api-keys'
}
export type ListWorkspaceApiKeysErrors = {
/**
* Unauthorized
*/
401: ErrorResponse
/**
* Forbidden
*/
403: ErrorResponse
/**
* Internal server error
*/
500: ErrorResponse
}
export type ListWorkspaceApiKeysError =
ListWorkspaceApiKeysErrors[keyof ListWorkspaceApiKeysErrors]
export type ListWorkspaceApiKeysResponses = {
/**
* List of API keys
*/
200: ListWorkspaceApiKeysResponse
}
export type ListWorkspaceApiKeysResponse2 =
ListWorkspaceApiKeysResponses[keyof ListWorkspaceApiKeysResponses]
export type CreateWorkspaceApiKeyData = {
body: CreateWorkspaceApiKeyRequest
path?: never
query?: never
url: '/api/workspace/api-keys'
}
export type CreateWorkspaceApiKeyErrors = {
/**
* Unauthorized
*/
401: ErrorResponse
/**
* Not a workspace member or personal workspace
*/
403: ErrorResponse
/**
* Workspace 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 CreateWorkspaceApiKeyResponses = {
/**
* API key created (plaintext returned once)
*/
201: CreateWorkspaceApiKeyResponse
}
export type CreateWorkspaceApiKeyResponse2 =
CreateWorkspaceApiKeyResponses[keyof CreateWorkspaceApiKeyResponses]
export type RevokeWorkspaceApiKeyData = {
body?: never
path: {
/**
* API key ID to revoke
*/
id: string
}
query?: never
url: '/api/workspace/api-keys/{id}'
}
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 RevokeWorkspaceApiKeyError =
RevokeWorkspaceApiKeyErrors[keyof RevokeWorkspaceApiKeyErrors]
export type RevokeWorkspaceApiKeyResponses = {
/**
* API key revoked
*/
204: void
}
export type RevokeWorkspaceApiKeyResponse =
RevokeWorkspaceApiKeyResponses[keyof RevokeWorkspaceApiKeyResponses]
export type VerifyWorkspaceApiKeyData = {
body: VerifyApiKeyRequest
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).
*/
include_billing?: boolean
}
url: '/admin/api/keys/verify'
}
export type VerifyWorkspaceApiKeyErrors = {
/**
* Invalid key or unauthorized
*/
401: ErrorResponse
/**
* Internal server error
*/
500: ErrorResponse
}
export type VerifyWorkspaceApiKeyError =
VerifyWorkspaceApiKeyErrors[keyof VerifyWorkspaceApiKeyErrors]
export type VerifyWorkspaceApiKeyResponses = {
/**
* Key is valid
*/
200: VerifyApiKeyResponse
}
export type VerifyWorkspaceApiKeyResponse =
VerifyWorkspaceApiKeyResponses[keyof VerifyWorkspaceApiKeyResponses]
export type GetUserData = {
body?: never
path?: never
@@ -5944,121 +6313,6 @@ export type GetUserResponses = {
export type GetUserResponse = GetUserResponses[keyof GetUserResponses]
export type GetInviteCodeStatusData = {
body?: never
path: {
/**
* The invite code to check
*/
code: string
}
query?: never
url: '/api/invite_code/{code}/status'
}
export type GetInviteCodeStatusErrors = {
/**
* Unauthorized - Firebase authentication required
*/
401: ErrorResponse
/**
* Invite code not found
*/
404: ErrorResponse
}
export type GetInviteCodeStatusError =
GetInviteCodeStatusErrors[keyof GetInviteCodeStatusErrors]
export type GetInviteCodeStatusResponses = {
/**
* Success - invite code exists
*/
200: InviteCodeStatusResponse
}
export type GetInviteCodeStatusResponse =
GetInviteCodeStatusResponses[keyof GetInviteCodeStatusResponses]
export type ClaimInviteCodeData = {
body?: never
path: {
/**
* The invite code to claim
*/
code: string
}
query?: never
url: '/api/invite_code/{code}/claim'
}
export type ClaimInviteCodeErrors = {
/**
* Bad request - invite code already claimed or expired
*/
400: ErrorResponse
/**
* Unauthorized - Firebase authentication required
*/
401: ErrorResponse
/**
* Invite code not found
*/
404: ErrorResponse
}
export type ClaimInviteCodeError =
ClaimInviteCodeErrors[keyof ClaimInviteCodeErrors]
export type ClaimInviteCodeResponses = {
/**
* Success - invite code claimed successfully
*/
200: InviteCodeClaimResponse
}
export type ClaimInviteCodeResponse =
ClaimInviteCodeResponses[keyof ClaimInviteCodeResponses]
export type SendUserInviteEmailData = {
body: SendUserInviteEmailRequest
path?: never
query?: never
url: '/admin/api/send_user_invite_email'
}
export type SendUserInviteEmailErrors = {
/**
* Bad request - invalid email or parameters
*/
400: ErrorResponse
/**
* Unauthorized - authentication required
*/
401: ErrorResponse
/**
* Forbidden - insufficient permissions
*/
403: ErrorResponse
/**
* Internal server error
*/
500: ErrorResponse
}
export type SendUserInviteEmailError =
SendUserInviteEmailErrors[keyof SendUserInviteEmailErrors]
export type SendUserInviteEmailResponses = {
/**
* Success - invite email sent successfully
*/
200: SendUserInviteEmailResponse
}
export type SendUserInviteEmailResponse2 =
SendUserInviteEmailResponses[keyof SendUserInviteEmailResponses]
export type SetReviewStatusData = {
body: SetReviewStatusRequest
path?: never
@@ -6098,6 +6352,51 @@ export type SetReviewStatusResponses = {
export type SetReviewStatusResponse2 =
SetReviewStatusResponses[keyof SetReviewStatusResponses]
export type UpdateHubWorkflowData = {
body: UpdateHubWorkflowRequest
path: {
share_id: string
}
query?: never
url: '/admin/api/hub/workflows/{share_id}'
}
export type UpdateHubWorkflowErrors = {
/**
* Bad request - invalid field, unknown label slug, or invalid media token
*/
400: ErrorResponse
/**
* 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 UpdateHubWorkflowResponses = {
/**
* Updated hub workflow detail
*/
200: HubWorkflowDetail
}
export type UpdateHubWorkflowResponse =
UpdateHubWorkflowResponses[keyof UpdateHubWorkflowResponses]
export type GetDeletionRequestData = {
body?: never
path?: never
@@ -7612,7 +7911,50 @@ export type GetExtensionsData = {
export type GetExtensionsResponses = {
/**
* JSON array of extension file paths
* URL paths (relative to web root) of available extension JS files
*/
200: Array<string>
}
export type GetExtensionsResponse =
GetExtensionsResponses[keyof GetExtensionsResponses]
export type GetNodeInfoSchemaData = {
body?: never
path?: never
query?: never
url: '/api/experiment/nodes'
}
export type GetNodeInfoSchemaResponses = {
/**
* Full node schema JSON
*/
200: unknown
}
export type GetNodeByIdData = {
body?: never
path: {
/**
* Node class_type identifier
*/
id: string
}
query?: never
url: '/api/experiment/nodes/{id}'
}
export type GetNodeByIdErrors = {
/**
* Node not found
*/
404: unknown
}
export type GetNodeByIdResponses = {
/**
* Node definition JSON
*/
200: unknown
}
@@ -7698,40 +8040,89 @@ export type GetVhsQueryVideoData = {
}
export type GetVhsQueryVideoErrors = {
/**
* Missing required query parameter. Produced by the oapi-codegen
* wrapper via echo.NewHTTPError, so the body shape matches Echo's
* default HTTPError serialization rather than ErrorResponse.
*
*/
400: BindingErrorResponse
/**
* Unauthorized
*/
401: unknown
401: ErrorResponse
}
export type GetVhsQueryVideoError =
GetVhsQueryVideoErrors[keyof GetVhsQueryVideoErrors]
export type GetVhsQueryVideoResponses = {
/**
* Video metadata
*/
200: unknown
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
}
}
}
export type GetUsersRawData = {
export type GetVhsQueryVideoResponse =
GetVhsQueryVideoResponses[keyof GetVhsQueryVideoResponses]
export type GetUsersInfoData = {
body?: never
path?: never
query?: never
url: '/api/users'
}
export type GetUsersRawErrors = {
export type GetUsersInfoErrors = {
/**
* Unauthorized
*/
401: unknown
401: ErrorResponse
}
export type GetUsersRawResponses = {
export type GetUsersInfoError = GetUsersInfoErrors[keyof GetUsersInfoErrors]
export type GetUsersInfoResponses = {
/**
* User list
* Userdata storage information
*/
200: unknown
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 GetUsersInfoResponse =
GetUsersInfoResponses[keyof GetUsersInfoResponses]
export type GetApiViewVideoAliasData = {
body?: never
path?: never
@@ -7833,16 +8224,20 @@ export type GetHealthErrors = {
/**
* Service is unhealthy
*/
503: unknown
503: string
}
export type GetHealthError = GetHealthErrors[keyof GetHealthErrors]
export type GetHealthResponses = {
/**
* Service is healthy
*/
200: unknown
200: string
}
export type GetHealthResponse = GetHealthResponses[keyof GetHealthResponses]
export type GetOpenapiSpecData = {
body?: never
path?: never
@@ -8043,3 +8438,57 @@ export type GetStaticExtensionsResponses = {
*/
200: unknown
}
export type GetCustomNodeProxyData = {
body?: never
path: {
path: string
}
query?: never
url: '/__custom_node_proxy/{path}'
}
export type GetCustomNodeProxyErrors = {
/**
* Unauthorized
*/
401: unknown
/**
* Path not in allowlist
*/
403: unknown
}
export type GetCustomNodeProxyResponses = {
/**
* Proxied response
*/
200: unknown
}
export type PostCustomNodeProxyData = {
body?: never
path: {
path: string
}
query?: never
url: '/__custom_node_proxy/{path}'
}
export type PostCustomNodeProxyErrors = {
/**
* Unauthorized
*/
401: unknown
/**
* Path not in allowlist
*/
403: unknown
}
export type PostCustomNodeProxyResponses = {
/**
* Proxied response
*/
200: unknown
}

View File

@@ -20,6 +20,32 @@ export const zHubAssetUploadUrlRequest = z.object({
content_type: z.string()
})
/**
* 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.
*
*/
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 zPublishHubWorkflowRequest = z.object({
username: z.string(),
name: z.string(),
@@ -134,8 +160,43 @@ export const zHubWorkflowTemplateEntry = z.object({
thumbnailVariant: z.string().optional(),
mediaType: z.string().optional(),
mediaSubtype: z.string().optional(),
size: z.number().optional(),
vram: z.number().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
.bigint()
.min(BigInt('-9223372036854775808'), {
message: 'Invalid value: Expected int64 to be >= -9223372036854775808'
})
.max(BigInt('9223372036854775807'), {
message: 'Invalid value: Expected int64 to be <= 9223372036854775807'
})
.optional(),
isEssential: z.boolean().optional(),
openSource: z.boolean().optional(),
profile: zHubProfileSummary.optional(),
tutorialUrl: z.string().optional(),
@@ -641,6 +702,53 @@ export const zJwksResponse = z.object({
keys: z.array(zJwkKey)
})
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())
})
export const zVerifyApiKeyRequest = z.object({
api_key: z.string()
})
export const zWorkspaceApiKeyInfo = z.object({
id: z.string().uuid(),
workspace_id: z.string(),
user_id: z.string(),
name: z.string(),
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 zListWorkspaceApiKeysResponse = z.object({
api_keys: z.array(zWorkspaceApiKeyInfo)
})
export const zCreateWorkspaceApiKeyResponse = z.object({
id: z.string().uuid(),
name: z.string(),
key: z.string(),
key_prefix: z.string(),
expires_at: z.string().datetime().optional(),
created_at: z.string().datetime()
})
export const zCreateWorkspaceApiKeyRequest = z.object({
name: z.string(),
expires_at: z.string().datetime().optional()
})
export const zAcceptInviteResponse = z.object({
workspace_id: z.string(),
workspace_name: z.string()
@@ -979,22 +1087,6 @@ export const zAssetCreated = zAsset.and(
})
)
/**
* Response after sending an invite email
*/
export const zSendUserInviteEmailResponse = z.object({
success: z.boolean(),
message: z.string()
})
/**
* Request to send an invite email to a user
*/
export const zSendUserInviteEmailRequest = z.object({
email: z.string(),
force: z.boolean().optional().default(false)
})
export const zSetReviewStatusResponse = z.object({
share_ids: z.array(z.string()),
status: z.enum(['approved', 'rejected'])
@@ -1005,22 +1097,6 @@ export const zSetReviewStatusRequest = z.object({
status: z.enum(['approved', 'rejected'])
})
/**
* Response after successfully claiming an invite code
*/
export const zInviteCodeClaimResponse = z.object({
success: z.boolean(),
message: z.string()
})
/**
* Invite code status response
*/
export const zInviteCodeStatusResponse = z.object({
claimed: z.boolean(),
expired: z.boolean()
})
/**
* Response after deleting a session cookie
*/
@@ -1194,8 +1270,16 @@ export const zQueueManageRequest = z.object({
* Queue information with pending and running jobs
*/
export const zQueueInfo = z.object({
queue_running: z.array(z.array(z.unknown())).optional(),
queue_pending: z.array(z.array(z.unknown())).optional()
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()
})
/**
@@ -1315,6 +1399,10 @@ export const zExportDownloadUrlResponse = z.object({
expires_at: z.string().datetime().optional()
})
export const zBindingErrorResponse = z.object({
message: z.string()
})
export const zErrorResponse = z.object({
code: z.string(),
message: z.string()
@@ -1427,6 +1515,17 @@ export const zGetFeaturesResponse = z.object({
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(),
@@ -1588,7 +1687,7 @@ export const zViewFileData = z.object({
})
/**
* Success - File content returned (used when channel or res parameter is present)
* Processed PNG image with extracted channel
*/
export const zViewFileResponse = z.string()
@@ -2429,6 +2528,56 @@ export const zRemoveWorkspaceMemberData = z.object({
*/
export const zRemoveWorkspaceMemberResponse = z.void()
export const zListWorkspaceApiKeysData = 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,
path: z.never().optional(),
query: z.never().optional()
})
/**
* API key created (plaintext returned once)
*/
export const zCreateWorkspaceApiKeyResponse2 = zCreateWorkspaceApiKeyResponse
export const zRevokeWorkspaceApiKeyData = z.object({
body: z.never().optional(),
path: z.object({
id: z.string().uuid()
}),
query: z.never().optional()
})
/**
* API key revoked
*/
export const zRevokeWorkspaceApiKeyResponse = z.void()
export const zVerifyWorkspaceApiKeyData = z.object({
body: zVerifyApiKeyRequest,
path: z.never().optional(),
query: z
.object({
include_billing: z.boolean().optional().default(false)
})
.optional()
})
/**
* Key is valid
*/
export const zVerifyWorkspaceApiKeyResponse = zVerifyApiKeyResponse
export const zGetUserData = z.object({
body: z.never().optional(),
path: z.never().optional(),
@@ -2440,43 +2589,6 @@ export const zGetUserData = z.object({
*/
export const zGetUserResponse = zUserResponse
export const zGetInviteCodeStatusData = z.object({
body: z.never().optional(),
path: z.object({
code: z.string()
}),
query: z.never().optional()
})
/**
* Success - invite code exists
*/
export const zGetInviteCodeStatusResponse = zInviteCodeStatusResponse
export const zClaimInviteCodeData = z.object({
body: z.never().optional(),
path: z.object({
code: z.string()
}),
query: z.never().optional()
})
/**
* Success - invite code claimed successfully
*/
export const zClaimInviteCodeResponse = zInviteCodeClaimResponse
export const zSendUserInviteEmailData = z.object({
body: zSendUserInviteEmailRequest,
path: z.never().optional(),
query: z.never().optional()
})
/**
* Success - invite email sent successfully
*/
export const zSendUserInviteEmailResponse2 = zSendUserInviteEmailResponse
export const zSetReviewStatusData = z.object({
body: zSetReviewStatusRequest,
path: z.never().optional(),
@@ -2488,6 +2600,19 @@ export const zSetReviewStatusData = z.object({
*/
export const zSetReviewStatusResponse2 = zSetReviewStatusResponse
export const zUpdateHubWorkflowData = z.object({
body: zUpdateHubWorkflowRequest,
path: z.object({
share_id: z.string()
}),
query: z.never().optional()
})
/**
* Updated hub workflow detail
*/
export const zUpdateHubWorkflowResponse = zHubWorkflowDetail
export const zGetDeletionRequestData = z.object({
body: z.never().optional(),
path: z.never().optional(),
@@ -2991,6 +3116,25 @@ export const zGetExtensionsData = z.object({
query: z.never().optional()
})
/**
* URL paths (relative to web root) of available extension JS files
*/
export const zGetExtensionsResponse = z.array(z.string())
export const zGetNodeInfoSchemaData = z.object({
body: z.never().optional(),
path: z.never().optional(),
query: z.never().optional()
})
export const zGetNodeByIdData = z.object({
body: z.never().optional(),
path: z.object({
id: z.string()
}),
query: z.never().optional()
})
export const zGetVhsViewVideoData = z.object({
body: z.never().optional(),
path: z.never().optional(),
@@ -3019,12 +3163,32 @@ export const zGetVhsQueryVideoData = z.object({
})
})
export const zGetUsersRawData = z.object({
/**
* Video metadata
*/
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 zGetUsersInfoData = z.object({
body: z.never().optional(),
path: z.never().optional(),
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(),
@@ -3065,6 +3229,11 @@ export const zGetHealthData = z.object({
query: z.never().optional()
})
/**
* Service is healthy
*/
export const zGetHealthResponse = z.string()
export const zGetOpenapiSpecData = z.object({
body: z.never().optional(),
path: z.never().optional(),
@@ -3134,3 +3303,19 @@ export const zGetStaticExtensionsData = z.object({
}),
query: z.never().optional()
})
export const zGetCustomNodeProxyData = z.object({
body: z.never().optional(),
path: z.object({
path: z.string()
}),
query: z.never().optional()
})
export const zPostCustomNodeProxyData = z.object({
body: z.never().optional(),
path: z.object({
path: z.string()
}),
query: z.never().optional()
})