@happyvertical/smrt-cli 0.57.9 → 0.57.10
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/{AuditLogCollection-WDHL-_AF-C4XUiuEx.js → AuditLogCollection-WDHL-_AF-B-XEAxVt.js} +1 -1
- package/dist/{OidcIdentity-BUblgQLs-e55giMbr.js → OidcIdentity-BUblgQLs-CNCLrvjW.js} +2 -2
- package/dist/{OidcIdentityCollection-ClOyaHeF-CaHNLNCO.js → OidcIdentityCollection-ClOyaHeF-CXbCuX6s.js} +1 -1
- package/dist/{ProfileAssetCollection-CRMcjLJ--B4UtPQ3_.js → ProfileAssetCollection-CRMcjLJ--c-GEluUg.js} +3 -3
- package/dist/{ProfileCollection-C4INKh7Y-B5SWDGlm.js → ProfileCollection-C4INKh7Y-DOp8miUa.js} +17 -17
- package/dist/{ProfileLinkCollection-DFfZRsgv-5HUe2id3.js → ProfileLinkCollection-DFfZRsgv-B6WUopKV.js} +2 -2
- package/dist/{ProfileMetadataCollection-BIYKy4Y3-DYsIbUpk.js → ProfileMetadataCollection-BIYKy4Y3-0ifgavRP.js} +1 -1
- package/dist/{ProfileMetafieldCollection-Buz7gzag-BxhNKXxI.js → ProfileMetafieldCollection-Buz7gzag-LmZuJkfj.js} +1 -1
- package/dist/{ProfileRelationshipCollection-C4g_QLI4-BXuiyTZa.js → ProfileRelationshipCollection-C4g_QLI4-zqqRMcCG.js} +1 -1
- package/dist/{ProfileTypeCollection-B7kwi1mU-pxb25IJ6.js → ProfileTypeCollection-B7kwi1mU-Ce3gA1Qy.js} +2 -2
- package/dist/{commands-DgGHIYMC.js → commands-DTdDVLOD.js} +2 -2
- package/dist/dist-Bh0ccFH6.js +5017 -0
- package/dist/{dist-DWUS-MxT.js → dist-Br3DJiYF.js} +5 -5
- package/dist/dist-DQc67vUC.js +1908 -0
- package/dist/{dist-DH1yeulh.js → dist-DtPJO_5w.js} +2 -2
- package/dist/dist-cdXD3BbE.js +21 -0
- package/dist/index.js +11 -11
- package/dist/{oidcProvisioningPrimitives-DNP9EZlU-ClU9HV60.js → oidcProvisioningPrimitives-DNP9EZlU-DwTTwWII.js} +3 -3
- package/dist/{resolveIdentity-CkyqvctR-DIgL16MM.js → resolveIdentity-CkyqvctR-AkDcBv37.js} +14 -14
- package/package.json +15 -15
- package/dist/dist-BGg1-1gH.js +0 -1908
- package/dist/dist-C4r0KFBC.js +0 -5017
- package/dist/dist-VrkK51hS.js +0 -21
package/dist/dist-BGg1-1gH.js
DELETED
|
@@ -1,1908 +0,0 @@
|
|
|
1
|
-
import { i as tenantId, l as withTenantGlobalRead, m as withSystemContext, o as queryGlobal, r as TenantScoped, s as queryWithGlobals, u as getCurrentTenant } from "./dist-DH1yeulh.js";
|
|
2
|
-
import { GlobalInterceptors, ObjectRegistry, SmrtCollection, SmrtHierarchical, SmrtJunction, SmrtJunctionBase, SmrtObject, SmrtPolymorphicAssociation, crossPackageRef, field, foreignKey, resolveGetStringFilter, smrt } from "@happyvertical/smrt-core";
|
|
3
|
-
//#region ../tags/dist/index.js
|
|
4
|
-
var __defProp$2$1 = Object.defineProperty;
|
|
5
|
-
var __exportAll$1 = (all, no_symbols) => {
|
|
6
|
-
let target = {};
|
|
7
|
-
for (var name in all) __defProp$2$1(target, name, {
|
|
8
|
-
get: all[name],
|
|
9
|
-
enumerable: true
|
|
10
|
-
});
|
|
11
|
-
if (!no_symbols) __defProp$2$1(target, Symbol.toStringTag, { value: "Module" });
|
|
12
|
-
return target;
|
|
13
|
-
};
|
|
14
|
-
ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-tags","packageVersion":"0.57.9","objects":{"@happyvertical/smrt-tags:TagAlias":{"name":"tagalias","className":"TagAlias","qualifiedName":"@happyvertical/smrt-tags:TagAlias","collection":"tagaliases","filePath":"/home/runner/work/smrt/smrt/packages/tags/src/tag-alias.ts","packageName":"@happyvertical/smrt-tags","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"tagSlug":{"type":"text","required":false,"default":"","description":"The tag this alternative name points to.","_meta":{"description":"The tag this alternative name points to."}},"alias":{"type":"text","required":true,"default":"","description":"Another name or a translation people may use for the tag.","_meta":{"required":true,"description":"Another name or a translation people may use for the tag."}},"language":{"type":"text","required":false,"default":"","description":"The two-letter language code of the alternative name.","_meta":{"description":"The two-letter language code of the alternative name."}},"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"createdAt":{"type":"datetime","required":false}},"methods":{"getTag":{"name":"getTag","async":true,"parameters":[],"returnType":"Promise<Tag | null>","isStatic":false,"isPublic":true},"searchByAlias":{"name":"searchByAlias","async":true,"parameters":[{"name":"_alias","type":"string","optional":false},{"name":"_language","type":"string","optional":true}],"returnType":"Promise<Tag[]>","isStatic":true,"isPublic":true},"getAliasesForTag":{"name":"getAliasesForTag","async":true,"parameters":[{"name":"_tagSlug","type":"string","optional":false}],"returnType":"Promise<TagAlias[]>","isStatic":true,"isPublic":true}},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create"]},"cli":{"skipApiCheck":true},"tenantScoped":{"mode":"optional"},"conflictColumns":["tenant_id","slug","context","_meta_type"]},"extends":"SmrtObject","exportName":"TagAlias","collectionExportName":"TagAliasCollection","validationRules":[{"field":"alias","rule":"required","fieldType":"text"}],"schema":{"tableName":"tag_aliases","ddl":"CREATE TABLE IF NOT EXISTS \\"tag_aliases\\" (\\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 \\"tag_slug\\" TEXT DEFAULT '',\\n \\"alias\\" TEXT DEFAULT '',\\n \\"language\\" TEXT DEFAULT '',\\n \\"tenant_id\\" UUID\\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"},"tag_slug":{"type":"TEXT","notNull":false,"default":""},"alias":{"type":"TEXT","notNull":false,"default":""},"language":{"type":"TEXT","notNull":false,"default":""},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false}},"indexes":[{"name":"tag_aliases_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"tag_aliases_meta_type_idx","columns":["_meta_type"]},{"name":"tag_aliases_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"95a4bc18"},"importPath":"@happyvertical/smrt-tags"},"@happyvertical/smrt-tags:TagAliasCollection":{"name":"tagaliascollection","className":"TagAliasCollection","qualifiedName":"@happyvertical/smrt-tags:TagAliasCollection","collection":"tagaliases","filePath":"/home/runner/work/smrt/smrt/packages/tags/src/tag-aliases.ts","packageName":"@happyvertical/smrt-tags","fields":{},"methods":{"addAlias":{"name":"addAlias","async":true,"parameters":[{"name":"tagSlug","type":"string","optional":false},{"name":"alias","type":"string","optional":false},{"name":"language","type":"string","optional":true},{"name":"context","type":"string","optional":true}],"returnType":"Promise<TagAlias>","isStatic":false,"isPublic":true},"searchByAlias":{"name":"searchByAlias","async":true,"parameters":[{"name":"alias","type":"string","optional":false},{"name":"language","type":"string","optional":true}],"returnType":"Promise<Tag[]>","isStatic":false,"isPublic":true},"getAliasesForTag":{"name":"getAliasesForTag","async":true,"parameters":[{"name":"tagSlug","type":"string","optional":false},{"name":"language","type":"string","optional":true}],"returnType":"Promise<TagAlias[]>","isStatic":false,"isPublic":true},"removeAlias":{"name":"removeAlias","async":true,"parameters":[{"name":"aliasId","type":"string","optional":false}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"bulkAddAliases":{"name":"bulkAddAliases","async":true,"parameters":[{"name":"tagSlug","type":"string","optional":false},{"name":"aliases","type":"Array<object>","optional":false,"memberTypes":["string"]}],"returnType":"Promise<TagAlias[]>","isStatic":false,"isPublic":true},"getAliasesByLanguage":{"name":"getAliasesByLanguage","async":true,"parameters":[{"name":"tagSlug","type":"string","optional":false}],"returnType":"Promise<Map<string, string[]>>","isStatic":false,"isPublic":true},"findMatchingAliases":{"name":"findMatchingAliases","async":true,"parameters":[{"name":"query","type":"string","optional":false},{"name":"language","type":"string","optional":true}],"returnType":"Promise<TagAlias[]>","isStatic":false,"isPublic":true},"findByTenant":{"name":"findByTenant","async":true,"parameters":[{"name":"tenantId","type":"string","optional":false}],"returnType":"Promise<TagAlias[]>","isStatic":false,"isPublic":true},"findGlobal":{"name":"findGlobal","async":true,"parameters":[],"returnType":"Promise<TagAlias[]>","isStatic":false,"isPublic":true},"findWithGlobals":{"name":"findWithGlobals","async":true,"parameters":[{"name":"tenantId","type":"string","optional":false}],"returnType":"Promise<TagAlias[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create"]}},"extends":"SmrtCollection","extendsTypeArg":"TagAlias","exportName":"TagAliasCollection","collectionExportName":"TagAliasCollectionCollection","schema":{"tableName":"tag_aliases","ddl":"CREATE TABLE IF NOT EXISTS \\"tag_aliases\\" (\\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 \\"tag_slug\\" TEXT DEFAULT '',\\n \\"alias\\" TEXT DEFAULT '',\\n \\"language\\" TEXT DEFAULT '',\\n \\"tenant_id\\" UUID\\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"},"tag_slug":{"type":"TEXT","notNull":false,"default":""},"alias":{"type":"TEXT","notNull":false,"default":""},"language":{"type":"TEXT","notNull":false,"default":""},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false}},"indexes":[{"name":"tag_aliases_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"tag_aliases_meta_type_idx","columns":["_meta_type"]},{"name":"tag_aliases_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"95a4bc18"},"importPath":"@happyvertical/smrt-tags"},"@happyvertical/smrt-tags:Tag":{"name":"tag","className":"Tag","qualifiedName":"@happyvertical/smrt-tags:Tag","collection":"tags","filePath":"/home/runner/work/smrt/smrt/packages/tags/src/tag.ts","packageName":"@happyvertical/smrt-tags","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"parentId":{"type":"foreignKey","required":false,"related":"Tag","_meta":{"nullable":true}},"name":{"type":"text","required":true,"default":"","description":"The name people see when they pick or browse tags.","_meta":{"required":true,"description":"The name people see when they pick or browse tags."}},"level":{"type":"integer","required":false,"default":0},"description":{"type":"text","required":false,"default":"","description":"A short note on what belongs under this tag.","_meta":{"description":"A short note on what belongs under this tag."}},"metadata":{"type":"text","required":false,"default":"","description":"Extra details about the tag, saved as named items.","_meta":{"description":"Extra details about the tag, saved as named items."}},"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"createdAt":{"type":"datetime","required":false},"updatedAt":{"type":"datetime","required":false}},"methods":{"getParent":{"name":"getParent","async":true,"parameters":[],"returnType":"Promise<this | null>","isStatic":false,"isPublic":true},"getChildren":{"name":"getChildren","async":true,"parameters":[],"returnType":"Promise<this[]>","isStatic":false,"isPublic":true},"getAncestors":{"name":"getAncestors","async":true,"parameters":[],"returnType":"Promise<this[]>","isStatic":false,"isPublic":true},"getDescendants":{"name":"getDescendants","async":true,"parameters":[],"returnType":"Promise<this[]>","isStatic":false,"isPublic":true},"getHierarchy":{"name":"getHierarchy","async":true,"parameters":[],"returnType":"Promise<HierarchyView<this>>","isStatic":false,"isPublic":true},"moveTo":{"name":"moveTo","async":true,"parameters":[{"name":"newParent","type":"this | string | null","optional":false,"unionBranches":[{"type":"this"},{"type":"string"},{"type":"null"}]}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"getMetadata":{"name":"getMetadata","async":false,"parameters":[],"returnType":"TagMetadata","isStatic":false,"isPublic":true},"setMetadata":{"name":"setMetadata","async":false,"parameters":[{"name":"data","type":"TagMetadata","optional":false}],"returnType":"void","isStatic":false,"isPublic":true},"updateMetadata":{"name":"updateMetadata","async":false,"parameters":[{"name":"updates","type":"Partial<TagMetadata>","optional":false}],"returnType":"void","isStatic":false,"isPublic":true},"getBySlug":{"name":"getBySlug","async":true,"parameters":[{"name":"_slug","type":"string","optional":false},{"name":"_context","type":"string","optional":true}],"returnType":"Promise<Tag | null>","isStatic":true,"isPublic":true},"getRootTags":{"name":"getRootTags","async":true,"parameters":[{"name":"_context","type":"string","optional":true,"default":"global"}],"returnType":"Promise<Tag[]>","isStatic":true,"isPublic":true}},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create","update"]},"cli":{"skipApiCheck":true},"tenantScoped":{"mode":"optional"},"conflictColumns":["tenant_id","slug","context","_meta_type"]},"extends":"SmrtHierarchical","exportName":"Tag","collectionExportName":"TagCollection","displayLabelField":"name","validationRules":[{"field":"name","rule":"required","fieldType":"text"}],"schema":{"tableName":"tags","ddl":"CREATE TABLE IF NOT EXISTS \\"tags\\" (\\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 \\"parent_id\\" UUID,\\n \\"name\\" TEXT DEFAULT '',\\n \\"level\\" INTEGER DEFAULT 0,\\n \\"description\\" TEXT DEFAULT '',\\n \\"metadata\\" TEXT DEFAULT '',\\n \\"tenant_id\\" UUID\\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"},"parent_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"tags","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"name":{"type":"TEXT","notNull":false,"default":""},"level":{"type":"INTEGER","notNull":false,"default":0},"description":{"type":"TEXT","notNull":false,"default":""},"metadata":{"type":"TEXT","notNull":false,"default":""},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false}},"indexes":[{"name":"tags_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"tags_meta_type_idx","columns":["_meta_type"]},{"name":"tags_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"tags_parent_id_idx","columns":["parent_id"]}],"version":"4da9de3e"},"importPath":"@happyvertical/smrt-tags"},"@happyvertical/smrt-tags:TagCollection":{"name":"tagcollection","className":"TagCollection","qualifiedName":"@happyvertical/smrt-tags:TagCollection","collection":"tags","filePath":"/home/runner/work/smrt/smrt/packages/tags/src/tags.ts","packageName":"@happyvertical/smrt-tags","fields":{},"methods":{"getOrCreate":{"name":"getOrCreate","async":true,"parameters":[{"name":"slug","type":"string","optional":false},{"name":"context","type":"string","optional":true,"default":"global"}],"returnType":"Promise<Tag>","isStatic":false,"isPublic":true},"listByContext":{"name":"listByContext","async":true,"parameters":[{"name":"context","type":"string","optional":false},{"name":"parentSlug","type":"string | null","optional":true,"unionBranches":[{"type":"string"},{"type":"null"}]}],"returnType":"Promise<Tag[]>","isStatic":false,"isPublic":true},"getRootTags":{"name":"getRootTags","async":true,"parameters":[{"name":"context","type":"string","optional":true,"default":"global"}],"returnType":"Promise<Tag[]>","isStatic":false,"isPublic":true},"getChildren":{"name":"getChildren","async":true,"parameters":[{"name":"parentSlug","type":"string","optional":false},{"name":"context","type":"string","optional":true}],"returnType":"Promise<Tag[]>","isStatic":false,"isPublic":true},"getHierarchy":{"name":"getHierarchy","async":true,"parameters":[{"name":"slug","type":"string","optional":false},{"name":"context","type":"string","optional":true}],"returnType":"Promise<TagHierarchy>","isStatic":false,"isPublic":true},"moveTag":{"name":"moveTag","async":true,"parameters":[{"name":"slug","type":"string","optional":false},{"name":"newParentSlug","type":"string | null","optional":false,"unionBranches":[{"type":"string"},{"type":"null"}]},{"name":"context","type":"string","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"mergeTag":{"name":"mergeTag","async":true,"parameters":[{"name":"fromSlug","type":"string","optional":false},{"name":"toSlug","type":"string","optional":false},{"name":"context","type":"string","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"cleanupUnused":{"name":"cleanupUnused","async":true,"parameters":[{"name":"context","type":"string","optional":true}],"returnType":"Promise<number>","isStatic":false,"isPublic":true},"calculateLevel":{"name":"calculateLevel","async":true,"parameters":[{"name":"parentSlug","type":"string | null","optional":false,"unionBranches":[{"type":"string"},{"type":"null"}]},{"name":"context","type":"string","optional":true}],"returnType":"Promise<number>","isStatic":false,"isPublic":true},"findByTenant":{"name":"findByTenant","async":true,"parameters":[{"name":"tenantId","type":"string","optional":false}],"returnType":"Promise<Tag[]>","isStatic":false,"isPublic":true},"findGlobal":{"name":"findGlobal","async":true,"parameters":[],"returnType":"Promise<Tag[]>","isStatic":false,"isPublic":true},"findWithGlobals":{"name":"findWithGlobals","async":true,"parameters":[{"name":"tenantId","type":"string","optional":false}],"returnType":"Promise<Tag[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create","update"]}},"extends":"SmrtCollection","extendsTypeArg":"Tag","exportName":"TagCollection","collectionExportName":"TagCollectionCollection","schema":{"tableName":"tags","ddl":"CREATE TABLE IF NOT EXISTS \\"tags\\" (\\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 \\"parent_id\\" UUID,\\n \\"name\\" TEXT DEFAULT '',\\n \\"level\\" INTEGER DEFAULT 0,\\n \\"description\\" TEXT DEFAULT '',\\n \\"metadata\\" TEXT DEFAULT '',\\n \\"tenant_id\\" UUID\\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"},"parent_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"tags","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"name":{"type":"TEXT","notNull":false,"default":""},"level":{"type":"INTEGER","notNull":false,"default":0},"description":{"type":"TEXT","notNull":false,"default":""},"metadata":{"type":"TEXT","notNull":false,"default":""},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false}},"indexes":[{"name":"tags_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"tags_meta_type_idx","columns":["_meta_type"]},{"name":"tags_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"tags_parent_id_idx","columns":["parent_id"]}],"version":"4da9de3e"},"importPath":"@happyvertical/smrt-tags"}},"moduleType":"smrt","recipes":[{"id":"tags.taxonomy","className":"TaxonomyRecipe","label":"Taxonomy","summary":"Organise anything with a shared set of nested tags and alternative names.","synonyms":["tags","tagging","categories","labels","topics"],"models":["@happyvertical/smrt-tags:Tag","@happyvertical/smrt-tags:TagAlias"],"nav":[{"label":"Tags","model":"@happyvertical/smrt-tags:Tag","icon":"tag","description":"The shared set of tags, including tags inside other tags."},{"label":"Alternative names","model":"@happyvertical/smrt-tags:TagAlias","icon":"book","description":"Other names and translations that lead people to the same tag."}],"requires":[],"section":{"id":"taxonomy","label":"Taxonomy","icon":"tag","description":"The tags people use to sort and find things."},"options":{"@happyvertical/smrt-tags:Tag":{"fields":{"name":{"order":1},"parentId":{"label":"Parent tag","help":"The broader tag this one sits under. Leave it empty for a top-level tag.","order":2},"description":{"order":3},"level":{"visibility":"hidden","locked":true},"metadata":{"visibility":"advanced"}}},"@happyvertical/smrt-tags:TagAlias":{"fields":{"alias":{"label":"Alternative name","order":1},"tagSlug":{"label":"Tag","order":2},"language":{"order":3}}}},"help":{"markdown":"## Overview\\n\\nTaxonomy is a shared list of tags you can use to organise anything in your app.\\nTags can sit inside other tags, so a broad tag such as \\"Events\\" can hold\\nnarrower ones such as \\"Concerts\\" and \\"Workshops\\". A tag can also have\\nalternative names, including translations, so people find it by whichever word\\nthey know.\\n\\n## Tasks\\n\\n### Add a tag\\n\\n1. Choose the **New** button above the list of tags.\\n2. Give the tag a **{field:name}** people will recognise.\\n3. Add a **{field:description}** that says what belongs under it.\\n4. Save. The tag is now ready to use.\\n\\n### Put a tag inside another tag\\n\\n1. Open the tag from the list and choose Edit.\\n2. Pick the **{field:parentId}**, the broader tag it belongs under.\\n3. Leave it empty to make the tag a top-level tag.\\n4. Save. Moving a tag moves everything under it too.\\n\\n### Add another name for a tag\\n\\n1. Open the list of alternative names and choose **New**.\\n2. Pick the **{field:tagSlug}** the new name belongs to.\\n3. Type the **{field:alias}**, for example a common nickname or a translation.\\n4. Set the **{field:language}** if the name is in a specific language.\\n5. Save. The alternative name is now on file for that tag.\\n\\n### Keep the list tidy\\n\\nKeep one tag for each idea. If two tags mean the same thing, record the second\\nas an alternative name instead of keeping both.\\n","fieldRefs":["alias","description","language","name","parentId","tagSlug"]},"demo":{"mode":"server","reasons":["Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624)."]}}],"smrtDependencies":["@happyvertical/smrt-core","@happyvertical/smrt-tenancy"],"browser":{"status":"server-only","issues":["#3624"],"via":["@happyvertical/smrt-tenancy"]},"stampsConstructors":true}`));
|
|
15
|
-
var __defProp$1$1 = Object.defineProperty;
|
|
16
|
-
var __getOwnPropDesc$1$1 = Object.getOwnPropertyDescriptor;
|
|
17
|
-
var __defNormalProp$1$1 = (obj, key, value) => key in obj ? __defProp$1$1(obj, key, {
|
|
18
|
-
enumerable: true,
|
|
19
|
-
configurable: true,
|
|
20
|
-
writable: true,
|
|
21
|
-
value
|
|
22
|
-
}) : obj[key] = value;
|
|
23
|
-
var __decorateClass$1$1 = (decorators, target, key, kind) => {
|
|
24
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1$1(target, key) : target;
|
|
25
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
26
|
-
if (kind && result) __defProp$1$1(target, key, result);
|
|
27
|
-
return result;
|
|
28
|
-
};
|
|
29
|
-
var __publicField$1$1 = (obj, key, value) => __defNormalProp$1$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
30
|
-
var Tag = class extends SmrtHierarchical {
|
|
31
|
-
_slug = "";
|
|
32
|
-
_context = "global";
|
|
33
|
-
get slug() {
|
|
34
|
-
return this._slug;
|
|
35
|
-
}
|
|
36
|
-
set slug(value) {
|
|
37
|
-
this._slug = value;
|
|
38
|
-
}
|
|
39
|
-
get context() {
|
|
40
|
-
return this._context;
|
|
41
|
-
}
|
|
42
|
-
set context(value) {
|
|
43
|
-
this._context = value;
|
|
44
|
-
}
|
|
45
|
-
name = "";
|
|
46
|
-
level = 0;
|
|
47
|
-
description = "";
|
|
48
|
-
metadata = "";
|
|
49
|
-
tenantId = null;
|
|
50
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
51
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
52
|
-
constructor(options = {}) {
|
|
53
|
-
super(options);
|
|
54
|
-
if (options.name) this.name = options.name;
|
|
55
|
-
if (options.parentId !== void 0) this.parentId = options.parentId ?? null;
|
|
56
|
-
if (options.slug) this._slug = options.slug;
|
|
57
|
-
if (options.context !== void 0) this._context = options.context;
|
|
58
|
-
if (options.level !== void 0) this.level = options.level;
|
|
59
|
-
if (options.description !== void 0) this.description = options.description;
|
|
60
|
-
if (options.metadata !== void 0) if (typeof options.metadata === "string") this.metadata = options.metadata;
|
|
61
|
-
else this.metadata = JSON.stringify(options.metadata);
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Get metadata as parsed object
|
|
65
|
-
*
|
|
66
|
-
* @returns Parsed metadata object or empty object if no metadata
|
|
67
|
-
*/
|
|
68
|
-
getMetadata() {
|
|
69
|
-
const metadataValue = String(this.metadata || "");
|
|
70
|
-
if (!metadataValue) return {};
|
|
71
|
-
try {
|
|
72
|
-
return JSON.parse(metadataValue);
|
|
73
|
-
} catch {
|
|
74
|
-
return {};
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Set metadata from object
|
|
79
|
-
*
|
|
80
|
-
* @param data - Metadata object to store
|
|
81
|
-
*/
|
|
82
|
-
setMetadata(data) {
|
|
83
|
-
this.metadata = JSON.stringify(data);
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Update metadata by merging with existing values
|
|
87
|
-
*
|
|
88
|
-
* @param updates - Partial metadata to merge
|
|
89
|
-
*/
|
|
90
|
-
updateMetadata(updates) {
|
|
91
|
-
const current = this.getMetadata();
|
|
92
|
-
this.setMetadata({
|
|
93
|
-
...current,
|
|
94
|
-
...updates
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Convenience method for slug-based lookup
|
|
99
|
-
*
|
|
100
|
-
* @param slug - The slug to search for
|
|
101
|
-
* @param context - Optional context filter
|
|
102
|
-
* @returns Tag instance or null if not found
|
|
103
|
-
*/
|
|
104
|
-
static async getBySlug(_slug, _context) {
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Get root tags (no parent) for a context
|
|
109
|
-
*
|
|
110
|
-
* @param context - The context to filter by
|
|
111
|
-
* @returns Array of root tags
|
|
112
|
-
*/
|
|
113
|
-
static async getRootTags(_context = "global") {
|
|
114
|
-
return [];
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
__publicField$1$1(Tag, "__smrtPackage__", "@happyvertical/smrt-tags");
|
|
118
|
-
__decorateClass$1$1([field({
|
|
119
|
-
required: true,
|
|
120
|
-
description: "The name people see when they pick or browse tags."
|
|
121
|
-
})], Tag.prototype, "name", 2);
|
|
122
|
-
__decorateClass$1$1([field({ description: "A short note on what belongs under this tag." })], Tag.prototype, "description", 2);
|
|
123
|
-
__decorateClass$1$1([field({ description: "Extra details about the tag, saved as named items." })], Tag.prototype, "metadata", 2);
|
|
124
|
-
__decorateClass$1$1([tenantId({ nullable: true })], Tag.prototype, "tenantId", 2);
|
|
125
|
-
Tag = __decorateClass$1$1([TenantScoped({ mode: "optional" }), smrt({
|
|
126
|
-
tableStrategy: "sti",
|
|
127
|
-
api: { include: [
|
|
128
|
-
"list",
|
|
129
|
-
"get",
|
|
130
|
-
"create",
|
|
131
|
-
"update",
|
|
132
|
-
"delete"
|
|
133
|
-
] },
|
|
134
|
-
mcp: { include: [
|
|
135
|
-
"list",
|
|
136
|
-
"get",
|
|
137
|
-
"create",
|
|
138
|
-
"update"
|
|
139
|
-
] },
|
|
140
|
-
cli: { skipApiCheck: true }
|
|
141
|
-
})], Tag);
|
|
142
|
-
var __defProp$10 = Object.defineProperty;
|
|
143
|
-
var __getOwnPropDesc$9 = Object.getOwnPropertyDescriptor;
|
|
144
|
-
var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$10(obj, key, {
|
|
145
|
-
enumerable: true,
|
|
146
|
-
configurable: true,
|
|
147
|
-
writable: true,
|
|
148
|
-
value
|
|
149
|
-
}) : obj[key] = value;
|
|
150
|
-
var __decorateClass$9 = (decorators, target, key, kind) => {
|
|
151
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$9(target, key) : target;
|
|
152
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
153
|
-
if (kind && result) __defProp$10(target, key, result);
|
|
154
|
-
return result;
|
|
155
|
-
};
|
|
156
|
-
var __publicField$9 = (obj, key, value) => __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
157
|
-
var TagAlias = class extends SmrtObject {
|
|
158
|
-
tagSlug = "";
|
|
159
|
-
alias = "";
|
|
160
|
-
language = "";
|
|
161
|
-
_context = "";
|
|
162
|
-
get context() {
|
|
163
|
-
return this._context;
|
|
164
|
-
}
|
|
165
|
-
set context(value) {
|
|
166
|
-
this._context = value;
|
|
167
|
-
}
|
|
168
|
-
tenantId = null;
|
|
169
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
170
|
-
constructor(options = {}) {
|
|
171
|
-
super(options);
|
|
172
|
-
if (options.tagSlug !== void 0) this.tagSlug = options.tagSlug;
|
|
173
|
-
if (options.alias) this.alias = options.alias;
|
|
174
|
-
if (options.language !== void 0) this.language = options.language;
|
|
175
|
-
if (options.context !== void 0) this._context = options.context;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Get the tag this alias belongs to
|
|
179
|
-
*
|
|
180
|
-
* @returns Tag instance or null if not found
|
|
181
|
-
*/
|
|
182
|
-
async getTag() {
|
|
183
|
-
const { TagCollection } = await Promise.resolve().then(() => tags_exports);
|
|
184
|
-
return await (await TagCollection.create(this.options)).get({ slug: this.tagSlug });
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Search tags by alias
|
|
188
|
-
*
|
|
189
|
-
* @param alias - The alias to search for
|
|
190
|
-
* @param language - Optional language filter
|
|
191
|
-
* @returns Array of matching tags
|
|
192
|
-
*/
|
|
193
|
-
static async searchByAlias(_alias, _language) {
|
|
194
|
-
return [];
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Get all aliases for a tag
|
|
198
|
-
*
|
|
199
|
-
* @param tagSlug - The tag slug to get aliases for
|
|
200
|
-
* @returns Array of TagAlias instances
|
|
201
|
-
*/
|
|
202
|
-
static async getAliasesForTag(_tagSlug) {
|
|
203
|
-
return [];
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
__publicField$9(TagAlias, "__smrtPackage__", "@happyvertical/smrt-tags");
|
|
207
|
-
__decorateClass$9([field({ description: "The tag this alternative name points to." })], TagAlias.prototype, "tagSlug", 2);
|
|
208
|
-
__decorateClass$9([field({
|
|
209
|
-
required: true,
|
|
210
|
-
description: "Another name or a translation people may use for the tag."
|
|
211
|
-
})], TagAlias.prototype, "alias", 2);
|
|
212
|
-
__decorateClass$9([field({ description: "The two-letter language code of the alternative name." })], TagAlias.prototype, "language", 2);
|
|
213
|
-
__decorateClass$9([tenantId({ nullable: true })], TagAlias.prototype, "tenantId", 2);
|
|
214
|
-
TagAlias = __decorateClass$9([TenantScoped({ mode: "optional" }), smrt({
|
|
215
|
-
tableStrategy: "sti",
|
|
216
|
-
api: { include: [
|
|
217
|
-
"list",
|
|
218
|
-
"get",
|
|
219
|
-
"create",
|
|
220
|
-
"update",
|
|
221
|
-
"delete"
|
|
222
|
-
] },
|
|
223
|
-
mcp: { include: [
|
|
224
|
-
"list",
|
|
225
|
-
"get",
|
|
226
|
-
"create"
|
|
227
|
-
] },
|
|
228
|
-
cli: { skipApiCheck: true }
|
|
229
|
-
})], TagAlias);
|
|
230
|
-
var tag_aliases_exports = /* @__PURE__ */ __exportAll$1({ TagAliasCollection: () => TagAliasCollection });
|
|
231
|
-
var TagAliasCollection = class extends SmrtCollection {
|
|
232
|
-
static _itemClass = TagAlias;
|
|
233
|
-
/**
|
|
234
|
-
* Add an alias to a tag (get or create)
|
|
235
|
-
*
|
|
236
|
-
* @param tagSlug - The tag slug
|
|
237
|
-
* @param alias - The alias text
|
|
238
|
-
* @param language - Optional language code
|
|
239
|
-
* @param context - Optional context
|
|
240
|
-
* @returns TagAlias instance
|
|
241
|
-
*/
|
|
242
|
-
async addAlias(tagSlug, alias, language, context) {
|
|
243
|
-
const where = {
|
|
244
|
-
tagSlug,
|
|
245
|
-
alias
|
|
246
|
-
};
|
|
247
|
-
if (language) where.language = language;
|
|
248
|
-
if (context) where.context = context;
|
|
249
|
-
const existing = await this.list({
|
|
250
|
-
where,
|
|
251
|
-
limit: 1
|
|
252
|
-
});
|
|
253
|
-
if (existing.length > 0) return existing[0];
|
|
254
|
-
return await this.create({
|
|
255
|
-
tagSlug,
|
|
256
|
-
alias,
|
|
257
|
-
language,
|
|
258
|
-
context
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* Search tags by alias
|
|
263
|
-
*
|
|
264
|
-
* @param alias - The alias to search for
|
|
265
|
-
* @param language - Optional language filter
|
|
266
|
-
* @returns Array of matching tags
|
|
267
|
-
*/
|
|
268
|
-
async searchByAlias(alias, language) {
|
|
269
|
-
const where = { alias };
|
|
270
|
-
if (language) where.language = language;
|
|
271
|
-
const aliases = await this.list({ where });
|
|
272
|
-
const tagSlugs = [...new Set(aliases.map((a) => a.tagSlug))];
|
|
273
|
-
const { TagCollection } = await Promise.resolve().then(() => tags_exports);
|
|
274
|
-
const tagCollection = await TagCollection.create(this.options);
|
|
275
|
-
const tags = [];
|
|
276
|
-
for (const slug of tagSlugs) {
|
|
277
|
-
const tag = await tagCollection.get({ slug });
|
|
278
|
-
if (tag) tags.push(tag);
|
|
279
|
-
}
|
|
280
|
-
return tags;
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Get all aliases for a tag
|
|
284
|
-
*
|
|
285
|
-
* @param tagSlug - The tag slug
|
|
286
|
-
* @param language - Optional language filter
|
|
287
|
-
* @returns Array of TagAlias instances
|
|
288
|
-
*/
|
|
289
|
-
async getAliasesForTag(tagSlug, language) {
|
|
290
|
-
const where = { tagSlug };
|
|
291
|
-
if (language) where.language = language;
|
|
292
|
-
return await this.list({ where });
|
|
293
|
-
}
|
|
294
|
-
/**
|
|
295
|
-
* Remove an alias by ID
|
|
296
|
-
*
|
|
297
|
-
* @param aliasId - The alias UUID
|
|
298
|
-
*/
|
|
299
|
-
async removeAlias(aliasId) {
|
|
300
|
-
const alias = await this.get({ id: aliasId });
|
|
301
|
-
if (alias) await alias.delete();
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Bulk add aliases to a tag
|
|
305
|
-
*
|
|
306
|
-
* @param tagSlug - The tag slug
|
|
307
|
-
* @param aliases - Array of alias configurations
|
|
308
|
-
* @returns Array of created TagAlias instances
|
|
309
|
-
*/
|
|
310
|
-
async bulkAddAliases(tagSlug, aliases) {
|
|
311
|
-
const created = [];
|
|
312
|
-
for (const aliasData of aliases) {
|
|
313
|
-
const tagAlias = await this.addAlias(tagSlug, aliasData.alias, aliasData.language, aliasData.context);
|
|
314
|
-
created.push(tagAlias);
|
|
315
|
-
}
|
|
316
|
-
return created;
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
* Get aliases grouped by language
|
|
320
|
-
*
|
|
321
|
-
* @param tagSlug - The tag slug
|
|
322
|
-
* @returns Map of language code to array of aliases
|
|
323
|
-
*/
|
|
324
|
-
async getAliasesByLanguage(tagSlug) {
|
|
325
|
-
const aliases = await this.getAliasesForTag(tagSlug);
|
|
326
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
327
|
-
for (const alias of aliases) {
|
|
328
|
-
const lang = String(alias.language || "default");
|
|
329
|
-
if (!grouped.has(lang)) grouped.set(lang, []);
|
|
330
|
-
grouped.get(lang)?.push(String(alias.alias));
|
|
331
|
-
}
|
|
332
|
-
return grouped;
|
|
333
|
-
}
|
|
334
|
-
/**
|
|
335
|
-
* Find matching aliases (case-insensitive partial match)
|
|
336
|
-
*
|
|
337
|
-
* Note: This is a simple implementation. For production use,
|
|
338
|
-
* consider using full-text search or fuzzy matching.
|
|
339
|
-
*
|
|
340
|
-
* @param query - The search query
|
|
341
|
-
* @param language - Optional language filter
|
|
342
|
-
* @returns Array of matching TagAlias instances
|
|
343
|
-
*/
|
|
344
|
-
async findMatchingAliases(query, language) {
|
|
345
|
-
const where = {};
|
|
346
|
-
if (language) where.language = language;
|
|
347
|
-
const all = await this.list({ where });
|
|
348
|
-
const queryLower = query.toLowerCase();
|
|
349
|
-
return all.filter((alias) => String(alias.alias).toLowerCase().includes(queryLower));
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Find all tag aliases belonging to a specific tenant
|
|
353
|
-
*
|
|
354
|
-
* @param tenantId - The tenant ID to filter by
|
|
355
|
-
* @returns Array of tag aliases for the specified tenant
|
|
356
|
-
*/
|
|
357
|
-
async findByTenant(tenantId) {
|
|
358
|
-
return this.list({ where: { tenantId } });
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* Find all global (tenant-less) tag aliases.
|
|
362
|
-
*
|
|
363
|
-
* Routes through the shared tenant-global helper so it does not throw under
|
|
364
|
-
* an active tenant context (an explicit `tenant_id IS NULL` filter would be
|
|
365
|
-
* flagged as an isolation violation). (#1600)
|
|
366
|
-
*
|
|
367
|
-
* @returns Array of global tag aliases with null tenantId
|
|
368
|
-
*/
|
|
369
|
-
async findGlobal() {
|
|
370
|
-
return queryGlobal(this);
|
|
371
|
-
}
|
|
372
|
-
/**
|
|
373
|
-
* Find tag aliases for a tenant including global aliases.
|
|
374
|
-
*
|
|
375
|
-
* Fails closed if an active tenant context requests a different tenant's
|
|
376
|
-
* rows; the admin/system path keeps the cross-tenant capability. (#1600)
|
|
377
|
-
*
|
|
378
|
-
* @param tenantId - The tenant ID to filter by
|
|
379
|
-
* @returns Array of tag aliases for the tenant plus all global aliases
|
|
380
|
-
*/
|
|
381
|
-
async findWithGlobals(tenantId) {
|
|
382
|
-
return queryWithGlobals(this, tenantId, "TagAlias.findWithGlobals");
|
|
383
|
-
}
|
|
384
|
-
};
|
|
385
|
-
var tags_exports = /* @__PURE__ */ __exportAll$1({ TagCollection: () => TagCollection });
|
|
386
|
-
var TagCollection = class extends SmrtCollection {
|
|
387
|
-
static _itemClass = Tag;
|
|
388
|
-
/**
|
|
389
|
-
* Get or create a tag with context
|
|
390
|
-
*
|
|
391
|
-
* @param slug - Tag slug
|
|
392
|
-
* @param context - Tag context (default: 'global')
|
|
393
|
-
* @returns Tag instance
|
|
394
|
-
*/
|
|
395
|
-
async getOrCreate(slug, context = "global") {
|
|
396
|
-
const existing = await this.list({
|
|
397
|
-
where: {
|
|
398
|
-
slug,
|
|
399
|
-
context
|
|
400
|
-
},
|
|
401
|
-
limit: 1
|
|
402
|
-
});
|
|
403
|
-
if (existing.length > 0) return existing[0];
|
|
404
|
-
return await this.create({
|
|
405
|
-
slug,
|
|
406
|
-
name: slug.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
407
|
-
context,
|
|
408
|
-
level: 0
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* Resolve a tag by slug, optionally scoped to a context.
|
|
413
|
-
*
|
|
414
|
-
* Tags are identified by `(slug, context)`. When `context` is omitted
|
|
415
|
-
* and the slug exists in more than one context, this throws a clear
|
|
416
|
-
* ambiguity error rather than silently picking the first matching row.
|
|
417
|
-
* Callers that know their context should pass it; callers that work in
|
|
418
|
-
* a single-context world can leave it off.
|
|
419
|
-
*
|
|
420
|
-
* @returns The matching Tag, or `null` if nothing matches.
|
|
421
|
-
* @throws Error if `context` is omitted and the slug is ambiguous.
|
|
422
|
-
*/
|
|
423
|
-
async resolveBySlug(slug, context) {
|
|
424
|
-
const where = { slug };
|
|
425
|
-
if (context !== void 0) where.context = context;
|
|
426
|
-
const matches = await this.list({
|
|
427
|
-
where,
|
|
428
|
-
limit: 2
|
|
429
|
-
});
|
|
430
|
-
if (matches.length === 0) return null;
|
|
431
|
-
if (matches.length > 1) throw new Error(`Tag slug '${slug}' is ambiguous: resolves to ${matches.length}+ rows across contexts. Pass an explicit \`context\` argument.`);
|
|
432
|
-
return matches[0];
|
|
433
|
-
}
|
|
434
|
-
/**
|
|
435
|
-
* List tags by context with optional parent filtering by slug.
|
|
436
|
-
*
|
|
437
|
-
* @param context - The context to filter by
|
|
438
|
-
* @param parentSlug - Optional parent slug to filter children. Pass an
|
|
439
|
-
* empty string or `null` to find root tags; pass a slug to find that
|
|
440
|
-
* tag's immediate children. Typed as `string | null` so TypeScript
|
|
441
|
-
* callers can pass `null` without a cast — the `null` and `''` paths
|
|
442
|
-
* are both treated as "roots only".
|
|
443
|
-
* @returns Array of matching tags
|
|
444
|
-
*/
|
|
445
|
-
async listByContext(context, parentSlug) {
|
|
446
|
-
const where = { context };
|
|
447
|
-
if (parentSlug === "" || parentSlug === null) where.parentId = null;
|
|
448
|
-
else if (parentSlug !== void 0) {
|
|
449
|
-
const parent = await this.get({
|
|
450
|
-
slug: parentSlug,
|
|
451
|
-
context
|
|
452
|
-
});
|
|
453
|
-
if (!parent?.id) return [];
|
|
454
|
-
where.parentId = parent.id;
|
|
455
|
-
}
|
|
456
|
-
return await this.list({ where });
|
|
457
|
-
}
|
|
458
|
-
/**
|
|
459
|
-
* Get root tags (no parent) for a context
|
|
460
|
-
*
|
|
461
|
-
* @param context - The context to filter by (default: 'global')
|
|
462
|
-
* @returns Array of root tags
|
|
463
|
-
*/
|
|
464
|
-
async getRootTags(context = "global") {
|
|
465
|
-
return await this.list({ where: {
|
|
466
|
-
context,
|
|
467
|
-
parentId: null
|
|
468
|
-
} });
|
|
469
|
-
}
|
|
470
|
-
/**
|
|
471
|
-
* Get immediate children of a parent tag, looked up by slug.
|
|
472
|
-
*
|
|
473
|
-
* @param parentSlug - The parent tag slug
|
|
474
|
-
* @param context - Optional context for the parent lookup. When omitted,
|
|
475
|
-
* the parent slug must be unambiguous across contexts (throws if not).
|
|
476
|
-
* @returns Array of child tags, or `[]` if the parent slug doesn't
|
|
477
|
-
* resolve. Children are filtered to the resolved parent's context so
|
|
478
|
-
* cross-context children don't leak in.
|
|
479
|
-
*/
|
|
480
|
-
async getChildren(parentSlug, context) {
|
|
481
|
-
const parent = await this.resolveBySlug(parentSlug, context);
|
|
482
|
-
if (!parent?.id) return [];
|
|
483
|
-
return await this.list({ where: {
|
|
484
|
-
parentId: parent.id,
|
|
485
|
-
context: parent.context
|
|
486
|
-
} });
|
|
487
|
-
}
|
|
488
|
-
/**
|
|
489
|
-
* Get tag hierarchy (all ancestors and descendants)
|
|
490
|
-
*
|
|
491
|
-
* @param slug - The tag slug
|
|
492
|
-
* @param context - Optional context for the slug lookup. When omitted,
|
|
493
|
-
* the slug must be unambiguous across contexts.
|
|
494
|
-
* @returns Object with ancestors, current tag, and descendants
|
|
495
|
-
*/
|
|
496
|
-
async getHierarchy(slug, context) {
|
|
497
|
-
const tag = await this.resolveBySlug(slug, context);
|
|
498
|
-
if (!tag) throw new Error(`Tag '${slug}' not found`);
|
|
499
|
-
const [ancestors, descendants] = await Promise.all([tag.getAncestors(), tag.getDescendants()]);
|
|
500
|
-
return {
|
|
501
|
-
ancestors,
|
|
502
|
-
current: tag,
|
|
503
|
-
descendants
|
|
504
|
-
};
|
|
505
|
-
}
|
|
506
|
-
/**
|
|
507
|
-
* Move a tag to a new parent. Slug-based API; UUIDs resolved internally.
|
|
508
|
-
*
|
|
509
|
-
* Cycle detection is inlined here (mirroring `SmrtHierarchical.moveTo`'s
|
|
510
|
-
* self-loop + descendant checks) so that both `parentId` and the
|
|
511
|
-
* denormalised `level` field can be persisted in a single `save()`.
|
|
512
|
-
* Delegating to `moveTo` would write `parentId` first and `level` in a
|
|
513
|
-
* second save — if the second save failed, the tag would be left with
|
|
514
|
-
* the new parent but a stale level, breaking the depth cache.
|
|
515
|
-
*
|
|
516
|
-
* After the moved tag persists, descendant levels are recalculated
|
|
517
|
-
* recursively via `updateDescendantLevels`.
|
|
518
|
-
*
|
|
519
|
-
* @param slug - The tag to move
|
|
520
|
-
* @param newParentSlug - The new parent slug (null for root)
|
|
521
|
-
* @param context - Optional context. When provided, both source and new
|
|
522
|
-
* parent are resolved within it. When omitted, both slugs must be
|
|
523
|
-
* unambiguous across contexts; the resolver throws otherwise.
|
|
524
|
-
* @throws Error if either slug fails to resolve, if either slug is
|
|
525
|
-
* ambiguous across contexts (no context provided), if source and new
|
|
526
|
-
* parent live in different contexts, or if the move would create a
|
|
527
|
-
* cycle.
|
|
528
|
-
*/
|
|
529
|
-
async moveTag(slug, newParentSlug, context) {
|
|
530
|
-
const tag = await this.resolveBySlug(slug, context);
|
|
531
|
-
if (!tag) throw new Error(`Tag '${slug}' not found`);
|
|
532
|
-
let newParent = null;
|
|
533
|
-
if (newParentSlug) {
|
|
534
|
-
newParent = await this.resolveBySlug(newParentSlug, context ?? tag.context);
|
|
535
|
-
if (!newParent) throw new Error(`Tag '${newParentSlug}' not found`);
|
|
536
|
-
if (newParent.context !== tag.context) throw new Error(`Cannot move Tag '${slug}' (context '${tag.context}') under '${newParentSlug}' (context '${newParent.context}') \u2014 contexts must match.`);
|
|
537
|
-
}
|
|
538
|
-
const newParentId = newParent?.id ?? null;
|
|
539
|
-
if (newParentId !== null && newParentId === tag.id) throw new Error(`Cannot move Tag ${tag.id} to itself.`);
|
|
540
|
-
if (newParentId !== null) {
|
|
541
|
-
if ((await tag.getDescendants()).some((d) => d.id === newParentId)) throw new Error(`Cannot move Tag ${tag.id} under one of its own descendants (${newParentId}) \u2014 would create a cycle.`);
|
|
542
|
-
}
|
|
543
|
-
tag.parentId = newParentId;
|
|
544
|
-
tag.level = newParent ? newParent.level + 1 : 0;
|
|
545
|
-
await tag.save();
|
|
546
|
-
await this.updateDescendantLevels(tag);
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* Merge one tag into another (updates all references)
|
|
550
|
-
*
|
|
551
|
-
* Reparents `fromTag`'s direct children onto `toTag` and recalculates
|
|
552
|
-
* their `level` field plus the level of every descendant — without
|
|
553
|
-
* this, children moved from a different depth would carry stale
|
|
554
|
-
* levels relative to their new parent. `TagAlias.tagSlug` references
|
|
555
|
-
* are also rewritten, then `fromTag` is deleted.
|
|
556
|
-
*
|
|
557
|
-
* Note: Consuming packages are responsible for updating their own
|
|
558
|
-
* join tables (e.g. `asset_tags`).
|
|
559
|
-
*
|
|
560
|
-
* @param fromSlug - The tag to merge from
|
|
561
|
-
* @param toSlug - The tag to merge into
|
|
562
|
-
* @param context - Optional context. When provided, both tags are
|
|
563
|
-
* resolved within it. When omitted, both slugs must be unambiguous
|
|
564
|
-
* across contexts.
|
|
565
|
-
* @throws Error if either slug fails to resolve, if either slug is
|
|
566
|
-
* ambiguous, or if the two tags live in different contexts.
|
|
567
|
-
*/
|
|
568
|
-
async mergeTag(fromSlug, toSlug, context) {
|
|
569
|
-
const fromTag = await this.resolveBySlug(fromSlug, context);
|
|
570
|
-
const toTag = await this.resolveBySlug(toSlug, context ?? fromTag?.context);
|
|
571
|
-
if (!fromTag) throw new Error(`Source tag '${fromSlug}' not found`);
|
|
572
|
-
if (!toTag) throw new Error(`Target tag '${toSlug}' not found`);
|
|
573
|
-
if (!fromTag.id) throw new Error(`Source tag '${fromSlug}' has no id`);
|
|
574
|
-
if (!toTag.id) throw new Error(`Target tag '${toSlug}' has no id`);
|
|
575
|
-
if (fromTag.context !== toTag.context) throw new Error(`Cannot merge '${fromSlug}' (context '${fromTag.context}') into '${toSlug}' (context '${toTag.context}') \u2014 contexts must match.`);
|
|
576
|
-
if (fromTag.id === toTag.id) throw new Error(`Cannot merge tag '${fromSlug}' into itself.`);
|
|
577
|
-
if ((await fromTag.getDescendants()).some((d) => d.id === toTag.id)) throw new Error(`Cannot merge '${fromSlug}' into '${toSlug}' \u2014 target is a descendant of source (would create a cycle).`);
|
|
578
|
-
const children = await this.list({ where: { parentId: fromTag.id } });
|
|
579
|
-
const newChildLevel = toTag.level + 1;
|
|
580
|
-
for (const child of children) {
|
|
581
|
-
child.parentId = toTag.id;
|
|
582
|
-
child.level = newChildLevel;
|
|
583
|
-
await child.save();
|
|
584
|
-
await this.updateDescendantLevels(child);
|
|
585
|
-
}
|
|
586
|
-
const { TagAliasCollection } = await Promise.resolve().then(() => tag_aliases_exports);
|
|
587
|
-
const aliasCollection = await TagAliasCollection.create(this.options);
|
|
588
|
-
const aliasContexts = [fromTag.context];
|
|
589
|
-
if (fromTag.context === "global") aliasContexts.push("");
|
|
590
|
-
const aliases = await aliasCollection.list({ where: {
|
|
591
|
-
tagSlug: fromSlug,
|
|
592
|
-
context: aliasContexts
|
|
593
|
-
} });
|
|
594
|
-
for (const alias of aliases) {
|
|
595
|
-
alias.tagSlug = toSlug;
|
|
596
|
-
await alias.save();
|
|
597
|
-
}
|
|
598
|
-
await this.repointTagReferences(fromTag.id, toTag.id);
|
|
599
|
-
await fromTag.delete();
|
|
600
|
-
}
|
|
601
|
-
/**
|
|
602
|
-
* Move every reference to tag `fromId` onto `toId`. A row whose natural key
|
|
603
|
-
* includes the tag column and that already exists for `toId` (an asset
|
|
604
|
-
* tagged with both) is a duplicate after the merge and is removed instead.
|
|
605
|
-
* Rows are matched by tag id, which is specific to one tenant's tag, so
|
|
606
|
-
* this reads and writes through the adapter directly.
|
|
607
|
-
*/
|
|
608
|
-
async repointTagReferences(fromId, toId) {
|
|
609
|
-
const tagClass = ObjectRegistry.getClassByConstructor(Tag)?.qualifiedName ?? "Tag";
|
|
610
|
-
const tagTable = ObjectRegistry.getTableName(tagClass);
|
|
611
|
-
for (const reference of ObjectRegistry.getIncomingReferences(tagClass)) {
|
|
612
|
-
if (reference.tableName === tagTable) continue;
|
|
613
|
-
if (!await this.db.tableExists(reference.tableName)) continue;
|
|
614
|
-
const conflictColumns = ObjectRegistry.getConflictColumns(reference.className);
|
|
615
|
-
const keyed = conflictColumns.includes(reference.column) && !(conflictColumns.length === 1 && conflictColumns[0] === "id");
|
|
616
|
-
const rows = await this.db.list(reference.tableName, { [reference.column]: fromId });
|
|
617
|
-
for (const row of rows) {
|
|
618
|
-
if (keyed) {
|
|
619
|
-
const probe = {};
|
|
620
|
-
for (const column of conflictColumns) probe[column] = column === reference.column ? toId : row[column];
|
|
621
|
-
if (await this.db.get(reference.tableName, probe)) {
|
|
622
|
-
await this.db.delete(reference.tableName, { id: row.id });
|
|
623
|
-
continue;
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
await this.db.update(reference.tableName, { id: row.id }, { [reference.column]: toId });
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
/**
|
|
631
|
-
* Remove tags with no references (cleanup unused tags)
|
|
632
|
-
*
|
|
633
|
-
* Note: This requires consuming packages to provide usage information.
|
|
634
|
-
* By default, only removes tags with no children and no aliases.
|
|
635
|
-
*
|
|
636
|
-
* @param context - Optional context to filter cleanup
|
|
637
|
-
*/
|
|
638
|
-
async cleanupUnused(context) {
|
|
639
|
-
const where = {};
|
|
640
|
-
if (context) where.context = context;
|
|
641
|
-
const tags = await this.list({ where });
|
|
642
|
-
const { TagAliasCollection } = await Promise.resolve().then(() => tag_aliases_exports);
|
|
643
|
-
const aliasCollection = await TagAliasCollection.create(this.options);
|
|
644
|
-
let deletedCount = 0;
|
|
645
|
-
for (const tag of tags) {
|
|
646
|
-
if (!tag.id) continue;
|
|
647
|
-
if ((await this.list({
|
|
648
|
-
where: { parentId: tag.id },
|
|
649
|
-
limit: 1
|
|
650
|
-
})).length > 0) continue;
|
|
651
|
-
if ((await aliasCollection.list({
|
|
652
|
-
where: { tagSlug: tag.slug },
|
|
653
|
-
limit: 1
|
|
654
|
-
})).length > 0) continue;
|
|
655
|
-
await tag.delete();
|
|
656
|
-
deletedCount++;
|
|
657
|
-
}
|
|
658
|
-
return deletedCount;
|
|
659
|
-
}
|
|
660
|
-
/**
|
|
661
|
-
* Calculate hierarchy level for a tag, looking the parent up by slug.
|
|
662
|
-
*
|
|
663
|
-
* @param parentSlug - The parent tag slug (null/empty for root)
|
|
664
|
-
* @param context - Optional context for the parent lookup. When
|
|
665
|
-
* omitted, the parent slug must be unambiguous across contexts.
|
|
666
|
-
* @returns The calculated level (root parent → 1, missing parent → 0)
|
|
667
|
-
*/
|
|
668
|
-
async calculateLevel(parentSlug, context) {
|
|
669
|
-
if (!parentSlug) return 0;
|
|
670
|
-
const parent = await this.resolveBySlug(parentSlug, context);
|
|
671
|
-
if (!parent) return 0;
|
|
672
|
-
return parent.level + 1;
|
|
673
|
-
}
|
|
674
|
-
/**
|
|
675
|
-
* Update levels for all descendants after moving a tag
|
|
676
|
-
*
|
|
677
|
-
* @param tag - The tag that was moved
|
|
678
|
-
*/
|
|
679
|
-
async updateDescendantLevels(tag) {
|
|
680
|
-
if (!tag.id) return;
|
|
681
|
-
const children = await this.list({ where: { parentId: tag.id } });
|
|
682
|
-
for (const child of children) {
|
|
683
|
-
child.level = tag.level + 1;
|
|
684
|
-
await child.save();
|
|
685
|
-
await this.updateDescendantLevels(child);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
/**
|
|
689
|
-
* Find all tags belonging to a specific tenant
|
|
690
|
-
*
|
|
691
|
-
* @param tenantId - The tenant ID to filter by
|
|
692
|
-
* @returns Array of tags for the specified tenant
|
|
693
|
-
*/
|
|
694
|
-
async findByTenant(tenantId) {
|
|
695
|
-
return this.list({ where: { tenantId } });
|
|
696
|
-
}
|
|
697
|
-
/**
|
|
698
|
-
* Find all global (tenant-less) tags.
|
|
699
|
-
*
|
|
700
|
-
* Routes through the shared tenant-global helper so it does not throw under
|
|
701
|
-
* an active tenant context (an explicit `tenant_id IS NULL` filter would be
|
|
702
|
-
* flagged as an isolation violation). (#1600)
|
|
703
|
-
*
|
|
704
|
-
* @returns Array of global tags with null tenantId
|
|
705
|
-
*/
|
|
706
|
-
async findGlobal() {
|
|
707
|
-
return queryGlobal(this);
|
|
708
|
-
}
|
|
709
|
-
/**
|
|
710
|
-
* Find tags for a tenant including global tags.
|
|
711
|
-
*
|
|
712
|
-
* Fails closed if an active tenant context requests a different tenant's
|
|
713
|
-
* rows; the admin/system path keeps the cross-tenant capability. (#1600)
|
|
714
|
-
*
|
|
715
|
-
* @param tenantId - The tenant ID to filter by
|
|
716
|
-
* @returns Array of tags for the tenant plus all global tags
|
|
717
|
-
*/
|
|
718
|
-
async findWithGlobals(tenantId) {
|
|
719
|
-
return queryWithGlobals(this, tenantId, "Tag.findWithGlobals");
|
|
720
|
-
}
|
|
721
|
-
};
|
|
722
|
-
//#endregion
|
|
723
|
-
//#region ../assets/dist/index.js
|
|
724
|
-
var __defProp$9 = Object.defineProperty;
|
|
725
|
-
var __exportAll = (all, no_symbols) => {
|
|
726
|
-
let target = {};
|
|
727
|
-
for (var name in all) __defProp$9(target, name, {
|
|
728
|
-
get: all[name],
|
|
729
|
-
enumerable: true
|
|
730
|
-
});
|
|
731
|
-
if (!no_symbols) __defProp$9(target, Symbol.toStringTag, { value: "Module" });
|
|
732
|
-
return target;
|
|
733
|
-
};
|
|
734
|
-
ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-assets","packageVersion":"0.57.9","objects":{"@happyvertical/smrt-assets:AssetAssociation":{"name":"assetassociation","className":"AssetAssociation","qualifiedName":"@happyvertical/smrt-assets:AssetAssociation","collection":"assetassociations","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/asset-association.ts","packageName":"@happyvertical/smrt-assets","fields":{"metaType":{"type":"text","required":true,"_meta":{"required":true}},"metaId":{"type":"text","required":true,"_meta":{"required":true}},"role":{"type":"text","required":true,"_meta":{"required":true}},"sortOrder":{"type":"integer","required":false,"default":0},"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"assetId":{"type":"foreignKey","required":true,"related":"Asset","description":"The file attached to the related record.","_meta":{"description":"The file attached to the related record.","required":true}}},"methods":{"hydrate":{"name":"hydrate","async":true,"parameters":[],"returnType":"Promise<T | null>","isStatic":false,"isPublic":true}},"decoratorConfig":{"conflictColumns":["asset_id","meta_type","meta_id","role"],"api":{"include":["list","get","create","delete"]},"mcp":{"include":["list","get","create"]},"cli":{"skipApiCheck":true},"tenantScoped":{"mode":"optional"}},"extends":"SmrtPolymorphicAssociation","exportName":"AssetAssociation","collectionExportName":"AssetAssociationCollection","validationRules":[{"field":"metaType","rule":"required","fieldType":"text"},{"field":"metaId","rule":"required","fieldType":"text"},{"field":"role","rule":"required","fieldType":"text"},{"field":"assetId","rule":"required","fieldType":"foreignKey"}],"schema":{"tableName":"asset_associations","ddl":"CREATE TABLE IF NOT EXISTS \\"asset_associations\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"meta_type\\" TEXT NOT NULL,\\n \\"meta_id\\" TEXT NOT NULL,\\n \\"role\\" TEXT NOT NULL,\\n \\"sort_order\\" INTEGER DEFAULT 0,\\n \\"tenant_id\\" UUID,\\n \\"asset_id\\" UUID NOT NULL\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"meta_type":{"type":"TEXT","notNull":true,"unique":false},"meta_id":{"type":"TEXT","notNull":true,"unique":false},"role":{"type":"TEXT","notNull":true,"unique":false},"sort_order":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"asset_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"assets","column":"id","onDelete":"CASCADE","onUpdate":"CASCADE"}}},"indexes":[{"name":"asset_associations_asset_id_meta_type_idx","columns":["asset_id","meta_type","meta_id","role"],"unique":true},{"name":"asset_associations_slug_context_idx","columns":["slug","context"]},{"name":"asset_associations_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"asset_associations_meta_type_meta_id_idx","columns":["meta_type","meta_id"]}],"version":"faa13cea"},"importPath":"@happyvertical/smrt-assets"},"@happyvertical/smrt-assets:AssetAssociationCollection":{"name":"assetassociationcollection","className":"AssetAssociationCollection","qualifiedName":"@happyvertical/smrt-assets:AssetAssociationCollection","collection":"assetassociations","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/asset-associations.ts","packageName":"@happyvertical/smrt-assets","fields":{},"methods":{"byRight":{"name":"byRight","async":true,"parameters":[{"name":"rightId","type":"string","optional":false},{"name":"opts","type":"JunctionFilterOptions","optional":true}],"returnType":"Promise<TItem[]>","isStatic":false,"isPublic":true},"byLeft":{"name":"byLeft","async":true,"parameters":[{"name":"metaType","type":"string","optional":false},{"name":"metaId","type":"string","optional":false},{"name":"opts","type":"JunctionFilterOptions","optional":true}],"returnType":"Promise<AssetAssociation[]>","isStatic":false,"isPublic":true},"attach":{"name":"attach","async":true,"parameters":[{"name":"metaType","type":"string","optional":false},{"name":"metaId","type":"string","optional":false},{"name":"assetId","type":"string","optional":false},{"name":"opts","type":"JunctionAttachOptions","optional":true}],"returnType":"Promise<AssetAssociation>","isStatic":false,"isPublic":true},"detach":{"name":"detach","async":true,"parameters":[{"name":"metaType","type":"string","optional":false},{"name":"metaId","type":"string","optional":false},{"name":"assetId","type":"string","optional":false},{"name":"opts","type":"JunctionFilterOptions","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"setLinks":{"name":"setLinks","async":true,"parameters":[{"name":"metaType","type":"string","optional":false},{"name":"metaId","type":"string","optional":false},{"name":"assetIds","type":"string[]","optional":false},{"name":"opts","type":"JunctionAttachOptions","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":{"include":["list","get","create","delete"]},"mcp":{"include":["list","get","create"]}},"extends":"SmrtJunctionBase","extendsTypeArg":"AssetAssociation","exportName":"AssetAssociationCollection","collectionExportName":"AssetAssociationCollectionCollection","schema":{"tableName":"asset_associations","ddl":"CREATE TABLE IF NOT EXISTS \\"asset_associations\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"meta_type\\" TEXT NOT NULL,\\n \\"meta_id\\" TEXT NOT NULL,\\n \\"role\\" TEXT NOT NULL,\\n \\"sort_order\\" INTEGER DEFAULT 0,\\n \\"tenant_id\\" UUID,\\n \\"asset_id\\" UUID NOT NULL\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"meta_type":{"type":"TEXT","notNull":true,"unique":false},"meta_id":{"type":"TEXT","notNull":true,"unique":false},"role":{"type":"TEXT","notNull":true,"unique":false},"sort_order":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"asset_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"assets","column":"id","onDelete":"CASCADE","onUpdate":"CASCADE"}}},"indexes":[{"name":"asset_associations_asset_id_meta_type_idx","columns":["asset_id","meta_type","meta_id","role"],"unique":true},{"name":"asset_associations_slug_context_idx","columns":["slug","context"]},{"name":"asset_associations_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"asset_associations_meta_type_meta_id_idx","columns":["meta_type","meta_id"]}],"version":"faa13cea"},"importPath":"@happyvertical/smrt-assets"},"@happyvertical/smrt-assets:AssetMetafield":{"name":"assetmetafield","className":"AssetMetafield","qualifiedName":"@happyvertical/smrt-assets:AssetMetafield","collection":"assetmetafields","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/asset-metafield.ts","packageName":"@happyvertical/smrt-assets","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"name":{"type":"text","required":false,"description":"The name of an additional asset detail, such as Width or Height.","_meta":{"description":"The name of an additional asset detail, such as Width or Height."}},"validation":{"type":"text","required":false,"description":"Rules that determine which values this asset detail accepts.","_meta":{"description":"Rules that determine which values this asset detail accepts."}}},"methods":{"getValidation":{"name":"getValidation","async":false,"parameters":[],"returnType":"Record<string, unknown>","isStatic":false,"isPublic":true},"setValidation":{"name":"setValidation","async":false,"parameters":[{"name":"rules","type":"Record<string, unknown>","optional":false}],"returnType":"void","isStatic":false,"isPublic":true},"getBySlug":{"name":"getBySlug","async":true,"parameters":[{"name":"_slug","type":"string","optional":false}],"returnType":"Promise<AssetMetafield | null>","isStatic":true,"isPublic":true}},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create"]},"cli":{"skipApiCheck":true}},"extends":"SmrtObject","exportName":"AssetMetafield","collectionExportName":"AssetMetafieldCollection","displayLabelField":"name","schema":{"tableName":"asset_metafields","ddl":"CREATE TABLE IF NOT EXISTS \\"asset_metafields\\" (\\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 \\"name\\" TEXT,\\n \\"validation\\" TEXT\\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"},"name":{"type":"TEXT","notNull":false},"validation":{"type":"TEXT","notNull":false}},"indexes":[{"name":"asset_metafields_slug_context_meta_type_idx","columns":["slug","context","_meta_type"],"unique":true},{"name":"asset_metafields_meta_type_idx","columns":["_meta_type"]},{"name":"asset_metafields_created_at_idx","columns":["created_at"]}],"version":"7393718c"},"importPath":"@happyvertical/smrt-assets"},"@happyvertical/smrt-assets:AssetMetafieldCollection":{"name":"assetmetafieldcollection","className":"AssetMetafieldCollection","qualifiedName":"@happyvertical/smrt-assets:AssetMetafieldCollection","collection":"assetmetafields","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/asset-metafields.ts","packageName":"@happyvertical/smrt-assets","fields":{},"methods":{"getOrCreate":{"name":"getOrCreate","async":true,"parameters":[{"name":"slug","type":"string","optional":false},{"name":"name","type":"string","optional":true},{"name":"validation","type":"string | Record<string, unknown>","optional":true,"unionBranches":[{"type":"string"},{"type":"Record<string, unknown>"}]}],"returnType":"Promise<AssetMetafield>","isStatic":false,"isPublic":true},"initializeCommonMetafields":{"name":"initializeCommonMetafields","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create"]}},"extends":"SmrtCollection","extendsTypeArg":"AssetMetafield","exportName":"AssetMetafieldCollection","collectionExportName":"AssetMetafieldCollectionCollection","schema":{"tableName":"asset_metafields","ddl":"CREATE TABLE IF NOT EXISTS \\"asset_metafields\\" (\\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 \\"name\\" TEXT,\\n \\"validation\\" TEXT\\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"},"name":{"type":"TEXT","notNull":false},"validation":{"type":"TEXT","notNull":false}},"indexes":[{"name":"asset_metafields_slug_context_meta_type_idx","columns":["slug","context","_meta_type"],"unique":true},{"name":"asset_metafields_meta_type_idx","columns":["_meta_type"]},{"name":"asset_metafields_created_at_idx","columns":["created_at"]}],"version":"7393718c"},"importPath":"@happyvertical/smrt-assets"},"@happyvertical/smrt-assets:AssetStatus":{"name":"assetstatus","className":"AssetStatus","qualifiedName":"@happyvertical/smrt-assets:AssetStatus","collection":"assetstatuses","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/asset-status.ts","packageName":"@happyvertical/smrt-assets","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"name":{"type":"text","required":false,"description":"The name of this lifecycle stage, such as Draft or Published.","_meta":{"description":"The name of this lifecycle stage, such as Draft or Published."}},"description":{"type":"text","required":false,"description":"Explain when an asset should use this lifecycle stage.","_meta":{"description":"Explain when an asset should use this lifecycle stage."}}},"methods":{"getBySlug":{"name":"getBySlug","async":true,"parameters":[{"name":"_slug","type":"string","optional":false}],"returnType":"Promise<AssetStatus | null>","isStatic":true,"isPublic":true}},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create"]},"cli":{"skipApiCheck":true}},"extends":"SmrtObject","exportName":"AssetStatus","collectionExportName":"AssetStatusCollection","displayLabelField":"name","schema":{"tableName":"asset_statuses","ddl":"CREATE TABLE IF NOT EXISTS \\"asset_statuses\\" (\\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 \\"name\\" TEXT,\\n \\"description\\" TEXT\\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"},"name":{"type":"TEXT","notNull":false},"description":{"type":"TEXT","notNull":false}},"indexes":[{"name":"asset_statuses_slug_context_meta_type_idx","columns":["slug","context","_meta_type"],"unique":true},{"name":"asset_statuses_meta_type_idx","columns":["_meta_type"]},{"name":"asset_statuses_created_at_idx","columns":["created_at"]}],"version":"8251a52f"},"importPath":"@happyvertical/smrt-assets"},"@happyvertical/smrt-assets:AssetStatusCollection":{"name":"assetstatuscollection","className":"AssetStatusCollection","qualifiedName":"@happyvertical/smrt-assets:AssetStatusCollection","collection":"assetstatuses","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/asset-statuses.ts","packageName":"@happyvertical/smrt-assets","fields":{},"methods":{"getOrCreate":{"name":"getOrCreate","async":true,"parameters":[{"name":"slug","type":"string","optional":false},{"name":"name","type":"string","optional":true},{"name":"description","type":"string","optional":true}],"returnType":"Promise<AssetStatus>","isStatic":false,"isPublic":true},"initializeCommonStatuses":{"name":"initializeCommonStatuses","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create"]}},"extends":"SmrtCollection","extendsTypeArg":"AssetStatus","exportName":"AssetStatusCollection","collectionExportName":"AssetStatusCollectionCollection","schema":{"tableName":"asset_statuses","ddl":"CREATE TABLE IF NOT EXISTS \\"asset_statuses\\" (\\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 \\"name\\" TEXT,\\n \\"description\\" TEXT\\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"},"name":{"type":"TEXT","notNull":false},"description":{"type":"TEXT","notNull":false}},"indexes":[{"name":"asset_statuses_slug_context_meta_type_idx","columns":["slug","context","_meta_type"],"unique":true},{"name":"asset_statuses_meta_type_idx","columns":["_meta_type"]},{"name":"asset_statuses_created_at_idx","columns":["created_at"]}],"version":"8251a52f"},"importPath":"@happyvertical/smrt-assets"},"@happyvertical/smrt-assets:AssetTag":{"name":"assettag","className":"AssetTag","qualifiedName":"@happyvertical/smrt-assets:AssetTag","collection":"assettags","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/asset-tag.ts","packageName":"@happyvertical/smrt-assets","fields":{"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"assetId":{"type":"foreignKey","required":true,"related":"Asset","_meta":{"required":true,"onDelete":"CASCADE"}},"tagId":{"type":"crossPackageRef","required":true,"related":"@happyvertical/smrt-tags:Tag","_meta":{"onDelete":"CASCADE"}}},"methods":{},"decoratorConfig":{"tableName":"asset_tags","conflictColumns":["asset_id","tag_id"],"api":false,"mcp":false,"cli":false,"tenantScoped":{"mode":"optional"}},"extends":"SmrtObject","exportName":"AssetTag","collectionExportName":"AssetTagCollection","validationRules":[{"field":"assetId","rule":"required","fieldType":"foreignKey"},{"field":"tagId","rule":"required","fieldType":"crossPackageRef"}],"schema":{"tableName":"asset_tags","ddl":"CREATE TABLE IF NOT EXISTS \\"asset_tags\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"asset_id\\" UUID NOT NULL,\\n \\"tag_id\\" UUID NOT NULL\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"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,"unique":false},"asset_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"assets","column":"id","onDelete":"CASCADE","onUpdate":"CASCADE"}},"tag_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":true,"unique":false}},"indexes":[{"name":"asset_tags_asset_id_tag_id_idx","columns":["asset_id","tag_id"],"unique":true},{"name":"asset_tags_slug_context_idx","columns":["slug","context"]},{"name":"asset_tags_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"asset_tags_tag_id_idx","columns":["tag_id"]}],"version":"e60d24f5"},"importPath":"@happyvertical/smrt-assets"},"@happyvertical/smrt-assets:AssetTagCollection":{"name":"assettagcollection","className":"AssetTagCollection","qualifiedName":"@happyvertical/smrt-assets:AssetTagCollection","collection":"assettags","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/asset-tags.ts","packageName":"@happyvertical/smrt-assets","fields":{},"methods":{"byRight":{"name":"byRight","async":true,"parameters":[{"name":"rightId","type":"string","optional":false},{"name":"opts","type":"JunctionFilterOptions","optional":true}],"returnType":"Promise<TItem[]>","isStatic":false,"isPublic":true},"byLeft":{"name":"byLeft","async":true,"parameters":[{"name":"leftId","type":"string","optional":false},{"name":"opts","type":"JunctionFilterOptions","optional":true}],"returnType":"Promise<TItem[]>","isStatic":false,"isPublic":true},"attach":{"name":"attach","async":true,"parameters":[{"name":"leftId","type":"string","optional":false},{"name":"rightId","type":"string","optional":false},{"name":"opts","type":"JunctionAttachOptions","optional":true}],"returnType":"Promise<TItem>","isStatic":false,"isPublic":true},"detach":{"name":"detach","async":true,"parameters":[{"name":"leftId","type":"string","optional":false},{"name":"rightId","type":"string","optional":false},{"name":"opts","type":"JunctionFilterOptions","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"setLinks":{"name":"setLinks","async":true,"parameters":[{"name":"leftId","type":"string","optional":false},{"name":"rightIds","type":"string[]","optional":false},{"name":"opts","type":"JunctionAttachOptions","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"asset_tags","api":false,"mcp":false,"cli":false},"extends":"SmrtJunction","extendsTypeArg":"AssetTag","exportName":"AssetTagCollection","collectionExportName":"AssetTagCollectionCollection","schema":{"tableName":"asset_tags","ddl":"CREATE TABLE IF NOT EXISTS \\"asset_tags\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"asset_id\\" UUID NOT NULL,\\n \\"tag_id\\" UUID NOT NULL\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"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,"unique":false},"asset_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"assets","column":"id","onDelete":"CASCADE","onUpdate":"CASCADE"}},"tag_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":true,"unique":false}},"indexes":[{"name":"asset_tags_asset_id_tag_id_idx","columns":["asset_id","tag_id"],"unique":true},{"name":"asset_tags_slug_context_idx","columns":["slug","context"]},{"name":"asset_tags_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"asset_tags_tag_id_idx","columns":["tag_id"]}],"version":"e60d24f5"},"importPath":"@happyvertical/smrt-assets"},"@happyvertical/smrt-assets:AssetType":{"name":"assettype","className":"AssetType","qualifiedName":"@happyvertical/smrt-assets:AssetType","collection":"assettypes","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/asset-type.ts","packageName":"@happyvertical/smrt-assets","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"name":{"type":"text","required":false,"description":"The name of this file category, such as Image or Document.","_meta":{"description":"The name of this file category, such as Image or Document."}},"description":{"type":"text","required":false,"description":"Explain which kinds of files belong in this category.","_meta":{"description":"Explain which kinds of files belong in this category."}}},"methods":{"getBySlug":{"name":"getBySlug","async":true,"parameters":[{"name":"_slug","type":"string","optional":false}],"returnType":"Promise<AssetType | null>","isStatic":true,"isPublic":true}},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create"]},"cli":{"skipApiCheck":true}},"extends":"SmrtObject","exportName":"AssetType","collectionExportName":"AssetTypeCollection","displayLabelField":"name","schema":{"tableName":"asset_types","ddl":"CREATE TABLE IF NOT EXISTS \\"asset_types\\" (\\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 \\"name\\" TEXT,\\n \\"description\\" TEXT\\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"},"name":{"type":"TEXT","notNull":false},"description":{"type":"TEXT","notNull":false}},"indexes":[{"name":"asset_types_slug_context_meta_type_idx","columns":["slug","context","_meta_type"],"unique":true},{"name":"asset_types_meta_type_idx","columns":["_meta_type"]},{"name":"asset_types_created_at_idx","columns":["created_at"]}],"version":"a9c93be2"},"importPath":"@happyvertical/smrt-assets"},"@happyvertical/smrt-assets:AssetTypeCollection":{"name":"assettypecollection","className":"AssetTypeCollection","qualifiedName":"@happyvertical/smrt-assets:AssetTypeCollection","collection":"assettypes","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/asset-types.ts","packageName":"@happyvertical/smrt-assets","fields":{},"methods":{"getOrCreate":{"name":"getOrCreate","async":true,"parameters":[{"name":"slug","type":"string","optional":false},{"name":"name","type":"string","optional":true},{"name":"description","type":"string","optional":true}],"returnType":"Promise<AssetType>","isStatic":false,"isPublic":true},"initializeCommonTypes":{"name":"initializeCommonTypes","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create"]}},"extends":"SmrtCollection","extendsTypeArg":"AssetType","exportName":"AssetTypeCollection","collectionExportName":"AssetTypeCollectionCollection","schema":{"tableName":"asset_types","ddl":"CREATE TABLE IF NOT EXISTS \\"asset_types\\" (\\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 \\"name\\" TEXT,\\n \\"description\\" TEXT\\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"},"name":{"type":"TEXT","notNull":false},"description":{"type":"TEXT","notNull":false}},"indexes":[{"name":"asset_types_slug_context_meta_type_idx","columns":["slug","context","_meta_type"],"unique":true},{"name":"asset_types_meta_type_idx","columns":["_meta_type"]},{"name":"asset_types_created_at_idx","columns":["created_at"]}],"version":"a9c93be2"},"importPath":"@happyvertical/smrt-assets"},"@happyvertical/smrt-assets:Asset":{"name":"asset","className":"Asset","qualifiedName":"@happyvertical/smrt-assets:Asset","collection":"assets","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/asset.ts","packageName":"@happyvertical/smrt-assets","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"accessMode":{"type":"text","required":false,"default":"public","description":"Whether this record is public to ordinary asset APIs or private.","_meta":{"description":"Whether this record is public to ordinary asset APIs or private."},"enum":["public","private"]},"name":{"type":"text","required":false,"description":"A recognizable name for this file or media item.","_meta":{"description":"A recognizable name for this file or media item."}},"sourceUri":{"type":"text","required":false,"description":"Where the original file is stored or can be retrieved.","_meta":{"description":"Where the original file is stored or can be retrieved."}},"mimeType":{"type":"text","required":false,"description":"The file format, such as image/jpeg or application/pdf.","_meta":{"description":"The file format, such as image/jpeg or application/pdf."}},"description":{"type":"text","required":false,"description":"Explain what the file contains and when it should be used.","_meta":{"description":"Explain what the file contains and when it should be used."}},"metadata":{"type":"text","required":false,"description":"Additional details recorded while processing this file.","_meta":{"description":"Additional details recorded while processing this file."}},"version":{"type":"integer","required":true,"default":1,"description":"The revision number of this file in its version history.","_meta":{"description":"The revision number of this file in its version history."}},"primaryVersionId":{"type":"foreignKey","required":false,"related":"Asset","description":"The first version of this file, linking its revision history.","_meta":{"description":"The first version of this file, linking its revision history."}},"typeSlug":{"type":"text","required":false,"description":"The category of asset, such as an image, video, or document.","_meta":{"description":"The category of asset, such as an image, video, or document."}},"statusSlug":{"type":"text","required":false,"description":"The stage of this asset, such as draft, published, or archived.","_meta":{"description":"The stage of this asset, such as draft, published, or archived."}},"ownerProfileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","description":"The person or organization responsible for this asset.","_meta":{"description":"The person or organization responsible for this asset."}},"sourceAssetId":{"type":"foreignKey","required":false,"related":"Asset","description":"The original asset used to produce this file or variation.","_meta":{"description":"The original asset used to produce this file or variation."}},"folderId":{"type":"foreignKey","required":false,"related":"Folder","description":"The folder that organizes this file in the asset library.","_meta":{"description":"The folder that organizes this file in the asset library."}},"sourceType":{"type":"text","required":false,"description":"The service or source from which this file was obtained.","_meta":{"description":"The service or source from which this file was obtained."}},"externalId":{"type":"text","required":false,"description":"The reference used to identify this file at its original source.","_meta":{"description":"The reference used to identify this file at its original source."}},"externalRefs":{"type":"text","required":false,"description":"References that connect this file to copies held by other services.","_meta":{"description":"References that connect this file to copies held by other services."}},"createdAt":{"type":"text","required":false},"updatedAt":{"type":"text","required":false}},"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}},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create","update"]},"cli":{"skipApiCheck":true},"tenantScoped":{"mode":"optional"},"conflictColumns":["tenant_id","slug","context","_meta_type"]},"extends":"SmrtObject","exportName":"Asset","collectionExportName":"AssetCollection","displayLabelField":"name","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 \\"access_mode\\" TEXT DEFAULT 'public',\\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);","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},"access_mode":{"type":"TEXT","notNull":false,"default":"public"},"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,"foreignKey":{"table":"folders","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"source_type":{"type":"TEXT","notNull":false},"external_id":{"type":"TEXT","notNull":false},"external_refs":{"type":"TEXT","notNull":false}},"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":"0e75029e"},"importPath":"@happyvertical/smrt-assets"},"@happyvertical/smrt-assets:AssetCollection":{"name":"assetcollection","className":"AssetCollection","qualifiedName":"@happyvertical/smrt-assets:AssetCollection","collection":"assets","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/assets.ts","packageName":"@happyvertical/smrt-assets","fields":{},"methods":{"findByTenant":{"name":"findByTenant","async":true,"parameters":[{"name":"tenantId","type":"string","optional":false}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"findGlobal":{"name":"findGlobal","async":true,"parameters":[],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"findWithGlobals":{"name":"findWithGlobals","async":true,"parameters":[{"name":"tenantId","type":"string","optional":false}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"addTag":{"name":"addTag","async":true,"parameters":[{"name":"assetId","type":"string","optional":false},{"name":"tag","type":"string","optional":false},{"name":"options","type":"AssetTagInput","optional":true}],"returnType":"Promise<Tag>","isStatic":false,"isPublic":true},"removeTag":{"name":"removeTag","async":true,"parameters":[{"name":"assetId","type":"string","optional":false},{"name":"tag","type":"string","optional":false},{"name":"options","type":"Pick<AssetTagInput, 'context'>","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"setTags":{"name":"setTags","async":true,"parameters":[{"name":"assetId","type":"string","optional":false},{"name":"tags","type":"string[]","optional":false},{"name":"options","type":"Pick<AssetTagInput, 'context'>","optional":true}],"returnType":"Promise<Tag[]>","isStatic":false,"isPublic":true},"getTagsForAssets":{"name":"getTagsForAssets","async":true,"parameters":[{"name":"assetIds","type":"string[]","optional":false}],"returnType":"Promise<Map<string, Tag[]>>","isStatic":false,"isPublic":true},"getByTag":{"name":"getByTag","async":true,"parameters":[{"name":"tag","type":"string","optional":false},{"name":"options","type":"Pick<AssetTagInput, 'context'>","optional":true}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"getByType":{"name":"getByType","async":true,"parameters":[{"name":"typeSlug","type":"string","optional":false}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"getByStatus":{"name":"getByStatus","async":true,"parameters":[{"name":"statusSlug","type":"string","optional":false}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"getByOwner":{"name":"getByOwner","async":true,"parameters":[{"name":"ownerProfileId","type":"string","optional":false}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"createNewVersion":{"name":"createNewVersion","async":true,"parameters":[{"name":"primaryVersionId","type":"string","optional":false},{"name":"newSourceUri","type":"string","optional":false},{"name":"updates","type":"Partial<Asset>","optional":true}],"returnType":"Promise<Asset>","isStatic":false,"isPublic":true},"getLatestVersion":{"name":"getLatestVersion","async":true,"parameters":[{"name":"primaryVersionId","type":"string","optional":false}],"returnType":"Promise<Asset | null>","isStatic":false,"isPublic":true},"listVersions":{"name":"listVersions","async":true,"parameters":[{"name":"primaryVersionId","type":"string","optional":false}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"getDerivatives":{"name":"getDerivatives","async":true,"parameters":[{"name":"sourceAssetId","type":"string","optional":false}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"getByMimeType":{"name":"getByMimeType","async":true,"parameters":[{"name":"mimePattern","type":"string","optional":false}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"rollbackToVersion":{"name":"rollbackToVersion","async":true,"parameters":[{"name":"primaryVersionId","type":"string","optional":false},{"name":"targetVersion","type":"number","optional":false}],"returnType":"Promise<Asset>","isStatic":false,"isPublic":true},"getByFolder":{"name":"getByFolder","async":true,"parameters":[{"name":"folderId","type":"string","optional":false}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create","update"]}},"extends":"SmrtCollection","extendsTypeArg":"Asset","exportName":"AssetCollection","collectionExportName":"AssetCollectionCollection","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 \\"access_mode\\" TEXT DEFAULT 'public',\\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);","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},"access_mode":{"type":"TEXT","notNull":false,"default":"public"},"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,"foreignKey":{"table":"folders","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"source_type":{"type":"TEXT","notNull":false},"external_id":{"type":"TEXT","notNull":false},"external_refs":{"type":"TEXT","notNull":false}},"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":"0e75029e"},"importPath":"@happyvertical/smrt-assets"},"@happyvertical/smrt-assets:Folder":{"name":"folder","className":"Folder","qualifiedName":"@happyvertical/smrt-assets:Folder","collection":"folders","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/folder.ts","packageName":"@happyvertical/smrt-assets","fields":{"parentId":{"type":"foreignKey","required":false,"related":"Folder","_meta":{"nullable":true}},"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"name":{"type":"text","required":false,"description":"A recognizable name for this group of files.","_meta":{"description":"A recognizable name for this group of files."}},"description":{"type":"text","required":false,"description":"Explain the purpose of this folder and which files belong here.","_meta":{"description":"Explain the purpose of this folder and which files belong here."}},"ownerProfileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","description":"The person or organization responsible for this folder.","_meta":{"description":"The person or organization responsible for this folder."}},"createdAt":{"type":"text","required":false},"updatedAt":{"type":"text","required":false}},"methods":{"getParent":{"name":"getParent","async":true,"parameters":[],"returnType":"Promise<this | null>","isStatic":false,"isPublic":true},"getChildren":{"name":"getChildren","async":true,"parameters":[],"returnType":"Promise<this[]>","isStatic":false,"isPublic":true},"getAncestors":{"name":"getAncestors","async":true,"parameters":[],"returnType":"Promise<this[]>","isStatic":false,"isPublic":true},"getDescendants":{"name":"getDescendants","async":true,"parameters":[],"returnType":"Promise<this[]>","isStatic":false,"isPublic":true},"getHierarchy":{"name":"getHierarchy","async":true,"parameters":[],"returnType":"Promise<HierarchyView<this>>","isStatic":false,"isPublic":true},"moveTo":{"name":"moveTo","async":true,"parameters":[{"name":"newParent","type":"this | string | null","optional":false,"unionBranches":[{"type":"this"},{"type":"string"},{"type":"null"}]}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"getBySlug":{"name":"getBySlug","async":true,"parameters":[{"name":"_slug","type":"string","optional":false}],"returnType":"Promise<Folder | null>","isStatic":true,"isPublic":true}},"decoratorConfig":{"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create","update"]},"cli":{"skipApiCheck":true},"tenantScoped":{"mode":"optional"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtHierarchical","exportName":"Folder","collectionExportName":"FolderCollection","displayLabelField":"name","schema":{"tableName":"folders","ddl":"CREATE TABLE IF NOT EXISTS \\"folders\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"parent_id\\" UUID,\\n \\"tenant_id\\" UUID,\\n \\"name\\" TEXT,\\n \\"description\\" TEXT,\\n \\"owner_profile_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"parent_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"folders","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"name":{"type":"TEXT","notNull":false,"unique":false},"description":{"type":"TEXT","notNull":false,"unique":false},"owner_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false}},"indexes":[{"name":"folders_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true,"nullsNotDistinct":true},{"name":"folders_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"folders_parent_id_idx","columns":["parent_id"]},{"name":"folders_owner_profile_id_idx","columns":["owner_profile_id"]}],"version":"1d0b1fcb"},"importPath":"@happyvertical/smrt-assets"},"@happyvertical/smrt-assets:FolderCollection":{"name":"foldercollection","className":"FolderCollection","qualifiedName":"@happyvertical/smrt-assets:FolderCollection","collection":"folders","filePath":"/home/runner/work/smrt/smrt/packages/assets/src/folders.ts","packageName":"@happyvertical/smrt-assets","fields":{},"methods":{"getTree":{"name":"getTree","async":true,"parameters":[{"name":"rootId","type":"string","optional":true}],"returnType":"Promise<Folder[]>","isStatic":false,"isPublic":true},"getPath":{"name":"getPath","async":true,"parameters":[{"name":"folderId","type":"string","optional":false}],"returnType":"Promise<Folder[]>","isStatic":false,"isPublic":true},"getContents":{"name":"getContents","async":true,"parameters":[{"name":"folderId","type":"string","optional":false},{"name":"assetCollection","type":"AssetCollection","optional":false}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"moveAsset":{"name":"moveAsset","async":true,"parameters":[{"name":"asset","type":"Asset","optional":false},{"name":"folderId","type":"string | null","optional":false,"unionBranches":[{"type":"string"},{"type":"null"}]}],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create","update"]}},"extends":"SmrtCollection","extendsTypeArg":"Folder","exportName":"FolderCollection","collectionExportName":"FolderCollectionCollection","schema":{"tableName":"folders","ddl":"CREATE TABLE IF NOT EXISTS \\"folders\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"parent_id\\" UUID,\\n \\"tenant_id\\" UUID,\\n \\"name\\" TEXT,\\n \\"description\\" TEXT,\\n \\"owner_profile_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"parent_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"folders","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"name":{"type":"TEXT","notNull":false,"unique":false},"description":{"type":"TEXT","notNull":false,"unique":false},"owner_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false}},"indexes":[{"name":"folders_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true,"nullsNotDistinct":true},{"name":"folders_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"folders_parent_id_idx","columns":["parent_id"]},{"name":"folders_owner_profile_id_idx","columns":["owner_profile_id"]}],"version":"1d0b1fcb"},"importPath":"@happyvertical/smrt-assets"}},"moduleType":"smrt","recipes":[{"id":"assets.attachments","className":"AssetAttachmentsRecipe","label":"Attachments","summary":"Attach authorized files to records and retain their history.","synonyms":["file attachments","record files","supporting documents"],"models":["@happyvertical/smrt-assets:Asset","@happyvertical/smrt-assets:AssetAssociation"],"nav":[{"label":"Attachments","model":"@happyvertical/smrt-assets:Asset","icon":"fileText","description":"Supporting files connected to the record you are viewing.","key":"attachments","noun":"attachment"}],"requires":["assets.library"],"group":{"id":"assets","label":"Files and media","summary":"Organize files and media, then attach them to the records that need them."},"section":{"id":"assets","label":"Assets","icon":"folder","description":"Files, media and attachments for your work."},"options":{"@happyvertical/smrt-assets:Asset":{"fields":{"name":{"label":"File name","order":1},"description":{"label":"Description","order":2},"mimeType":{"label":"File type","order":3}}},"@happyvertical/smrt-assets:AssetAssociation":{"fields":{"assetId":{"label":"Attachment","order":1},"metaType":{"help":"The kind of record this file is connected to, such as an article or event."},"metaId":{"help":"The specific record that this file is connected to."},"role":{"label":"Role","order":2,"help":"How this file is used by the related record, such as a cover image or attachment."},"sortOrder":{"label":"Display order","order":3,"help":"The position of this attachment among files with the same role; lower numbers appear first."}}}},"help":{"markdown":"## Overview\\n\\nAttachments keep authorized supporting files connected to a record without making a public storage link. The application supplies the authorization and upload endpoint; this recipe records the asset and its relationship.\\n\\n## Tasks\\n\\n### Describe an attachment\\n\\n1. Use a clear {field:Asset.name} so people can identify the file.\\n2. Add a {field:Asset.description} when the attachment needs context.\\n3. Check the {field:Asset.mimeType} before offering the file to a viewer.\\n\\n### Link an attachment to a record\\n\\n1. Select the {field:AssetAssociation.assetId} to link.\\n2. Set a {field:AssetAssociation.role} when the record uses more than one file.\\n3. Adjust {field:AssetAssociation.sortOrder} to control display order.\\n","fieldRefs":["Asset.description","Asset.mimeType","Asset.name","AssetAssociation.assetId","AssetAssociation.role","AssetAssociation.sortOrder"]},"runtime":"both","demoSeed":{"export":"@happyvertical/smrt-assets/playground#assetAttachmentMockAttachments"},"demo":{"mode":"server","reasons":["Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624)."]}},{"id":"assets.library","className":"AssetLibraryRecipe","label":"Asset Library","summary":"Organize files and media with folders, types, and statuses.","synonyms":["media library","file library","digital assets"],"models":["@happyvertical/smrt-assets:Asset","@happyvertical/smrt-assets:Folder","@happyvertical/smrt-assets:AssetType","@happyvertical/smrt-assets:AssetStatus","@happyvertical/smrt-assets:AssetMetafield"],"nav":[{"label":"Files & media","model":"@happyvertical/smrt-assets:Asset","icon":"archive","description":"Files and media you can organize, reuse and share.","noun":"asset"},{"label":"Folders","model":"@happyvertical/smrt-assets:Folder","icon":"folder","description":"Organize assets into clear, reusable groups.","noun":"folder"}],"requires":[],"group":{"id":"assets","label":"Files and media","summary":"Organize files and media, then attach them to the records that need them."},"section":{"id":"assets","label":"Assets","icon":"folder","description":"Files, media and attachments for your work."},"options":{"@happyvertical/smrt-assets:Asset":{"fields":{"name":{"label":"Name","order":1},"description":{"order":2},"folderId":{"label":"Folder","order":3},"typeSlug":{"label":"Type","order":4},"statusSlug":{"label":"Status","order":5},"mimeType":{"label":"File type","order":6}}},"@happyvertical/smrt-assets:Folder":{"fields":{"parentId":{"help":"The containing folder; leave empty to place this folder at the top level."},"name":{"label":"Name","order":1},"description":{"order":2}}}},"help":{"markdown":"## Overview\\n\\nThe Asset Library keeps files and media in one place. Organize assets into folders, classify them by type and status, and keep a clear description for people who need to find them later.\\n\\n## Tasks\\n\\n### Add an asset\\n\\n1. Give the asset a recognizable {field:Asset.name}.\\n2. Add a {field:Asset.description} that explains how the file can be used.\\n3. Select its {field:Asset.folderId}, {field:Asset.typeSlug}, and {field:Asset.statusSlug}.\\n4. Confirm the {field:Asset.mimeType} matches the file you intend to manage.\\n\\n### Organize folders\\n\\n1. Create a folder with a descriptive {field:Folder.name}.\\n2. Use the {field:Folder.description} to explain the folder's purpose.\\n","fieldRefs":["Asset.description","Asset.folderId","Asset.mimeType","Asset.name","Asset.statusSlug","Asset.typeSlug","Folder.description","Folder.name"]},"runtime":"both","demoSeed":{"export":"@happyvertical/smrt-assets/playground#assetGridMockAssets"},"demo":{"mode":"server","reasons":["Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624)."]}}],"smrtDependencies":["@happyvertical/smrt-core","@happyvertical/smrt-tags","@happyvertical/smrt-tenancy"],"browser":{"status":"server-only","issues":["#3624"],"via":["@happyvertical/smrt-tenancy"]},"stampsConstructors":true}`));
|
|
735
|
-
var __defProp$8 = Object.defineProperty;
|
|
736
|
-
var __getOwnPropDesc$8 = Object.getOwnPropertyDescriptor;
|
|
737
|
-
var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, {
|
|
738
|
-
enumerable: true,
|
|
739
|
-
configurable: true,
|
|
740
|
-
writable: true,
|
|
741
|
-
value
|
|
742
|
-
}) : obj[key] = value;
|
|
743
|
-
var __decorateClass$8 = (decorators, target, key, kind) => {
|
|
744
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$8(target, key) : target;
|
|
745
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
746
|
-
if (kind && result) __defProp$8(target, key, result);
|
|
747
|
-
return result;
|
|
748
|
-
};
|
|
749
|
-
var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
750
|
-
var AssetAssociation = class extends SmrtPolymorphicAssociation {
|
|
751
|
-
tenantId = null;
|
|
752
|
-
assetId = "";
|
|
753
|
-
constructor(options = {}) {
|
|
754
|
-
super(options);
|
|
755
|
-
if (options.assetId) this.assetId = options.assetId;
|
|
756
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
757
|
-
}
|
|
758
|
-
};
|
|
759
|
-
__publicField$8(AssetAssociation, "__smrtPackage__", "@happyvertical/smrt-assets");
|
|
760
|
-
__decorateClass$8([tenantId({ nullable: true })], AssetAssociation.prototype, "tenantId", 2);
|
|
761
|
-
__decorateClass$8([foreignKey("Asset", { required: true }), field({ description: "The file attached to the related record." })], AssetAssociation.prototype, "assetId", 2);
|
|
762
|
-
AssetAssociation = __decorateClass$8([TenantScoped({ mode: "optional" }), smrt({
|
|
763
|
-
conflictColumns: [
|
|
764
|
-
"asset_id",
|
|
765
|
-
"meta_type",
|
|
766
|
-
"meta_id",
|
|
767
|
-
"role"
|
|
768
|
-
],
|
|
769
|
-
api: { include: [
|
|
770
|
-
"list",
|
|
771
|
-
"get",
|
|
772
|
-
"create",
|
|
773
|
-
"delete"
|
|
774
|
-
] },
|
|
775
|
-
mcp: { include: [
|
|
776
|
-
"list",
|
|
777
|
-
"get",
|
|
778
|
-
"create"
|
|
779
|
-
] },
|
|
780
|
-
cli: { skipApiCheck: true }
|
|
781
|
-
})], AssetAssociation);
|
|
782
|
-
var __defProp$7 = Object.defineProperty;
|
|
783
|
-
var __getOwnPropDesc$7 = Object.getOwnPropertyDescriptor;
|
|
784
|
-
var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, {
|
|
785
|
-
enumerable: true,
|
|
786
|
-
configurable: true,
|
|
787
|
-
writable: true,
|
|
788
|
-
value
|
|
789
|
-
}) : obj[key] = value;
|
|
790
|
-
var __decorateClass$7 = (decorators, target, key, kind) => {
|
|
791
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$7(target, key) : target;
|
|
792
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
793
|
-
if (kind && result) __defProp$7(target, key, result);
|
|
794
|
-
return result;
|
|
795
|
-
};
|
|
796
|
-
var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
797
|
-
async function metaTypeFilter(metaType) {
|
|
798
|
-
const names = await ObjectRegistry.getEquivalentQualifiedNamesAsync(metaType, { source: "AssetAssociationCollection" });
|
|
799
|
-
return names.length === 1 ? names[0] : names;
|
|
800
|
-
}
|
|
801
|
-
var AssetAssociationCollection = class extends SmrtJunctionBase {
|
|
802
|
-
rightField = "assetId";
|
|
803
|
-
/**
|
|
804
|
-
* List associations for a polymorphic owner.
|
|
805
|
-
*
|
|
806
|
-
* Composite left key — pass both halves.
|
|
807
|
-
*/
|
|
808
|
-
async byLeft(metaType, metaId, opts = {}) {
|
|
809
|
-
return await this.list({
|
|
810
|
-
where: {
|
|
811
|
-
...opts,
|
|
812
|
-
metaType: await metaTypeFilter(metaType),
|
|
813
|
-
metaId
|
|
814
|
-
},
|
|
815
|
-
orderBy: "sort_order ASC"
|
|
816
|
-
});
|
|
817
|
-
}
|
|
818
|
-
/**
|
|
819
|
-
* Create an association. Composite left (metaType, metaId) precedes right (assetId).
|
|
820
|
-
*/
|
|
821
|
-
async attach(metaType, metaId, assetId, opts = {}) {
|
|
822
|
-
return await this.create({
|
|
823
|
-
...opts,
|
|
824
|
-
assetId,
|
|
825
|
-
metaType,
|
|
826
|
-
metaId
|
|
827
|
-
});
|
|
828
|
-
}
|
|
829
|
-
/**
|
|
830
|
-
* Delete matching associations. Composite left (metaType, metaId) precedes right (assetId).
|
|
831
|
-
*/
|
|
832
|
-
async detach(metaType, metaId, assetId, opts = {}) {
|
|
833
|
-
const links = await this.list({ where: {
|
|
834
|
-
...opts,
|
|
835
|
-
metaType: await metaTypeFilter(metaType),
|
|
836
|
-
metaId,
|
|
837
|
-
assetId
|
|
838
|
-
} });
|
|
839
|
-
for (const link of links) await link.delete();
|
|
840
|
-
}
|
|
841
|
-
/**
|
|
842
|
-
* Replace all associations for a polymorphic owner with the given asset IDs.
|
|
843
|
-
* Not transactional — see `SmrtJunction.setLinks` for caveats.
|
|
844
|
-
*/
|
|
845
|
-
async setLinks(metaType, metaId, assetIds, opts = {}) {
|
|
846
|
-
const snapshotOpts = { ...opts };
|
|
847
|
-
delete snapshotOpts.assetId;
|
|
848
|
-
const existing = await this.list({ where: {
|
|
849
|
-
...snapshotOpts,
|
|
850
|
-
metaType: await metaTypeFilter(metaType),
|
|
851
|
-
metaId
|
|
852
|
-
} });
|
|
853
|
-
for (const link of existing) await link.delete();
|
|
854
|
-
const positionKey = this.positionField;
|
|
855
|
-
for (let i = 0; i < assetIds.length; i++) {
|
|
856
|
-
const rowOpts = { ...opts };
|
|
857
|
-
if (positionKey && rowOpts[positionKey] === void 0) rowOpts[positionKey] = i;
|
|
858
|
-
await this.attach(metaType, metaId, assetIds[i], rowOpts);
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
};
|
|
862
|
-
__publicField$7(AssetAssociationCollection, "__smrtPackage__", "@happyvertical/smrt-assets");
|
|
863
|
-
__publicField$7(AssetAssociationCollection, "_itemClass", AssetAssociation);
|
|
864
|
-
AssetAssociationCollection = __decorateClass$7([smrt()], AssetAssociationCollection);
|
|
865
|
-
var __defProp$6 = Object.defineProperty;
|
|
866
|
-
var __getOwnPropDesc$6 = Object.getOwnPropertyDescriptor;
|
|
867
|
-
var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, {
|
|
868
|
-
enumerable: true,
|
|
869
|
-
configurable: true,
|
|
870
|
-
writable: true,
|
|
871
|
-
value
|
|
872
|
-
}) : obj[key] = value;
|
|
873
|
-
var __decorateClass$6 = (decorators, target, key, kind) => {
|
|
874
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$6(target, key) : target;
|
|
875
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
876
|
-
if (kind && result) __defProp$6(target, key, result);
|
|
877
|
-
return result;
|
|
878
|
-
};
|
|
879
|
-
var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
880
|
-
var AssetStatus = class extends SmrtObject {
|
|
881
|
-
name = "";
|
|
882
|
-
description = "";
|
|
883
|
-
constructor(options = {}) {
|
|
884
|
-
super(options);
|
|
885
|
-
if (options.slug) this.slug = options.slug;
|
|
886
|
-
if (options.name) this.name = options.name;
|
|
887
|
-
if (options.description) this.description = options.description;
|
|
888
|
-
}
|
|
889
|
-
/**
|
|
890
|
-
* Get asset status by slug
|
|
891
|
-
*
|
|
892
|
-
* @param slug - The slug to search for
|
|
893
|
-
* @returns AssetStatus instance or null
|
|
894
|
-
*/
|
|
895
|
-
static async getBySlug(_slug) {
|
|
896
|
-
return null;
|
|
897
|
-
}
|
|
898
|
-
};
|
|
899
|
-
__publicField$6(AssetStatus, "__smrtPackage__", "@happyvertical/smrt-assets");
|
|
900
|
-
__decorateClass$6([field({ description: "The name of this lifecycle stage, such as Draft or Published." })], AssetStatus.prototype, "name", 2);
|
|
901
|
-
__decorateClass$6([field({ description: "Explain when an asset should use this lifecycle stage." })], AssetStatus.prototype, "description", 2);
|
|
902
|
-
AssetStatus = __decorateClass$6([smrt({
|
|
903
|
-
tableStrategy: "sti",
|
|
904
|
-
api: { include: [
|
|
905
|
-
"list",
|
|
906
|
-
"get",
|
|
907
|
-
"create",
|
|
908
|
-
"update",
|
|
909
|
-
"delete"
|
|
910
|
-
] },
|
|
911
|
-
mcp: { include: [
|
|
912
|
-
"list",
|
|
913
|
-
"get",
|
|
914
|
-
"create"
|
|
915
|
-
] },
|
|
916
|
-
cli: { skipApiCheck: true }
|
|
917
|
-
})], AssetStatus);
|
|
918
|
-
var __defProp$5 = Object.defineProperty;
|
|
919
|
-
var __getOwnPropDesc$5 = Object.getOwnPropertyDescriptor;
|
|
920
|
-
var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, {
|
|
921
|
-
enumerable: true,
|
|
922
|
-
configurable: true,
|
|
923
|
-
writable: true,
|
|
924
|
-
value
|
|
925
|
-
}) : obj[key] = value;
|
|
926
|
-
var __decorateClass$5 = (decorators, target, key, kind) => {
|
|
927
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$5(target, key) : target;
|
|
928
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
929
|
-
if (kind && result) __defProp$5(target, key, result);
|
|
930
|
-
return result;
|
|
931
|
-
};
|
|
932
|
-
var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
933
|
-
var AssetType = class extends SmrtObject {
|
|
934
|
-
name = "";
|
|
935
|
-
description = "";
|
|
936
|
-
constructor(options = {}) {
|
|
937
|
-
super(options);
|
|
938
|
-
if (options.slug) this.slug = options.slug;
|
|
939
|
-
if (options.name) this.name = options.name;
|
|
940
|
-
if (options.description) this.description = options.description;
|
|
941
|
-
}
|
|
942
|
-
/**
|
|
943
|
-
* Get asset type by slug
|
|
944
|
-
*
|
|
945
|
-
* @param slug - The slug to search for
|
|
946
|
-
* @returns AssetType instance or null
|
|
947
|
-
*/
|
|
948
|
-
static async getBySlug(_slug) {
|
|
949
|
-
return null;
|
|
950
|
-
}
|
|
951
|
-
};
|
|
952
|
-
__publicField$5(AssetType, "__smrtPackage__", "@happyvertical/smrt-assets");
|
|
953
|
-
__decorateClass$5([field({ description: "The name of this file category, such as Image or Document." })], AssetType.prototype, "name", 2);
|
|
954
|
-
__decorateClass$5([field({ description: "Explain which kinds of files belong in this category." })], AssetType.prototype, "description", 2);
|
|
955
|
-
AssetType = __decorateClass$5([smrt({
|
|
956
|
-
tableStrategy: "sti",
|
|
957
|
-
api: { include: [
|
|
958
|
-
"list",
|
|
959
|
-
"get",
|
|
960
|
-
"create",
|
|
961
|
-
"update",
|
|
962
|
-
"delete"
|
|
963
|
-
] },
|
|
964
|
-
mcp: { include: [
|
|
965
|
-
"list",
|
|
966
|
-
"get",
|
|
967
|
-
"create"
|
|
968
|
-
] },
|
|
969
|
-
cli: { skipApiCheck: true }
|
|
970
|
-
})], AssetType);
|
|
971
|
-
var KEY = /* @__PURE__ */ Symbol.for("smrt:private-asset-access");
|
|
972
|
-
var root = globalThis;
|
|
973
|
-
function scopeStorage() {
|
|
974
|
-
if (root[KEY]) return root[KEY];
|
|
975
|
-
if (typeof process === "undefined" || !process.getBuiltinModule) return void 0;
|
|
976
|
-
const { AsyncLocalStorage } = process.getBuiltinModule("node:async_hooks");
|
|
977
|
-
root[KEY] = new AsyncLocalStorage();
|
|
978
|
-
return root[KEY];
|
|
979
|
-
}
|
|
980
|
-
function currentScope() {
|
|
981
|
-
const scope = scopeStorage()?.getStore();
|
|
982
|
-
if (!scope) return void 0;
|
|
983
|
-
const actor = getCurrentTenant();
|
|
984
|
-
if (!scope.active || actor?.tenantId !== scope.tenantId || actor.userId !== scope.actorUserId) throw new Error("Private asset capability is closed or actor identity changed");
|
|
985
|
-
return scope;
|
|
986
|
-
}
|
|
987
|
-
function applies(context) {
|
|
988
|
-
const identity = context.qualifiedClassName ?? context.className;
|
|
989
|
-
return ObjectRegistry.getSTIBase(identity) === "@happyvertical/smrt-assets:Asset";
|
|
990
|
-
}
|
|
991
|
-
function predicate() {
|
|
992
|
-
const scope = currentScope();
|
|
993
|
-
return scope ? {
|
|
994
|
-
accessMode: "private",
|
|
995
|
-
tenantId: scope.tenantId,
|
|
996
|
-
ownerProfileId: scope.ownerProfileId,
|
|
997
|
-
"id in": [...scope.assetIds]
|
|
998
|
-
} : { accessMode: "public" };
|
|
999
|
-
}
|
|
1000
|
-
function assertOwner(record, scope) {
|
|
1001
|
-
if (!scope || record.tenantId !== scope.tenantId || record.ownerProfileId !== scope.ownerProfileId || !scope.assetIds.includes(String(record.id))) throw new Error("Private asset access denied");
|
|
1002
|
-
}
|
|
1003
|
-
async function guardMutation(instance, context) {
|
|
1004
|
-
if (!applies(context)) return;
|
|
1005
|
-
const record = instance;
|
|
1006
|
-
const prior = instance.id ? await instance.db.get(instance.tableName, { id: instance.id }) : null;
|
|
1007
|
-
const scope = currentScope();
|
|
1008
|
-
if (prior?.access_mode === "private") {
|
|
1009
|
-
assertOwner({
|
|
1010
|
-
id: prior.id,
|
|
1011
|
-
tenantId: prior.tenant_id,
|
|
1012
|
-
ownerProfileId: prior.owner_profile_id
|
|
1013
|
-
}, scope);
|
|
1014
|
-
if (record.accessMode !== "private" || record.tenantId !== prior.tenant_id || record.ownerProfileId !== prior.owner_profile_id) throw new Error("Private asset classification and ownership are immutable");
|
|
1015
|
-
}
|
|
1016
|
-
if (record.accessMode !== "public" && record.accessMode !== "private") throw new Error("Invalid asset access mode");
|
|
1017
|
-
if (record.accessMode === "private") {
|
|
1018
|
-
assertOwner(record, scope);
|
|
1019
|
-
if (record.sourceUri && /^https?:$/.test(new URL(String(record.sourceUri)).protocol)) throw new Error("Private assets require non-public storage, not HTTP(S) source locators");
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
GlobalInterceptors.register({
|
|
1023
|
-
name: "asset-private-records",
|
|
1024
|
-
priority: 90,
|
|
1025
|
-
bulkMutation: { compatible(className) {
|
|
1026
|
-
return ObjectRegistry.getSTIBase(className) !== "@happyvertical/smrt-assets:Asset";
|
|
1027
|
-
} },
|
|
1028
|
-
beforeList(_name, options, context) {
|
|
1029
|
-
if (!applies(context)) return;
|
|
1030
|
-
const condition = predicate();
|
|
1031
|
-
return {
|
|
1032
|
-
...options,
|
|
1033
|
-
where: Array.isArray(options.where) ? options.where.map((group) => [condition, ...group]) : {
|
|
1034
|
-
...options.where,
|
|
1035
|
-
...condition
|
|
1036
|
-
}
|
|
1037
|
-
};
|
|
1038
|
-
},
|
|
1039
|
-
beforeGet(_name, filter, context) {
|
|
1040
|
-
if (!applies(context)) return;
|
|
1041
|
-
return {
|
|
1042
|
-
...typeof filter === "string" ? resolveGetStringFilter(filter) : filter,
|
|
1043
|
-
...predicate()
|
|
1044
|
-
};
|
|
1045
|
-
},
|
|
1046
|
-
beforeQuery(_name, _options, context) {
|
|
1047
|
-
if (applies(context)) throw new Error("Raw Asset collection queries cannot enforce private record access; use guarded list/get APIs");
|
|
1048
|
-
},
|
|
1049
|
-
writeGuard(instance, context) {
|
|
1050
|
-
if (!applies(context)) return;
|
|
1051
|
-
const record = instance;
|
|
1052
|
-
const scope = currentScope();
|
|
1053
|
-
if (record.accessMode === "private") {
|
|
1054
|
-
assertOwner(record, scope);
|
|
1055
|
-
return {
|
|
1056
|
-
access_mode: "private",
|
|
1057
|
-
tenant_id: scope.tenantId,
|
|
1058
|
-
owner_profile_id: scope.ownerProfileId,
|
|
1059
|
-
"id in": [...scope.assetIds]
|
|
1060
|
-
};
|
|
1061
|
-
}
|
|
1062
|
-
return { access_mode: "public" };
|
|
1063
|
-
},
|
|
1064
|
-
beforeSave: guardMutation,
|
|
1065
|
-
beforeDelete: guardMutation
|
|
1066
|
-
});
|
|
1067
|
-
var __defProp$4 = Object.defineProperty;
|
|
1068
|
-
var __getOwnPropDesc$4 = Object.getOwnPropertyDescriptor;
|
|
1069
|
-
var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, {
|
|
1070
|
-
enumerable: true,
|
|
1071
|
-
configurable: true,
|
|
1072
|
-
writable: true,
|
|
1073
|
-
value
|
|
1074
|
-
}) : obj[key] = value;
|
|
1075
|
-
var __decorateClass$4 = (decorators, target, key, kind) => {
|
|
1076
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$4(target, key) : target;
|
|
1077
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
1078
|
-
if (kind && result) __defProp$4(target, key, result);
|
|
1079
|
-
return result;
|
|
1080
|
-
};
|
|
1081
|
-
var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1082
|
-
function parseAssetRecord(value) {
|
|
1083
|
-
if (!value) return {};
|
|
1084
|
-
if (typeof value !== "string") return value;
|
|
1085
|
-
if (!value.trim()) return {};
|
|
1086
|
-
try {
|
|
1087
|
-
const parsed = JSON.parse(value);
|
|
1088
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
1089
|
-
} catch {
|
|
1090
|
-
return {};
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
function stringifyAssetRecord(value) {
|
|
1094
|
-
if (!value || Object.keys(value).length === 0) return "";
|
|
1095
|
-
return JSON.stringify(value);
|
|
1096
|
-
}
|
|
1097
|
-
var Asset = class extends SmrtObject {
|
|
1098
|
-
tenantId = null;
|
|
1099
|
-
accessMode = "public";
|
|
1100
|
-
name = "";
|
|
1101
|
-
sourceUri = "";
|
|
1102
|
-
mimeType = "";
|
|
1103
|
-
description = "";
|
|
1104
|
-
metadata = "";
|
|
1105
|
-
version = 1;
|
|
1106
|
-
primaryVersionId = null;
|
|
1107
|
-
typeSlug = "";
|
|
1108
|
-
statusSlug = "";
|
|
1109
|
-
ownerProfileId = null;
|
|
1110
|
-
sourceAssetId = null;
|
|
1111
|
-
folderId = null;
|
|
1112
|
-
sourceType = "";
|
|
1113
|
-
externalId = "";
|
|
1114
|
-
externalRefs = "";
|
|
1115
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
1116
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
1117
|
-
/**
|
|
1118
|
-
* A file's name is not its identity: two pictures named "photo.jpg" are two
|
|
1119
|
-
* assets. Without an explicit slug the default (name-derived) slug would
|
|
1120
|
-
* make the second save adopt the first row through the (tenant, slug,
|
|
1121
|
-
* context) natural key and overwrite it, so an asset's default slug is its
|
|
1122
|
-
* id. An explicit slug is kept.
|
|
1123
|
-
*/
|
|
1124
|
-
async getSlug() {
|
|
1125
|
-
if (!this.slug && this.id) this.slug = String(this.id);
|
|
1126
|
-
return super.getSlug();
|
|
1127
|
-
}
|
|
1128
|
-
constructor(options = {}) {
|
|
1129
|
-
super(options);
|
|
1130
|
-
if (options.accessMode !== void 0) this.accessMode = options.accessMode;
|
|
1131
|
-
if (options.name) this.name = options.name;
|
|
1132
|
-
if (options.slug) this.slug = options.slug;
|
|
1133
|
-
if (options.sourceUri) this.sourceUri = options.sourceUri;
|
|
1134
|
-
if (options.mimeType) this.mimeType = options.mimeType;
|
|
1135
|
-
if (options.description) this.description = options.description;
|
|
1136
|
-
if (options.metadata !== void 0) this.metadata = typeof options.metadata === "string" ? options.metadata : stringifyAssetRecord(options.metadata);
|
|
1137
|
-
if (options.version !== void 0) this.version = options.version;
|
|
1138
|
-
if (options.primaryVersionId !== void 0) this.primaryVersionId = options.primaryVersionId;
|
|
1139
|
-
if (options.typeSlug) this.typeSlug = options.typeSlug;
|
|
1140
|
-
if (options.statusSlug) this.statusSlug = options.statusSlug;
|
|
1141
|
-
if (options.ownerProfileId !== void 0) this.ownerProfileId = options.ownerProfileId;
|
|
1142
|
-
if (options.sourceAssetId !== void 0) this.sourceAssetId = options.sourceAssetId;
|
|
1143
|
-
if (options.folderId !== void 0) this.folderId = options.folderId;
|
|
1144
|
-
if (options.sourceType) this.sourceType = options.sourceType;
|
|
1145
|
-
if (options.externalId) this.externalId = options.externalId;
|
|
1146
|
-
if (options.externalRefs !== void 0) this.externalRefs = typeof options.externalRefs === "string" ? options.externalRefs : stringifyAssetRecord(options.externalRefs);
|
|
1147
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
1148
|
-
if (options.createdAt) this.createdAt = options.createdAt;
|
|
1149
|
-
if (options.updatedAt) this.updatedAt = options.updatedAt;
|
|
1150
|
-
}
|
|
1151
|
-
getMetadata() {
|
|
1152
|
-
return parseAssetRecord(this.metadata);
|
|
1153
|
-
}
|
|
1154
|
-
setMetadata(metadata) {
|
|
1155
|
-
this.metadata = stringifyAssetRecord(metadata);
|
|
1156
|
-
}
|
|
1157
|
-
mergeMetadata(metadata) {
|
|
1158
|
-
this.setMetadata({
|
|
1159
|
-
...this.getMetadata(),
|
|
1160
|
-
...metadata
|
|
1161
|
-
});
|
|
1162
|
-
}
|
|
1163
|
-
getExternalRefs() {
|
|
1164
|
-
const refs = parseAssetRecord(this.externalRefs);
|
|
1165
|
-
const normalized = {};
|
|
1166
|
-
for (const [provider, value] of Object.entries(refs)) if (value && typeof value === "object" && !Array.isArray(value)) normalized[provider] = {
|
|
1167
|
-
...value,
|
|
1168
|
-
provider
|
|
1169
|
-
};
|
|
1170
|
-
return normalized;
|
|
1171
|
-
}
|
|
1172
|
-
getExternalRef(provider) {
|
|
1173
|
-
return this.getExternalRefs()[provider] ?? null;
|
|
1174
|
-
}
|
|
1175
|
-
setExternalRef(provider, reference) {
|
|
1176
|
-
this.externalRefs = stringifyAssetRecord({
|
|
1177
|
-
...this.getExternalRefs(),
|
|
1178
|
-
[provider]: {
|
|
1179
|
-
...this.getExternalRef(provider) ?? {},
|
|
1180
|
-
...reference,
|
|
1181
|
-
provider: reference.provider ?? provider
|
|
1182
|
-
}
|
|
1183
|
-
});
|
|
1184
|
-
}
|
|
1185
|
-
/**
|
|
1186
|
-
* Get all tags for this asset from @happyvertical/smrt-tags, through the
|
|
1187
|
-
* `asset_tags` join (`AssetTag`), sorted by name.
|
|
1188
|
-
*
|
|
1189
|
-
* @returns Array of Tag instances from @happyvertical/smrt-tags package
|
|
1190
|
-
*/
|
|
1191
|
-
async getTags() {
|
|
1192
|
-
if (!this.id) return [];
|
|
1193
|
-
const { AssetTagCollection } = await Promise.resolve().then(() => asset_tags_exports);
|
|
1194
|
-
const rows = await (await AssetTagCollection.create({ db: this.db })).byLeft(this.id);
|
|
1195
|
-
if (rows.length === 0) return [];
|
|
1196
|
-
return (await (await TagCollection.create({ db: this.db })).listByIds([...new Set(rows.map((row) => row.tagId))])).sort((a, b) => a.name.localeCompare(b.name));
|
|
1197
|
-
}
|
|
1198
|
-
/**
|
|
1199
|
-
* Check if this asset has a specific tag
|
|
1200
|
-
*
|
|
1201
|
-
* @param tagSlug - The slug of the tag to check
|
|
1202
|
-
* @param context - Tag context; any context when omitted
|
|
1203
|
-
* @returns True if the asset has this tag
|
|
1204
|
-
*/
|
|
1205
|
-
async hasTag(tagSlug, context) {
|
|
1206
|
-
return (await this.getTags()).some((tag) => tag.slug === tagSlug && (context === void 0 || tag.context === context));
|
|
1207
|
-
}
|
|
1208
|
-
/**
|
|
1209
|
-
* Resolve the AssetCollection lazily. Going through `ObjectRegistry`
|
|
1210
|
-
* mirrors the pattern used by `SmrtHierarchical._hierarchyCollection`
|
|
1211
|
-
* so source/derivative lookups inherit tenant scoping and ORM
|
|
1212
|
-
* hydration without hard-coding an import of `./assets` (which would
|
|
1213
|
-
* create a module-import cycle).
|
|
1214
|
-
*
|
|
1215
|
-
* The return type is `SmrtCollection<Asset>` (the framework base, type-
|
|
1216
|
-
* only import from core) rather than the concrete `AssetCollection` —
|
|
1217
|
-
* importing the concrete class is what would create the cycle, but the
|
|
1218
|
-
* base-class shape gives callers full `.get()` / `.list()` type
|
|
1219
|
-
* safety here.
|
|
1220
|
-
*
|
|
1221
|
-
* R5-canon: hardcode the base Asset's qualified key so a different
|
|
1222
|
-
* package also registering a class called `Asset` can't be picked
|
|
1223
|
-
* by `findClass`'s multi-strategy fallback. Crucially we DON'T
|
|
1224
|
-
* resolve via `this.constructor._smrtQualifiedName` — for an STI
|
|
1225
|
-
* subclass like `Image`, that would yield the Image collection
|
|
1226
|
-
* (which auto-filters `_meta_type = '...:Image'` on `get`/`list`),
|
|
1227
|
-
* and `getSource()` / `getDerivatives()` would miss cross-type
|
|
1228
|
-
* derivation links (Image derived from a plain Asset, etc.).
|
|
1229
|
-
* `sourceAssetId` is a base-table derivation link, so it always
|
|
1230
|
-
* resolves through the base Asset collection.
|
|
1231
|
-
*/
|
|
1232
|
-
async _assetCollection() {
|
|
1233
|
-
return await ObjectRegistry.getCollection("@happyvertical/smrt-assets:Asset", this.options);
|
|
1234
|
-
}
|
|
1235
|
-
/**
|
|
1236
|
-
* Get the source asset this one was derived from, if any.
|
|
1237
|
-
*
|
|
1238
|
-
* Renamed from `getParent` in R3-D. The relationship is "I was produced
|
|
1239
|
-
* from that asset" (e.g. a thumbnail's source is its original image),
|
|
1240
|
-
* not a structural-hierarchy parent.
|
|
1241
|
-
*
|
|
1242
|
-
* Goes through the AssetCollection so tenant interceptors and ORM
|
|
1243
|
-
* hydration apply — important because a tenant-scoped consumer with
|
|
1244
|
-
* cross-tenant derivative chains would otherwise return assets from
|
|
1245
|
-
* tenants the caller cannot see, and a raw `db.get` returns
|
|
1246
|
-
* snake_case rows that leave camelCase props (e.g. `sourceUri`) at
|
|
1247
|
-
* their constructor defaults.
|
|
1248
|
-
*
|
|
1249
|
-
* @returns Source Asset instance, or null if this asset has no source
|
|
1250
|
-
*/
|
|
1251
|
-
async getSource() {
|
|
1252
|
-
if (!this.sourceAssetId) return null;
|
|
1253
|
-
return await (await this._assetCollection()).get({ id: this.sourceAssetId });
|
|
1254
|
-
}
|
|
1255
|
-
/**
|
|
1256
|
-
* Get all assets derived from this one (e.g. thumbnails, variants,
|
|
1257
|
-
* transcodes, AI edits).
|
|
1258
|
-
*
|
|
1259
|
-
* Renamed from `getChildren` in R3-D to match the derivation
|
|
1260
|
-
* semantics. Goes through the AssetCollection so tenant interceptors
|
|
1261
|
-
* and ORM hydration apply (see `getSource` for why this matters —
|
|
1262
|
-
* the pre-R3-D `getChildren` used raw `db.list`, which both bypassed
|
|
1263
|
-
* tenant scoping and dropped camelCase property hydration; that
|
|
1264
|
-
* latent breakage is fixed here).
|
|
1265
|
-
*
|
|
1266
|
-
* @returns Array of derivative Asset instances
|
|
1267
|
-
*/
|
|
1268
|
-
async getDerivatives() {
|
|
1269
|
-
if (!this.id) return [];
|
|
1270
|
-
return await (await this._assetCollection()).list({ where: { sourceAssetId: this.id } });
|
|
1271
|
-
}
|
|
1272
|
-
/**
|
|
1273
|
-
* Get the type of this asset
|
|
1274
|
-
*
|
|
1275
|
-
* @returns AssetType instance or null
|
|
1276
|
-
*/
|
|
1277
|
-
async getType() {
|
|
1278
|
-
if (!this.typeSlug) return null;
|
|
1279
|
-
return await AssetType.getBySlug(this.typeSlug);
|
|
1280
|
-
}
|
|
1281
|
-
/**
|
|
1282
|
-
* Get the status of this asset
|
|
1283
|
-
*
|
|
1284
|
-
* @returns AssetStatus instance or null
|
|
1285
|
-
*/
|
|
1286
|
-
async getStatus() {
|
|
1287
|
-
if (!this.statusSlug) return null;
|
|
1288
|
-
return await AssetStatus.getBySlug(this.statusSlug);
|
|
1289
|
-
}
|
|
1290
|
-
/**
|
|
1291
|
-
* Get all associations for this asset
|
|
1292
|
-
*
|
|
1293
|
-
* @returns Array of AssetAssociation instances
|
|
1294
|
-
*/
|
|
1295
|
-
async getAssociations() {
|
|
1296
|
-
return await (await AssetAssociationCollection.create({ db: this.db })).byRight(this.id);
|
|
1297
|
-
}
|
|
1298
|
-
/**
|
|
1299
|
-
* Associate this asset with a target object
|
|
1300
|
-
*
|
|
1301
|
-
* @param metaType - Target class name or qualified name (e.g., 'Article' or '@pkg:Article')
|
|
1302
|
-
* @param metaId - Target object ID
|
|
1303
|
-
* @param role - Association role (default: 'default')
|
|
1304
|
-
* @returns The created AssetAssociation
|
|
1305
|
-
*/
|
|
1306
|
-
async associateWith(metaType, metaId, role = "default") {
|
|
1307
|
-
return await (await AssetAssociationCollection.create({ db: this.db })).attach(metaType, metaId, this.id, { role });
|
|
1308
|
-
}
|
|
1309
|
-
/**
|
|
1310
|
-
* Get asset by slug
|
|
1311
|
-
*
|
|
1312
|
-
* @param slug - The slug to search for
|
|
1313
|
-
* @returns Asset instance or null
|
|
1314
|
-
*/
|
|
1315
|
-
static async getBySlug(_slug) {
|
|
1316
|
-
return null;
|
|
1317
|
-
}
|
|
1318
|
-
};
|
|
1319
|
-
__publicField$4(Asset, "__smrtPackage__", "@happyvertical/smrt-assets");
|
|
1320
|
-
__decorateClass$4([tenantId({ nullable: true })], Asset.prototype, "tenantId", 2);
|
|
1321
|
-
__decorateClass$4([field({ description: "Whether this record is public to ordinary asset APIs or private." })], Asset.prototype, "accessMode", 2);
|
|
1322
|
-
__decorateClass$4([field({ description: "A recognizable name for this file or media item." })], Asset.prototype, "name", 2);
|
|
1323
|
-
__decorateClass$4([field({ description: "Where the original file is stored or can be retrieved." })], Asset.prototype, "sourceUri", 2);
|
|
1324
|
-
__decorateClass$4([field({ description: "The file format, such as image/jpeg or application/pdf." })], Asset.prototype, "mimeType", 2);
|
|
1325
|
-
__decorateClass$4([field({ description: "Explain what the file contains and when it should be used." })], Asset.prototype, "description", 2);
|
|
1326
|
-
__decorateClass$4([field({ description: "Additional details recorded while processing this file." })], Asset.prototype, "metadata", 2);
|
|
1327
|
-
__decorateClass$4([field({ description: "The revision number of this file in its version history." })], Asset.prototype, "version", 2);
|
|
1328
|
-
__decorateClass$4([foreignKey("Asset"), field({ description: "The first version of this file, linking its revision history." })], Asset.prototype, "primaryVersionId", 2);
|
|
1329
|
-
__decorateClass$4([field({ description: "The category of asset, such as an image, video, or document." })], Asset.prototype, "typeSlug", 2);
|
|
1330
|
-
__decorateClass$4([field({ description: "The stage of this asset, such as draft, published, or archived." })], Asset.prototype, "statusSlug", 2);
|
|
1331
|
-
__decorateClass$4([crossPackageRef("@happyvertical/smrt-profiles:Profile"), field({ description: "The person or organization responsible for this asset." })], Asset.prototype, "ownerProfileId", 2);
|
|
1332
|
-
__decorateClass$4([foreignKey("Asset"), field({ description: "The original asset used to produce this file or variation." })], Asset.prototype, "sourceAssetId", 2);
|
|
1333
|
-
__decorateClass$4([foreignKey("Folder"), field({ description: "The folder that organizes this file in the asset library." })], Asset.prototype, "folderId", 2);
|
|
1334
|
-
__decorateClass$4([field({ description: "The service or source from which this file was obtained." })], Asset.prototype, "sourceType", 2);
|
|
1335
|
-
__decorateClass$4([field({ description: "The reference used to identify this file at its original source." })], Asset.prototype, "externalId", 2);
|
|
1336
|
-
__decorateClass$4([field({ description: "References that connect this file to copies held by other services." })], Asset.prototype, "externalRefs", 2);
|
|
1337
|
-
Asset = __decorateClass$4([TenantScoped({ mode: "optional" }), smrt({
|
|
1338
|
-
tableStrategy: "sti",
|
|
1339
|
-
api: { include: [
|
|
1340
|
-
"list",
|
|
1341
|
-
"get",
|
|
1342
|
-
"create",
|
|
1343
|
-
"update",
|
|
1344
|
-
"delete"
|
|
1345
|
-
] },
|
|
1346
|
-
mcp: { include: [
|
|
1347
|
-
"list",
|
|
1348
|
-
"get",
|
|
1349
|
-
"create",
|
|
1350
|
-
"update"
|
|
1351
|
-
] },
|
|
1352
|
-
cli: { skipApiCheck: true }
|
|
1353
|
-
})], Asset);
|
|
1354
|
-
var __defProp$3 = Object.defineProperty;
|
|
1355
|
-
var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor;
|
|
1356
|
-
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, {
|
|
1357
|
-
enumerable: true,
|
|
1358
|
-
configurable: true,
|
|
1359
|
-
writable: true,
|
|
1360
|
-
value
|
|
1361
|
-
}) : obj[key] = value;
|
|
1362
|
-
var __decorateClass$3 = (decorators, target, key, kind) => {
|
|
1363
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$3(target, key) : target;
|
|
1364
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
1365
|
-
if (kind && result) __defProp$3(target, key, result);
|
|
1366
|
-
return result;
|
|
1367
|
-
};
|
|
1368
|
-
var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1369
|
-
var AssetMetafield = class extends SmrtObject {
|
|
1370
|
-
name = "";
|
|
1371
|
-
validation = "";
|
|
1372
|
-
constructor(options = {}) {
|
|
1373
|
-
super(options);
|
|
1374
|
-
if (options.slug) this.slug = options.slug;
|
|
1375
|
-
if (options.name) this.name = options.name;
|
|
1376
|
-
if (options.validation) this.validation = options.validation;
|
|
1377
|
-
}
|
|
1378
|
-
/**
|
|
1379
|
-
* Get validation rules as parsed object
|
|
1380
|
-
*
|
|
1381
|
-
* @returns Parsed validation object or empty object if no validation
|
|
1382
|
-
*/
|
|
1383
|
-
getValidation() {
|
|
1384
|
-
if (!this.validation) return {};
|
|
1385
|
-
try {
|
|
1386
|
-
return JSON.parse(this.validation);
|
|
1387
|
-
} catch {
|
|
1388
|
-
return {};
|
|
1389
|
-
}
|
|
1390
|
-
}
|
|
1391
|
-
/**
|
|
1392
|
-
* Set validation rules from object
|
|
1393
|
-
*
|
|
1394
|
-
* @param rules - Validation rules object
|
|
1395
|
-
*/
|
|
1396
|
-
setValidation(rules) {
|
|
1397
|
-
this.validation = JSON.stringify(rules);
|
|
1398
|
-
}
|
|
1399
|
-
/**
|
|
1400
|
-
* Get asset metafield by slug
|
|
1401
|
-
*
|
|
1402
|
-
* @param slug - The slug to search for
|
|
1403
|
-
* @returns AssetMetafield instance or null
|
|
1404
|
-
*/
|
|
1405
|
-
static async getBySlug(_slug) {
|
|
1406
|
-
return null;
|
|
1407
|
-
}
|
|
1408
|
-
};
|
|
1409
|
-
__publicField$3(AssetMetafield, "__smrtPackage__", "@happyvertical/smrt-assets");
|
|
1410
|
-
__decorateClass$3([field({ description: "The name of an additional asset detail, such as Width or Height." })], AssetMetafield.prototype, "name", 2);
|
|
1411
|
-
__decorateClass$3([field({ description: "Rules that determine which values this asset detail accepts." })], AssetMetafield.prototype, "validation", 2);
|
|
1412
|
-
AssetMetafield = __decorateClass$3([smrt({
|
|
1413
|
-
tableStrategy: "sti",
|
|
1414
|
-
api: { include: [
|
|
1415
|
-
"list",
|
|
1416
|
-
"get",
|
|
1417
|
-
"create",
|
|
1418
|
-
"update",
|
|
1419
|
-
"delete"
|
|
1420
|
-
] },
|
|
1421
|
-
mcp: { include: [
|
|
1422
|
-
"list",
|
|
1423
|
-
"get",
|
|
1424
|
-
"create"
|
|
1425
|
-
] },
|
|
1426
|
-
cli: { skipApiCheck: true }
|
|
1427
|
-
})], AssetMetafield);
|
|
1428
|
-
function assetTagSlug(label) {
|
|
1429
|
-
return String(label ?? "").normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
1430
|
-
}
|
|
1431
|
-
function titleFromSlug(slug) {
|
|
1432
|
-
const words = slug.replace(/-/g, " ");
|
|
1433
|
-
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
1434
|
-
}
|
|
1435
|
-
var AssetCollection = class extends SmrtCollection {
|
|
1436
|
-
static _itemClass = Asset;
|
|
1437
|
-
/**
|
|
1438
|
-
* Find all assets belonging to a specific tenant
|
|
1439
|
-
*
|
|
1440
|
-
* @param tenantId - The tenant ID to filter by
|
|
1441
|
-
* @returns Array of assets belonging to this tenant
|
|
1442
|
-
*/
|
|
1443
|
-
async findByTenant(tenantId) {
|
|
1444
|
-
return await this.list({ where: { tenantId } });
|
|
1445
|
-
}
|
|
1446
|
-
/**
|
|
1447
|
-
* Find all global assets (assets without a tenant).
|
|
1448
|
-
*
|
|
1449
|
-
* Routes through the shared tenant-global helper so it does not throw under
|
|
1450
|
-
* an active tenant context (an explicit `tenant_id IS NULL` filter would be
|
|
1451
|
-
* flagged as an isolation violation). (#1600)
|
|
1452
|
-
*
|
|
1453
|
-
* @returns Array of global assets
|
|
1454
|
-
*/
|
|
1455
|
-
async findGlobal() {
|
|
1456
|
-
const tenantId = getCurrentTenant()?.tenantId;
|
|
1457
|
-
const read = async () => this.list({ where: { tenantId: null } });
|
|
1458
|
-
return tenantId ? withTenantGlobalRead(tenantId, read) : read();
|
|
1459
|
-
}
|
|
1460
|
-
/**
|
|
1461
|
-
* Find assets belonging to a tenant plus all global assets.
|
|
1462
|
-
*
|
|
1463
|
-
* Fails closed if an active tenant context requests a different tenant's
|
|
1464
|
-
* rows; the admin/system path keeps the cross-tenant capability. (#1600)
|
|
1465
|
-
*
|
|
1466
|
-
* @param tenantId - The tenant ID to include
|
|
1467
|
-
* @returns Array of tenant-specific and global assets
|
|
1468
|
-
*/
|
|
1469
|
-
async findWithGlobals(tenantId) {
|
|
1470
|
-
return withTenantGlobalRead(tenantId, async () => this.list({ where: [[{ tenantId }], [{ tenantId: null }]] }));
|
|
1471
|
-
}
|
|
1472
|
-
async assetTagCollection() {
|
|
1473
|
-
const { AssetTagCollection } = await Promise.resolve().then(() => asset_tags_exports);
|
|
1474
|
-
return AssetTagCollection.create({ db: this.db });
|
|
1475
|
-
}
|
|
1476
|
-
async tagCollection() {
|
|
1477
|
-
return TagCollection.create({ db: this.db });
|
|
1478
|
-
}
|
|
1479
|
-
async requireAsset(assetId) {
|
|
1480
|
-
const asset = await this.get({ id: assetId });
|
|
1481
|
-
if (!asset?.id) throw new Error(`Asset '${assetId}' not found`);
|
|
1482
|
-
return asset;
|
|
1483
|
-
}
|
|
1484
|
-
/**
|
|
1485
|
-
* Find the asset's tag for `tag` (a slug or a label) in the asset's own
|
|
1486
|
-
* tenant, optionally creating it. A tag of another tenant is never used.
|
|
1487
|
-
*/
|
|
1488
|
-
async resolveAssetTag(asset, tag, options) {
|
|
1489
|
-
const slug = assetTagSlug(tag);
|
|
1490
|
-
if (!slug) throw new Error("A tag needs at least one letter or digit");
|
|
1491
|
-
const context = options.context ?? "asset";
|
|
1492
|
-
const tags = await this.tagCollection();
|
|
1493
|
-
const existing = (await tags.list({
|
|
1494
|
-
where: asset.tenantId ? {
|
|
1495
|
-
slug,
|
|
1496
|
-
context,
|
|
1497
|
-
tenantId: asset.tenantId
|
|
1498
|
-
} : {
|
|
1499
|
-
slug,
|
|
1500
|
-
context
|
|
1501
|
-
},
|
|
1502
|
-
limit: 10
|
|
1503
|
-
})).find((candidate) => (candidate.tenantId ?? null) === (asset.tenantId ?? null));
|
|
1504
|
-
if (existing || !options.create) return existing ?? null;
|
|
1505
|
-
const trimmed = tag.trim();
|
|
1506
|
-
return await tags.create({
|
|
1507
|
-
slug,
|
|
1508
|
-
name: options.name?.trim() || (trimmed !== slug ? trimmed : titleFromSlug(slug)),
|
|
1509
|
-
context,
|
|
1510
|
-
level: 0,
|
|
1511
|
-
tenantId: asset.tenantId ?? null
|
|
1512
|
-
});
|
|
1513
|
-
}
|
|
1514
|
-
/**
|
|
1515
|
-
* Add a tag to an asset. `tag` is a slug (`town-hall`) or a label
|
|
1516
|
-
* (`Town hall`); the tag is found or created in the asset's tenant under
|
|
1517
|
-
* `context` (default {@link ASSET_TAG_CONTEXT}). Adding a tag twice is a
|
|
1518
|
-
* no-op. Returns the Tag.
|
|
1519
|
-
*
|
|
1520
|
-
* @throws when the asset does not exist (or is not visible in the active
|
|
1521
|
-
* tenant context)
|
|
1522
|
-
*/
|
|
1523
|
-
async addTag(assetId, tag, options = {}) {
|
|
1524
|
-
const asset = await this.requireAsset(assetId);
|
|
1525
|
-
const resolved = await this.resolveAssetTag(asset, tag, {
|
|
1526
|
-
...options,
|
|
1527
|
-
create: true
|
|
1528
|
-
});
|
|
1529
|
-
const links = await this.assetTagCollection();
|
|
1530
|
-
if ((await links.byLeft(asset.id, { tagId: resolved.id })).length === 0) await links.attach(asset.id, resolved.id, { tenantId: asset.tenantId ?? null });
|
|
1531
|
-
return resolved;
|
|
1532
|
-
}
|
|
1533
|
-
/**
|
|
1534
|
-
* Remove a tag (slug or label) from an asset. Unknown tags are ignored.
|
|
1535
|
-
* The Tag itself is kept; only the link goes.
|
|
1536
|
-
*/
|
|
1537
|
-
async removeTag(assetId, tag, options = {}) {
|
|
1538
|
-
const asset = await this.requireAsset(assetId);
|
|
1539
|
-
const resolved = await this.resolveAssetTag(asset, tag, {
|
|
1540
|
-
...options,
|
|
1541
|
-
create: false
|
|
1542
|
-
});
|
|
1543
|
-
if (!resolved?.id) return;
|
|
1544
|
-
await (await this.assetTagCollection()).detach(asset.id, resolved.id);
|
|
1545
|
-
}
|
|
1546
|
-
/**
|
|
1547
|
-
* Make the asset's tags (in `context`) exactly `tags`: missing ones are
|
|
1548
|
-
* added, others in the same context removed. Returns the resulting Tags.
|
|
1549
|
-
*/
|
|
1550
|
-
async setTags(assetId, tags, options = {}) {
|
|
1551
|
-
const asset = await this.requireAsset(assetId);
|
|
1552
|
-
const context = options.context ?? "asset";
|
|
1553
|
-
const wanted = [];
|
|
1554
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1555
|
-
for (const tag of tags) {
|
|
1556
|
-
const slug = assetTagSlug(tag);
|
|
1557
|
-
if (!slug || seen.has(slug)) continue;
|
|
1558
|
-
seen.add(slug);
|
|
1559
|
-
wanted.push(await this.addTag(asset.id, tag, { context }));
|
|
1560
|
-
}
|
|
1561
|
-
const wantedIds = new Set(wanted.map((tag) => tag.id));
|
|
1562
|
-
const current = await asset.getTags();
|
|
1563
|
-
for (const tag of current) if (tag.context === context && !wantedIds.has(tag.id)) await this.removeTag(asset.id, tag.slug, { context });
|
|
1564
|
-
return wanted;
|
|
1565
|
-
}
|
|
1566
|
-
/**
|
|
1567
|
-
* Tags for many assets in two queries, keyed by asset id (assets without
|
|
1568
|
-
* tags map to an empty list). Useful for list views.
|
|
1569
|
-
*/
|
|
1570
|
-
async getTagsForAssets(assetIds) {
|
|
1571
|
-
const result = /* @__PURE__ */ new Map();
|
|
1572
|
-
const ids = [...new Set(assetIds.filter(Boolean))];
|
|
1573
|
-
for (const id of ids) result.set(id, []);
|
|
1574
|
-
if (ids.length === 0) return result;
|
|
1575
|
-
const rows = await (await this.assetTagCollection()).list({ where: { "assetId in": ids } });
|
|
1576
|
-
if (rows.length === 0) return result;
|
|
1577
|
-
const tags = await this.tagCollection();
|
|
1578
|
-
const tagById = new Map((await tags.listByIds([...new Set(rows.map((row) => row.tagId))])).filter((tag) => tag.id).map((tag) => [tag.id, tag]));
|
|
1579
|
-
for (const row of rows) {
|
|
1580
|
-
const tag = tagById.get(row.tagId);
|
|
1581
|
-
if (tag) result.get(row.assetId)?.push(tag);
|
|
1582
|
-
}
|
|
1583
|
-
for (const list of result.values()) list.sort((a, b) => a.name.localeCompare(b.name));
|
|
1584
|
-
return result;
|
|
1585
|
-
}
|
|
1586
|
-
/**
|
|
1587
|
-
* Get all assets with a specific tag (slug or label), within the active
|
|
1588
|
-
* tenant context.
|
|
1589
|
-
*/
|
|
1590
|
-
async getByTag(tag, options = {}) {
|
|
1591
|
-
const slug = assetTagSlug(tag);
|
|
1592
|
-
if (!slug) return [];
|
|
1593
|
-
const tagIds = (await (await this.tagCollection()).list({ where: {
|
|
1594
|
-
slug,
|
|
1595
|
-
context: options.context ?? "asset"
|
|
1596
|
-
} })).map((match) => match.id).filter(Boolean);
|
|
1597
|
-
if (tagIds.length === 0) return [];
|
|
1598
|
-
const rows = await (await this.assetTagCollection()).list({ where: { "tagId in": tagIds } });
|
|
1599
|
-
const assetIds = [...new Set(rows.map((row) => row.assetId))];
|
|
1600
|
-
if (assetIds.length === 0) return [];
|
|
1601
|
-
return await this.listByIds(assetIds);
|
|
1602
|
-
}
|
|
1603
|
-
/**
|
|
1604
|
-
* Get assets by type
|
|
1605
|
-
*
|
|
1606
|
-
* @param typeSlug - The asset type slug (e.g., 'image', 'video')
|
|
1607
|
-
* @returns Array of assets matching the type
|
|
1608
|
-
*/
|
|
1609
|
-
async getByType(typeSlug) {
|
|
1610
|
-
return await this.list({ where: { typeSlug } });
|
|
1611
|
-
}
|
|
1612
|
-
/**
|
|
1613
|
-
* Get assets by status
|
|
1614
|
-
*
|
|
1615
|
-
* @param statusSlug - The asset status slug (e.g., 'published', 'draft')
|
|
1616
|
-
* @returns Array of assets matching the status
|
|
1617
|
-
*/
|
|
1618
|
-
async getByStatus(statusSlug) {
|
|
1619
|
-
return await this.list({ where: { statusSlug } });
|
|
1620
|
-
}
|
|
1621
|
-
/**
|
|
1622
|
-
* Get assets by owner
|
|
1623
|
-
*
|
|
1624
|
-
* @param ownerProfileId - The profile ID of the owner
|
|
1625
|
-
* @returns Array of assets owned by this profile
|
|
1626
|
-
*/
|
|
1627
|
-
async getByOwner(ownerProfileId) {
|
|
1628
|
-
return await this.list({ where: { ownerProfileId } });
|
|
1629
|
-
}
|
|
1630
|
-
/**
|
|
1631
|
-
* Create a new version of an existing asset
|
|
1632
|
-
*
|
|
1633
|
-
* @param primaryVersionId - The primary version ID (first version's ID)
|
|
1634
|
-
* @param newSourceUri - The new source URI for this version
|
|
1635
|
-
* @param updates - Optional additional updates
|
|
1636
|
-
* @returns The newly created asset version
|
|
1637
|
-
*/
|
|
1638
|
-
async createNewVersion(primaryVersionId, newSourceUri, updates = {}) {
|
|
1639
|
-
const versions = await this.listVersions(primaryVersionId);
|
|
1640
|
-
if (versions.length === 0) throw new Error(`No asset found with primary version ID: ${primaryVersionId}`);
|
|
1641
|
-
versions.sort((a, b) => b.version - a.version);
|
|
1642
|
-
const latestVersion = versions[0];
|
|
1643
|
-
const newVersionNumber = latestVersion.version + 1;
|
|
1644
|
-
const primary = versions.find((v) => v.id === primaryVersionId) ?? versions[versions.length - 1];
|
|
1645
|
-
const baseSlug = String(primary?.slug ?? "") || "asset";
|
|
1646
|
-
const takenInChain = new Set(versions.map((v) => v.slug).filter(Boolean));
|
|
1647
|
-
let candidate = `${baseSlug}-v${newVersionNumber}`;
|
|
1648
|
-
for (let attempt = 1;; attempt += 1) {
|
|
1649
|
-
if (!(takenInChain.has(candidate) || await this.get({ slug: candidate }) !== null)) break;
|
|
1650
|
-
candidate = `${baseSlug}-v${newVersionNumber}-${attempt}`;
|
|
1651
|
-
}
|
|
1652
|
-
return await this.create({
|
|
1653
|
-
...latestVersion,
|
|
1654
|
-
id: void 0,
|
|
1655
|
-
slug: candidate,
|
|
1656
|
-
sourceUri: newSourceUri,
|
|
1657
|
-
version: newVersionNumber,
|
|
1658
|
-
primaryVersionId,
|
|
1659
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
1660
|
-
updatedAt: /* @__PURE__ */ new Date(),
|
|
1661
|
-
...updates
|
|
1662
|
-
});
|
|
1663
|
-
}
|
|
1664
|
-
/**
|
|
1665
|
-
* Get the latest version of an asset
|
|
1666
|
-
*
|
|
1667
|
-
* @param primaryVersionId - The primary version ID
|
|
1668
|
-
* @returns The latest version or null
|
|
1669
|
-
*/
|
|
1670
|
-
async getLatestVersion(primaryVersionId) {
|
|
1671
|
-
const versions = await this.listVersions(primaryVersionId);
|
|
1672
|
-
if (versions.length === 0) return null;
|
|
1673
|
-
versions.sort((a, b) => b.version - a.version);
|
|
1674
|
-
return versions[0];
|
|
1675
|
-
}
|
|
1676
|
-
/**
|
|
1677
|
-
* List all versions of an asset
|
|
1678
|
-
*
|
|
1679
|
-
* @param primaryVersionId - The primary version ID
|
|
1680
|
-
* @returns Array of all asset versions, ordered by version number
|
|
1681
|
-
*/
|
|
1682
|
-
async listVersions(primaryVersionId) {
|
|
1683
|
-
const [chained, primary] = await Promise.all([this.list({ where: { primaryVersionId } }), this.get({ id: primaryVersionId })]);
|
|
1684
|
-
const byId = /* @__PURE__ */ new Map();
|
|
1685
|
-
for (const asset of [...primary ? [primary] : [], ...chained]) if (asset?.id) byId.set(asset.id, asset);
|
|
1686
|
-
const assets = Array.from(byId.values());
|
|
1687
|
-
assets.sort((a, b) => a.version - b.version);
|
|
1688
|
-
return assets;
|
|
1689
|
-
}
|
|
1690
|
-
/**
|
|
1691
|
-
* Get derivative assets of a source asset.
|
|
1692
|
-
*
|
|
1693
|
-
* Renamed from `getChildren(parentId)` in R3-D to match the rename of
|
|
1694
|
-
* the underlying column (`parent_id` → `source_asset_id`) and method
|
|
1695
|
-
* (`Asset.getChildren` → `Asset.getDerivatives`).
|
|
1696
|
-
*
|
|
1697
|
-
* @param sourceAssetId - The source asset ID
|
|
1698
|
-
* @returns Array of derivative assets
|
|
1699
|
-
*/
|
|
1700
|
-
async getDerivatives(sourceAssetId) {
|
|
1701
|
-
return await this.list({ where: { sourceAssetId } });
|
|
1702
|
-
}
|
|
1703
|
-
/**
|
|
1704
|
-
* Get assets by MIME type pattern
|
|
1705
|
-
*
|
|
1706
|
-
* @param mimePattern - MIME type pattern (e.g., 'image/*', 'video/mp4')
|
|
1707
|
-
* @returns Array of matching assets
|
|
1708
|
-
*/
|
|
1709
|
-
async getByMimeType(mimePattern) {
|
|
1710
|
-
const pattern = mimePattern.replace("*", "%");
|
|
1711
|
-
return await this.list({ where: { "mimeType like": pattern } });
|
|
1712
|
-
}
|
|
1713
|
-
/**
|
|
1714
|
-
* Rollback to a previous version by creating a new version with the target's content.
|
|
1715
|
-
* Does NOT delete intermediate versions (safe rollback).
|
|
1716
|
-
*
|
|
1717
|
-
* @param primaryVersionId - The primary version ID of the version chain
|
|
1718
|
-
* @param targetVersion - The version number to rollback to
|
|
1719
|
-
* @returns The newly created asset version with content copied from target
|
|
1720
|
-
*/
|
|
1721
|
-
async rollbackToVersion(primaryVersionId, targetVersion) {
|
|
1722
|
-
const target = (await this.listVersions(primaryVersionId)).find((v) => v.version === targetVersion);
|
|
1723
|
-
if (!target) throw new Error(`Version ${targetVersion} not found for asset ${primaryVersionId}`);
|
|
1724
|
-
return await this.createNewVersion(primaryVersionId, target.sourceUri, { description: `Rollback to version ${targetVersion}` });
|
|
1725
|
-
}
|
|
1726
|
-
/**
|
|
1727
|
-
* Get assets in a specific folder
|
|
1728
|
-
*
|
|
1729
|
-
* @param folderId - The folder ID to list contents for
|
|
1730
|
-
* @returns Array of assets in this folder
|
|
1731
|
-
*/
|
|
1732
|
-
async getByFolder(folderId) {
|
|
1733
|
-
return await this.list({ where: { folderId } });
|
|
1734
|
-
}
|
|
1735
|
-
};
|
|
1736
|
-
var __defProp$2 = Object.defineProperty;
|
|
1737
|
-
var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
|
|
1738
|
-
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, {
|
|
1739
|
-
enumerable: true,
|
|
1740
|
-
configurable: true,
|
|
1741
|
-
writable: true,
|
|
1742
|
-
value
|
|
1743
|
-
}) : obj[key] = value;
|
|
1744
|
-
var __decorateClass$2 = (decorators, target, key, kind) => {
|
|
1745
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
|
|
1746
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
1747
|
-
if (kind && result) __defProp$2(target, key, result);
|
|
1748
|
-
return result;
|
|
1749
|
-
};
|
|
1750
|
-
var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1751
|
-
var AssetTag = class extends SmrtObject {
|
|
1752
|
-
tenantId = null;
|
|
1753
|
-
assetId = "";
|
|
1754
|
-
tagId = "";
|
|
1755
|
-
constructor(options = {}) {
|
|
1756
|
-
super(options);
|
|
1757
|
-
if (options.assetId) this.assetId = options.assetId;
|
|
1758
|
-
if (options.tagId) this.tagId = options.tagId;
|
|
1759
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
1760
|
-
}
|
|
1761
|
-
};
|
|
1762
|
-
__publicField$2(AssetTag, "__smrtPackage__", "@happyvertical/smrt-assets");
|
|
1763
|
-
__decorateClass$2([tenantId({ nullable: true })], AssetTag.prototype, "tenantId", 2);
|
|
1764
|
-
__decorateClass$2([foreignKey("Asset", {
|
|
1765
|
-
required: true,
|
|
1766
|
-
onDelete: "CASCADE"
|
|
1767
|
-
})], AssetTag.prototype, "assetId", 2);
|
|
1768
|
-
__decorateClass$2([crossPackageRef("@happyvertical/smrt-tags:Tag", {
|
|
1769
|
-
required: true,
|
|
1770
|
-
onDelete: "CASCADE"
|
|
1771
|
-
})], AssetTag.prototype, "tagId", 2);
|
|
1772
|
-
AssetTag = __decorateClass$2([TenantScoped({ mode: "optional" }), smrt({
|
|
1773
|
-
tableName: "asset_tags",
|
|
1774
|
-
conflictColumns: ["asset_id", "tag_id"],
|
|
1775
|
-
api: false,
|
|
1776
|
-
mcp: false,
|
|
1777
|
-
cli: false
|
|
1778
|
-
})], AssetTag);
|
|
1779
|
-
var asset_tags_exports = /* @__PURE__ */ __exportAll({ AssetTagCollection: () => AssetTagCollection });
|
|
1780
|
-
var __defProp$1 = Object.defineProperty;
|
|
1781
|
-
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
1782
|
-
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, {
|
|
1783
|
-
enumerable: true,
|
|
1784
|
-
configurable: true,
|
|
1785
|
-
writable: true,
|
|
1786
|
-
value
|
|
1787
|
-
}) : obj[key] = value;
|
|
1788
|
-
var __decorateClass$1 = (decorators, target, key, kind) => {
|
|
1789
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
|
|
1790
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
1791
|
-
if (kind && result) __defProp$1(target, key, result);
|
|
1792
|
-
return result;
|
|
1793
|
-
};
|
|
1794
|
-
var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1795
|
-
var AssetTagCollection = class extends SmrtJunction {
|
|
1796
|
-
leftField = "assetId";
|
|
1797
|
-
rightField = "tagId";
|
|
1798
|
-
sortField = null;
|
|
1799
|
-
positionField = null;
|
|
1800
|
-
};
|
|
1801
|
-
__publicField$1(AssetTagCollection, "__smrtPackage__", "@happyvertical/smrt-assets");
|
|
1802
|
-
__publicField$1(AssetTagCollection, "_itemClass", AssetTag);
|
|
1803
|
-
AssetTagCollection = __decorateClass$1([smrt()], AssetTagCollection);
|
|
1804
|
-
var __defProp = Object.defineProperty;
|
|
1805
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
1806
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {
|
|
1807
|
-
enumerable: true,
|
|
1808
|
-
configurable: true,
|
|
1809
|
-
writable: true,
|
|
1810
|
-
value
|
|
1811
|
-
}) : obj[key] = value;
|
|
1812
|
-
var __decorateClass = (decorators, target, key, kind) => {
|
|
1813
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
1814
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
1815
|
-
if (kind && result) __defProp(target, key, result);
|
|
1816
|
-
return result;
|
|
1817
|
-
};
|
|
1818
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1819
|
-
var Folder = class extends SmrtHierarchical {
|
|
1820
|
-
tenantId = null;
|
|
1821
|
-
name = "";
|
|
1822
|
-
description = "";
|
|
1823
|
-
ownerProfileId = null;
|
|
1824
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
1825
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
1826
|
-
constructor(options = {}) {
|
|
1827
|
-
super(options);
|
|
1828
|
-
if (options.name !== void 0) this.name = options.name;
|
|
1829
|
-
if (options.slug !== void 0) this.slug = options.slug;
|
|
1830
|
-
if (options.description !== void 0) this.description = options.description;
|
|
1831
|
-
if (options.parentId !== void 0) this.parentId = options.parentId ?? null;
|
|
1832
|
-
if (options.ownerProfileId !== void 0) this.ownerProfileId = options.ownerProfileId;
|
|
1833
|
-
if (options.tenantId !== void 0) this.tenantId = options.tenantId;
|
|
1834
|
-
if (options.createdAt) this.createdAt = options.createdAt;
|
|
1835
|
-
if (options.updatedAt) this.updatedAt = options.updatedAt;
|
|
1836
|
-
}
|
|
1837
|
-
/**
|
|
1838
|
-
* Look up a folder by slug.
|
|
1839
|
-
*/
|
|
1840
|
-
static async getBySlug(_slug) {
|
|
1841
|
-
return null;
|
|
1842
|
-
}
|
|
1843
|
-
};
|
|
1844
|
-
__publicField(Folder, "__smrtPackage__", "@happyvertical/smrt-assets");
|
|
1845
|
-
__decorateClass([tenantId({ nullable: true })], Folder.prototype, "tenantId", 2);
|
|
1846
|
-
__decorateClass([field({ description: "A recognizable name for this group of files." })], Folder.prototype, "name", 2);
|
|
1847
|
-
__decorateClass([field({ description: "Explain the purpose of this folder and which files belong here." })], Folder.prototype, "description", 2);
|
|
1848
|
-
__decorateClass([crossPackageRef("@happyvertical/smrt-profiles:Profile"), field({ description: "The person or organization responsible for this folder." })], Folder.prototype, "ownerProfileId", 2);
|
|
1849
|
-
Folder = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
|
|
1850
|
-
api: { include: [
|
|
1851
|
-
"list",
|
|
1852
|
-
"get",
|
|
1853
|
-
"create",
|
|
1854
|
-
"update",
|
|
1855
|
-
"delete"
|
|
1856
|
-
] },
|
|
1857
|
-
mcp: { include: [
|
|
1858
|
-
"list",
|
|
1859
|
-
"get",
|
|
1860
|
-
"create",
|
|
1861
|
-
"update"
|
|
1862
|
-
] },
|
|
1863
|
-
cli: { skipApiCheck: true }
|
|
1864
|
-
})], Folder);
|
|
1865
|
-
var OWNED_ASSET_RELATIONSHIP_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
1866
|
-
function assertValidOwnedAssetRelationship(relationship) {
|
|
1867
|
-
if (!OWNED_ASSET_RELATIONSHIP_PATTERN.test(relationship)) throw new Error(`Invalid relationship type "${relationship}"; must start with a letter or underscore and contain only letters, digits, and underscores`);
|
|
1868
|
-
}
|
|
1869
|
-
function assertValidOwnedAssetSortOrder(sortOrder) {
|
|
1870
|
-
if (!Number.isInteger(sortOrder) || sortOrder < 0 || sortOrder > 2147483647) throw new Error(`Invalid sortOrder "${sortOrder}"; must be a non-negative integer`);
|
|
1871
|
-
}
|
|
1872
|
-
async function assertAssetLinkable(db, assetId, ownerTenantId, ownerLabel) {
|
|
1873
|
-
const assets = await AssetCollection.create({ db });
|
|
1874
|
-
const [stored] = await withSystemContext(async () => assets.listByIds([assetId]));
|
|
1875
|
-
if (!stored) throw new Error(`Cannot associate asset ${assetId}: it does not exist`);
|
|
1876
|
-
const assetTenant = stored.tenantId ? String(stored.tenantId) : null;
|
|
1877
|
-
const ownerTenant = ownerTenantId ? String(ownerTenantId) : null;
|
|
1878
|
-
if (assetTenant === null || assetTenant === ownerTenant) return;
|
|
1879
|
-
throw new Error(ownerTenant === null ? `Cannot associate a tenant's asset with a shared ${ownerLabel}` : `Cannot associate an asset from another tenant with this ${ownerLabel}`);
|
|
1880
|
-
}
|
|
1881
|
-
async function resolveOwnedAssetsById(db, assetIds, tenantId) {
|
|
1882
|
-
if (assetIds.length === 0) return [];
|
|
1883
|
-
const assets = await AssetCollection.create({ db });
|
|
1884
|
-
const resolved = tenantId ? await withSystemContext(async () => assets.listByIds(assetIds)) : await assets.listByIds(assetIds);
|
|
1885
|
-
const visibleAssets = tenantId ? resolved.filter((asset) => asset.tenantId === tenantId || asset.tenantId === null) : resolved;
|
|
1886
|
-
const assetsById = new Map(visibleAssets.filter((asset) => asset.id).map((asset) => [asset.id, asset]));
|
|
1887
|
-
return assetIds.map((assetId) => assetsById.get(assetId)).filter(Boolean);
|
|
1888
|
-
}
|
|
1889
|
-
async function getOwnerRecord(collection, ownerId) {
|
|
1890
|
-
return collection.get({ id: ownerId });
|
|
1891
|
-
}
|
|
1892
|
-
async function getOwnedAssetsFromCollection(collection, ownerId, relationship) {
|
|
1893
|
-
const owner = await getOwnerRecord(collection, ownerId);
|
|
1894
|
-
if (!owner) return [];
|
|
1895
|
-
return owner.getAssets(relationship);
|
|
1896
|
-
}
|
|
1897
|
-
async function addOwnedAssetFromCollection(collection, ownerType, ownerId, asset, relationship = "attachment", sortOrder = 0) {
|
|
1898
|
-
const owner = await getOwnerRecord(collection, ownerId);
|
|
1899
|
-
if (!owner) throw new Error(`${ownerType} '${ownerId}' not found`);
|
|
1900
|
-
await owner.addAsset(asset, relationship, sortOrder);
|
|
1901
|
-
}
|
|
1902
|
-
async function removeOwnedAssetFromCollection(collection, ownerType, ownerId, assetId, relationship) {
|
|
1903
|
-
const owner = await getOwnerRecord(collection, ownerId);
|
|
1904
|
-
if (!owner) throw new Error(`${ownerType} '${ownerId}' not found`);
|
|
1905
|
-
await owner.removeAsset(assetId, relationship);
|
|
1906
|
-
}
|
|
1907
|
-
//#endregion
|
|
1908
|
-
export { getOwnedAssetsFromCollection as a, assertValidOwnedAssetSortOrder as i, assertAssetLinkable as n, removeOwnedAssetFromCollection as o, assertValidOwnedAssetRelationship as r, resolveOwnedAssetsById as s, addOwnedAssetFromCollection as t };
|