mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-06-02 03:14:53 +00:00
Compare commits
2 Commits
feat/app-m
...
update-ing
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5370ea456 | ||
|
|
a422c47b4a |
@@ -35,6 +35,9 @@ export type {
|
||||
BulkRevokeWorkspaceMemberApiKeysErrors,
|
||||
BulkRevokeWorkspaceMemberApiKeysResponse,
|
||||
BulkRevokeWorkspaceMemberApiKeysResponses,
|
||||
CancelAssetSeedData,
|
||||
CancelAssetSeedResponse,
|
||||
CancelAssetSeedResponses,
|
||||
CancelJobData,
|
||||
CancelJobError,
|
||||
CancelJobErrors,
|
||||
@@ -208,6 +211,8 @@ export type {
|
||||
ForkWorkflowRequest,
|
||||
ForkWorkflowResponse,
|
||||
ForkWorkflowResponses,
|
||||
FreeMemoryData,
|
||||
FreeMemoryResponses,
|
||||
GetAllSettingsData,
|
||||
GetAllSettingsError,
|
||||
GetAllSettingsErrors,
|
||||
@@ -221,6 +226,9 @@ export type {
|
||||
GetAssetByIdErrors,
|
||||
GetAssetByIdResponse,
|
||||
GetAssetByIdResponses,
|
||||
GetAssetSeedStatusData,
|
||||
GetAssetSeedStatusResponse,
|
||||
GetAssetSeedStatusResponses,
|
||||
GetAssetTagHistogramData,
|
||||
GetAssetTagHistogramError,
|
||||
GetAssetTagHistogramErrors,
|
||||
@@ -259,6 +267,9 @@ export type {
|
||||
GetDeletionRequestErrors,
|
||||
GetDeletionRequestResponse,
|
||||
GetDeletionRequestResponses,
|
||||
GetEmbeddingsData,
|
||||
GetEmbeddingsResponse,
|
||||
GetEmbeddingsResponses,
|
||||
GetExtensionsData,
|
||||
GetExtensionsResponse,
|
||||
GetExtensionsResponses,
|
||||
@@ -305,6 +316,18 @@ export type {
|
||||
GetHubWorkflowErrors,
|
||||
GetHubWorkflowResponse,
|
||||
GetHubWorkflowResponses,
|
||||
GetI18nData,
|
||||
GetI18nResponse,
|
||||
GetI18nResponses,
|
||||
GetInternalFolderPathsData,
|
||||
GetInternalFolderPathsResponse,
|
||||
GetInternalFolderPathsResponses,
|
||||
GetInternalLogsData,
|
||||
GetInternalLogsRawData,
|
||||
GetInternalLogsRawResponse,
|
||||
GetInternalLogsRawResponses,
|
||||
GetInternalLogsResponse,
|
||||
GetInternalLogsResponses,
|
||||
GetJobDetailData,
|
||||
GetJobDetailError,
|
||||
GetJobDetailErrors,
|
||||
@@ -356,10 +379,7 @@ export type {
|
||||
GetModelFoldersResponse,
|
||||
GetModelFoldersResponses,
|
||||
GetModelPreviewData,
|
||||
GetModelPreviewError,
|
||||
GetModelPreviewErrors,
|
||||
GetModelPreviewResponse,
|
||||
GetModelPreviewResponses,
|
||||
GetModelsInFolderData,
|
||||
GetModelsInFolderError,
|
||||
GetModelsInFolderErrors,
|
||||
@@ -389,8 +409,26 @@ export type {
|
||||
GetNodeReplacementsErrors,
|
||||
GetNodeReplacementsResponse,
|
||||
GetNodeReplacementsResponses,
|
||||
GetOpenapiSpecData,
|
||||
GetOpenapiSpecResponses,
|
||||
GetOAuthAuthorizationServerData,
|
||||
GetOAuthAuthorizationServerError,
|
||||
GetOAuthAuthorizationServerErrors,
|
||||
GetOAuthAuthorizationServerResponse,
|
||||
GetOAuthAuthorizationServerResponses,
|
||||
GetOAuthAuthorizeData,
|
||||
GetOAuthAuthorizeError,
|
||||
GetOAuthAuthorizeErrors,
|
||||
GetOAuthAuthorizeResponse,
|
||||
GetOAuthAuthorizeResponses,
|
||||
GetOAuthProtectedResourceByPathData,
|
||||
GetOAuthProtectedResourceByPathError,
|
||||
GetOAuthProtectedResourceByPathErrors,
|
||||
GetOAuthProtectedResourceByPathResponse,
|
||||
GetOAuthProtectedResourceByPathResponses,
|
||||
GetOAuthProtectedResourceData,
|
||||
GetOAuthProtectedResourceError,
|
||||
GetOAuthProtectedResourceErrors,
|
||||
GetOAuthProtectedResourceResponse,
|
||||
GetOAuthProtectedResourceResponses,
|
||||
GetPaymentPortalData,
|
||||
GetPaymentPortalError,
|
||||
GetPaymentPortalErrors,
|
||||
@@ -427,11 +465,11 @@ export type {
|
||||
GetSecretErrors,
|
||||
GetSecretResponse,
|
||||
GetSecretResponses,
|
||||
GetSettingByKeyData,
|
||||
GetSettingByKeyError,
|
||||
GetSettingByKeyErrors,
|
||||
GetSettingByKeyResponse,
|
||||
GetSettingByKeyResponses,
|
||||
GetSettingByIdData,
|
||||
GetSettingByIdError,
|
||||
GetSettingByIdErrors,
|
||||
GetSettingByIdResponse,
|
||||
GetSettingByIdResponses,
|
||||
GetStaticExtensionsData,
|
||||
GetStaticExtensionsErrors,
|
||||
GetStaticExtensionsResponses,
|
||||
@@ -447,6 +485,7 @@ export type {
|
||||
GetTaskResponses,
|
||||
GetTemplateProxyData,
|
||||
GetTemplateProxyErrors,
|
||||
GetTemplateProxyResponses,
|
||||
GetUserData,
|
||||
GetUserdataData,
|
||||
GetUserdataError,
|
||||
@@ -534,6 +573,11 @@ export type {
|
||||
ImportPublishedAssetsResponse,
|
||||
ImportPublishedAssetsResponse2,
|
||||
ImportPublishedAssetsResponses,
|
||||
InsertDynamicConfigData,
|
||||
InsertDynamicConfigError,
|
||||
InsertDynamicConfigErrors,
|
||||
InsertDynamicConfigResponse,
|
||||
InsertDynamicConfigResponses,
|
||||
InterruptJobData,
|
||||
InterruptJobError,
|
||||
InterruptJobErrors,
|
||||
@@ -642,6 +686,17 @@ export type {
|
||||
MoveUserdataFileResponse,
|
||||
MoveUserdataFileResponses,
|
||||
NodeInfo,
|
||||
OAuthAuthorizationServerMetadata,
|
||||
OAuthAuthorizeRedirectResponse,
|
||||
OAuthConsentChallenge,
|
||||
OAuthConsentChallengeWorkspace,
|
||||
OAuthProtectedResourceMetadata,
|
||||
OAuthRegisterBadRequestResponse,
|
||||
OAuthRegisterError,
|
||||
OAuthRegisterRequest,
|
||||
OAuthRegisterResponse,
|
||||
OAuthTokenError,
|
||||
OAuthTokenResponse,
|
||||
PaginationInfo,
|
||||
PartnerUsageRequest,
|
||||
PartnerUsageResponse,
|
||||
@@ -663,6 +718,21 @@ export type {
|
||||
PostMonitoringTasksSubpathData,
|
||||
PostMonitoringTasksSubpathErrors,
|
||||
PostMonitoringTasksSubpathResponses,
|
||||
PostOAuthAuthorizeData,
|
||||
PostOAuthAuthorizeError,
|
||||
PostOAuthAuthorizeErrors,
|
||||
PostOAuthAuthorizeResponse,
|
||||
PostOAuthAuthorizeResponses,
|
||||
PostOAuthRegisterData,
|
||||
PostOAuthRegisterError,
|
||||
PostOAuthRegisterErrors,
|
||||
PostOAuthRegisterResponse,
|
||||
PostOAuthRegisterResponses,
|
||||
PostOAuthTokenData,
|
||||
PostOAuthTokenError,
|
||||
PostOAuthTokenErrors,
|
||||
PostOAuthTokenResponse,
|
||||
PostOAuthTokenResponses,
|
||||
PostPprofSymbolData,
|
||||
PostPprofSymbolResponses,
|
||||
PostUserdataFileData,
|
||||
@@ -687,6 +757,9 @@ export type {
|
||||
PromptInfo,
|
||||
PromptRequest,
|
||||
PromptResponse,
|
||||
PruneAssetsData,
|
||||
PruneAssetsResponse,
|
||||
PruneAssetsResponses,
|
||||
PublishedWorkflowDetail,
|
||||
PublishHubWorkflowData,
|
||||
PublishHubWorkflowError,
|
||||
@@ -732,6 +805,9 @@ export type {
|
||||
RevokeWorkspaceInviteResponses,
|
||||
SecretListResponse,
|
||||
SecretResponse,
|
||||
SeedAssetsData,
|
||||
SeedAssetsResponse,
|
||||
SeedAssetsResponses,
|
||||
SetReviewStatusData,
|
||||
SetReviewStatusError,
|
||||
SetReviewStatusErrors,
|
||||
@@ -751,6 +827,8 @@ export type {
|
||||
SubscribeResponse,
|
||||
SubscribeResponse2,
|
||||
SubscribeResponses,
|
||||
SubscribeToLogsData,
|
||||
SubscribeToLogsResponses,
|
||||
SubscriptionDuration,
|
||||
SubscriptionTier,
|
||||
SyncApiKeyData,
|
||||
@@ -799,11 +877,11 @@ export type {
|
||||
UpdateSecretRequest,
|
||||
UpdateSecretResponse,
|
||||
UpdateSecretResponses,
|
||||
UpdateSettingByKeyData,
|
||||
UpdateSettingByKeyError,
|
||||
UpdateSettingByKeyErrors,
|
||||
UpdateSettingByKeyResponse,
|
||||
UpdateSettingByKeyResponses,
|
||||
UpdateSettingByIdData,
|
||||
UpdateSettingByIdError,
|
||||
UpdateSettingByIdErrors,
|
||||
UpdateSettingByIdResponse,
|
||||
UpdateSettingByIdResponses,
|
||||
UpdateSubscriptionCacheData,
|
||||
UpdateSubscriptionCacheError,
|
||||
UpdateSubscriptionCacheErrors,
|
||||
|
||||
1027
packages/ingest-types/src/types.gen.ts
generated
1027
packages/ingest-types/src/types.gen.ts
generated
File diff suppressed because it is too large
Load Diff
514
packages/ingest-types/src/zod.gen.ts
generated
514
packages/ingest-types/src/zod.gen.ts
generated
@@ -879,6 +879,153 @@ export const zJwkKey = z.object({
|
||||
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.
|
||||
*
|
||||
*/
|
||||
export const zOAuthConsentChallengeWorkspace = z.object({
|
||||
id: z.string(),
|
||||
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.
|
||||
*/
|
||||
export const zOAuthAuthorizeRedirectResponse = z.object({
|
||||
redirect_url: z.string().url()
|
||||
})
|
||||
|
||||
/**
|
||||
* 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 zOAuthConsentChallenge = z.object({
|
||||
oauth_request_id: z.string().uuid(),
|
||||
csrf_token: z.string(),
|
||||
client_display_name: z.string(),
|
||||
resource_display_name: z.string(),
|
||||
scopes: z.array(z.string()),
|
||||
workspaces: z.array(zOAuthConsentChallengeWorkspace)
|
||||
})
|
||||
|
||||
/**
|
||||
* OAuth 2.1 protected-resource metadata (RFC 9728).
|
||||
*/
|
||||
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()
|
||||
})
|
||||
|
||||
/**
|
||||
* RFC 7591 §3.2.2 error response.
|
||||
*/
|
||||
export const zOAuthRegisterError = z.object({
|
||||
error: z.enum(['invalid_redirect_uri', 'invalid_client_metadata']),
|
||||
error_description: z.string().nullish()
|
||||
})
|
||||
|
||||
/**
|
||||
* Error shape returned when request binding or validation fails before the handler runs.
|
||||
*/
|
||||
export const zBindingErrorResponse = z.object({
|
||||
message: z.string()
|
||||
})
|
||||
|
||||
/**
|
||||
* Union of the two 400 shapes /oauth/register can emit. `OAuthRegisterError` is the handler-shaped RFC 7591 §3.2.2 error; `BindingErrorResponse` is the strict-server binding-layer error fired when the request body fails OpenAPI-schema validation before the handler runs.
|
||||
*
|
||||
*/
|
||||
export const zOAuthRegisterBadRequestResponse = z.union([
|
||||
zOAuthRegisterError,
|
||||
zBindingErrorResponse
|
||||
])
|
||||
|
||||
/**
|
||||
* RFC 7591 §3.2.1 successful registration response.
|
||||
*/
|
||||
export const zOAuthRegisterResponse = z.object({
|
||||
client_id: z.string(),
|
||||
client_id_issued_at: 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()
|
||||
})
|
||||
|
||||
/**
|
||||
* OAuth 2.1 authorization-server metadata (RFC 8414).
|
||||
*/
|
||||
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()
|
||||
})
|
||||
|
||||
/**
|
||||
* JSON Web Key Set containing the public keys used to verify Cloud JWTs.
|
||||
*/
|
||||
@@ -940,6 +1087,7 @@ export const zWorkspaceApiKeyInfo = z.object({
|
||||
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(),
|
||||
@@ -960,6 +1108,7 @@ export const zListWorkspaceApiKeysResponse = z.object({
|
||||
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(),
|
||||
@@ -971,6 +1120,7 @@ export const zCreateWorkspaceApiKeyResponse = z.object({
|
||||
*/
|
||||
export const zCreateWorkspaceApiKeyRequest = z.object({
|
||||
name: z.string(),
|
||||
description: z.string().max(5000).optional(),
|
||||
expires_at: z.string().datetime().optional()
|
||||
})
|
||||
|
||||
@@ -1353,6 +1503,7 @@ export const zListTagsResponse = z.object({
|
||||
export const zAsset = z.object({
|
||||
id: z.string().uuid(),
|
||||
name: z.string(),
|
||||
display_name: z.string().nullish(),
|
||||
asset_hash: z
|
||||
.string()
|
||||
.regex(/^blake3:[a-f0-9]{64}$/)
|
||||
@@ -1385,7 +1536,8 @@ export const zAsset = z.object({
|
||||
export const zListAssetsResponse = z.object({
|
||||
assets: z.array(zAsset),
|
||||
total: z.number().int(),
|
||||
has_more: z.boolean()
|
||||
has_more: z.boolean(),
|
||||
next_cursor: z.string().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -1394,6 +1546,7 @@ export const zListAssetsResponse = z.object({
|
||||
export const zAssetUpdated = z.object({
|
||||
id: z.string().uuid(),
|
||||
name: z.string().optional(),
|
||||
display_name: z.string().nullish(),
|
||||
asset_hash: z
|
||||
.string()
|
||||
.regex(/^blake3:[a-f0-9]{64}$/)
|
||||
@@ -1753,13 +1906,6 @@ export const zExportDownloadUrlResponse = z.object({
|
||||
expires_at: z.string().datetime().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Error shape returned when request binding or validation fails before the handler runs.
|
||||
*/
|
||||
export const zBindingErrorResponse = z.object({
|
||||
message: z.string()
|
||||
})
|
||||
|
||||
/**
|
||||
* Standard error response with a machine-readable code and human-readable message.
|
||||
*/
|
||||
@@ -1796,6 +1942,7 @@ export const zPromptRequest = z.object({
|
||||
export const zAssetWritable = z.object({
|
||||
id: z.string().uuid(),
|
||||
name: z.string(),
|
||||
display_name: z.string().nullish(),
|
||||
asset_hash: z
|
||||
.string()
|
||||
.regex(/^blake3:[a-f0-9]{64}$/)
|
||||
@@ -1827,7 +1974,8 @@ export const zAssetWritable = z.object({
|
||||
export const zListAssetsResponseWritable = z.object({
|
||||
assets: z.array(zAssetWritable),
|
||||
total: z.number().int(),
|
||||
has_more: z.boolean()
|
||||
has_more: z.boolean(),
|
||||
next_cursor: z.string().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -1961,21 +2109,6 @@ export const zGetModelsInFolderData = z.object({
|
||||
*/
|
||||
export const zGetModelsInFolderResponse = z.array(zModelFile)
|
||||
|
||||
export const zGetModelPreviewData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.object({
|
||||
folder: z.string(),
|
||||
path_index: z.number().int(),
|
||||
filename: z.string()
|
||||
}),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Success - Model preview image
|
||||
*/
|
||||
export const zGetModelPreviewResponse = z.string()
|
||||
|
||||
export const zGetLegacyHistoryData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
@@ -2132,9 +2265,9 @@ export const zListAssetsData = z.object({
|
||||
.enum(['name', 'created_at', 'updated_at', 'size', 'last_access_time'])
|
||||
.optional(),
|
||||
order: z.enum(['asc', 'desc']).optional(),
|
||||
job_ids: z.array(z.string().uuid()).optional(),
|
||||
include_public: z.boolean().optional().default(true),
|
||||
asset_hash: z.string().optional()
|
||||
asset_hash: z.string().optional(),
|
||||
after: z.string().optional()
|
||||
})
|
||||
.optional()
|
||||
})
|
||||
@@ -2157,7 +2290,7 @@ export const zUploadAssetData = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* Asset already exists (returned existing asset)
|
||||
* Asset created successfully
|
||||
*/
|
||||
export const zUploadAssetResponse = zAssetCreated
|
||||
|
||||
@@ -2174,7 +2307,7 @@ export const zCreateAssetFromHashData = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* Asset reference already exists (returned existing)
|
||||
* Asset reference created successfully
|
||||
*/
|
||||
export const zCreateAssetFromHashResponse = zAssetCreated
|
||||
|
||||
@@ -2214,7 +2347,8 @@ export const zCreateAssetExportData = z.object({
|
||||
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()
|
||||
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()
|
||||
@@ -2509,10 +2643,10 @@ export const zUpdateMultipleSettingsData = z.object({
|
||||
*/
|
||||
export const zUpdateMultipleSettingsResponse = z.record(z.unknown())
|
||||
|
||||
export const zGetSettingByKeyData = z.object({
|
||||
export const zGetSettingByIdData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.object({
|
||||
key: z.string()
|
||||
id: z.string()
|
||||
}),
|
||||
query: z.never().optional()
|
||||
})
|
||||
@@ -2520,14 +2654,14 @@ export const zGetSettingByKeyData = z.object({
|
||||
/**
|
||||
* Setting value response
|
||||
*/
|
||||
export const zGetSettingByKeyResponse = z.object({
|
||||
export const zGetSettingByIdResponse = z.object({
|
||||
value: z.unknown().optional()
|
||||
})
|
||||
|
||||
export const zUpdateSettingByKeyData = z.object({
|
||||
export const zUpdateSettingByIdData = z.object({
|
||||
body: z.unknown(),
|
||||
path: z.object({
|
||||
key: z.string()
|
||||
id: z.string()
|
||||
}),
|
||||
query: z.never().optional()
|
||||
})
|
||||
@@ -2535,7 +2669,7 @@ export const zUpdateSettingByKeyData = z.object({
|
||||
/**
|
||||
* Updated setting value response
|
||||
*/
|
||||
export const zUpdateSettingByKeyResponse = z.object({
|
||||
export const zUpdateSettingByIdResponse = z.object({
|
||||
value: z.unknown().optional()
|
||||
})
|
||||
|
||||
@@ -2691,21 +2825,7 @@ export const zUploadMaskData = z.object({
|
||||
export const zUploadMaskResponse = z.object({
|
||||
name: z.string().optional(),
|
||||
subfolder: z.string().optional(),
|
||||
type: z.string().optional(),
|
||||
metadata: z
|
||||
.object({
|
||||
is_mask: z.boolean().optional(),
|
||||
original_hash: z.string().optional(),
|
||||
mask_type: z.string().optional(),
|
||||
related_files: z
|
||||
.object({
|
||||
mask: z.string().optional(),
|
||||
paint: z.string().optional(),
|
||||
painted: z.string().optional()
|
||||
})
|
||||
.optional()
|
||||
})
|
||||
.optional()
|
||||
type: z.string().optional()
|
||||
})
|
||||
|
||||
export const zGetLogsData = z.object({
|
||||
@@ -2774,6 +2894,115 @@ export const zGetJwksData = z.object({
|
||||
*/
|
||||
export const zGetJwksResponse = zJwksResponse
|
||||
|
||||
export const zGetOAuthAuthorizationServerData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Authorization-server metadata
|
||||
*/
|
||||
export const zGetOAuthAuthorizationServerResponse =
|
||||
zOAuthAuthorizationServerMetadata
|
||||
|
||||
export const zGetOAuthProtectedResourceData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Protected-resource metadata
|
||||
*/
|
||||
export const zGetOAuthProtectedResourceResponse =
|
||||
zOAuthProtectedResourceMetadata
|
||||
|
||||
export const zGetOAuthProtectedResourceByPathData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.object({
|
||||
resourcePath: z.string().regex(/^[a-zA-Z0-9._-]+$/)
|
||||
}),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Protected-resource metadata
|
||||
*/
|
||||
export const zGetOAuthProtectedResourceByPathResponse =
|
||||
zOAuthProtectedResourceMetadata
|
||||
|
||||
export const zGetOAuthAuthorizeData = z.object({
|
||||
body: z.never().optional(),
|
||||
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()
|
||||
})
|
||||
|
||||
/**
|
||||
* Consent challenge payload (cookie present, email verified). Frontend renders the consent UI from this payload and POSTs back to /oauth/authorize.
|
||||
*
|
||||
*/
|
||||
export const zGetOAuthAuthorizeResponse = zOAuthConsentChallenge
|
||||
|
||||
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()
|
||||
}),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Redirect URL for the frontend to navigate to (allow → with code+state; deny → with error+state)
|
||||
*/
|
||||
export const zPostOAuthAuthorizeResponse = zOAuthAuthorizeRedirectResponse
|
||||
|
||||
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()
|
||||
}),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* New token pair
|
||||
*/
|
||||
export const zPostOAuthTokenResponse = zOAuthTokenResponse
|
||||
|
||||
export const zPostOAuthRegisterData = z.object({
|
||||
body: zOAuthRegisterRequest,
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Registered. Body echoes the metadata RFC 7591 §3.2.1 requires.
|
||||
*/
|
||||
export const zPostOAuthRegisterResponse = zOAuthRegisterResponse
|
||||
|
||||
export const zListWorkspacesData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
@@ -3078,6 +3307,28 @@ export const zUpdateSubscriptionCacheResponse = z.object({
|
||||
status: z.string().optional()
|
||||
})
|
||||
|
||||
export const zInsertDynamicConfigData = z.object({
|
||||
body: z.record(z.unknown()),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Config inserted successfully
|
||||
*/
|
||||
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 zSyncApiKeyData = z.object({
|
||||
body: zSyncApiKeyRequest,
|
||||
path: z.never().optional(),
|
||||
@@ -3671,12 +3922,6 @@ export const zGetHealthData = z.object({
|
||||
*/
|
||||
export const zGetHealthResponse = z.string()
|
||||
|
||||
export const zGetOpenapiSpecData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
export const zGetMonitoringTasksData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
@@ -3757,6 +4002,16 @@ export const zPostCustomNodeProxyData = z.object({
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
export const zGetModelPreviewData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.object({
|
||||
folder: z.string(),
|
||||
path_index: z.number().int(),
|
||||
filename: z.string()
|
||||
}),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
export const zGetLegacyPromptByIdData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.object({
|
||||
@@ -3832,3 +4087,150 @@ export const zGetLegacyViewMetadataData = z.object({
|
||||
}),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
export const zGetEmbeddingsData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Embedding names
|
||||
*/
|
||||
export const zGetEmbeddingsResponse = z.array(z.string())
|
||||
|
||||
export const zFreeMemoryData = z.object({
|
||||
body: z
|
||||
.object({
|
||||
unload_models: z.boolean().optional(),
|
||||
free_memory: z.boolean().optional()
|
||||
})
|
||||
.optional(),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
export const zGetI18nData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Nested map of locale to translation key-value pairs
|
||||
*/
|
||||
export const zGetI18nResponse = z.record(z.unknown())
|
||||
|
||||
export const zGetInternalFolderPathsData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Map of folder type name to list of path entries
|
||||
*/
|
||||
export const zGetInternalFolderPathsResponse = z.record(
|
||||
z.array(z.array(z.string()))
|
||||
)
|
||||
|
||||
export const zGetInternalLogsData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Log text
|
||||
*/
|
||||
export const zGetInternalLogsResponse = z.string()
|
||||
|
||||
export const zGetInternalLogsRawData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Structured log data
|
||||
*/
|
||||
export const zGetInternalLogsRawResponse = z.object({
|
||||
entries: z
|
||||
.array(
|
||||
z.object({
|
||||
t: z.number().optional(),
|
||||
m: z.string().optional()
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
size: z
|
||||
.object({
|
||||
cols: z.number().int().optional(),
|
||||
rows: z.number().int().optional()
|
||||
})
|
||||
.optional()
|
||||
})
|
||||
|
||||
export const zSubscribeToLogsData = z.object({
|
||||
body: z.object({
|
||||
clientId: z.string(),
|
||||
enabled: z.boolean()
|
||||
}),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
export const zPruneAssetsData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Prune result
|
||||
*/
|
||||
export const zPruneAssetsResponse = z.object({
|
||||
status: z.string().optional(),
|
||||
marked: z.number().int().optional()
|
||||
})
|
||||
|
||||
export const zSeedAssetsData = z.object({
|
||||
body: z
|
||||
.object({
|
||||
roots: z.array(z.string()).optional()
|
||||
})
|
||||
.optional(),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Seed started
|
||||
*/
|
||||
export const zSeedAssetsResponse = z.object({
|
||||
status: z.string().optional()
|
||||
})
|
||||
|
||||
export const zGetAssetSeedStatusData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Scan progress details (files scanned, total, status, etc.)
|
||||
*/
|
||||
export const zGetAssetSeedStatusResponse = z.record(z.unknown())
|
||||
|
||||
export const zCancelAssetSeedData = z.object({
|
||||
body: z.never().optional(),
|
||||
path: z.never().optional(),
|
||||
query: z.never().optional()
|
||||
})
|
||||
|
||||
/**
|
||||
* Scan cancelled
|
||||
*/
|
||||
export const zCancelAssetSeedResponse = z.object({
|
||||
status: z.string().optional()
|
||||
})
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { Ref } from 'vue'
|
||||
import { effectScope, nextTick, ref } from 'vue'
|
||||
|
||||
import type { AppMode } from './useAppMode'
|
||||
|
||||
const hoisted = vi.hoisted(() => ({
|
||||
telemetry: null as { trackModeTimeSpent: ReturnType<typeof vi.fn> } | null,
|
||||
mode: null as unknown as Ref<AppMode>
|
||||
}))
|
||||
|
||||
vi.mock('@/platform/telemetry', () => ({
|
||||
useTelemetry: () => hoisted.telemetry
|
||||
}))
|
||||
|
||||
vi.mock('./useAppMode', () => ({
|
||||
useAppMode: () => ({ mode: hoisted.mode })
|
||||
}))
|
||||
|
||||
import { useModeTimeTracking } from './useModeTimeTracking'
|
||||
|
||||
function setVisibility(state: 'visible' | 'hidden') {
|
||||
Object.defineProperty(document, 'visibilityState', {
|
||||
value: state,
|
||||
configurable: true
|
||||
})
|
||||
document.dispatchEvent(new Event('visibilitychange'))
|
||||
}
|
||||
|
||||
describe('useModeTimeTracking', () => {
|
||||
let scope: ReturnType<typeof effectScope>
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
vi.setSystemTime(0)
|
||||
hoisted.telemetry = { trackModeTimeSpent: vi.fn() }
|
||||
hoisted.mode = ref<AppMode>('graph')
|
||||
setVisibility('visible')
|
||||
scope = effectScope()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
scope.stop()
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
const track = () => hoisted.telemetry!.trackModeTimeSpent
|
||||
|
||||
it('emits the elapsed seconds for the previous mode on mode change', async () => {
|
||||
scope.run(() => useModeTimeTracking())
|
||||
|
||||
vi.setSystemTime(5000)
|
||||
hoisted.mode.value = 'app'
|
||||
await nextTick()
|
||||
|
||||
expect(track()).toHaveBeenCalledWith({
|
||||
mode: 'graph',
|
||||
duration_seconds: 5
|
||||
})
|
||||
})
|
||||
|
||||
it('excludes time while the tab is hidden', async () => {
|
||||
hoisted.mode = ref<AppMode>('app')
|
||||
scope.run(() => useModeTimeTracking())
|
||||
|
||||
vi.setSystemTime(2000)
|
||||
setVisibility('hidden')
|
||||
expect(track()).toHaveBeenCalledWith({ mode: 'app', duration_seconds: 2 })
|
||||
|
||||
track().mockClear()
|
||||
vi.setSystemTime(10_000)
|
||||
setVisibility('visible')
|
||||
vi.setSystemTime(11_000)
|
||||
|
||||
hoisted.mode.value = 'graph'
|
||||
await nextTick()
|
||||
|
||||
expect(track()).toHaveBeenCalledTimes(1)
|
||||
expect(track()).toHaveBeenCalledWith({ mode: 'app', duration_seconds: 1 })
|
||||
})
|
||||
|
||||
it('does not emit sub-second durations', async () => {
|
||||
scope.run(() => useModeTimeTracking())
|
||||
|
||||
vi.setSystemTime(300)
|
||||
hoisted.mode.value = 'app'
|
||||
await nextTick()
|
||||
|
||||
expect(track()).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('flushes the final mode when the scope is disposed', () => {
|
||||
hoisted.mode = ref<AppMode>('app')
|
||||
scope.run(() => useModeTimeTracking())
|
||||
|
||||
vi.setSystemTime(3000)
|
||||
scope.stop()
|
||||
|
||||
expect(track()).toHaveBeenCalledWith({ mode: 'app', duration_seconds: 3 })
|
||||
})
|
||||
|
||||
it('no-ops without a telemetry provider', async () => {
|
||||
hoisted.telemetry = null
|
||||
expect(() => scope.run(() => useModeTimeTracking())).not.toThrow()
|
||||
|
||||
vi.setSystemTime(5000)
|
||||
hoisted.mode.value = 'app'
|
||||
await expect(nextTick()).resolves.not.toThrow()
|
||||
})
|
||||
})
|
||||
@@ -1,65 +0,0 @@
|
||||
import { tryOnScopeDispose, useEventListener } from '@vueuse/core'
|
||||
import { watch } from 'vue'
|
||||
|
||||
import { useTelemetry } from '@/platform/telemetry'
|
||||
|
||||
import type { AppMode } from './useAppMode'
|
||||
import { useAppMode } from './useAppMode'
|
||||
|
||||
/**
|
||||
* Tracks active (tab-visible) time spent in each {@link AppMode} and emits an
|
||||
* `app:mode_time_spent` event whenever the user leaves a mode, backgrounds the
|
||||
* tab, or tears down. Hidden-tab time is excluded, and flushing on tab-hide
|
||||
* means a closing tab is still captured (`visibilitychange` fires before
|
||||
* unload). Summing `duration_seconds` grouped by `mode` yields time per mode.
|
||||
*
|
||||
* Side-effecting composable: call once from a long-lived scope (GraphView).
|
||||
*/
|
||||
export function useModeTimeTracking() {
|
||||
const dispatcher = useTelemetry()
|
||||
if (!dispatcher) return
|
||||
const trackModeTimeSpent = dispatcher.trackModeTimeSpent.bind(dispatcher)
|
||||
|
||||
const { mode } = useAppMode()
|
||||
|
||||
const isVisible = () => document.visibilityState === 'visible'
|
||||
|
||||
let trackedMode: AppMode = mode.value
|
||||
let accumulatedMs = 0
|
||||
let segmentStart: number | null = isVisible() ? Date.now() : null
|
||||
|
||||
function closeSegment() {
|
||||
if (segmentStart !== null) {
|
||||
accumulatedMs += Date.now() - segmentStart
|
||||
segmentStart = null
|
||||
}
|
||||
}
|
||||
|
||||
function flush() {
|
||||
closeSegment()
|
||||
const durationSeconds = Math.round(accumulatedMs / 1000)
|
||||
accumulatedMs = 0
|
||||
if (durationSeconds >= 1) {
|
||||
trackModeTimeSpent({
|
||||
mode: trackedMode,
|
||||
duration_seconds: durationSeconds
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
watch(mode, (newMode) => {
|
||||
flush()
|
||||
trackedMode = newMode
|
||||
segmentStart = isVisible() ? Date.now() : null
|
||||
})
|
||||
|
||||
useEventListener(document, 'visibilitychange', () => {
|
||||
if (isVisible()) {
|
||||
segmentStart = Date.now()
|
||||
} else {
|
||||
flush()
|
||||
}
|
||||
})
|
||||
|
||||
tryOnScopeDispose(flush)
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import type {
|
||||
BeginCheckoutMetadata,
|
||||
DefaultViewSetMetadata,
|
||||
EnterLinearMetadata,
|
||||
ModeTimeSpentMetadata,
|
||||
ShareFlowMetadata,
|
||||
ExecutionErrorMetadata,
|
||||
ExecutionSuccessMetadata,
|
||||
@@ -177,10 +176,6 @@ export class TelemetryRegistry implements TelemetryDispatcher {
|
||||
this.dispatch((provider) => provider.trackEnterLinear?.(metadata))
|
||||
}
|
||||
|
||||
trackModeTimeSpent(metadata: ModeTimeSpentMetadata): void {
|
||||
this.dispatch((provider) => provider.trackModeTimeSpent?.(metadata))
|
||||
}
|
||||
|
||||
trackShareFlow(metadata: ShareFlowMetadata): void {
|
||||
this.dispatch((provider) => provider.trackShareFlow?.(metadata))
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import type {
|
||||
BeginCheckoutMetadata,
|
||||
DefaultViewSetMetadata,
|
||||
EnterLinearMetadata,
|
||||
ModeTimeSpentMetadata,
|
||||
ExecutionErrorMetadata,
|
||||
ExecutionSuccessMetadata,
|
||||
ExecutionTriggerSource,
|
||||
@@ -281,15 +280,7 @@ export class GtmTelemetryProvider implements TelemetryProvider {
|
||||
|
||||
trackEnterLinear(metadata: EnterLinearMetadata): void {
|
||||
this.pushEvent('app_mode_opened', {
|
||||
source: metadata.source,
|
||||
open_source: metadata.open_source
|
||||
})
|
||||
}
|
||||
|
||||
trackModeTimeSpent(metadata: ModeTimeSpentMetadata): void {
|
||||
this.pushEvent('mode_time_spent', {
|
||||
mode: metadata.mode,
|
||||
duration_seconds: metadata.duration_seconds
|
||||
source: metadata.source
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ import type {
|
||||
EnterLinearMetadata,
|
||||
ExecutionErrorMetadata,
|
||||
ExecutionSuccessMetadata,
|
||||
ModeTimeSpentMetadata,
|
||||
ShareFlowMetadata,
|
||||
SurveyResponses,
|
||||
TemplateLibraryClosedMetadata,
|
||||
@@ -288,10 +287,6 @@ describe('MixpanelTelemetryProvider — direct event tracking methods', () => {
|
||||
default_view: 'graph'
|
||||
}
|
||||
const enterLinearMetadata: EnterLinearMetadata = {}
|
||||
const modeTimeSpentMetadata: ModeTimeSpentMetadata = {
|
||||
mode: 'app',
|
||||
duration_seconds: 42
|
||||
}
|
||||
const shareFlowMetadata: ShareFlowMetadata = { step: 'dialog_opened' }
|
||||
const executionErrorMetadata: ExecutionErrorMetadata = { jobId: 'job-1' }
|
||||
const executionSuccessMetadata: ExecutionSuccessMetadata = { jobId: 'job-1' }
|
||||
@@ -355,11 +350,6 @@ describe('MixpanelTelemetryProvider — direct event tracking methods', () => {
|
||||
(p) => p.trackEnterLinear(enterLinearMetadata),
|
||||
TelemetryEvents.ENTER_LINEAR_MODE
|
||||
],
|
||||
[
|
||||
'trackModeTimeSpent',
|
||||
(p) => p.trackModeTimeSpent(modeTimeSpentMetadata),
|
||||
TelemetryEvents.MODE_TIME_SPENT
|
||||
],
|
||||
[
|
||||
'trackShareFlow',
|
||||
(p) => p.trackShareFlow(shareFlowMetadata),
|
||||
|
||||
@@ -17,7 +17,6 @@ import type {
|
||||
CreditTopupMetadata,
|
||||
DefaultViewSetMetadata,
|
||||
EnterLinearMetadata,
|
||||
ModeTimeSpentMetadata,
|
||||
ShareFlowMetadata,
|
||||
ExecutionContext,
|
||||
ExecutionTriggerSource,
|
||||
@@ -381,10 +380,6 @@ export class MixpanelTelemetryProvider implements TelemetryProvider {
|
||||
this.trackEvent(TelemetryEvents.ENTER_LINEAR_MODE, metadata)
|
||||
}
|
||||
|
||||
trackModeTimeSpent(metadata: ModeTimeSpentMetadata): void {
|
||||
this.trackEvent(TelemetryEvents.MODE_TIME_SPENT, metadata)
|
||||
}
|
||||
|
||||
trackShareFlow(metadata: ShareFlowMetadata): void {
|
||||
this.trackEvent(TelemetryEvents.SHARE_FLOW, metadata)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import type {
|
||||
AuthMetadata,
|
||||
DefaultViewSetMetadata,
|
||||
EnterLinearMetadata,
|
||||
ModeTimeSpentMetadata,
|
||||
ShareFlowMetadata,
|
||||
ExecutionContext,
|
||||
ExecutionErrorMetadata,
|
||||
@@ -392,10 +391,6 @@ export class PostHogTelemetryProvider implements TelemetryProvider {
|
||||
this.trackEvent(TelemetryEvents.ENTER_LINEAR_MODE, metadata)
|
||||
}
|
||||
|
||||
trackModeTimeSpent(metadata: ModeTimeSpentMetadata): void {
|
||||
this.trackEvent(TelemetryEvents.MODE_TIME_SPENT, metadata)
|
||||
}
|
||||
|
||||
trackShareFlow(metadata: ShareFlowMetadata): void {
|
||||
this.trackEvent(TelemetryEvents.SHARE_FLOW, metadata)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
* 3. Check dist/assets/*.js files contain no tracking code
|
||||
*/
|
||||
|
||||
import type { AppMode } from '@/composables/useAppMode'
|
||||
import type { SubscriptionDialogReason } from '@/platform/cloud/subscription/composables/useSubscriptionDialog'
|
||||
import type { TierKey } from '@/platform/cloud/subscription/constants/tierPricing'
|
||||
import type { BillingCycle } from '@/platform/cloud/subscription/utils/subscriptionTierRank'
|
||||
@@ -166,12 +165,6 @@ export interface WorkflowImportMetadata {
|
||||
|
||||
export interface EnterLinearMetadata {
|
||||
source?: string
|
||||
/**
|
||||
* The workflow's entry path for this session. `'shared_url'` means App Mode
|
||||
* was reached via a link someone shared (`?share=`), as opposed to the user
|
||||
* opening their own/original workflow.
|
||||
*/
|
||||
open_source?: AppModeOpenSource
|
||||
workflow_id?: string
|
||||
}
|
||||
|
||||
@@ -181,16 +174,6 @@ export interface WorkflowSavedMetadata {
|
||||
workflow_id?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Mode time-spent metadata. Emitted when leaving a mode (or hiding the tab),
|
||||
* reporting the active (tab-visible) seconds spent in that mode. Summing
|
||||
* `duration_seconds` grouped by `mode` yields time spent per mode.
|
||||
*/
|
||||
export interface ModeTimeSpentMetadata {
|
||||
mode: AppMode
|
||||
duration_seconds: number
|
||||
}
|
||||
|
||||
export interface DefaultViewSetMetadata {
|
||||
default_view: 'app' | 'graph'
|
||||
}
|
||||
@@ -218,12 +201,6 @@ export type WorkflowOpenSource = NonNullable<
|
||||
WorkflowImportMetadata['open_source']
|
||||
>
|
||||
|
||||
/**
|
||||
* Narrower type for app mode entry tracking.
|
||||
* Maps WorkflowOpenSource values to allowed app mode sources.
|
||||
*/
|
||||
export type AppModeOpenSource = 'shared_url' | 'original' | 'unknown'
|
||||
|
||||
/**
|
||||
* Template library metadata
|
||||
*/
|
||||
@@ -462,7 +439,6 @@ export interface TelemetryProvider {
|
||||
trackWorkflowSaved?(metadata: WorkflowSavedMetadata): void
|
||||
trackDefaultViewSet?(metadata: DefaultViewSetMetadata): void
|
||||
trackEnterLinear?(metadata: EnterLinearMetadata): void
|
||||
trackModeTimeSpent?(metadata: ModeTimeSpentMetadata): void
|
||||
trackShareFlow?(metadata: ShareFlowMetadata): void
|
||||
|
||||
// Page visibility events
|
||||
@@ -550,7 +526,6 @@ export const TelemetryEvents = {
|
||||
WORKFLOW_IMPORTED: 'app:workflow_imported',
|
||||
WORKFLOW_OPENED: 'app:workflow_opened',
|
||||
ENTER_LINEAR_MODE: 'app:app_mode_opened',
|
||||
MODE_TIME_SPENT: 'app:mode_time_spent',
|
||||
SHARE_FLOW: 'app:share_flow',
|
||||
|
||||
// Page Visibility
|
||||
@@ -627,7 +602,6 @@ export type TelemetryEventProperties =
|
||||
| HelpCenterClosedMetadata
|
||||
| WorkflowCreatedMetadata
|
||||
| EnterLinearMetadata
|
||||
| ModeTimeSpentMetadata
|
||||
| ShareFlowMetadata
|
||||
| WorkflowSavedMetadata
|
||||
| DefaultViewSetMetadata
|
||||
|
||||
@@ -61,12 +61,10 @@ function makeWorkflowData(
|
||||
}
|
||||
}
|
||||
|
||||
const { mockConfirm, mockTrackWorkflowSaved, mockTrackEnterLinear } =
|
||||
vi.hoisted(() => ({
|
||||
mockConfirm: vi.fn(),
|
||||
mockTrackWorkflowSaved: vi.fn(),
|
||||
mockTrackEnterLinear: vi.fn()
|
||||
}))
|
||||
const { mockConfirm, mockTrackWorkflowSaved } = vi.hoisted(() => ({
|
||||
mockConfirm: vi.fn(),
|
||||
mockTrackWorkflowSaved: vi.fn()
|
||||
}))
|
||||
|
||||
const draftStoreMocks = vi.hoisted(() => ({
|
||||
saveDraft: vi.fn(() => true),
|
||||
@@ -110,7 +108,7 @@ vi.mock('@/platform/telemetry', () => ({
|
||||
useTelemetry: () => ({
|
||||
trackDefaultViewSet: vi.fn(),
|
||||
trackWorkflowSaved: mockTrackWorkflowSaved,
|
||||
trackEnterLinear: mockTrackEnterLinear
|
||||
trackEnterLinear: vi.fn()
|
||||
})
|
||||
}))
|
||||
|
||||
@@ -846,69 +844,6 @@ describe('useWorkflowService', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('app:app_mode_opened open_source', () => {
|
||||
beforeEach(() => {
|
||||
mockOpenWorkflow()
|
||||
mockTrackEnterLinear.mockClear()
|
||||
})
|
||||
|
||||
it('tags the entry as shared_url when loaded from a shared link', async () => {
|
||||
const workflow = createModeTestWorkflow({ loaded: false })
|
||||
|
||||
await service.afterLoadNewGraph(
|
||||
workflow,
|
||||
makeWorkflowData({ linearMode: true }),
|
||||
'shared_url'
|
||||
)
|
||||
|
||||
expect(mockTrackEnterLinear).toHaveBeenCalledWith({
|
||||
source: 'workflow',
|
||||
open_source: 'shared_url'
|
||||
})
|
||||
})
|
||||
|
||||
it('defaults open_source to unknown when no source is provided', async () => {
|
||||
const workflow = createModeTestWorkflow({ loaded: false })
|
||||
|
||||
await service.afterLoadNewGraph(
|
||||
workflow,
|
||||
makeWorkflowData({ linearMode: true })
|
||||
)
|
||||
|
||||
expect(mockTrackEnterLinear).toHaveBeenCalledWith({
|
||||
source: 'workflow',
|
||||
open_source: 'unknown'
|
||||
})
|
||||
})
|
||||
|
||||
it('tags the entry as original when loaded from a non-shared source', async () => {
|
||||
const workflow = createModeTestWorkflow({ loaded: false })
|
||||
|
||||
await service.afterLoadNewGraph(
|
||||
workflow,
|
||||
makeWorkflowData({ linearMode: true }),
|
||||
'template'
|
||||
)
|
||||
|
||||
expect(mockTrackEnterLinear).toHaveBeenCalledWith({
|
||||
source: 'workflow',
|
||||
open_source: 'original'
|
||||
})
|
||||
})
|
||||
|
||||
it('does not fire when the workflow is not in app mode', async () => {
|
||||
const workflow = createModeTestWorkflow({ loaded: false })
|
||||
|
||||
await service.afterLoadNewGraph(
|
||||
workflow,
|
||||
makeWorkflowData({ linearMode: false }),
|
||||
'shared_url'
|
||||
)
|
||||
|
||||
expect(mockTrackEnterLinear).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('round-trip mode preservation', () => {
|
||||
it('each workflow retains its own mode across tab switches', () => {
|
||||
const workflow1 = createModeTestWorkflow({
|
||||
|
||||
@@ -16,10 +16,6 @@ import {
|
||||
useWorkflowStore
|
||||
} from '@/platform/workflow/management/stores/workflowStore'
|
||||
import { useTelemetry } from '@/platform/telemetry'
|
||||
import type {
|
||||
WorkflowOpenSource,
|
||||
AppModeOpenSource
|
||||
} from '@/platform/telemetry/types'
|
||||
import { workflowTelemetryId } from '@/platform/telemetry/utils/workflowTelemetryId'
|
||||
import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
// eslint-disable-next-line import-x/no-restricted-paths
|
||||
@@ -48,13 +44,6 @@ function linearModeToAppMode(linearMode: unknown): AppMode | null {
|
||||
return linearMode ? 'app' : 'graph'
|
||||
}
|
||||
|
||||
function normalizeOpenSource(
|
||||
source: WorkflowOpenSource | undefined
|
||||
): AppModeOpenSource {
|
||||
if (source === 'shared_url') return 'shared_url'
|
||||
return source ? 'original' : 'unknown'
|
||||
}
|
||||
|
||||
export const useWorkflowService = () => {
|
||||
const settingStore = useSettingStore()
|
||||
const workflowStore = useWorkflowStore()
|
||||
@@ -467,8 +456,7 @@ export const useWorkflowService = () => {
|
||||
*/
|
||||
const afterLoadNewGraph = async (
|
||||
value: string | ComfyWorkflow | null,
|
||||
workflowData: ComfyWorkflowJSON,
|
||||
openSource?: WorkflowOpenSource
|
||||
workflowData: ComfyWorkflowJSON
|
||||
) => {
|
||||
const workflowStore = useWorkspaceStore().workflow
|
||||
const { isAppMode } = useAppMode()
|
||||
@@ -483,7 +471,6 @@ export const useWorkflowService = () => {
|
||||
if (!wasAppMode && workflow.initialMode === 'app') {
|
||||
useTelemetry()?.trackEnterLinear({
|
||||
source: 'workflow',
|
||||
open_source: normalizeOpenSource(openSource),
|
||||
workflow_id: workflowTelemetryId(workflow)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1433,11 +1433,7 @@ export class ComfyApp {
|
||||
}
|
||||
useTelemetry()?.trackWorkflowOpened(telemetryPayload)
|
||||
useTelemetry()?.trackWorkflowImported(telemetryPayload)
|
||||
await useWorkflowService().afterLoadNewGraph(
|
||||
workflow,
|
||||
serializedGraph,
|
||||
openSource
|
||||
)
|
||||
await useWorkflowService().afterLoadNewGraph(workflow, serializedGraph)
|
||||
|
||||
// If the canvas was not visible and we're a fresh load, resize the canvas and fit the view
|
||||
// This fixes switching from app mode to a new graph mode workflow (e.g. load template)
|
||||
|
||||
@@ -54,7 +54,6 @@ import InviteAcceptedToast from '@/platform/workspace/components/toasts/InviteAc
|
||||
import RerouteMigrationToast from '@/components/toast/RerouteMigrationToast.vue'
|
||||
import { useBrowserTabTitle } from '@/composables/useBrowserTabTitle'
|
||||
import { useCoreCommands } from '@/composables/useCoreCommands'
|
||||
import { useModeTimeTracking } from '@/composables/useModeTimeTracking'
|
||||
import { useQueuePolling } from '@/platform/remote/comfyui/useQueuePolling'
|
||||
import { useErrorHandling } from '@/composables/useErrorHandling'
|
||||
import { useReconnectQueueRefresh } from '@/composables/useReconnectQueueRefresh'
|
||||
@@ -124,12 +123,6 @@ const telemetry = useTelemetry()
|
||||
const authStore = useAuthStore()
|
||||
let hasTrackedLogin = false
|
||||
|
||||
// Track active time spent in each mode (cloud only). Must run in the
|
||||
// synchronous setup scope so the composable's scope-bound cleanup registers.
|
||||
if (isCloud && telemetry) {
|
||||
useModeTimeTracking()
|
||||
}
|
||||
|
||||
watch(
|
||||
() => colorPaletteStore.completedActivePalette,
|
||||
(newTheme) => {
|
||||
|
||||
Reference in New Issue
Block a user