@happyvertical/smrt-images 0.51.39 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { join } from "node:path";
7
7
  import { Asset, persistMediaBundleInspection as persistImageMediaBundleInspection } from "@happyvertical/smrt-assets";
8
8
  import { TenantIsolationError, TenantScoped, getCurrentTenant, isSuperAdminBypass } from "@happyvertical/smrt-tenancy";
9
9
  //#region src/__smrt-register__.ts
10
- ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-images\",\"packageVersion\":\"0.51.39\",\"objects\":{\"@happyvertical/smrt-images:Image\":{\"name\":\"image\",\"className\":\"Image\",\"qualifiedName\":\"@happyvertical/smrt-images:Image\",\"collection\":\"assets\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/images/src/image.ts\",\"packageName\":\"@happyvertical/smrt-images\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"generated\":true,\"source\":\"tenantScoped_decorator\",\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"autoFilter\":true,\"autoPopulate\":true,\"allowSuperAdminBypass\":false}}},\"name\":{\"type\":\"text\",\"required\":false},\"sourceUri\":{\"type\":\"text\",\"required\":false},\"mimeType\":{\"type\":\"text\",\"required\":false},\"description\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"text\",\"required\":false},\"version\":{\"type\":\"integer\",\"required\":true,\"default\":1},\"primaryVersionId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Asset\"},\"typeSlug\":{\"type\":\"text\",\"required\":false},\"statusSlug\":{\"type\":\"text\",\"required\":false},\"ownerProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\"},\"sourceAssetId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Asset\"},\"folderId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Folder\"},\"sourceType\":{\"type\":\"text\",\"required\":false},\"externalId\":{\"type\":\"text\",\"required\":false},\"externalRefs\":{\"type\":\"text\",\"required\":false},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false},\"width\":{\"type\":\"integer\",\"required\":false,\"default\":0},\"height\":{\"type\":\"integer\",\"required\":false,\"default\":0},\"alt\":{\"type\":\"text\",\"required\":false,\"default\":\"\"}},\"methods\":{\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"mergeMetadata\":{\"name\":\"mergeMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getExternalRefs\":{\"name\":\"getExternalRefs\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, AssetExternalReference>\",\"isStatic\":false,\"isPublic\":true},\"getExternalRef\":{\"name\":\"getExternalRef\",\"async\":false,\"parameters\":[{\"name\":\"provider\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"AssetExternalReference | null\",\"isStatic\":false,\"isPublic\":true},\"setExternalRef\":{\"name\":\"setExternalRef\",\"async\":false,\"parameters\":[{\"name\":\"provider\",\"type\":\"string\",\"optional\":false},{\"name\":\"reference\",\"type\":\"any\",\"optional\":false,\"typeUnresolved\":true}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getTags\":{\"name\":\"getTags\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Tag[]>\",\"isStatic\":false,\"isPublic\":true},\"hasTag\":{\"name\":\"hasTag\",\"async\":true,\"parameters\":[{\"name\":\"tagSlug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"getSource\":{\"name\":\"getSource\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Asset | null>\",\"isStatic\":false,\"isPublic\":true},\"getDerivatives\":{\"name\":\"getDerivatives\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"getType\":{\"name\":\"getType\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<AssetType | null>\",\"isStatic\":false,\"isPublic\":true},\"getStatus\":{\"name\":\"getStatus\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<AssetStatus | null>\",\"isStatic\":false,\"isPublic\":true},\"getAssociations\":{\"name\":\"getAssociations\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<AssetAssociation[]>\",\"isStatic\":false,\"isPublic\":true},\"associateWith\":{\"name\":\"associateWith\",\"async\":true,\"parameters\":[{\"name\":\"metaType\",\"type\":\"string\",\"optional\":false},{\"name\":\"metaId\",\"type\":\"string\",\"optional\":false},{\"name\":\"role\",\"type\":\"any\",\"optional\":true,\"default\":\"default\"}],\"returnType\":\"Promise<AssetAssociation>\",\"isStatic\":false,\"isPublic\":true},\"getBySlug\":{\"name\":\"getBySlug\",\"async\":true,\"parameters\":[{\"name\":\"_slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Asset | null>\",\"isStatic\":true,\"isPublic\":true},\"isValidImageFormat\":{\"name\":\"isValidImageFormat\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isHighResolution\":{\"name\":\"isHighResolution\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"generateAltText\":{\"name\":\"generateAltText\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"generateAltText\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"tableName\":\"assets\",\"tableStrategy\":\"sti\"},\"extends\":\"Asset\",\"exportName\":\"Image\",\"collectionExportName\":\"ImageCollection\",\"validationRules\":[{\"field\":\"version\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"assets\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"assets\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"name\\\" TEXT,\\n \\\"source_uri\\\" TEXT,\\n \\\"mime_type\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"metadata\\\" TEXT,\\n \\\"version\\\" INTEGER DEFAULT 1,\\n \\\"primary_version_id\\\" UUID,\\n \\\"type_slug\\\" TEXT,\\n \\\"status_slug\\\" TEXT,\\n \\\"owner_profile_id\\\" UUID,\\n \\\"source_asset_id\\\" UUID,\\n \\\"folder_id\\\" UUID,\\n \\\"source_type\\\" TEXT,\\n \\\"external_id\\\" TEXT,\\n \\\"external_refs\\\" TEXT,\\n \\\"width\\\" INTEGER DEFAULT 0,\\n \\\"height\\\" INTEGER DEFAULT 0,\\n \\\"alt\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false},\"source_uri\":{\"type\":\"TEXT\",\"notNull\":false},\"mime_type\":{\"type\":\"TEXT\",\"notNull\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false},\"version\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":1},\"primary_version_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"assets\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"type_slug\":{\"type\":\"TEXT\",\"notNull\":false},\"status_slug\":{\"type\":\"TEXT\",\"notNull\":false},\"owner_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false},\"source_asset_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"assets\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"folder_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false},\"source_type\":{\"type\":\"TEXT\",\"notNull\":false},\"external_id\":{\"type\":\"TEXT\",\"notNull\":false},\"external_refs\":{\"type\":\"TEXT\",\"notNull\":false},\"width\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"height\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"alt\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"assets_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"assets_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"assets_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"assets_primary_version_id_idx\",\"columns\":[\"primary_version_id\"]},{\"name\":\"assets_owner_profile_id_idx\",\"columns\":[\"owner_profile_id\"]},{\"name\":\"assets_source_asset_id_idx\",\"columns\":[\"source_asset_id\"]},{\"name\":\"assets_folder_id_idx\",\"columns\":[\"folder_id\"]}],\"version\":\"dd79a8b6\"},\"importPath\":\"@happyvertical/smrt-images\"},\"@happyvertical/smrt-images:ImageCollection\":{\"name\":\"imagecollection\",\"className\":\"ImageCollection\",\"qualifiedName\":\"@happyvertical/smrt-images:ImageCollection\",\"collection\":\"assets\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/images/src/images.ts\",\"packageName\":\"@happyvertical/smrt-images\",\"fields\":{},\"methods\":{\"findByTenant\":{\"name\":\"findByTenant\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"findGlobal\":{\"name\":\"findGlobal\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"findWithGlobals\":{\"name\":\"findWithGlobals\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getByMinDimensions\":{\"name\":\"getByMinDimensions\",\"async\":true,\"parameters\":[{\"name\":\"minWidth\",\"type\":\"number\",\"optional\":false},{\"name\":\"minHeight\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getByMaxDimensions\":{\"name\":\"getByMaxDimensions\",\"async\":true,\"parameters\":[{\"name\":\"maxWidth\",\"type\":\"number\",\"optional\":false},{\"name\":\"maxHeight\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getLandscape\":{\"name\":\"getLandscape\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getPortrait\":{\"name\":\"getPortrait\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getSquare\":{\"name\":\"getSquare\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getMissingAltText\":{\"name\":\"getMissingAltText\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getHighResolution\":{\"name\":\"getHighResolution\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getByAspectRatio\":{\"name\":\"getByAspectRatio\",\"async\":true,\"parameters\":[{\"name\":\"minRatio\",\"type\":\"number\",\"optional\":false},{\"name\":\"maxRatio\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"assets\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Image\",\"exportName\":\"ImageCollection\",\"collectionExportName\":\"ImageCollectionCollection\",\"schema\":{\"tableName\":\"assets\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"assets\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"name\\\" TEXT,\\n \\\"source_uri\\\" TEXT,\\n \\\"mime_type\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"metadata\\\" TEXT,\\n \\\"version\\\" INTEGER DEFAULT 1,\\n \\\"primary_version_id\\\" UUID,\\n \\\"type_slug\\\" TEXT,\\n \\\"status_slug\\\" TEXT,\\n \\\"owner_profile_id\\\" UUID,\\n \\\"source_asset_id\\\" UUID,\\n \\\"folder_id\\\" UUID,\\n \\\"source_type\\\" TEXT,\\n \\\"external_id\\\" TEXT,\\n \\\"external_refs\\\" TEXT,\\n \\\"width\\\" INTEGER DEFAULT 0,\\n \\\"height\\\" INTEGER DEFAULT 0,\\n \\\"alt\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false},\"source_uri\":{\"type\":\"TEXT\",\"notNull\":false},\"mime_type\":{\"type\":\"TEXT\",\"notNull\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false},\"version\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":1},\"primary_version_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"assets\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"type_slug\":{\"type\":\"TEXT\",\"notNull\":false},\"status_slug\":{\"type\":\"TEXT\",\"notNull\":false},\"owner_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false},\"source_asset_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"assets\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"folder_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false},\"source_type\":{\"type\":\"TEXT\",\"notNull\":false},\"external_id\":{\"type\":\"TEXT\",\"notNull\":false},\"external_refs\":{\"type\":\"TEXT\",\"notNull\":false},\"width\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"height\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"alt\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"assets_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"assets_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"assets_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"assets_primary_version_id_idx\",\"columns\":[\"primary_version_id\"]},{\"name\":\"assets_owner_profile_id_idx\",\"columns\":[\"owner_profile_id\"]},{\"name\":\"assets_source_asset_id_idx\",\"columns\":[\"source_asset_id\"]},{\"name\":\"assets_folder_id_idx\",\"columns\":[\"folder_id\"]}],\"version\":\"dd79a8b6\"},\"importPath\":\"@happyvertical/smrt-images\"}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-assets\",\"@happyvertical/smrt-core\",\"@happyvertical/smrt-prompts\",\"@happyvertical/smrt-tenancy\"]}"));
10
+ ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-images\",\"packageVersion\":\"0.52.0\",\"objects\":{\"@happyvertical/smrt-images:Image\":{\"name\":\"image\",\"className\":\"Image\",\"qualifiedName\":\"@happyvertical/smrt-images:Image\",\"collection\":\"assets\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/images/src/image.ts\",\"packageName\":\"@happyvertical/smrt-images\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"generated\":true,\"source\":\"tenantScoped_decorator\",\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"autoFilter\":true,\"autoPopulate\":true,\"allowSuperAdminBypass\":false}}},\"name\":{\"type\":\"text\",\"required\":false},\"sourceUri\":{\"type\":\"text\",\"required\":false},\"mimeType\":{\"type\":\"text\",\"required\":false},\"description\":{\"type\":\"text\",\"required\":false},\"metadata\":{\"type\":\"text\",\"required\":false},\"version\":{\"type\":\"integer\",\"required\":true,\"default\":1},\"primaryVersionId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Asset\"},\"typeSlug\":{\"type\":\"text\",\"required\":false},\"statusSlug\":{\"type\":\"text\",\"required\":false},\"ownerProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\"},\"sourceAssetId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Asset\"},\"folderId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Folder\"},\"sourceType\":{\"type\":\"text\",\"required\":false},\"externalId\":{\"type\":\"text\",\"required\":false},\"externalRefs\":{\"type\":\"text\",\"required\":false},\"createdAt\":{\"type\":\"text\",\"required\":false},\"updatedAt\":{\"type\":\"text\",\"required\":false},\"width\":{\"type\":\"integer\",\"required\":false,\"default\":0},\"height\":{\"type\":\"integer\",\"required\":false,\"default\":0},\"alt\":{\"type\":\"text\",\"required\":false,\"default\":\"\"}},\"methods\":{\"getSlug\":{\"name\":\"getSlug\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string | null | undefined>\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, unknown>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"mergeMetadata\":{\"name\":\"mergeMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"Record<string, unknown>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getExternalRefs\":{\"name\":\"getExternalRefs\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string, AssetExternalReference>\",\"isStatic\":false,\"isPublic\":true},\"getExternalRef\":{\"name\":\"getExternalRef\",\"async\":false,\"parameters\":[{\"name\":\"provider\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"AssetExternalReference | null\",\"isStatic\":false,\"isPublic\":true},\"setExternalRef\":{\"name\":\"setExternalRef\",\"async\":false,\"parameters\":[{\"name\":\"provider\",\"type\":\"string\",\"optional\":false},{\"name\":\"reference\",\"type\":\"any\",\"optional\":false,\"typeUnresolved\":true}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getTags\":{\"name\":\"getTags\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Tag[]>\",\"isStatic\":false,\"isPublic\":true},\"hasTag\":{\"name\":\"hasTag\",\"async\":true,\"parameters\":[{\"name\":\"tagSlug\",\"type\":\"string\",\"optional\":false},{\"name\":\"context\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true},\"getSource\":{\"name\":\"getSource\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Asset | null>\",\"isStatic\":false,\"isPublic\":true},\"getDerivatives\":{\"name\":\"getDerivatives\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"getType\":{\"name\":\"getType\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<AssetType | null>\",\"isStatic\":false,\"isPublic\":true},\"getStatus\":{\"name\":\"getStatus\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<AssetStatus | null>\",\"isStatic\":false,\"isPublic\":true},\"getAssociations\":{\"name\":\"getAssociations\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<AssetAssociation[]>\",\"isStatic\":false,\"isPublic\":true},\"associateWith\":{\"name\":\"associateWith\",\"async\":true,\"parameters\":[{\"name\":\"metaType\",\"type\":\"string\",\"optional\":false},{\"name\":\"metaId\",\"type\":\"string\",\"optional\":false},{\"name\":\"role\",\"type\":\"any\",\"optional\":true,\"default\":\"default\"}],\"returnType\":\"Promise<AssetAssociation>\",\"isStatic\":false,\"isPublic\":true},\"getBySlug\":{\"name\":\"getBySlug\",\"async\":true,\"parameters\":[{\"name\":\"_slug\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Asset | null>\",\"isStatic\":true,\"isPublic\":true},\"isValidImageFormat\":{\"name\":\"isValidImageFormat\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isHighResolution\":{\"name\":\"isHighResolution\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"generateAltText\":{\"name\":\"generateAltText\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<string>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"mcp\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"generateAltText\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"tableName\":\"assets\",\"tableStrategy\":\"sti\"},\"extends\":\"Asset\",\"exportName\":\"Image\",\"collectionExportName\":\"ImageCollection\",\"validationRules\":[{\"field\":\"version\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"assets\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"assets\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"name\\\" TEXT,\\n \\\"source_uri\\\" TEXT,\\n \\\"mime_type\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"metadata\\\" TEXT,\\n \\\"version\\\" INTEGER DEFAULT 1,\\n \\\"primary_version_id\\\" UUID,\\n \\\"type_slug\\\" TEXT,\\n \\\"status_slug\\\" TEXT,\\n \\\"owner_profile_id\\\" UUID,\\n \\\"source_asset_id\\\" UUID,\\n \\\"folder_id\\\" UUID,\\n \\\"source_type\\\" TEXT,\\n \\\"external_id\\\" TEXT,\\n \\\"external_refs\\\" TEXT,\\n \\\"width\\\" INTEGER DEFAULT 0,\\n \\\"height\\\" INTEGER DEFAULT 0,\\n \\\"alt\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false},\"source_uri\":{\"type\":\"TEXT\",\"notNull\":false},\"mime_type\":{\"type\":\"TEXT\",\"notNull\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false},\"version\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":1},\"primary_version_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"assets\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"type_slug\":{\"type\":\"TEXT\",\"notNull\":false},\"status_slug\":{\"type\":\"TEXT\",\"notNull\":false},\"owner_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false},\"source_asset_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"assets\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"folder_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false},\"source_type\":{\"type\":\"TEXT\",\"notNull\":false},\"external_id\":{\"type\":\"TEXT\",\"notNull\":false},\"external_refs\":{\"type\":\"TEXT\",\"notNull\":false},\"width\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"height\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"alt\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"assets_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"assets_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"assets_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"assets_primary_version_id_idx\",\"columns\":[\"primary_version_id\"]},{\"name\":\"assets_owner_profile_id_idx\",\"columns\":[\"owner_profile_id\"]},{\"name\":\"assets_source_asset_id_idx\",\"columns\":[\"source_asset_id\"]},{\"name\":\"assets_folder_id_idx\",\"columns\":[\"folder_id\"]}],\"version\":\"dd79a8b6\"},\"importPath\":\"@happyvertical/smrt-images\"},\"@happyvertical/smrt-images:ImageCollection\":{\"name\":\"imagecollection\",\"className\":\"ImageCollection\",\"qualifiedName\":\"@happyvertical/smrt-images:ImageCollection\",\"collection\":\"assets\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/images/src/images.ts\",\"packageName\":\"@happyvertical/smrt-images\",\"fields\":{},\"methods\":{\"findByTenant\":{\"name\":\"findByTenant\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"findGlobal\":{\"name\":\"findGlobal\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"findWithGlobals\":{\"name\":\"findWithGlobals\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getByMinDimensions\":{\"name\":\"getByMinDimensions\",\"async\":true,\"parameters\":[{\"name\":\"minWidth\",\"type\":\"number\",\"optional\":false},{\"name\":\"minHeight\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getByMaxDimensions\":{\"name\":\"getByMaxDimensions\",\"async\":true,\"parameters\":[{\"name\":\"maxWidth\",\"type\":\"number\",\"optional\":false},{\"name\":\"maxHeight\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getLandscape\":{\"name\":\"getLandscape\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getPortrait\":{\"name\":\"getPortrait\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getSquare\":{\"name\":\"getSquare\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getMissingAltText\":{\"name\":\"getMissingAltText\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getHighResolution\":{\"name\":\"getHighResolution\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true},\"getByAspectRatio\":{\"name\":\"getByAspectRatio\",\"async\":true,\"parameters\":[{\"name\":\"minRatio\",\"type\":\"number\",\"optional\":false},{\"name\":\"maxRatio\",\"type\":\"number\",\"optional\":false}],\"returnType\":\"Promise<Image[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"assets\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Image\",\"exportName\":\"ImageCollection\",\"collectionExportName\":\"ImageCollectionCollection\",\"schema\":{\"tableName\":\"assets\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"assets\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"name\\\" TEXT,\\n \\\"source_uri\\\" TEXT,\\n \\\"mime_type\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"metadata\\\" TEXT,\\n \\\"version\\\" INTEGER DEFAULT 1,\\n \\\"primary_version_id\\\" UUID,\\n \\\"type_slug\\\" TEXT,\\n \\\"status_slug\\\" TEXT,\\n \\\"owner_profile_id\\\" UUID,\\n \\\"source_asset_id\\\" UUID,\\n \\\"folder_id\\\" UUID,\\n \\\"source_type\\\" TEXT,\\n \\\"external_id\\\" TEXT,\\n \\\"external_refs\\\" TEXT,\\n \\\"width\\\" INTEGER DEFAULT 0,\\n \\\"height\\\" INTEGER DEFAULT 0,\\n \\\"alt\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false},\"source_uri\":{\"type\":\"TEXT\",\"notNull\":false},\"mime_type\":{\"type\":\"TEXT\",\"notNull\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false},\"version\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":1},\"primary_version_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"assets\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"type_slug\":{\"type\":\"TEXT\",\"notNull\":false},\"status_slug\":{\"type\":\"TEXT\",\"notNull\":false},\"owner_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false},\"source_asset_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"assets\",\"column\":\"id\",\"onDelete\":\"NO ACTION\",\"onUpdate\":\"CASCADE\"}},\"folder_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false},\"source_type\":{\"type\":\"TEXT\",\"notNull\":false},\"external_id\":{\"type\":\"TEXT\",\"notNull\":false},\"external_refs\":{\"type\":\"TEXT\",\"notNull\":false},\"width\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"height\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"alt\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"assets_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"assets_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"assets_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"assets_primary_version_id_idx\",\"columns\":[\"primary_version_id\"]},{\"name\":\"assets_owner_profile_id_idx\",\"columns\":[\"owner_profile_id\"]},{\"name\":\"assets_source_asset_id_idx\",\"columns\":[\"source_asset_id\"]},{\"name\":\"assets_folder_id_idx\",\"columns\":[\"folder_id\"]}],\"version\":\"dd79a8b6\"},\"importPath\":\"@happyvertical/smrt-images\"}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-assets\",\"@happyvertical/smrt-core\",\"@happyvertical/smrt-prompts\",\"@happyvertical/smrt-tenancy\"]}"));
11
11
  //#endregion
12
12
  //#region src/prompts.ts
13
13
  var smrtImagesGenerateAltTextPrompt = definePrompt({
@@ -36,6 +36,417 @@ function promptMessageOptions(ai) {
36
36
  };
37
37
  }
38
38
  //#endregion
39
+ //#region src/adjust.ts
40
+ var IMAGE_ADJUST_OPERATIONS = Object.freeze([
41
+ {
42
+ id: "brighter",
43
+ description: "Lighten the picture."
44
+ },
45
+ {
46
+ id: "darker",
47
+ description: "Darken the picture."
48
+ },
49
+ {
50
+ id: "more-contrast",
51
+ description: "Stronger lights and darks."
52
+ },
53
+ {
54
+ id: "less-contrast",
55
+ description: "Softer, flatter lights and darks."
56
+ },
57
+ {
58
+ id: "more-color",
59
+ description: "Richer colour."
60
+ },
61
+ {
62
+ id: "less-color",
63
+ description: "Muted colour."
64
+ },
65
+ {
66
+ id: "black-and-white",
67
+ description: "No colour."
68
+ },
69
+ {
70
+ id: "rotate",
71
+ description: "Turn the picture a quarter or half turn."
72
+ },
73
+ {
74
+ id: "flip",
75
+ description: "Mirror the picture."
76
+ },
77
+ {
78
+ id: "zoom",
79
+ description: "Zoom in on one part of the picture (a closer crop)."
80
+ },
81
+ {
82
+ id: "resize",
83
+ description: "Make the picture smaller."
84
+ }
85
+ ]);
86
+ var OPERATION_IDS = new Set(IMAGE_ADJUST_OPERATIONS.map((op) => op.id));
87
+ function isImageAdjustOperation(value) {
88
+ return typeof value === "string" && OPERATION_IDS.has(value);
89
+ }
90
+ var FOCI = [
91
+ "center",
92
+ "top",
93
+ "bottom",
94
+ "left",
95
+ "right",
96
+ "top-left",
97
+ "top-right",
98
+ "bottom-left",
99
+ "bottom-right"
100
+ ];
101
+ function isImageFocus(value) {
102
+ return typeof value === "string" && FOCI.includes(value);
103
+ }
104
+ var MIN_SIDE = 16;
105
+ var MAX_SIDE = 8192;
106
+ var MIN_REGION = .05;
107
+ function clamp(value, min, max) {
108
+ return Math.min(max, Math.max(min, value));
109
+ }
110
+ function round(value, places = 3) {
111
+ const factor = 10 ** places;
112
+ return Math.round(value * factor) / factor;
113
+ }
114
+ function finite(value) {
115
+ const n = typeof value === "string" ? Number(value) : value;
116
+ return typeof n === "number" && Number.isFinite(n) ? n : null;
117
+ }
118
+ function normalizeRegion(value) {
119
+ if (!value || typeof value !== "object") return void 0;
120
+ const record = value;
121
+ const left = finite(record.left);
122
+ const top = finite(record.top);
123
+ const width = finite(record.width);
124
+ const height = finite(record.height);
125
+ if (left == null || top == null || width == null || height == null) throw new Error("A region needs left, top, width and height (0 to 1).");
126
+ const l = clamp(left, 0, 1 - MIN_REGION);
127
+ const t = clamp(top, 0, 1 - MIN_REGION);
128
+ const w = clamp(width, MIN_REGION, 1 - l);
129
+ const h = clamp(height, MIN_REGION, 1 - t);
130
+ if (l === 0 && t === 0 && w === 1 && h === 1) return void 0;
131
+ return {
132
+ left: round(l),
133
+ top: round(t),
134
+ width: round(w),
135
+ height: round(h)
136
+ };
137
+ }
138
+ function normalizeImageAdjustments(input) {
139
+ if (!input || typeof input !== "object") return {};
140
+ const record = input;
141
+ const result = {};
142
+ const multiplier = (key, min, max) => {
143
+ const value = finite(record[key]);
144
+ if (value == null) return void 0;
145
+ const clamped = round(clamp(value, min, max));
146
+ return clamped === 1 ? void 0 : clamped;
147
+ };
148
+ const brightness = multiplier("brightness", .2, 3);
149
+ if (brightness != null) result.brightness = brightness;
150
+ const contrast = multiplier("contrast", .2, 3);
151
+ if (contrast != null) result.contrast = contrast;
152
+ const saturation = multiplier("saturation", 0, 3);
153
+ if (saturation != null) result.saturation = saturation;
154
+ if (record.grayscale === true) result.grayscale = true;
155
+ const rotate = finite(record.rotate);
156
+ if (rotate != null) {
157
+ const turn = (Math.round(rotate) % 360 + 360) % 360;
158
+ if (turn % 90 !== 0) throw new Error("Pictures can only be turned a quarter or half turn.");
159
+ if (turn !== 0) result.rotate = turn;
160
+ }
161
+ if (record.flipHorizontal === true) result.flipHorizontal = true;
162
+ if (record.flipVertical === true) result.flipVertical = true;
163
+ const region = normalizeRegion(record.region);
164
+ if (region) result.region = region;
165
+ for (const key of ["maxWidth", "maxHeight"]) {
166
+ const value = finite(record[key]);
167
+ if (value != null) result[key] = Math.round(clamp(value, MIN_SIDE, MAX_SIDE));
168
+ }
169
+ return result;
170
+ }
171
+ function isEmptyImageAdjustments(adjustments) {
172
+ return Object.keys(normalizeImageAdjustments(adjustments)).length === 0;
173
+ }
174
+ function encodeImageAdjustments(input) {
175
+ const a = normalizeImageAdjustments(input);
176
+ const parts = [];
177
+ if (a.brightness != null) parts.push(`b${a.brightness}`);
178
+ if (a.contrast != null) parts.push(`c${a.contrast}`);
179
+ if (a.saturation != null) parts.push(`s${a.saturation}`);
180
+ if (a.grayscale) parts.push("g");
181
+ if (a.rotate) parts.push(`r${a.rotate}`);
182
+ if (a.flipHorizontal) parts.push("fh");
183
+ if (a.flipVertical) parts.push("fv");
184
+ if (a.region) {
185
+ const { left, top, width, height } = a.region;
186
+ parts.push(`x${left}_${top}_${width}_${height}`);
187
+ }
188
+ if (a.maxWidth != null) parts.push(`w${a.maxWidth}`);
189
+ if (a.maxHeight != null) parts.push(`h${a.maxHeight}`);
190
+ return parts.join(",");
191
+ }
192
+ function decodeImageAdjustments(spec) {
193
+ const text = typeof spec === "string" ? spec.trim() : "";
194
+ if (!text) return {};
195
+ if (text.length > 200) throw new Error("Unknown picture adjustment.");
196
+ const raw = {};
197
+ for (const part of text.split(",")) {
198
+ const match = /^(b|c|s|r|w|h|x)([0-9._-]+)$|^(g|fh|fv)$/.exec(part);
199
+ if (!match) throw new Error("Unknown picture adjustment.");
200
+ if (match[3] === "g") raw.grayscale = true;
201
+ else if (match[3] === "fh") raw.flipHorizontal = true;
202
+ else if (match[3] === "fv") raw.flipVertical = true;
203
+ else if (match[1] === "x") {
204
+ const values = match[2].split("_").map(Number);
205
+ if (values.length !== 4 || values.some((v) => !Number.isFinite(v))) throw new Error("Unknown picture adjustment.");
206
+ const [left, top, width, height] = values;
207
+ raw.region = {
208
+ left,
209
+ top,
210
+ width,
211
+ height
212
+ };
213
+ } else {
214
+ const value = Number(match[2]);
215
+ if (!Number.isFinite(value)) throw new Error("Unknown picture adjustment.");
216
+ const key = {
217
+ b: "brightness",
218
+ c: "contrast",
219
+ s: "saturation",
220
+ r: "rotate",
221
+ w: "maxWidth",
222
+ h: "maxHeight"
223
+ }[match[1]];
224
+ raw[key] = value;
225
+ }
226
+ }
227
+ return normalizeImageAdjustments(raw);
228
+ }
229
+ function regionForFocus(focus, scale) {
230
+ const size = clamp(scale, .3, .95);
231
+ const spare = 1 - size;
232
+ const horizontal = focus.includes("left") ? 0 : focus.includes("right") ? spare : spare / 2;
233
+ const vertical = focus.startsWith("top") ? 0 : focus.startsWith("bottom") ? spare : spare / 2;
234
+ return {
235
+ left: round(horizontal),
236
+ top: round(vertical),
237
+ width: round(size),
238
+ height: round(size)
239
+ };
240
+ }
241
+ var PERCENT_STEPS = [
242
+ 10,
243
+ 20,
244
+ 30
245
+ ];
246
+ function imageAdjustVariants(operation, options = {}) {
247
+ switch (operation) {
248
+ case "brighter": return PERCENT_STEPS.map((step) => ({
249
+ id: `brighter-${step}`,
250
+ label: `${step}% brighter`,
251
+ adjustments: { brightness: 1 + step / 100 }
252
+ }));
253
+ case "darker": return PERCENT_STEPS.map((step) => ({
254
+ id: `darker-${step}`,
255
+ label: `${step}% darker`,
256
+ adjustments: { brightness: 1 - step / 100 }
257
+ }));
258
+ case "more-contrast": return PERCENT_STEPS.map((step) => ({
259
+ id: `contrast-up-${step}`,
260
+ label: `${step}% more contrast`,
261
+ adjustments: { contrast: 1 + step / 100 }
262
+ }));
263
+ case "less-contrast": return PERCENT_STEPS.map((step) => ({
264
+ id: `contrast-down-${step}`,
265
+ label: `${step}% less contrast`,
266
+ adjustments: { contrast: 1 - step / 100 }
267
+ }));
268
+ case "more-color": return PERCENT_STEPS.map((step) => ({
269
+ id: `color-up-${step}`,
270
+ label: `${step * 2}% more colour`,
271
+ adjustments: { saturation: 1 + step * 2 / 100 }
272
+ }));
273
+ case "less-color": return PERCENT_STEPS.map((step) => ({
274
+ id: `color-down-${step}`,
275
+ label: `${step * 2}% less colour`,
276
+ adjustments: { saturation: 1 - step * 2 / 100 }
277
+ }));
278
+ case "black-and-white": return [
279
+ {
280
+ id: "bw",
281
+ label: "Black and white",
282
+ adjustments: { grayscale: true }
283
+ },
284
+ {
285
+ id: "bw-contrast",
286
+ label: "Black and white, stronger",
287
+ description: "More contrast, like a newspaper photo.",
288
+ adjustments: {
289
+ grayscale: true,
290
+ contrast: 1.25
291
+ }
292
+ },
293
+ {
294
+ id: "bw-soft",
295
+ label: "Black and white, softer",
296
+ adjustments: {
297
+ grayscale: true,
298
+ contrast: .85,
299
+ brightness: 1.05
300
+ }
301
+ }
302
+ ];
303
+ case "rotate": return [
304
+ {
305
+ id: "rotate-right",
306
+ label: "Turn right",
307
+ adjustments: { rotate: 90 }
308
+ },
309
+ {
310
+ id: "rotate-left",
311
+ label: "Turn left",
312
+ adjustments: { rotate: 270 }
313
+ },
314
+ {
315
+ id: "rotate-half",
316
+ label: "Upside down",
317
+ adjustments: { rotate: 180 }
318
+ }
319
+ ];
320
+ case "flip": return [{
321
+ id: "flip-horizontal",
322
+ label: "Mirror left to right",
323
+ adjustments: { flipHorizontal: true }
324
+ }, {
325
+ id: "flip-vertical",
326
+ label: "Mirror top to bottom",
327
+ adjustments: { flipVertical: true }
328
+ }];
329
+ case "zoom": {
330
+ const focus = options.focus ?? "center";
331
+ return [
332
+ {
333
+ id: "zoom-1",
334
+ label: "A little closer",
335
+ scale: .8
336
+ },
337
+ {
338
+ id: "zoom-2",
339
+ label: "Closer",
340
+ scale: .65
341
+ },
342
+ {
343
+ id: "zoom-3",
344
+ label: "Much closer",
345
+ scale: .5
346
+ }
347
+ ].map(({ id, label, scale }) => ({
348
+ id,
349
+ label,
350
+ adjustments: { region: regionForFocus(focus, scale) }
351
+ }));
352
+ }
353
+ case "resize": return [
354
+ {
355
+ id: "size-large",
356
+ label: "Large (1600 wide)",
357
+ side: 1600
358
+ },
359
+ {
360
+ id: "size-medium",
361
+ label: "Medium (1200 wide)",
362
+ side: 1200
363
+ },
364
+ {
365
+ id: "size-small",
366
+ label: "Small (800 wide)",
367
+ side: 800
368
+ }
369
+ ].map(({ id, label, side }) => ({
370
+ id,
371
+ label,
372
+ adjustments: {
373
+ maxWidth: side,
374
+ maxHeight: side
375
+ }
376
+ }));
377
+ default: throw new Error("Unknown picture adjustment.");
378
+ }
379
+ }
380
+ function describeImageAdjustments(input) {
381
+ const a = normalizeImageAdjustments(input);
382
+ const percent = (value) => Math.round(Math.abs(value - 1) * 100);
383
+ const parts = [];
384
+ if (a.rotate) parts.push(a.rotate === 90 ? "turned right" : a.rotate === 270 ? "turned left" : "turned upside down");
385
+ if (a.flipHorizontal) parts.push("mirrored left to right");
386
+ if (a.flipVertical) parts.push("mirrored top to bottom");
387
+ if (a.region) parts.push("zoomed in");
388
+ if (a.brightness != null) parts.push(`${percent(a.brightness)}% ${a.brightness > 1 ? "brighter" : "darker"}`);
389
+ if (a.contrast != null) parts.push(`${percent(a.contrast)}% ${a.contrast > 1 ? "more" : "less"} contrast`);
390
+ if (a.saturation != null) parts.push(`${percent(a.saturation)}% ${a.saturation > 1 ? "more" : "less"} colour`);
391
+ if (a.grayscale) parts.push("black and white");
392
+ if (a.maxWidth != null || a.maxHeight != null) parts.push("smaller");
393
+ return parts.join(", ") || "unchanged";
394
+ }
395
+ function regionToPixels(region, width, height) {
396
+ const left = clamp(Math.round(region.left * width), 0, width - 1);
397
+ const top = clamp(Math.round(region.top * height), 0, height - 1);
398
+ return {
399
+ left,
400
+ top,
401
+ width: clamp(Math.round(region.width * width), 1, width - left),
402
+ height: clamp(Math.round(region.height * height), 1, height - top)
403
+ };
404
+ }
405
+ async function applyImageAdjustments(data, input, options = {}) {
406
+ const a = normalizeImageAdjustments(input);
407
+ const { default: sharp } = await import("sharp");
408
+ let pipeline = sharp(data, { failOn: "error" }).rotate();
409
+ if (a.rotate) pipeline = pipeline.rotate(a.rotate);
410
+ if (a.flipHorizontal) pipeline = pipeline.flop();
411
+ if (a.flipVertical) pipeline = pipeline.flip();
412
+ if (a.region) {
413
+ const turned = await pipeline.clone().toBuffer({ resolveWithObject: true });
414
+ pipeline = sharp(turned.data).extract(regionToPixels(a.region, turned.info.width, turned.info.height));
415
+ }
416
+ if (a.brightness != null || a.saturation != null) pipeline = pipeline.modulate({
417
+ ...a.brightness != null ? { brightness: a.brightness } : {},
418
+ ...a.saturation != null ? { saturation: a.saturation } : {}
419
+ });
420
+ if (a.contrast != null) pipeline = pipeline.linear(a.contrast, 128 * (1 - a.contrast));
421
+ if (a.grayscale) pipeline = pipeline.grayscale();
422
+ if (a.maxWidth != null || a.maxHeight != null) pipeline = pipeline.resize({
423
+ width: a.maxWidth,
424
+ height: a.maxHeight,
425
+ fit: "inside",
426
+ withoutEnlargement: true
427
+ });
428
+ if (options.fit) pipeline = sharp(await pipeline.toBuffer()).resize({
429
+ width: options.fit.width,
430
+ height: options.fit.height,
431
+ fit: options.fit.fit ?? "inside",
432
+ withoutEnlargement: options.fit.fit !== "cover"
433
+ });
434
+ const sourceFormat = (await sharp(data).metadata()).format;
435
+ const format = options.format ?? (sourceFormat === "png" || sourceFormat === "webp" ? sourceFormat : "jpeg");
436
+ const quality = clamp(Math.round(options.quality ?? 88), 30, 100);
437
+ pipeline = format === "png" ? pipeline.png() : format === "webp" ? pipeline.webp({ quality }) : pipeline.jpeg({
438
+ quality,
439
+ mozjpeg: true
440
+ });
441
+ const out = await pipeline.toBuffer({ resolveWithObject: true });
442
+ return {
443
+ data: out.data,
444
+ mimeType: `image/${format}`,
445
+ width: out.info.width,
446
+ height: out.info.height
447
+ };
448
+ }
449
+ //#endregion
39
450
  //#region src/categorizer.ts
40
451
  var MAX_LABEL_VOCABULARY_ENTRIES = 64;
41
452
  var MAX_LABEL_NAME_LENGTH = 128;
@@ -372,7 +783,8 @@ var ImageEditor = class {
372
783
  }
373
784
  }
374
785
  /**
375
- * Crop an image to the specified region
786
+ * Crop an image to the specified region (in pixels of the picture as it is
787
+ * seen, after its EXIF orientation). The region is clamped to the picture.
376
788
  *
377
789
  * @param image - Source image
378
790
  * @param x - Left offset
@@ -382,29 +794,54 @@ var ImageEditor = class {
382
794
  * @returns New derivative Image
383
795
  */
384
796
  async crop(image, x, y, w, h) {
385
- const { getImageProcessor } = await import("@happyvertical/images");
386
- const processor = await getImageProcessor();
797
+ if ([
798
+ x,
799
+ y,
800
+ w,
801
+ h
802
+ ].some((value) => !Number.isFinite(value))) throw new Error("Crop needs a left, top, width and height in pixels.");
803
+ if (w < 1 || h < 1) throw new Error("A crop must be at least one pixel wide and tall.");
387
804
  const sourceData = await this.store.read(image);
388
- const inputPath = join(tmpdir(), `smrt-crop-in-${randomUUID()}.bin`);
389
- const outputPath = join(tmpdir(), `smrt-crop-out-${randomUUID()}.bin`);
390
- try {
391
- await writeFile(inputPath, sourceData);
392
- await processor.resize(inputPath, outputPath, {
393
- width: w,
394
- height: h,
395
- fit: "cover"
396
- });
397
- const cropped = await readFile(outputPath);
398
- return this.createDerivative(image, cropped, {
399
- name: `${image.name}-crop`,
400
- width: w,
401
- height: h,
402
- description: `Cropped region ${x},${y} ${w}x${h}`
403
- });
404
- } finally {
405
- await unlink(inputPath).catch(() => {});
406
- await unlink(outputPath).catch(() => {});
407
- }
805
+ const { default: sharp } = await import("sharp");
806
+ const oriented = await sharp(sourceData).rotate().toBuffer({ resolveWithObject: true });
807
+ const { width, height } = oriented.info;
808
+ const left = Math.min(Math.max(Math.round(x), 0), width - 1);
809
+ const top = Math.min(Math.max(Math.round(y), 0), height - 1);
810
+ const cropWidth = Math.min(Math.round(w), width - left);
811
+ const cropHeight = Math.min(Math.round(h), height - top);
812
+ const cropped = await sharp(oriented.data).extract({
813
+ left,
814
+ top,
815
+ width: cropWidth,
816
+ height: cropHeight
817
+ }).toBuffer();
818
+ return this.createDerivative(image, cropped, {
819
+ name: `${image.name}-crop`,
820
+ width: cropWidth,
821
+ height: cropHeight,
822
+ description: `Cropped region ${left},${top} ${cropWidth}x${cropHeight}`
823
+ });
824
+ }
825
+ /**
826
+ * Brightness, contrast, colour, black-and-white, rotate, flip, region crop
827
+ * or resize, in one pass (see `./adjust.ts`). The source is unchanged; the
828
+ * result is a new derivative linked to it.
829
+ *
830
+ * @param image - Source image
831
+ * @param adjustments - What to change (checked and clamped)
832
+ * @returns New derivative Image
833
+ */
834
+ async adjust(image, adjustments) {
835
+ const normalized = normalizeImageAdjustments(adjustments);
836
+ if (Object.keys(normalized).length === 0) throw new Error("Nothing to change: the adjustments leave the picture as it is.");
837
+ const adjusted = await applyImageAdjustments(await this.store.read(image), normalized);
838
+ return this.createDerivative(image, adjusted.data, {
839
+ name: `${image.name}-adjusted`,
840
+ width: adjusted.width,
841
+ height: adjusted.height,
842
+ mimeType: adjusted.mimeType,
843
+ description: `Adjusted: ${describeImageAdjustments(normalized)}`
844
+ });
408
845
  }
409
846
  /**
410
847
  * Convert an image to a different format
@@ -912,6 +1349,6 @@ var UpstreamManager = class {
912
1349
  }
913
1350
  };
914
1351
  //#endregion
915
- export { Image, ImageCategorizer, ImageCollection, ImageDeriver, ImageEditor, ImageMetadataExtractor, ImageSearch, UpstreamManager, persistImageMediaBundleInspection, smrtImagesGenerateAltTextPrompt };
1352
+ export { IMAGE_ADJUST_OPERATIONS, Image, ImageCategorizer, ImageCollection, ImageDeriver, ImageEditor, ImageMetadataExtractor, ImageSearch, UpstreamManager, applyImageAdjustments, decodeImageAdjustments, describeImageAdjustments, encodeImageAdjustments, imageAdjustVariants, isEmptyImageAdjustments, isImageAdjustOperation, isImageFocus, normalizeImageAdjustments, persistImageMediaBundleInspection, regionForFocus, regionToPixels, smrtImagesGenerateAltTextPrompt };
916
1353
 
917
1354
  //# sourceMappingURL=index.js.map