diff --git a/browser_tests/fixtures/data/assetFixtures.ts b/browser_tests/fixtures/data/assetFixtures.ts index 9e8538ae62..c7188edd69 100644 --- a/browser_tests/fixtures/data/assetFixtures.ts +++ b/browser_tests/fixtures/data/assetFixtures.ts @@ -1,10 +1,11 @@ import type { Asset } from '@comfyorg/ingest-types' -function createModelAsset(overrides: Partial = {}): Asset { +function createModelAsset( + overrides: Partial = {} +): Asset & { hash?: string } { return { id: 'test-model-001', name: 'model.safetensors', - asset_hash: - 'blake3:0000000000000000000000000000000000000000000000000000000000000000', + hash: 'blake3:0000000000000000000000000000000000000000000000000000000000000000', size: 2_147_483_648, mime_type: 'application/octet-stream', tags: ['models', 'checkpoints'], @@ -16,12 +17,13 @@ function createModelAsset(overrides: Partial = {}): Asset { } } -function createInputAsset(overrides: Partial = {}): Asset { +function createInputAsset( + overrides: Partial = {} +): Asset & { hash?: string } { return { id: 'test-input-001', name: 'input.png', - asset_hash: - 'blake3:1111111111111111111111111111111111111111111111111111111111111111', + hash: 'blake3:1111111111111111111111111111111111111111111111111111111111111111', size: 2_048_576, mime_type: 'image/png', tags: ['input'], @@ -32,12 +34,13 @@ function createInputAsset(overrides: Partial = {}): Asset { } } -function createOutputAsset(overrides: Partial = {}): Asset { +function createOutputAsset( + overrides: Partial = {} +): Asset & { hash?: string } { return { id: 'test-output-001', name: 'output_00001.png', - asset_hash: - 'blake3:2222222222222222222222222222222222222222222222222222222222222222', + hash: 'blake3:2222222222222222222222222222222222222222222222222222222222222222', size: 4_194_304, mime_type: 'image/png', tags: ['output'], diff --git a/browser_tests/fixtures/sharedWorkflowImportFixture.ts b/browser_tests/fixtures/sharedWorkflowImportFixture.ts index ac3a5802d1..0a5c626863 100644 --- a/browser_tests/fixtures/sharedWorkflowImportFixture.ts +++ b/browser_tests/fixtures/sharedWorkflowImportFixture.ts @@ -43,10 +43,10 @@ const sharedWorkflowAsset: AssetInfo = { in_library: false } -const defaultInputAsset: Asset = { +const defaultInputAsset: Asset & { hash?: string } = { id: 'default-input-asset', name: defaultInputFileName, - asset_hash: defaultInputFileName, + hash: defaultInputFileName, size: 1_024, mime_type: 'image/png', tags: ['input'], @@ -55,10 +55,10 @@ const defaultInputAsset: Asset = { last_access_time: '2026-05-01T00:00:00Z' } -const importedInputAsset: Asset = { +const importedInputAsset: Asset & { hash?: string } = { id: 'imported-input-asset', name: sharedWorkflowImportScenario.inputFileName, - asset_hash: sharedWorkflowImportScenario.inputFileName, + hash: sharedWorkflowImportScenario.inputFileName, size: 1_024, mime_type: 'image/png', tags: ['input'], diff --git a/browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts b/browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts index a2bdc77bf6..922d7d319b 100644 --- a/browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts +++ b/browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts @@ -12,11 +12,10 @@ const WORKFLOW = 'missing/nested_subgraph_installed_model' const OUTER_SUBGRAPH_NODE_ID = '205' const LOTUS_MODEL_NAME = 'lotus-depth-d-v1-1.safetensors' -const LOTUS_DIFFUSION_MODEL: Asset = { +const LOTUS_DIFFUSION_MODEL: Asset & { hash?: string } = { id: 'test-lotus-depth-d-v1-1', name: LOTUS_MODEL_NAME, - asset_hash: - 'blake3:0000000000000000000000000000000000000000000000000000000000000203', + hash: 'blake3:0000000000000000000000000000000000000000000000000000000000000203', size: 1_024, mime_type: 'application/octet-stream', tags: ['models', 'diffusion_models'], diff --git a/browser_tests/tests/propertiesPanel/errorsTabMissingMediaRuntime.spec.ts b/browser_tests/tests/propertiesPanel/errorsTabMissingMediaRuntime.spec.ts index fd79e6a42c..5b982f33b9 100644 --- a/browser_tests/tests/propertiesPanel/errorsTabMissingMediaRuntime.spec.ts +++ b/browser_tests/tests/propertiesPanel/errorsTabMissingMediaRuntime.spec.ts @@ -44,10 +44,10 @@ const emptyMediaLoaderNodes = [ } ] -const cloudOutputAsset: Asset = { +const cloudOutputAsset: Asset & { hash?: string } = { id: 'test-output-hash-001', name: 'ComfyUI_00001_.png', - asset_hash: outputHash, + hash: outputHash, size: 4_194_304, mime_type: 'image/png', tags: ['output'], @@ -56,10 +56,10 @@ const cloudOutputAsset: Asset = { last_access_time: '2026-05-01T00:00:00Z' } -const cloudUploadedVideoAsset: Asset = { +const cloudUploadedVideoAsset: Asset & { hash?: string } = { id: 'test-uploaded-video-001', name: plainVideoFileName, - asset_hash: plainVideoFileName, + hash: plainVideoFileName, size: 1_024, mime_type: 'video/mp4', tags: ['input'], @@ -70,10 +70,10 @@ const cloudUploadedVideoAsset: Asset = { // The Cloud test app starts with a default LoadImage node. Keep that baseline // input resolvable so this spec only observes the media it creates. -const cloudDefaultGraphInputAsset: Asset = { +const cloudDefaultGraphInputAsset: Asset & { hash?: string } = { id: 'test-default-input-001', name: '00000000000000000000000Aexample.png', - asset_hash: '00000000000000000000000Aexample.png', + hash: '00000000000000000000000Aexample.png', size: 1_024, mime_type: 'image/png', tags: ['input'], diff --git a/src/platform/assets/components/AssetBrowserModal.test.ts b/src/platform/assets/components/AssetBrowserModal.test.ts index e2d6ed7da7..da02105f44 100644 --- a/src/platform/assets/components/AssetBrowserModal.test.ts +++ b/src/platform/assets/components/AssetBrowserModal.test.ts @@ -176,7 +176,7 @@ describe('AssetBrowserModal', () => { ): AssetItem => ({ id, name, - asset_hash: `blake3:${id.padEnd(64, '0')}`, + hash: `blake3:${id.padEnd(64, '0')}`, size: 1024000, mime_type: 'application/octet-stream', tags: ['models', category, 'test'], diff --git a/src/platform/assets/components/AssetCard.test.ts b/src/platform/assets/components/AssetCard.test.ts index 0433ad29cc..a32e1cd89f 100644 --- a/src/platform/assets/components/AssetCard.test.ts +++ b/src/platform/assets/components/AssetCard.test.ts @@ -49,10 +49,10 @@ const ORIGINAL_FILENAME = 'sunset_photo.png' function createDisplayAsset( overrides: Partial = {} ): AssetDisplayItem { - return { + const base = { id: 'asset-1', name: HASH, - asset_hash: HASH, + hash: HASH, tags: ['input'], preview_url: '/preview.png', secondaryText: '', @@ -62,6 +62,7 @@ function createDisplayAsset( metadata: { filename: ORIGINAL_FILENAME }, ...overrides } + return base } function renderCard(asset: AssetDisplayItem) { @@ -97,7 +98,7 @@ describe('AssetCard', () => { }) describe('FE-228: filename rendering', () => { - it('renders the human-readable filename instead of asset_hash when asset.name equals asset_hash', () => { + it('renders the human-readable filename instead of hash when asset.name equals hash', () => { const asset = createDisplayAsset() renderCard(asset) @@ -130,7 +131,7 @@ describe('AssetCard', () => { const asset = createDisplayAsset({ id: 'model-1', name: MODEL_FILENAME, - asset_hash: undefined, + hash: undefined, tags: ['models', 'loras'], user_metadata: { name: CURATED_NAME }, metadata: { filename: MODEL_FILENAME } @@ -146,7 +147,7 @@ describe('AssetCard', () => { it('ignores user_metadata.name that duplicates the hash and falls back to metadata.filename', () => { const asset = createDisplayAsset({ name: HASH, - asset_hash: HASH, + hash: HASH, user_metadata: { name: HASH }, metadata: { filename: ORIGINAL_FILENAME } }) diff --git a/src/platform/assets/components/Media3DTop.test.ts b/src/platform/assets/components/Media3DTop.test.ts index 4c98ac0f47..2133049573 100644 --- a/src/platform/assets/components/Media3DTop.test.ts +++ b/src/platform/assets/components/Media3DTop.test.ts @@ -32,7 +32,7 @@ function makeAsset(overrides: Partial = {}): AssetMeta { return { id: 'asset-1', name: 'mesh.glb', - asset_hash: null, + hash: null, mime_type: 'model/gltf-binary', tags: [], kind: '3D', diff --git a/src/platform/assets/components/MediaVideoTop.test.ts b/src/platform/assets/components/MediaVideoTop.test.ts index f166c025ce..6a5c96cdc6 100644 --- a/src/platform/assets/components/MediaVideoTop.test.ts +++ b/src/platform/assets/components/MediaVideoTop.test.ts @@ -13,7 +13,7 @@ function createVideoAsset( return { id: 'video-1', name: 'clip.mp4', - asset_hash: null, + hash: null, mime_type: mimeType, tags: [], kind: 'video', diff --git a/src/platform/assets/components/modelInfo/ModelInfoPanel.test.ts b/src/platform/assets/components/modelInfo/ModelInfoPanel.test.ts index afa672ec09..fc731e82b5 100644 --- a/src/platform/assets/components/modelInfo/ModelInfoPanel.test.ts +++ b/src/platform/assets/components/modelInfo/ModelInfoPanel.test.ts @@ -28,7 +28,7 @@ describe('ModelInfoPanel', () => { ): AssetDisplayItem => ({ id: 'test-id', name: 'test-model.safetensors', - asset_hash: 'hash123', + hash: 'hash123', size: 1024, mime_type: 'application/octet-stream', tags: ['models', 'checkpoints'], diff --git a/src/platform/assets/composables/useAssetBrowser.perf.test.ts b/src/platform/assets/composables/useAssetBrowser.perf.test.ts index b15b44a492..fc4ec3dd51 100644 --- a/src/platform/assets/composables/useAssetBrowser.perf.test.ts +++ b/src/platform/assets/composables/useAssetBrowser.perf.test.ts @@ -26,7 +26,7 @@ function makeAsset(index: number): AssetItem { return { id: `asset-${index}`, name: `asset-${index}.safetensors`, - asset_hash: `blake3:${index}`, + hash: `blake3:${index}`, size: 1024, mime_type: 'application/octet-stream', tags: ['models', category], diff --git a/src/platform/assets/composables/useAssetBrowser.test.ts b/src/platform/assets/composables/useAssetBrowser.test.ts index ead824bef9..c767c5c216 100644 --- a/src/platform/assets/composables/useAssetBrowser.test.ts +++ b/src/platform/assets/composables/useAssetBrowser.test.ts @@ -35,7 +35,7 @@ describe('useAssetBrowser', () => { const createApiAsset = (overrides: Partial = {}): AssetItem => ({ id: 'test-id', name: 'test-asset.safetensors', - asset_hash: 'blake3:abc123', + hash: 'blake3:abc123', size: 1024, mime_type: 'application/octet-stream', tags: ['models', 'checkpoints'], diff --git a/src/platform/assets/composables/useMediaAssetActions.test.ts b/src/platform/assets/composables/useMediaAssetActions.test.ts index 60165076c9..531aad4748 100644 --- a/src/platform/assets/composables/useMediaAssetActions.test.ts +++ b/src/platform/assets/composables/useMediaAssetActions.test.ts @@ -296,7 +296,7 @@ describe('useMediaAssetActions', () => { const asset = createMockAsset({ name: 'my-image.jpeg', - asset_hash: 'hash123.jpeg' + hash: 'hash123.jpeg' }) await actions.addWorkflow(asset) @@ -310,12 +310,12 @@ describe('useMediaAssetActions', () => { mockIsCloud.value = true }) - it('should use asset_hash as filename when available', async () => { + it('should use hash as filename when available', async () => { const actions = useMediaAssetActions() const asset = createMockAsset({ name: 'original.jpeg', - asset_hash: 'abc123hash.jpeg' + hash: 'abc123hash.jpeg' }) await actions.addWorkflow(asset) @@ -323,12 +323,12 @@ describe('useMediaAssetActions', () => { expect(capturedFilenames.values).toContain('abc123hash.jpeg') }) - it('should fall back to asset.name when asset_hash is not available', async () => { + it('should fall back to asset.name when hash is not available', async () => { const actions = useMediaAssetActions() const asset = createMockAsset({ name: 'fallback-name.jpeg', - asset_hash: undefined + hash: undefined }) await actions.addWorkflow(asset) @@ -336,12 +336,12 @@ describe('useMediaAssetActions', () => { expect(capturedFilenames.values).toContain('fallback-name.jpeg') }) - it('should fall back to asset.name when asset_hash is null', async () => { + it('should fall back to asset.name when hash is null', async () => { const actions = useMediaAssetActions() const asset = createMockAsset({ name: 'fallback-null.jpeg', - asset_hash: null + hash: null }) await actions.addWorkflow(asset) @@ -357,19 +357,19 @@ describe('useMediaAssetActions', () => { mockIsCloud.value = true }) - it('should use asset_hash for each asset', async () => { + it('should use hash for each asset', async () => { const actions = useMediaAssetActions() const assets = [ createMockAsset({ id: '1', name: 'file1.jpeg', - asset_hash: 'hash1.jpeg' + hash: 'hash1.jpeg' }), createMockAsset({ id: '2', name: 'file2.jpeg', - asset_hash: 'hash2.jpeg' + hash: 'hash2.jpeg' }) ] @@ -973,7 +973,7 @@ describe('useMediaAssetActions', () => { const asset = createMockAsset({ id: 'asset-match', name: 'foo.png', - asset_hash: 'abc123.png', + hash: 'abc123.png', tags: ['input'] }) @@ -1051,7 +1051,7 @@ describe('useMediaAssetActions', () => { const asset = createMockAsset({ id: 'asset-failed', name: 'failed.png', - asset_hash: 'failhash.png' + hash: 'failhash.png' }) await actions.deleteAssets(asset) diff --git a/src/platform/assets/composables/useMediaAssetActions.ts b/src/platform/assets/composables/useMediaAssetActions.ts index 25d5f9b58b..37330837fe 100644 --- a/src/platform/assets/composables/useMediaAssetActions.ts +++ b/src/platform/assets/composables/useMediaAssetActions.ts @@ -43,8 +43,8 @@ const EXCLUDED_TAGS = new Set(['models', 'input', 'output']) * * Output assets emit ` [output]` (and the subfolder-prefixed form when * present in metadata). Input/temp assets emit the bare name plus the explicit - * annotation. `asset_hash` is included whenever present, since cloud-stored - * assets can be referenced by hash. + * annotation. The content `hash` is included whenever present, since + * cloud-stored assets can be referenced by hash. */ function widgetValueVariantsForAsset(asset: AssetItem): string[] { const variants: string[] = [] @@ -62,7 +62,7 @@ function widgetValueVariantsForAsset(asset: AssetItem): string[] { variants.push(`${name} [input]`) } } - const hash = asset.hash ?? asset.asset_hash + const hash = asset.hash if (hash) variants.push(hash) return variants } @@ -300,10 +300,9 @@ export function useMediaAssetActions() { const metadata = getOutputAssetMetadata(targetAsset.user_metadata) const assetType = getAssetType(targetAsset, 'input') - // In Cloud mode, use the content hash (the actual stored filename), - // preferring hash and falling back to the deprecated asset_hash alias. + // In Cloud mode, use the content hash (the actual stored filename). // In OSS mode, use the original name. - const cloudHash = targetAsset.hash ?? targetAsset.asset_hash + const cloudHash = targetAsset.hash const filename = isCloud && cloudHash ? cloudHash : targetAsset.name // Create annotated path for the asset @@ -445,10 +444,9 @@ export function useMediaAssetActions() { const metadata = getOutputAssetMetadata(asset.user_metadata) const assetType = getAssetType(asset, 'input') - // In Cloud mode, use the content hash (the actual stored filename), - // preferring hash and falling back to the deprecated asset_hash alias. + // In Cloud mode, use the content hash (the actual stored filename). // In OSS mode, use the original name. - const cloudHash = asset.hash ?? asset.asset_hash + const cloudHash = asset.hash const filename = isCloud && cloudHash ? cloudHash : asset.name const annotated = createAnnotatedPath( diff --git a/src/platform/assets/fixtures/ui-mock-assets.ts b/src/platform/assets/fixtures/ui-mock-assets.ts index a31c7b859c..afa6f27e26 100644 --- a/src/platform/assets/fixtures/ui-mock-assets.ts +++ b/src/platform/assets/fixtures/ui-mock-assets.ts @@ -97,11 +97,12 @@ export function createMockAssets(count: number = 20): AssetItem[] { const lastAccessTime = getRandomISODate() const fakeFileName = `${fakeFunnyModelNames[index]}${extension}` + const fakeAssetHash = generateFakeAssetHash() return { id: `mock-asset-uuid-${(index + 1).toString().padStart(3, '0')}-fake`, name: fakeFileName, - asset_hash: generateFakeAssetHash(), + hash: fakeAssetHash, size: sizeInBytes, mime_type: mimeType, tags: [ diff --git a/src/platform/assets/schemas/assetSchema.ts b/src/platform/assets/schemas/assetSchema.ts index dfc07d194e..ab88b1bbb3 100644 --- a/src/platform/assets/schemas/assetSchema.ts +++ b/src/platform/assets/schemas/assetSchema.ts @@ -6,7 +6,6 @@ const zAsset = z.object({ id: z.string(), name: z.string(), hash: z.string().nullish(), - asset_hash: z.string().nullish(), size: z.number().optional(), // TBD: Will be provided by history API in the future mime_type: z.string().nullish(), tags: z.array(z.string()).optional().default([]), diff --git a/src/platform/assets/utils/assetMetadataUtils.test.ts b/src/platform/assets/utils/assetMetadataUtils.test.ts index 2de2277fc6..703c3a6683 100644 --- a/src/platform/assets/utils/assetMetadataUtils.test.ts +++ b/src/platform/assets/utils/assetMetadataUtils.test.ts @@ -21,7 +21,7 @@ describe('assetMetadataUtils', () => { const mockAsset: AssetItem = { id: 'test-id', name: 'test-model', - asset_hash: 'hash123', + hash: 'hash123', size: 1024, mime_type: 'application/octet-stream', tags: ['models', 'checkpoints'], diff --git a/src/platform/assets/utils/assetMetadataUtils.ts b/src/platform/assets/utils/assetMetadataUtils.ts index 0e8308ff30..1570a6cf24 100644 --- a/src/platform/assets/utils/assetMetadataUtils.ts +++ b/src/platform/assets/utils/assetMetadataUtils.ts @@ -201,10 +201,10 @@ export function getAssetCardTitle(asset: AssetItem): string { /** * Returns the filename component the cloud `/api/view` endpoint resolves - * for this asset — `asset_hash` when present (cloud assets are hash-keyed + * for this asset — `hash` when present (cloud assets are hash-keyed * in storage), otherwise `asset.name`. Use this when constructing widget * values or media URLs that must round-trip through the view endpoint. */ export function getAssetUrlFilename(asset: AssetItem): string { - return asset.hash ?? asset.asset_hash ?? asset.name + return asset.hash ?? asset.name } diff --git a/src/platform/assets/utils/assetPreviewUtil.test.ts b/src/platform/assets/utils/assetPreviewUtil.test.ts index 07c71a9b99..15a846032f 100644 --- a/src/platform/assets/utils/assetPreviewUtil.test.ts +++ b/src/platform/assets/utils/assetPreviewUtil.test.ts @@ -56,7 +56,7 @@ function mockFetchError() { const cloudAsset = { id: '72d169cc-7f9a-40d2-9382-35eadcba0a6a', name: 'mesh/ComfyUI_00003_.glb', - asset_hash: 'c6cadcee57dd.glb', + hash: 'c6cadcee57dd.glb', preview_id: null, preview_url: undefined } @@ -110,9 +110,7 @@ describe('findOutputAsset', () => { const result = await findOutputAsset('c6cadcee57dd.glb') expect(mockFetchApi).toHaveBeenCalledOnce() - expect(mockFetchApi.mock.calls[0][0]).toContain( - 'asset_hash=c6cadcee57dd.glb' - ) + expect(mockFetchApi.mock.calls[0][0]).toContain('hash=c6cadcee57dd.glb') expect(result).toEqual(cloudAsset) }) @@ -123,7 +121,7 @@ describe('findOutputAsset', () => { const result = await findOutputAsset('ComfyUI_00081_.glb') expect(mockFetchApi).toHaveBeenCalledTimes(2) - expect(mockFetchApi.mock.calls[0][0]).toContain('asset_hash=') + expect(mockFetchApi.mock.calls[0][0]).toContain('hash=') expect(mockFetchApi.mock.calls[1][0]).toContain('name_contains=') expect(result).toEqual(localAsset) }) diff --git a/src/platform/assets/utils/assetPreviewUtil.ts b/src/platform/assets/utils/assetPreviewUtil.ts index 117b540241..1ffdbd3185 100644 --- a/src/platform/assets/utils/assetPreviewUtil.ts +++ b/src/platform/assets/utils/assetPreviewUtil.ts @@ -6,7 +6,6 @@ interface AssetRecord { id: string name: string hash?: string - asset_hash?: string preview_url?: string preview_id?: string | null } @@ -36,14 +35,14 @@ function resolvePreviewUrl(asset: AssetRecord): string { /** * Find an output asset record by content hash, falling back to name. - * On cloud, output filenames are content-hashed; use asset_hash to match. + * On cloud, output filenames are content-hashed; use hash to match. * On local, filenames are not hashed; use name_contains to match. */ export async function findOutputAsset( name: string ): Promise { - const byHash = await fetchAssets({ asset_hash: name }) - const hashMatch = byHash.find((a) => (a.hash ?? a.asset_hash) === name) + const byHash = await fetchAssets({ hash: name }) + const hashMatch = byHash.find((a) => a.hash === name) if (hashMatch) return hashMatch const byName = await fetchAssets({ name_contains: name }) diff --git a/src/platform/assets/utils/clearNodePreviewCacheForValues.ts b/src/platform/assets/utils/clearNodePreviewCacheForValues.ts index bbd6d9c5f2..0d21e2358d 100644 --- a/src/platform/assets/utils/clearNodePreviewCacheForValues.ts +++ b/src/platform/assets/utils/clearNodePreviewCacheForValues.ts @@ -15,7 +15,7 @@ import { collectAllNodes } from '@/utils/graphTraversalUtil' * * Comparison is full-string against the widget value as stored — callers must * provide the canonical widget-value variants for each deleted asset (e.g. - * `foo.png`, `foo.png [output]`, `sub/foo.png [output]`, ``). This + * `foo.png`, `foo.png [output]`, `sub/foo.png [output]`, ``). This * avoids false matches when two distinct assets share a basename across * input/output sources. * diff --git a/src/platform/missingMedia/missingMediaAssetResolver.test.ts b/src/platform/missingMedia/missingMediaAssetResolver.test.ts index c6eee64c47..632320759c 100644 --- a/src/platform/missingMedia/missingMediaAssetResolver.test.ts +++ b/src/platform/missingMedia/missingMediaAssetResolver.test.ts @@ -50,7 +50,7 @@ function makeAsset(name: string, assetHash: string | null = null): AssetItem { return { id: name, name, - asset_hash: assetHash, + hash: assetHash, mime_type: null, tags: ['input'] } diff --git a/src/platform/missingMedia/missingMediaAssetResolver.ts b/src/platform/missingMedia/missingMediaAssetResolver.ts index 946a530166..20f803c51a 100644 --- a/src/platform/missingMedia/missingMediaAssetResolver.ts +++ b/src/platform/missingMedia/missingMediaAssetResolver.ts @@ -85,7 +85,7 @@ export function getAssetDetectionNames( ): string[] { const names = new Set() // Treat names and hashes as opaque match keys because Cloud may use either in widget values. - addPathDetectionNames(names, asset.hash ?? asset.asset_hash, options) + addPathDetectionNames(names, asset.hash, options) addPathDetectionNames(names, asset.name, options) const subfolder = asset.user_metadata?.subfolder diff --git a/src/platform/missingMedia/missingMediaScan.test.ts b/src/platform/missingMedia/missingMediaScan.test.ts index 80580a8960..205ea0b265 100644 --- a/src/platform/missingMedia/missingMediaScan.test.ts +++ b/src/platform/missingMedia/missingMediaScan.test.ts @@ -115,7 +115,7 @@ function makeAsset(name: string, assetHash: string | null = null): AssetItem { return { id: name, name, - asset_hash: assetHash, + hash: assetHash, mime_type: null, tags: ['input'] } @@ -532,7 +532,7 @@ describe('verifyMediaCandidates', () => { }) }) - it('matches asset names when asset_hash is null', async () => { + it('matches asset names when hash is null', async () => { const candidates = [ makeCandidate('1', 'legacy-photo.png', { isMissing: undefined }), makeCandidate('2', 'missing-photo.png', { isMissing: undefined }) diff --git a/src/platform/missingMedia/missingMediaScan.ts b/src/platform/missingMedia/missingMediaScan.ts index 9adb179f82..db74350554 100644 --- a/src/platform/missingMedia/missingMediaScan.ts +++ b/src/platform/missingMedia/missingMediaScan.ts @@ -140,8 +140,8 @@ interface MediaVerificationOptions { * Verify media candidates against assets available to the current runtime. * * A candidate's `name` may be either a filename or an opaque asset hash. - * Cloud-side `asset_hash` is not guaranteed to follow a single shape, so we - * match against the union of `asset.name` and `asset.asset_hash`. Output + * Cloud-side `hash` is not guaranteed to follow a single shape, so we + * match against the union of `asset.name` and `asset.hash`. Output * candidates are matched against Cloud output assets or Core generated-history * assets because Core resolves those annotations against output folders, not * input files. diff --git a/src/platform/missingModel/missingModelScan.test.ts b/src/platform/missingModel/missingModelScan.test.ts index e365718d28..879ba8de89 100644 --- a/src/platform/missingModel/missingModelScan.test.ts +++ b/src/platform/missingModel/missingModelScan.test.ts @@ -1445,13 +1445,13 @@ describe('verifyAssetSupportedCandidates', () => { { id: '1', name: 'my_model.safetensors', - asset_hash: null, + hash: null, metadata: { filename: 'my_model.safetensors' } }, { id: '2', name: 'other_model.safetensors', - asset_hash: null, + hash: null, metadata: { filename: 'other_model.safetensors' } } ]) @@ -1465,7 +1465,7 @@ describe('verifyAssetSupportedCandidates', () => { ) }) - it('should resolve isMissing=false when asset with matching asset_hash exists', async () => { + it('should resolve isMissing=false when asset with matching hash exists', async () => { const candidates = [ makeAssetCandidate('model.safetensors', { hash: 'abc123', @@ -1473,7 +1473,7 @@ describe('verifyAssetSupportedCandidates', () => { }) ] mockGetAssets.mockReturnValue([ - { id: '1', name: 'model.safetensors', asset_hash: 'sha256:abc123' } + { id: '1', name: 'model.safetensors', hash: 'sha256:abc123' } ]) await verifyAssetSupportedCandidates(candidates) @@ -1487,7 +1487,7 @@ describe('verifyAssetSupportedCandidates', () => { { id: '1', name: 'my_model.safetensors', - asset_hash: null, + hash: null, metadata: { filename: 'my_model.safetensors' } } ]) @@ -1578,7 +1578,7 @@ describe('verifyAssetSupportedCandidates', () => { { id: '1', name: 'checkpoint.safetensors', - asset_hash: null, + hash: null, metadata: { filename: 'checkpoint.safetensors' } } ] @@ -1601,7 +1601,7 @@ describe('verifyAssetSupportedCandidates', () => { { id: '1', name: 'model.safetensors', - asset_hash: null, + hash: null, metadata: { filename: 'model.safetensors' } } ]) @@ -1617,7 +1617,7 @@ describe('verifyAssetSupportedCandidates', () => { { id: '1', name: 'my_model.safetensors', - asset_hash: null, + hash: null, metadata: { filename: 'subfolder/my_model.safetensors' } } ]) diff --git a/src/platform/missingModel/missingModelScan.ts b/src/platform/missingModel/missingModelScan.ts index 6e3b96b65e..34708b4a63 100644 --- a/src/platform/missingModel/missingModelScan.ts +++ b/src/platform/missingModel/missingModelScan.ts @@ -501,8 +501,7 @@ function isAssetInstalled( ): boolean { if (candidate.hash && candidate.hashType) { const candidateHash = `${candidate.hashType}:${candidate.hash}` - if (assets.some((a) => (a.hash ?? a.asset_hash) === candidateHash)) - return true + if (assets.some((a) => a.hash === candidateHash)) return true } const normalizedName = normalizePath(candidate.name) diff --git a/src/renderer/extensions/vueNodes/widgets/composables/useComboWidget.test.ts b/src/renderer/extensions/vueNodes/widgets/composables/useComboWidget.test.ts index 0eaab34c95..357a03852b 100644 --- a/src/renderer/extensions/vueNodes/widgets/composables/useComboWidget.test.ts +++ b/src/renderer/extensions/vueNodes/widgets/composables/useComboWidget.test.ts @@ -12,7 +12,7 @@ function createMockAssetItem(overrides: Partial = {}): AssetItem { return { id: 'test-asset-id', name: 'test-image.png', - asset_hash: 'hash123', + hash: 'hash123', size: 1024, mime_type: 'image/png', tags: ['input'], @@ -432,7 +432,7 @@ describe('useComboWidget', () => { [ createMockAssetItem({ name: scenario.assetName, - asset_hash: scenario.assetHash + hash: scenario.assetHash }) ] ) @@ -463,7 +463,7 @@ describe('useComboWidget', () => { [ createMockAssetItem({ name: scenario.assetName, - asset_hash: scenario.assetHash + hash: scenario.assetHash }) ] ) @@ -483,11 +483,11 @@ describe('useComboWidget', () => { [ createMockAssetItem({ name: `fallback-${scenario.assetName}`, - asset_hash: fallbackHash + hash: fallbackHash }), createMockAssetItem({ name: scenario.assetName, - asset_hash: scenario.assetHash + hash: scenario.assetHash }) ] ) @@ -507,11 +507,11 @@ describe('useComboWidget', () => { [ createMockAssetItem({ name: `fallback-${scenario.assetName}`, - asset_hash: fallbackHash + hash: fallbackHash }), createMockAssetItem({ name: scenario.assetName, - asset_hash: scenario.assetHash + hash: scenario.assetHash }) ] ) @@ -531,11 +531,11 @@ describe('useComboWidget', () => { [ createMockAssetItem({ name: scenario.assetHash, - asset_hash: nameMatchHash + hash: nameMatchHash }), createMockAssetItem({ name: scenario.assetName, - asset_hash: scenario.assetHash + hash: scenario.assetHash }) ] ) @@ -575,15 +575,15 @@ describe('useComboWidget', () => { [ createMockAssetItem({ name: 'wrong-kind.txt', - asset_hash: 'wrong-kind.txt' + hash: 'wrong-kind.txt' }), createMockAssetItem({ name: scenario.assetName, - asset_hash: scenario.assetHash + hash: scenario.assetHash }), createMockAssetItem({ name: `second-${scenario.assetName}`, - asset_hash: `second-${scenario.assetHash}` + hash: `second-${scenario.assetHash}` }) ] ) @@ -606,7 +606,7 @@ describe('useComboWidget', () => { [ createMockAssetItem({ name: scenario.assetName, - asset_hash: '' + hash: '' }) ] ) @@ -639,7 +639,7 @@ describe('useComboWidget', () => { [ createMockAssetItem({ name: scenario.assetName, - asset_hash: scenario.assetHash + hash: scenario.assetHash }) ] ) @@ -667,7 +667,7 @@ describe('useComboWidget', () => { [ createMockAssetItem({ name: scenario.assetName, - asset_hash: scenario.assetHash + hash: scenario.assetHash }) ] ) @@ -769,7 +769,7 @@ describe('useComboWidget', () => { mockAssetsStoreState.inputAssets = [ createMockAssetItem({ name: scenario.assetName, - asset_hash: scenario.assetHash + hash: scenario.assetHash }) ] }) @@ -820,7 +820,7 @@ describe('useComboWidget', () => { createMockAssetItem({ id: 'asset-123', name: scenario.assetName, - asset_hash: scenario.assetHash + hash: scenario.assetHash }) ] mockAssetsStoreState.inputLoading = false diff --git a/src/renderer/extensions/vueNodes/widgets/composables/useComboWidget.ts b/src/renderer/extensions/vueNodes/widgets/composables/useComboWidget.ts index b06709cee6..646cfbf594 100644 --- a/src/renderer/extensions/vueNodes/widgets/composables/useComboWidget.ts +++ b/src/renderer/extensions/vueNodes/widgets/composables/useComboWidget.ts @@ -137,7 +137,7 @@ function getCloudInputAssets(nodeType: string | undefined): AssetItem[] { } function getCloudInputAssetValue(asset: AssetItem): string | undefined { - return asset.hash ?? asset.asset_hash ?? undefined + return asset.hash ?? undefined } function getCloudInputAssetValues(nodeType: string | undefined): string[] { diff --git a/src/renderer/extensions/vueNodes/widgets/composables/useWidgetSelectItems.test.ts b/src/renderer/extensions/vueNodes/widgets/composables/useWidgetSelectItems.test.ts index d669d6a489..43a4c99e97 100644 --- a/src/renderer/extensions/vueNodes/widgets/composables/useWidgetSelectItems.test.ts +++ b/src/renderer/extensions/vueNodes/widgets/composables/useWidgetSelectItems.test.ts @@ -684,15 +684,14 @@ describe('useWidgetSelectItems', () => { it('does not expand a hash-keyed asset even if its metadata reports outputCount > 1', async () => { // Defense against future cloud-schema changes: if a flat output row - // ever ships with both asset_hash AND multi-output user_metadata, the + // ever ships with both hash AND multi-output user_metadata, the // watcher must NOT replace it with synthesized AssetItems lacking the // hash, or select+load reverts to the FE-227 broken state. mockMediaAssets.media.value = [ { id: 'asset-flat-1', name: 'z-image-turbo_00093_.png', - asset_hash: - '039b051670f08941649419dcecea41cb9057f2895388f2e8165ec99df3af0b13.png', + hash: '039b051670f08941649419dcecea41cb9057f2895388f2e8165ec99df3af0b13.png', tags: ['output'], user_metadata: { jobId: 'job-future', @@ -729,13 +728,12 @@ describe('useWidgetSelectItems', () => { ) }) - it('uses asset_hash (not human filename) as the dropdown value when present, so cloud /view can resolve by hash', async () => { + it('uses hash (not human filename) as the dropdown value when present, so cloud /view can resolve by hash', async () => { mockMediaAssets.media.value = [ { id: 'asset-out-1', name: 'z-image-turbo_00093_.png', - asset_hash: - '039b051670f08941649419dcecea41cb9057f2895388f2e8165ec99df3af0b13.png', + hash: '039b051670f08941649419dcecea41cb9057f2895388f2e8165ec99df3af0b13.png', preview_url: '/api/view?filename=039b...0b13.png', tags: ['output'] } @@ -753,7 +751,7 @@ describe('useWidgetSelectItems', () => { expect(dropdownItems.value).toHaveLength(1) // The value (item.name) — what becomes modelValue on click — must be the // hash-keyed path so /api/view resolves it. Cloud's hash is in - // asset_hash, not asset.name (which is the human filename). + // asset.hash, not asset.name (which is the human filename). expect(dropdownItems.value[0].name).toBe( '039b051670f08941649419dcecea41cb9057f2895388f2e8165ec99df3af0b13.png [output]' ) @@ -761,7 +759,7 @@ describe('useWidgetSelectItems', () => { expect(dropdownItems.value[0].label).toContain('z-image-turbo_00093_.png') }) - it('falls back to asset.name when asset_hash is absent (local/history path)', async () => { + it('falls back to asset.name when hash is absent (local/history path)', async () => { mockMediaAssets.media.value = [ { id: 'local-1', @@ -973,8 +971,7 @@ describe('useWidgetSelectItems', () => { { id: 'asset-hash-1', name: 'a1ef7d292026e89ce9bbbd8093e2d0ed6a8850361a0c22e49522ac7baa5494e5.png', - asset_hash: - 'a1ef7d292026e89ce9bbbd8093e2d0ed6a8850361a0c22e49522ac7baa5494e5', + hash: 'a1ef7d292026e89ce9bbbd8093e2d0ed6a8850361a0c22e49522ac7baa5494e5', preview_url: '/preview.png', tags: ['output'], metadata: { diff --git a/src/renderer/extensions/vueNodes/widgets/composables/useWidgetSelectItems.ts b/src/renderer/extensions/vueNodes/widgets/composables/useWidgetSelectItems.ts index c4bd112c00..8f0919480e 100644 --- a/src/renderer/extensions/vueNodes/widgets/composables/useWidgetSelectItems.ts +++ b/src/renderer/extensions/vueNodes/widgets/composables/useWidgetSelectItems.ts @@ -131,8 +131,8 @@ export function useWidgetSelectItems(options: UseWidgetSelectItemsOptions) { // Hash-keyed assets are leaf rows from the cloud `/assets` API and // already carry their own URL-resolvable filename. Expanding them via // resolveOutputAssetItems would synthesize sibling AssetItems without - // an asset_hash and reintroduce the FE-227 hash→name fallback bug. - if (asset.hash ?? asset.asset_hash) continue + // a hash and reintroduce the FE-227 hash→name fallback bug. + if (asset.hash) continue const meta = getOutputAssetMetadata(asset.user_metadata) if (!meta) continue diff --git a/src/stores/assetsStore.test.ts b/src/stores/assetsStore.test.ts index af822532f8..dacaadfdc9 100644 --- a/src/stores/assetsStore.test.ts +++ b/src/stores/assetsStore.test.ts @@ -1463,7 +1463,7 @@ describe('assetsStore - Deletion State and Input Mapping', () => { { id: 'input-1', name: 'cute-puppy.png', - asset_hash: 'abc123def.png', + hash: 'abc123def.png', tags: ['input'] } ]) @@ -1509,14 +1509,10 @@ describe('assetsStore - Deletion State and Input Mapping', () => { describe('assetsStore - Flat Output Assets (cloud-only)', () => { const FLAT_OUTPUT_PAGE_SIZE = 200 - const makeAsset = ( - id: string, - name: string, - asset_hash?: string - ): AssetItem => ({ + const makeAsset = (id: string, name: string, hash?: string): AssetItem => ({ id, name, - asset_hash, + hash, size: 0, tags: ['output'] }) diff --git a/src/stores/assetsStore.ts b/src/stores/assetsStore.ts index f34d7d530e..3889182465 100644 --- a/src/stores/assetsStore.ts +++ b/src/stores/assetsStore.ts @@ -347,12 +347,12 @@ export const useAssetsStore = defineStore('assets', () => { /** * Map of asset hash filename to asset item for O(1) lookup - * Cloud assets use asset_hash for the hash-based filename + * Cloud assets use hash for the hash-based filename */ const inputAssetsByFilename = computed(() => { const map = new Map() for (const asset of inputAssets.value) { - const hash = asset.hash ?? asset.asset_hash + const hash = asset.hash if (hash) { map.set(hash, asset) }