fix(catalog-backend): move generateStableHash out of shared util to fix Storybook build (#34284)

* fix(catalog-backend): move generateStableHash out of shared util to fix Storybook build

The util.ts file mixed Node.js-only code (createHash from node:crypto)
with pure constants. Since InMemoryCatalogClient reaches into
buildEntitySearch via a relative import, and buildEntitySearch imports
from util.ts, the node:crypto dependency leaked into Vite's browser
bundle causing the Storybook build to fail.

Signed-off-by: benjdlambert <ben@blam.sh>

* add changeset

Signed-off-by: benjdlambert <ben@blam.sh>

---------

Signed-off-by: benjdlambert <ben@blam.sh>
This commit is contained in:
Ben Lambert
2026-05-18 16:57:26 +02:00
committed by GitHub
parent 97515d8356
commit 07ec25de2c
3 changed files with 14 additions and 11 deletions
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Moved `generateStableHash` out of shared utility file to avoid pulling `node:crypto` into browser bundles
@@ -18,11 +18,14 @@ import { ENTITY_STATUS_CATALOG_PROCESSING_TYPE } from '@backstage/catalog-client
import {
ANNOTATION_EDIT_URL,
ANNOTATION_VIEW_URL,
Entity,
EntityRelation,
} from '@backstage/catalog-model';
import { AlphaEntity, EntityStatusItem } from '@backstage/catalog-model/alpha';
import { SerializedError } from '@backstage/errors';
import { Knex } from 'knex';
import { createHash } from 'node:crypto';
import stableStringify from 'fast-json-stable-stringify';
import { StitchingStrategy } from '../../../stitching/types';
import {
DbFinalEntitiesRow,
@@ -32,12 +35,17 @@ import {
import { buildEntitySearch } from './buildEntitySearch';
import { markDeferredStitchCompleted } from './markDeferredStitchCompleted';
import { syncSearchRows } from './syncSearchRows';
import { generateStableHash } from './util';
import {
LoggerService,
isDatabaseConflictError,
} from '@backstage/backend-plugin-api';
function generateStableHash(entity: Entity) {
return createHash('sha1')
.update(stableStringify({ ...entity }))
.digest('hex');
}
// See https://github.com/facebook/react/blob/f0cf832e1d0c8544c36aa8b310960885a11a847c/packages/react-dom-bindings/src/shared/sanitizeURL.js
const scriptProtocolPattern =
// eslint-disable-next-line no-control-regex
@@ -14,10 +14,6 @@
* limitations under the License.
*/
import { Entity } from '@backstage/catalog-model';
import { createHash } from 'node:crypto';
import stableStringify from 'fast-json-stable-stringify';
// The number of items that are sent per batch to the database layer, when
// doing .batchInsert calls to knex. This needs to be low enough to not cause
// errors in the underlying engine due to exceeding query limits, but large
@@ -29,9 +25,3 @@ export const BATCH_SIZE = 50;
// COALESCE, JS dedup keys). It cannot appear in real entity metadata values
// since they are human-readable strings.
export const NULL_SENTINEL = '\x01';
export function generateStableHash(entity: Entity) {
return createHash('sha1')
.update(stableStringify({ ...entity }))
.digest('hex');
}