@happyvertical/smrt-places 0.57.46 → 0.57.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { addOwnedAssetFromCollection, assertAssetLinkable, assertValidOwnedAsset
5
5
  import { TenantScoped, queryGlobal, queryWithGlobals, tenantId } from "@happyvertical/smrt-tenancy";
6
6
  import { getGeoAdapter } from "@happyvertical/geo";
7
7
  //#region src/__smrt-register__.ts
8
- ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-places","packageVersion":"0.57.46","objects":{"@happyvertical/smrt-places:PlaceAssetCollection":{"name":"placeassetcollection","className":"PlaceAssetCollection","qualifiedName":"@happyvertical/smrt-places:PlaceAssetCollection","collection":"placeassets","filePath":"/home/runner/work/smrt/smrt/packages/places/src/collections/PlaceAssetCollection.ts","packageName":"@happyvertical/smrt-places","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},"getAssets":{"name":"getAssets","async":true,"parameters":[{"name":"placeId","type":"string","optional":false},{"name":"relationship","type":"string","optional":true}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"addAsset":{"name":"addAsset","async":true,"parameters":[{"name":"placeId","type":"string","optional":false},{"name":"asset","type":"Asset","optional":false},{"name":"relationship","type":"any","optional":true,"default":"attachment"},{"name":"sortOrder","type":"any","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"removeAsset":{"name":"removeAsset","async":true,"parameters":[{"name":"placeId","type":"string","optional":false},{"name":"assetId","type":"string","optional":false},{"name":"relationship","type":"string","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":false,"mcp":false,"cli":false,"tableName":"place_assets"},"extends":"SmrtJunction","extendsTypeArg":"PlaceAsset","exportName":"PlaceAssetCollection","collectionExportName":"PlaceAssetCollectionCollection","schema":{"tableName":"place_assets","ddl":"CREATE TABLE IF NOT EXISTS \\"place_assets\\" (\\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 \\"place_id\\" UUID NOT NULL,\\n \\"asset_id\\" UUID NOT NULL,\\n \\"relationship\\" TEXT NOT NULL,\\n \\"sort_order\\" INTEGER NOT NULL DEFAULT 0\\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},"place_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"places","column":"id","onDelete":"CASCADE","onUpdate":"CASCADE"}},"asset_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":true,"unique":false},"relationship":{"type":"TEXT","notNull":true,"unique":false},"sort_order":{"type":"INTEGER","notNull":true,"unique":false,"default":0}},"indexes":[{"name":"place_assets_place_id_asset_id_idx","columns":["place_id","asset_id","relationship"],"unique":true},{"name":"place_assets_slug_context_idx","columns":["slug","context"]},{"name":"place_assets_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"place_assets_asset_id_idx","columns":["asset_id"]}],"version":"adf47666"},"importPath":"@happyvertical/smrt-places"},"@happyvertical/smrt-places:PlaceCollection":{"name":"placecollection","className":"PlaceCollection","qualifiedName":"@happyvertical/smrt-places:PlaceCollection","collection":"places","filePath":"/home/runner/work/smrt/smrt/packages/places/src/collections/PlaceCollection.ts","packageName":"@happyvertical/smrt-places","fields":{},"methods":{"lookupOrCreate":{"name":"lookupOrCreate","async":true,"parameters":[{"name":"query","type":"string","optional":false},{"name":"options","type":"LookupOrCreateOptions","optional":true}],"returnType":"Promise<Place | null>","isStatic":false,"isPublic":true},"discoverNearby":{"name":"discoverNearby","async":true,"parameters":[{"name":"latitude","type":"number","optional":false},{"name":"longitude","type":"number","optional":false},{"name":"radiusMeters","type":"number","optional":false},{"name":"options","type":"DiscoverNearbyOptions","optional":true}],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"resolveTrackPlaces":{"name":"resolveTrackPlaces","async":true,"parameters":[{"name":"points","type":"ReadonlyArray<TrackPoint>","optional":false},{"name":"options","type":"ResolveTrackPlacesOptions","optional":true}],"returnType":"Promise<TrackPlacesResult>","isStatic":false,"isPublic":true},"getChildren":{"name":"getChildren","async":true,"parameters":[{"name":"parentId","type":"string","optional":false}],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"getRootPlaces":{"name":"getRootPlaces","async":true,"parameters":[],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"getByType":{"name":"getByType","async":true,"parameters":[{"name":"typeSlug","type":"string","optional":false}],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"getHierarchy":{"name":"getHierarchy","async":true,"parameters":[{"name":"placeId","type":"string","optional":false}],"returnType":"any","isStatic":false,"isPublic":true},"getAssets":{"name":"getAssets","async":true,"parameters":[{"name":"placeId","type":"string","optional":false},{"name":"relationship","type":"string","optional":true}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"addAsset":{"name":"addAsset","async":true,"parameters":[{"name":"placeId","type":"string","optional":false},{"name":"asset","type":"Asset","optional":false},{"name":"relationship","type":"any","optional":true,"default":"attachment"},{"name":"sortOrder","type":"any","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"removeAsset":{"name":"removeAsset","async":true,"parameters":[{"name":"placeId","type":"string","optional":false},{"name":"assetId","type":"string","optional":false},{"name":"relationship","type":"string","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"searchByProximity":{"name":"searchByProximity","async":true,"parameters":[{"name":"latitude","type":"number","optional":false},{"name":"longitude","type":"number","optional":false},{"name":"radiusKm","type":"number","optional":true}],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"findByTenant":{"name":"findByTenant","async":true,"parameters":[{"name":"tenantId","type":"string","optional":false}],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"findGlobal":{"name":"findGlobal","async":true,"parameters":[],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"findWithGlobals":{"name":"findWithGlobals","async":true,"parameters":[{"name":"tenantId","type":"string","optional":false}],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create","update"]}},"extends":"SmrtCollection","extendsTypeArg":"Place","exportName":"PlaceCollection","collectionExportName":"PlaceCollectionCollection","schema":{"tableName":"places","ddl":"CREATE TABLE IF NOT EXISTS \\"places\\" (\\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 \\"tenant_id\\" UUID,\\n \\"type_id\\" UUID,\\n \\"name\\" TEXT,\\n \\"description\\" TEXT,\\n \\"latitude\\" REAL,\\n \\"longitude\\" REAL,\\n \\"street_number\\" TEXT,\\n \\"street_name\\" TEXT,\\n \\"city\\" TEXT,\\n \\"region\\" TEXT,\\n \\"country\\" TEXT,\\n \\"postal_code\\" TEXT,\\n \\"country_code\\" TEXT,\\n \\"timezone\\" TEXT,\\n \\"external_id\\" TEXT,\\n \\"source\\" TEXT,\\n \\"metadata\\" 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"},"parent_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"places","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"type_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"place_types","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"name":{"type":"TEXT","notNull":false},"description":{"type":"TEXT","notNull":false},"latitude":{"type":"REAL","notNull":false},"longitude":{"type":"REAL","notNull":false},"street_number":{"type":"TEXT","notNull":false},"street_name":{"type":"TEXT","notNull":false},"city":{"type":"TEXT","notNull":false},"region":{"type":"TEXT","notNull":false},"country":{"type":"TEXT","notNull":false},"postal_code":{"type":"TEXT","notNull":false},"country_code":{"type":"TEXT","notNull":false},"timezone":{"type":"TEXT","notNull":false},"external_id":{"type":"TEXT","notNull":false},"source":{"type":"TEXT","notNull":false},"metadata":{"type":"TEXT","notNull":false}},"indexes":[{"name":"places_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"places_meta_type_idx","columns":["_meta_type"]},{"name":"places_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"places_parent_id_idx","columns":["parent_id"]},{"name":"places_type_id_idx","columns":["type_id"]}],"version":"f670088c"},"importPath":"@happyvertical/smrt-places"},"@happyvertical/smrt-places:PlaceTypeCollection":{"name":"placetypecollection","className":"PlaceTypeCollection","qualifiedName":"@happyvertical/smrt-places:PlaceTypeCollection","collection":"placetypes","filePath":"/home/runner/work/smrt/smrt/packages/places/src/collections/PlaceTypeCollection.ts","packageName":"@happyvertical/smrt-places","fields":{},"methods":{"getOrCreate":{"name":"getOrCreate","async":true,"parameters":[{"name":"slug","type":"string","optional":false},{"name":"name","type":"string","optional":true}],"returnType":"Promise<PlaceType>","isStatic":false,"isPublic":true},"getBySlug":{"name":"getBySlug","async":true,"parameters":[{"name":"slug","type":"string","optional":false}],"returnType":"Promise<PlaceType | null>","isStatic":false,"isPublic":true},"initializeDefaults":{"name":"initializeDefaults","async":true,"parameters":[],"returnType":"Promise<PlaceType[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create"]}},"extends":"SmrtCollection","extendsTypeArg":"PlaceType","exportName":"PlaceTypeCollection","collectionExportName":"PlaceTypeCollectionCollection","schema":{"tableName":"place_types","ddl":"CREATE TABLE IF NOT EXISTS \\"place_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 DEFAULT '',\\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,"default":""},"description":{"type":"TEXT","notNull":false}},"indexes":[{"name":"place_types_slug_context_meta_type_idx","columns":["slug","context","_meta_type"],"unique":true},{"name":"place_types_meta_type_idx","columns":["_meta_type"]},{"name":"place_types_created_at_idx","columns":["created_at"]}],"version":"8c3bb691"},"importPath":"@happyvertical/smrt-places"},"@happyvertical/smrt-places:Place":{"name":"place","className":"Place","qualifiedName":"@happyvertical/smrt-places:Place","collection":"places","filePath":"/home/runner/work/smrt/smrt/packages/places/src/models/Place.ts","packageName":"@happyvertical/smrt-places","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"parentId":{"type":"foreignKey","required":false,"related":"Place","_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}}},"typeId":{"type":"foreignKey","required":false,"related":"PlaceType","description":"What kind of place this is, such as a building, a room or a storage zone.","_meta":{"description":"What kind of place this is, such as a building, a room or a storage zone."}},"name":{"type":"text","required":false,"description":"What the place is called, such as \\"Main warehouse\\" or \\"Aisle 4\\".","_meta":{"description":"What the place is called, such as \\"Main warehouse\\" or \\"Aisle 4\\"."}},"description":{"type":"text","required":false,"description":"A few words about the place and what happens there.","_meta":{"description":"A few words about the place and what happens there."}},"latitude":{"type":"decimal","required":false,"description":"How far north or south the place is on a map. Leave empty for a place that is not on a map.","_meta":{"description":"How far north or south the place is on a map. Leave empty for a place that is not on a map."}},"longitude":{"type":"decimal","required":false,"description":"How far east or west the place is on a map. Leave empty for a place that is not on a map.","_meta":{"description":"How far east or west the place is on a map. Leave empty for a place that is not on a map."}},"streetNumber":{"type":"text","required":false,"description":"The number of the building on its street.","_meta":{"description":"The number of the building on its street."}},"streetName":{"type":"text","required":false,"description":"The name of the street the place is on.","_meta":{"description":"The name of the street the place is on."}},"city":{"type":"text","required":false,"description":"The town or city the place is in.","_meta":{"description":"The town or city the place is in."}},"region":{"type":"text","required":false,"description":"The state, province or region the place is in.","_meta":{"description":"The state, province or region the place is in."}},"country":{"type":"text","required":false,"description":"The country the place is in.","_meta":{"description":"The country the place is in."}},"postalCode":{"type":"text","required":false,"description":"The postal or zip code of the address.","_meta":{"description":"The postal or zip code of the address."}},"countryCode":{"type":"text","required":false,"description":"The short two-letter code for the country, such as CA or US.","_meta":{"description":"The short two-letter code for the country, such as CA or US."}},"timezone":{"type":"text","required":false,"description":"The time zone the place keeps, such as America/Toronto.","_meta":{"description":"The time zone the place keeps, such as America/Toronto."}},"externalId":{"type":"text","required":false,"description":"The reference the map provider uses for this place, filled in when the app looks it up.","_meta":{"description":"The reference the map provider uses for this place, filled in when the app looks it up."}},"source":{"type":"text","required":false,"description":"Which map provider the place was looked up from, if any.","_meta":{"description":"Which map provider the place was looked up from, if any."}},"metadata":{"type":"text","required":false},"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},"getGeoData":{"name":"getGeoData","async":false,"parameters":[],"returnType":"GeoData","isStatic":false,"isPublic":true},"hasCoordinates":{"name":"hasCoordinates","async":false,"parameters":[],"returnType":"boolean","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":"data","type":"Record<string, unknown>","optional":false}],"returnType":"void","isStatic":false,"isPublic":true},"updateMetadata":{"name":"updateMetadata","async":false,"parameters":[{"name":"updates","type":"Record<string, unknown>","optional":false}],"returnType":"void","isStatic":false,"isPublic":true},"getType":{"name":"getType","async":true,"parameters":[],"returnType":"any","isStatic":false,"isPublic":true},"getAssets":{"name":"getAssets","async":true,"parameters":[{"name":"relationship","type":"string","optional":true}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"addAsset":{"name":"addAsset","async":true,"parameters":[{"name":"asset","type":"Asset","optional":false},{"name":"relationship","type":"any","optional":true,"default":"attachment"},{"name":"sortOrder","type":"any","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"getMainAsset":{"name":"getMainAsset","async":true,"parameters":[],"returnType":"Promise<Asset | null>","isStatic":false,"isPublic":true},"setMainAsset":{"name":"setMainAsset","async":true,"parameters":[{"name":"asset","type":"Asset | null","optional":false,"unionBranches":[{"type":"Asset"},{"type":"null"}]}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"removeAsset":{"name":"removeAsset","async":true,"parameters":[{"name":"assetId","type":"string","optional":false},{"name":"relationship","type":"string","optional":true}],"returnType":"Promise<void>","isStatic":false,"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":"Place","collectionExportName":"PlaceCollection","displayLabelField":"name","schema":{"tableName":"places","ddl":"CREATE TABLE IF NOT EXISTS \\"places\\" (\\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 \\"tenant_id\\" UUID,\\n \\"type_id\\" UUID,\\n \\"name\\" TEXT,\\n \\"description\\" TEXT,\\n \\"latitude\\" REAL,\\n \\"longitude\\" REAL,\\n \\"street_number\\" TEXT,\\n \\"street_name\\" TEXT,\\n \\"city\\" TEXT,\\n \\"region\\" TEXT,\\n \\"country\\" TEXT,\\n \\"postal_code\\" TEXT,\\n \\"country_code\\" TEXT,\\n \\"timezone\\" TEXT,\\n \\"external_id\\" TEXT,\\n \\"source\\" TEXT,\\n \\"metadata\\" 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"},"parent_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"places","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"type_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"place_types","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"name":{"type":"TEXT","notNull":false},"description":{"type":"TEXT","notNull":false},"latitude":{"type":"REAL","notNull":false},"longitude":{"type":"REAL","notNull":false},"street_number":{"type":"TEXT","notNull":false},"street_name":{"type":"TEXT","notNull":false},"city":{"type":"TEXT","notNull":false},"region":{"type":"TEXT","notNull":false},"country":{"type":"TEXT","notNull":false},"postal_code":{"type":"TEXT","notNull":false},"country_code":{"type":"TEXT","notNull":false},"timezone":{"type":"TEXT","notNull":false},"external_id":{"type":"TEXT","notNull":false},"source":{"type":"TEXT","notNull":false},"metadata":{"type":"TEXT","notNull":false}},"indexes":[{"name":"places_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"places_meta_type_idx","columns":["_meta_type"]},{"name":"places_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"places_parent_id_idx","columns":["parent_id"]},{"name":"places_type_id_idx","columns":["type_id"]}],"version":"f670088c"},"importPath":"@happyvertical/smrt-places"},"@happyvertical/smrt-places:PlaceAsset":{"name":"placeasset","className":"PlaceAsset","qualifiedName":"@happyvertical/smrt-places:PlaceAsset","collection":"placeassets","filePath":"/home/runner/work/smrt/smrt/packages/places/src/models/PlaceAsset.ts","packageName":"@happyvertical/smrt-places","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}}},"placeId":{"type":"foreignKey","required":true,"related":"Place","_meta":{"required":true,"onDelete":"CASCADE"}},"assetId":{"type":"crossPackageRef","required":true,"related":"@happyvertical/smrt-assets:Asset","_meta":{"onDelete":"CASCADE"}},"relationship":{"type":"text","required":true,"_meta":{"required":true}},"sortOrder":{"type":"integer","required":true,"default":0}},"methods":{},"decoratorConfig":{"tableName":"place_assets","conflictColumns":["place_id","asset_id","relationship"],"api":false,"mcp":false,"cli":false,"tenantScoped":{"mode":"optional"}},"extends":"SmrtObject","exportName":"PlaceAsset","collectionExportName":"PlaceAssetCollection","validationRules":[{"field":"placeId","rule":"required","fieldType":"foreignKey"},{"field":"assetId","rule":"required","fieldType":"crossPackageRef"},{"field":"relationship","rule":"required","fieldType":"text"},{"field":"sortOrder","rule":"required","fieldType":"integer"}],"schema":{"tableName":"place_assets","ddl":"CREATE TABLE IF NOT EXISTS \\"place_assets\\" (\\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 \\"place_id\\" UUID NOT NULL,\\n \\"asset_id\\" UUID NOT NULL,\\n \\"relationship\\" TEXT NOT NULL,\\n \\"sort_order\\" INTEGER NOT NULL DEFAULT 0\\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},"place_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"places","column":"id","onDelete":"CASCADE","onUpdate":"CASCADE"}},"asset_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":true,"unique":false},"relationship":{"type":"TEXT","notNull":true,"unique":false},"sort_order":{"type":"INTEGER","notNull":true,"unique":false,"default":0}},"indexes":[{"name":"place_assets_place_id_asset_id_idx","columns":["place_id","asset_id","relationship"],"unique":true},{"name":"place_assets_slug_context_idx","columns":["slug","context"]},{"name":"place_assets_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"place_assets_asset_id_idx","columns":["asset_id"]}],"version":"adf47666"},"importPath":"@happyvertical/smrt-places"},"@happyvertical/smrt-places:PlaceType":{"name":"placetype","className":"PlaceType","qualifiedName":"@happyvertical/smrt-places:PlaceType","collection":"placetypes","filePath":"/home/runner/work/smrt/smrt/packages/places/src/models/PlaceType.ts","packageName":"@happyvertical/smrt-places","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"name":{"type":"text","required":true,"default":"","description":"The name of the kind of place, such as \\"Building\\", \\"Room\\" or \\"Zone\\".","_meta":{"required":true,"description":"The name of the kind of place, such as \\"Building\\", \\"Room\\" or \\"Zone\\"."}},"description":{"type":"text","required":false,"description":"A few words about when to use this kind of place.","_meta":{"description":"A few words about when to use this kind of place."}},"createdAt":{"type":"text","required":false},"updatedAt":{"type":"text","required":false}},"methods":{"getBySlug":{"name":"getBySlug","async":true,"parameters":[{"name":"_slug","type":"string","optional":false}],"returnType":"Promise<PlaceType | 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":"PlaceType","collectionExportName":"PlaceTypeCollection","displayLabelField":"name","validationRules":[{"field":"name","rule":"required","fieldType":"text"}],"schema":{"tableName":"place_types","ddl":"CREATE TABLE IF NOT EXISTS \\"place_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 DEFAULT '',\\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,"default":""},"description":{"type":"TEXT","notNull":false}},"indexes":[{"name":"place_types_slug_context_meta_type_idx","columns":["slug","context","_meta_type"],"unique":true},{"name":"place_types_meta_type_idx","columns":["_meta_type"]},{"name":"place_types_created_at_idx","columns":["created_at"]}],"version":"8c3bb691"},"importPath":"@happyvertical/smrt-places"}},"moduleType":"smrt","recipes":[{"id":"places.locations","className":"PlacesLocationsRecipe","label":"Places","summary":"Keep a list of the places your work happens, such as sites, buildings, rooms and storage zones, one inside another.","synonyms":["places","locations","sites","buildings","rooms","addresses","warehouses"],"models":["@happyvertical/smrt-places:Place","@happyvertical/smrt-places:PlaceType"],"nav":[{"label":"Places","model":"@happyvertical/smrt-places:Place","icon":"home","description":"Every site, building, room and zone, with its address and what it is inside.","noun":"place"},{"label":"Place types","model":"@happyvertical/smrt-places:PlaceType","icon":"tag","description":"The kinds of place you keep, such as building or room.","noun":"place type"}],"requires":[],"section":{"id":"places","label":"Locations","icon":"home","description":"The places your work happens."},"options":{"@happyvertical/smrt-places:Place":{"fields":{"name":{"order":1},"typeId":{"label":"Type","order":2},"parentId":{"label":"Inside","help":"The larger place this one is part of, such as the building a room is in.","order":3},"description":{"order":4},"streetNumber":{"label":"Street number","order":5},"streetName":{"label":"Street name","order":6},"city":{"order":7},"region":{"order":8},"country":{"order":9},"postalCode":{"label":"Postal code","order":10},"latitude":{"visibility":"advanced"},"longitude":{"visibility":"advanced"},"countryCode":{"label":"Country code","visibility":"advanced"},"timezone":{"label":"Time zone","visibility":"advanced"},"externalId":{"label":"Map reference","visibility":"advanced"},"source":{"label":"Map provider","visibility":"advanced"},"metadata":{"visibility":"hidden"},"tenantId":{"visibility":"hidden"},"createdAt":{"visibility":"hidden"},"updatedAt":{"visibility":"hidden"}}},"@happyvertical/smrt-places:PlaceType":{"fields":{"name":{"order":1},"description":{"order":2},"createdAt":{"visibility":"hidden"},"updatedAt":{"visibility":"hidden"}}}},"help":{"markdown":"## Overview\\n\\nPlaces is where you keep the sites, buildings, rooms and storage zones your\\nwork happens in. Each place has a name, a type and, when it is somewhere real,\\nan address. A place can sit inside a larger one, so a room belongs to a\\nbuilding and a shelf to a room, and you can follow that chain either way. A\\nplace does not have to be on a map: a storage zone or a work area with no\\naddress is fine.\\n\\n## Tasks\\n\\n### Add a place\\n\\n1. Open the list of places and choose **New**.\\n2. Type the **{field:Place.name}**, for example \\"Main warehouse\\".\\n3. Pick its **{field:Place.typeId}**, such as building or room. Add a type first if the one you need is missing.\\n4. Fill in the address: the **{field:Place.streetNumber}**, **{field:Place.streetName}**, **{field:Place.city}**, **{field:Place.region}**, **{field:Place.country}** and **{field:Place.postalCode}**. Leave these empty for a place that is not on a map.\\n5. Save. When your app searches a map for a place, it can add the place for you with the address filled in from the map provider.\\n\\n### Put a place inside another\\n\\n1. Open the place and choose to edit it.\\n2. In **{field:Place.parentId}**, pick the larger place it belongs to, such as the building a room is in.\\n3. Save. The place now shows up under the one you chose.\\n\\n### Change or remove a place\\n\\n1. Open the place and choose to edit it.\\n2. Change the **{field:Place.name}**, **{field:Place.description}** or address, then save.\\n3. To remove a place you no longer use, open it and choose to delete it. Move anything inside it first.\\n\\n### Add a place type\\n\\n1. Open the list of place types and choose **New**.\\n2. Type the **{field:PlaceType.name}**, for example \\"Room\\".\\n3. Add a **{field:PlaceType.description}** so others know when to use it.\\n4. Save. The type can now be picked when you add a place.\\n","fieldRefs":["Place.city","Place.country","Place.description","Place.name","Place.parentId","Place.postalCode","Place.region","Place.streetName","Place.streetNumber","Place.typeId","PlaceType.description","PlaceType.name"]},"demo":{"mode":"server","reasons":["Needs a server because its package does not build for a browser: geo -> cache -> redis, node:zlib; url-signature node:crypto; and its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624, #3627)."]}}],"smrtDependencies":["@happyvertical/smrt-assets","@happyvertical/smrt-core","@happyvertical/smrt-tenancy"],"browser":{"status":"server-only","issues":["#3624","#3627"],"reason":"geo -> cache -> redis, node:zlib; url-signature node:crypto","via":["@happyvertical/smrt-tenancy"]},"stampsConstructors":true}`));
8
+ ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-places","packageVersion":"0.57.47","objects":{"@happyvertical/smrt-places:PlaceAssetCollection":{"name":"placeassetcollection","className":"PlaceAssetCollection","qualifiedName":"@happyvertical/smrt-places:PlaceAssetCollection","collection":"placeassets","filePath":"/home/runner/work/smrt/smrt/packages/places/src/collections/PlaceAssetCollection.ts","packageName":"@happyvertical/smrt-places","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,"resolvedType":"Record<string, unknown>"}],"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,"resolvedType":"Record<string, unknown>"}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"getAssets":{"name":"getAssets","async":true,"parameters":[{"name":"placeId","type":"string","optional":false},{"name":"relationship","type":"string","optional":true}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"addAsset":{"name":"addAsset","async":true,"parameters":[{"name":"placeId","type":"string","optional":false},{"name":"asset","type":"Asset","optional":false},{"name":"relationship","type":"any","optional":true,"default":"attachment"},{"name":"sortOrder","type":"any","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"removeAsset":{"name":"removeAsset","async":true,"parameters":[{"name":"placeId","type":"string","optional":false},{"name":"assetId","type":"string","optional":false},{"name":"relationship","type":"string","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":false,"mcp":false,"cli":false,"tableName":"place_assets"},"extends":"SmrtJunction","extendsTypeArg":"PlaceAsset","exportName":"PlaceAssetCollection","collectionExportName":"PlaceAssetCollectionCollection","collectionOf":"@happyvertical/smrt-places:PlaceAsset","schema":{"tableName":"place_assets","ddl":"CREATE TABLE IF NOT EXISTS \\"place_assets\\" (\\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 \\"place_id\\" UUID NOT NULL,\\n \\"asset_id\\" UUID NOT NULL,\\n \\"relationship\\" TEXT NOT NULL,\\n \\"sort_order\\" INTEGER NOT NULL DEFAULT 0\\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},"place_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"places","column":"id","onDelete":"CASCADE","onUpdate":"CASCADE"}},"asset_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":true,"unique":false},"relationship":{"type":"TEXT","notNull":true,"unique":false},"sort_order":{"type":"INTEGER","notNull":true,"unique":false,"default":0}},"indexes":[{"name":"place_assets_place_id_asset_id_idx","columns":["place_id","asset_id","relationship"],"unique":true},{"name":"place_assets_slug_context_idx","columns":["slug","context"]},{"name":"place_assets_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"place_assets_asset_id_idx","columns":["asset_id"]}],"version":"adf47666"},"importPath":"@happyvertical/smrt-places"},"@happyvertical/smrt-places:PlaceCollection":{"name":"placecollection","className":"PlaceCollection","qualifiedName":"@happyvertical/smrt-places:PlaceCollection","collection":"places","filePath":"/home/runner/work/smrt/smrt/packages/places/src/collections/PlaceCollection.ts","packageName":"@happyvertical/smrt-places","fields":{},"methods":{"lookupOrCreate":{"name":"lookupOrCreate","async":true,"parameters":[{"name":"query","type":"string","optional":false},{"name":"options","type":"LookupOrCreateOptions","optional":true}],"returnType":"Promise<Place | null>","isStatic":false,"isPublic":true},"discoverNearby":{"name":"discoverNearby","async":true,"parameters":[{"name":"latitude","type":"number","optional":false},{"name":"longitude","type":"number","optional":false},{"name":"radiusMeters","type":"number","optional":false},{"name":"options","type":"DiscoverNearbyOptions","optional":true}],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"resolveTrackPlaces":{"name":"resolveTrackPlaces","async":true,"parameters":[{"name":"points","type":"ReadonlyArray<TrackPoint>","optional":false},{"name":"options","type":"ResolveTrackPlacesOptions","optional":true}],"returnType":"Promise<TrackPlacesResult>","isStatic":false,"isPublic":true},"getChildren":{"name":"getChildren","async":true,"parameters":[{"name":"parentId","type":"string","optional":false}],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"getRootPlaces":{"name":"getRootPlaces","async":true,"parameters":[],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"getByType":{"name":"getByType","async":true,"parameters":[{"name":"typeSlug","type":"string","optional":false}],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"getHierarchy":{"name":"getHierarchy","async":true,"parameters":[{"name":"placeId","type":"string","optional":false}],"returnType":"any","isStatic":false,"isPublic":true},"getAssets":{"name":"getAssets","async":true,"parameters":[{"name":"placeId","type":"string","optional":false},{"name":"relationship","type":"string","optional":true}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"addAsset":{"name":"addAsset","async":true,"parameters":[{"name":"placeId","type":"string","optional":false},{"name":"asset","type":"Asset","optional":false},{"name":"relationship","type":"any","optional":true,"default":"attachment"},{"name":"sortOrder","type":"any","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"removeAsset":{"name":"removeAsset","async":true,"parameters":[{"name":"placeId","type":"string","optional":false},{"name":"assetId","type":"string","optional":false},{"name":"relationship","type":"string","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"searchByProximity":{"name":"searchByProximity","async":true,"parameters":[{"name":"latitude","type":"number","optional":false},{"name":"longitude","type":"number","optional":false},{"name":"radiusKm","type":"number","optional":true}],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"findByTenant":{"name":"findByTenant","async":true,"parameters":[{"name":"tenantId","type":"string","optional":false}],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"findGlobal":{"name":"findGlobal","async":true,"parameters":[],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true},"findWithGlobals":{"name":"findWithGlobals","async":true,"parameters":[{"name":"tenantId","type":"string","optional":false}],"returnType":"Promise<Place[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create","update"]}},"extends":"SmrtCollection","extendsTypeArg":"Place","exportName":"PlaceCollection","collectionExportName":"PlaceCollectionCollection","collectionOf":"@happyvertical/smrt-places:Place","inheritedExposure":["api","mcp"],"schema":{"tableName":"places","ddl":"CREATE TABLE IF NOT EXISTS \\"places\\" (\\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 \\"tenant_id\\" UUID,\\n \\"type_id\\" UUID,\\n \\"name\\" TEXT,\\n \\"description\\" TEXT,\\n \\"latitude\\" REAL,\\n \\"longitude\\" REAL,\\n \\"street_number\\" TEXT,\\n \\"street_name\\" TEXT,\\n \\"city\\" TEXT,\\n \\"region\\" TEXT,\\n \\"country\\" TEXT,\\n \\"postal_code\\" TEXT,\\n \\"country_code\\" TEXT,\\n \\"timezone\\" TEXT,\\n \\"external_id\\" TEXT,\\n \\"source\\" TEXT,\\n \\"metadata\\" 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"},"parent_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"places","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"type_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"place_types","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"name":{"type":"TEXT","notNull":false},"description":{"type":"TEXT","notNull":false},"latitude":{"type":"REAL","notNull":false},"longitude":{"type":"REAL","notNull":false},"street_number":{"type":"TEXT","notNull":false},"street_name":{"type":"TEXT","notNull":false},"city":{"type":"TEXT","notNull":false},"region":{"type":"TEXT","notNull":false},"country":{"type":"TEXT","notNull":false},"postal_code":{"type":"TEXT","notNull":false},"country_code":{"type":"TEXT","notNull":false},"timezone":{"type":"TEXT","notNull":false},"external_id":{"type":"TEXT","notNull":false},"source":{"type":"TEXT","notNull":false},"metadata":{"type":"TEXT","notNull":false}},"indexes":[{"name":"places_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"places_meta_type_idx","columns":["_meta_type"]},{"name":"places_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"places_parent_id_idx","columns":["parent_id"]},{"name":"places_type_id_idx","columns":["type_id"]}],"version":"f670088c"},"importPath":"@happyvertical/smrt-places"},"@happyvertical/smrt-places:PlaceTypeCollection":{"name":"placetypecollection","className":"PlaceTypeCollection","qualifiedName":"@happyvertical/smrt-places:PlaceTypeCollection","collection":"placetypes","filePath":"/home/runner/work/smrt/smrt/packages/places/src/collections/PlaceTypeCollection.ts","packageName":"@happyvertical/smrt-places","fields":{},"methods":{"getOrCreate":{"name":"getOrCreate","async":true,"parameters":[{"name":"slug","type":"string","optional":false},{"name":"name","type":"string","optional":true}],"returnType":"Promise<PlaceType>","isStatic":false,"isPublic":true},"getBySlug":{"name":"getBySlug","async":true,"parameters":[{"name":"slug","type":"string","optional":false}],"returnType":"Promise<PlaceType | null>","isStatic":false,"isPublic":true},"initializeDefaults":{"name":"initializeDefaults","async":true,"parameters":[],"returnType":"Promise<PlaceType[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create"]}},"extends":"SmrtCollection","extendsTypeArg":"PlaceType","exportName":"PlaceTypeCollection","collectionExportName":"PlaceTypeCollectionCollection","collectionOf":"@happyvertical/smrt-places:PlaceType","inheritedExposure":["api","mcp"],"schema":{"tableName":"place_types","ddl":"CREATE TABLE IF NOT EXISTS \\"place_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 DEFAULT '',\\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,"default":""},"description":{"type":"TEXT","notNull":false}},"indexes":[{"name":"place_types_slug_context_meta_type_idx","columns":["slug","context","_meta_type"],"unique":true},{"name":"place_types_meta_type_idx","columns":["_meta_type"]},{"name":"place_types_created_at_idx","columns":["created_at"]}],"version":"8c3bb691"},"importPath":"@happyvertical/smrt-places"},"@happyvertical/smrt-places:Place":{"name":"place","className":"Place","qualifiedName":"@happyvertical/smrt-places:Place","collection":"places","filePath":"/home/runner/work/smrt/smrt/packages/places/src/models/Place.ts","packageName":"@happyvertical/smrt-places","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"parentId":{"type":"foreignKey","required":false,"related":"Place","_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}}},"typeId":{"type":"foreignKey","required":false,"related":"PlaceType","description":"What kind of place this is, such as a building, a room or a storage zone.","_meta":{"description":"What kind of place this is, such as a building, a room or a storage zone."}},"name":{"type":"text","required":false,"description":"What the place is called, such as \\"Main warehouse\\" or \\"Aisle 4\\".","_meta":{"description":"What the place is called, such as \\"Main warehouse\\" or \\"Aisle 4\\"."}},"description":{"type":"text","required":false,"description":"A few words about the place and what happens there.","_meta":{"description":"A few words about the place and what happens there."}},"latitude":{"type":"decimal","required":false,"description":"How far north or south the place is on a map. Leave empty for a place that is not on a map.","_meta":{"description":"How far north or south the place is on a map. Leave empty for a place that is not on a map."}},"longitude":{"type":"decimal","required":false,"description":"How far east or west the place is on a map. Leave empty for a place that is not on a map.","_meta":{"description":"How far east or west the place is on a map. Leave empty for a place that is not on a map."}},"streetNumber":{"type":"text","required":false,"description":"The number of the building on its street.","_meta":{"description":"The number of the building on its street."}},"streetName":{"type":"text","required":false,"description":"The name of the street the place is on.","_meta":{"description":"The name of the street the place is on."}},"city":{"type":"text","required":false,"description":"The town or city the place is in.","_meta":{"description":"The town or city the place is in."}},"region":{"type":"text","required":false,"description":"The state, province or region the place is in.","_meta":{"description":"The state, province or region the place is in."}},"country":{"type":"text","required":false,"description":"The country the place is in.","_meta":{"description":"The country the place is in."}},"postalCode":{"type":"text","required":false,"description":"The postal or zip code of the address.","_meta":{"description":"The postal or zip code of the address."}},"countryCode":{"type":"text","required":false,"description":"The short two-letter code for the country, such as CA or US.","_meta":{"description":"The short two-letter code for the country, such as CA or US."}},"timezone":{"type":"text","required":false,"description":"The time zone the place keeps, such as America/Toronto.","_meta":{"description":"The time zone the place keeps, such as America/Toronto."}},"externalId":{"type":"text","required":false,"description":"The reference the map provider uses for this place, filled in when the app looks it up.","_meta":{"description":"The reference the map provider uses for this place, filled in when the app looks it up."}},"source":{"type":"text","required":false,"description":"Which map provider the place was looked up from, if any.","_meta":{"description":"Which map provider the place was looked up from, if any."}},"metadata":{"type":"text","required":false},"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},"getGeoData":{"name":"getGeoData","async":false,"parameters":[],"returnType":"GeoData","isStatic":false,"isPublic":true},"hasCoordinates":{"name":"hasCoordinates","async":false,"parameters":[],"returnType":"boolean","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":"data","type":"Record<string, unknown>","optional":false}],"returnType":"void","isStatic":false,"isPublic":true},"updateMetadata":{"name":"updateMetadata","async":false,"parameters":[{"name":"updates","type":"Record<string, unknown>","optional":false}],"returnType":"void","isStatic":false,"isPublic":true},"getType":{"name":"getType","async":true,"parameters":[],"returnType":"any","isStatic":false,"isPublic":true},"getAssets":{"name":"getAssets","async":true,"parameters":[{"name":"relationship","type":"string","optional":true}],"returnType":"Promise<Asset[]>","isStatic":false,"isPublic":true},"addAsset":{"name":"addAsset","async":true,"parameters":[{"name":"asset","type":"Asset","optional":false},{"name":"relationship","type":"any","optional":true,"default":"attachment"},{"name":"sortOrder","type":"any","optional":true}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"getMainAsset":{"name":"getMainAsset","async":true,"parameters":[],"returnType":"Promise<Asset | null>","isStatic":false,"isPublic":true},"setMainAsset":{"name":"setMainAsset","async":true,"parameters":[{"name":"asset","type":"Asset | null","optional":false,"unionBranches":[{"type":"Asset"},{"type":"null"}]}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"removeAsset":{"name":"removeAsset","async":true,"parameters":[{"name":"assetId","type":"string","optional":false},{"name":"relationship","type":"string","optional":true}],"returnType":"Promise<void>","isStatic":false,"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":"Place","collectionExportName":"PlaceCollection","displayLabelField":"name","schema":{"tableName":"places","ddl":"CREATE TABLE IF NOT EXISTS \\"places\\" (\\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 \\"tenant_id\\" UUID,\\n \\"type_id\\" UUID,\\n \\"name\\" TEXT,\\n \\"description\\" TEXT,\\n \\"latitude\\" REAL,\\n \\"longitude\\" REAL,\\n \\"street_number\\" TEXT,\\n \\"street_name\\" TEXT,\\n \\"city\\" TEXT,\\n \\"region\\" TEXT,\\n \\"country\\" TEXT,\\n \\"postal_code\\" TEXT,\\n \\"country_code\\" TEXT,\\n \\"timezone\\" TEXT,\\n \\"external_id\\" TEXT,\\n \\"source\\" TEXT,\\n \\"metadata\\" 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"},"parent_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"places","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"type_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"place_types","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"name":{"type":"TEXT","notNull":false},"description":{"type":"TEXT","notNull":false},"latitude":{"type":"REAL","notNull":false},"longitude":{"type":"REAL","notNull":false},"street_number":{"type":"TEXT","notNull":false},"street_name":{"type":"TEXT","notNull":false},"city":{"type":"TEXT","notNull":false},"region":{"type":"TEXT","notNull":false},"country":{"type":"TEXT","notNull":false},"postal_code":{"type":"TEXT","notNull":false},"country_code":{"type":"TEXT","notNull":false},"timezone":{"type":"TEXT","notNull":false},"external_id":{"type":"TEXT","notNull":false},"source":{"type":"TEXT","notNull":false},"metadata":{"type":"TEXT","notNull":false}},"indexes":[{"name":"places_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"places_meta_type_idx","columns":["_meta_type"]},{"name":"places_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"places_parent_id_idx","columns":["parent_id"]},{"name":"places_type_id_idx","columns":["type_id"]}],"version":"f670088c"},"importPath":"@happyvertical/smrt-places"},"@happyvertical/smrt-places:PlaceAsset":{"name":"placeasset","className":"PlaceAsset","qualifiedName":"@happyvertical/smrt-places:PlaceAsset","collection":"placeassets","filePath":"/home/runner/work/smrt/smrt/packages/places/src/models/PlaceAsset.ts","packageName":"@happyvertical/smrt-places","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}}},"placeId":{"type":"foreignKey","required":true,"related":"Place","_meta":{"required":true,"onDelete":"CASCADE"}},"assetId":{"type":"crossPackageRef","required":true,"related":"@happyvertical/smrt-assets:Asset","_meta":{"onDelete":"CASCADE"}},"relationship":{"type":"text","required":true,"_meta":{"required":true}},"sortOrder":{"type":"integer","required":true,"default":0}},"methods":{},"decoratorConfig":{"tableName":"place_assets","conflictColumns":["place_id","asset_id","relationship"],"api":false,"mcp":false,"cli":false,"tenantScoped":{"mode":"optional"}},"extends":"SmrtObject","exportName":"PlaceAsset","collectionExportName":"PlaceAssetCollection","validationRules":[{"field":"placeId","rule":"required","fieldType":"foreignKey"},{"field":"assetId","rule":"required","fieldType":"crossPackageRef"},{"field":"relationship","rule":"required","fieldType":"text"},{"field":"sortOrder","rule":"required","fieldType":"integer"}],"schema":{"tableName":"place_assets","ddl":"CREATE TABLE IF NOT EXISTS \\"place_assets\\" (\\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 \\"place_id\\" UUID NOT NULL,\\n \\"asset_id\\" UUID NOT NULL,\\n \\"relationship\\" TEXT NOT NULL,\\n \\"sort_order\\" INTEGER NOT NULL DEFAULT 0\\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},"place_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"places","column":"id","onDelete":"CASCADE","onUpdate":"CASCADE"}},"asset_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":true,"unique":false},"relationship":{"type":"TEXT","notNull":true,"unique":false},"sort_order":{"type":"INTEGER","notNull":true,"unique":false,"default":0}},"indexes":[{"name":"place_assets_place_id_asset_id_idx","columns":["place_id","asset_id","relationship"],"unique":true},{"name":"place_assets_slug_context_idx","columns":["slug","context"]},{"name":"place_assets_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"place_assets_asset_id_idx","columns":["asset_id"]}],"version":"adf47666"},"importPath":"@happyvertical/smrt-places"},"@happyvertical/smrt-places:PlaceType":{"name":"placetype","className":"PlaceType","qualifiedName":"@happyvertical/smrt-places:PlaceType","collection":"placetypes","filePath":"/home/runner/work/smrt/smrt/packages/places/src/models/PlaceType.ts","packageName":"@happyvertical/smrt-places","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"name":{"type":"text","required":true,"default":"","description":"The name of the kind of place, such as \\"Building\\", \\"Room\\" or \\"Zone\\".","_meta":{"required":true,"description":"The name of the kind of place, such as \\"Building\\", \\"Room\\" or \\"Zone\\"."}},"description":{"type":"text","required":false,"description":"A few words about when to use this kind of place.","_meta":{"description":"A few words about when to use this kind of place."}},"createdAt":{"type":"text","required":false},"updatedAt":{"type":"text","required":false}},"methods":{"getBySlug":{"name":"getBySlug","async":true,"parameters":[{"name":"_slug","type":"string","optional":false}],"returnType":"Promise<PlaceType | 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":"PlaceType","collectionExportName":"PlaceTypeCollection","displayLabelField":"name","validationRules":[{"field":"name","rule":"required","fieldType":"text"}],"schema":{"tableName":"place_types","ddl":"CREATE TABLE IF NOT EXISTS \\"place_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 DEFAULT '',\\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,"default":""},"description":{"type":"TEXT","notNull":false}},"indexes":[{"name":"place_types_slug_context_meta_type_idx","columns":["slug","context","_meta_type"],"unique":true},{"name":"place_types_meta_type_idx","columns":["_meta_type"]},{"name":"place_types_created_at_idx","columns":["created_at"]}],"version":"8c3bb691"},"importPath":"@happyvertical/smrt-places"}},"moduleType":"smrt","recipes":[{"id":"places.locations","className":"PlacesLocationsRecipe","label":"Places","summary":"Keep a list of the places your work happens, such as sites, buildings, rooms and storage zones, one inside another.","synonyms":["places","locations","sites","buildings","rooms","addresses","warehouses"],"models":["@happyvertical/smrt-places:Place","@happyvertical/smrt-places:PlaceType"],"nav":[{"label":"Places","model":"@happyvertical/smrt-places:Place","icon":"home","description":"Every site, building, room and zone, with its address and what it is inside.","noun":"place"},{"label":"Place types","model":"@happyvertical/smrt-places:PlaceType","icon":"tag","description":"The kinds of place you keep, such as building or room.","noun":"place type"}],"requires":[],"section":{"id":"places","label":"Locations","icon":"home","description":"The places your work happens."},"options":{"@happyvertical/smrt-places:Place":{"fields":{"name":{"order":1},"typeId":{"label":"Type","order":2},"parentId":{"label":"Inside","help":"The larger place this one is part of, such as the building a room is in.","order":3},"description":{"order":4},"streetNumber":{"label":"Street number","order":5},"streetName":{"label":"Street name","order":6},"city":{"order":7},"region":{"order":8},"country":{"order":9},"postalCode":{"label":"Postal code","order":10},"latitude":{"visibility":"advanced"},"longitude":{"visibility":"advanced"},"countryCode":{"label":"Country code","visibility":"advanced"},"timezone":{"label":"Time zone","visibility":"advanced"},"externalId":{"label":"Map reference","visibility":"advanced"},"source":{"label":"Map provider","visibility":"advanced"},"metadata":{"visibility":"hidden"},"tenantId":{"visibility":"hidden"},"createdAt":{"visibility":"hidden"},"updatedAt":{"visibility":"hidden"}}},"@happyvertical/smrt-places:PlaceType":{"fields":{"name":{"order":1},"description":{"order":2},"createdAt":{"visibility":"hidden"},"updatedAt":{"visibility":"hidden"}}}},"help":{"markdown":"## Overview\\n\\nPlaces is where you keep the sites, buildings, rooms and storage zones your\\nwork happens in. Each place has a name, a type and, when it is somewhere real,\\nan address. A place can sit inside a larger one, so a room belongs to a\\nbuilding and a shelf to a room, and you can follow that chain either way. A\\nplace does not have to be on a map: a storage zone or a work area with no\\naddress is fine.\\n\\n## Tasks\\n\\n### Add a place\\n\\n1. Open the list of places and choose **New**.\\n2. Type the **{field:Place.name}**, for example \\"Main warehouse\\".\\n3. Pick its **{field:Place.typeId}**, such as building or room. Add a type first if the one you need is missing.\\n4. Fill in the address: the **{field:Place.streetNumber}**, **{field:Place.streetName}**, **{field:Place.city}**, **{field:Place.region}**, **{field:Place.country}** and **{field:Place.postalCode}**. Leave these empty for a place that is not on a map.\\n5. Save. When your app searches a map for a place, it can add the place for you with the address filled in from the map provider.\\n\\n### Put a place inside another\\n\\n1. Open the place and choose to edit it.\\n2. In **{field:Place.parentId}**, pick the larger place it belongs to, such as the building a room is in.\\n3. Save. The place now shows up under the one you chose.\\n\\n### Change or remove a place\\n\\n1. Open the place and choose to edit it.\\n2. Change the **{field:Place.name}**, **{field:Place.description}** or address, then save.\\n3. To remove a place you no longer use, open it and choose to delete it. Move anything inside it first.\\n\\n### Add a place type\\n\\n1. Open the list of place types and choose **New**.\\n2. Type the **{field:PlaceType.name}**, for example \\"Room\\".\\n3. Add a **{field:PlaceType.description}** so others know when to use it.\\n4. Save. The type can now be picked when you add a place.\\n","fieldRefs":["Place.city","Place.country","Place.description","Place.name","Place.parentId","Place.postalCode","Place.region","Place.streetName","Place.streetNumber","Place.typeId","PlaceType.description","PlaceType.name"]},"demo":{"mode":"server","reasons":["Needs a server because its package does not build for a browser: geo -> cache -> redis, node:zlib; url-signature node:crypto; and its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624, #3627)."]}}],"smrtDependencies":["@happyvertical/smrt-assets","@happyvertical/smrt-core","@happyvertical/smrt-tenancy"],"browser":{"status":"server-only","issues":["#3624","#3627"],"reason":"geo -> cache -> redis, node:zlib; url-signature node:crypto","via":["@happyvertical/smrt-tenancy"]},"stampsConstructors":true}`));
9
9
  //#endregion
10
10
  //#region src/models/PlaceAsset.ts
11
11
  var __defProp$2 = Object.defineProperty;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/__smrt-register__.ts","../src/models/PlaceAsset.ts","../src/collections/PlaceAssetCollection.ts","../src/models/Place.ts","../src/collections/PlaceCollection.ts","../src/recipes.ts"],"sourcesContent":["// Generated by @happyvertical/smrt-core smrtPlugin at library build time.\n// The package manifest is inlined so self-registration cannot miss when a\n// downstream bundler relocates this module away from dist/manifest.json\n// (https://github.com/happyvertical/smrt/issues/1506,\n// https://github.com/happyvertical/smrt/issues/1507).\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(JSON.parse(\"{\\\"version\\\":\\\"1.0.0\\\",\\\"timestamp\\\":0,\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"packageVersion\\\":\\\"0.57.46\\\",\\\"objects\\\":{\\\"@happyvertical/smrt-places:PlaceAssetCollection\\\":{\\\"name\\\":\\\"placeassetcollection\\\",\\\"className\\\":\\\"PlaceAssetCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-places:PlaceAssetCollection\\\",\\\"collection\\\":\\\"placeassets\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/places/src/collections/PlaceAssetCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"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},\\\"getAssets\\\":{\\\"name\\\":\\\"getAssets\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Asset[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"addAsset\\\":{\\\"name\\\":\\\"addAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"asset\\\",\\\"type\\\":\\\"Asset\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"default\\\":\\\"attachment\\\"},{\\\"name\\\":\\\"sortOrder\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"removeAsset\\\":{\\\"name\\\":\\\"removeAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"assetId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":false,\\\"mcp\\\":false,\\\"cli\\\":false,\\\"tableName\\\":\\\"place_assets\\\"},\\\"extends\\\":\\\"SmrtJunction\\\",\\\"extendsTypeArg\\\":\\\"PlaceAsset\\\",\\\"exportName\\\":\\\"PlaceAssetCollection\\\",\\\"collectionExportName\\\":\\\"PlaceAssetCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"place_assets\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"place_assets\\\\\\\" (\\\\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 \\\\\\\"place_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"asset_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"relationship\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"sort_order\\\\\\\" INTEGER NOT NULL DEFAULT 0\\\\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},\\\"place_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"places\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"CASCADE\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"asset_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"relationship\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"sort_order\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":0}},\\\"indexes\\\":[{\\\"name\\\":\\\"place_assets_place_id_asset_id_idx\\\",\\\"columns\\\":[\\\"place_id\\\",\\\"asset_id\\\",\\\"relationship\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"place_assets_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"place_assets_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"place_assets_asset_id_idx\\\",\\\"columns\\\":[\\\"asset_id\\\"]}],\\\"version\\\":\\\"adf47666\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-places\\\"},\\\"@happyvertical/smrt-places:PlaceCollection\\\":{\\\"name\\\":\\\"placecollection\\\",\\\"className\\\":\\\"PlaceCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-places:PlaceCollection\\\",\\\"collection\\\":\\\"places\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/places/src/collections/PlaceCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"lookupOrCreate\\\":{\\\"name\\\":\\\"lookupOrCreate\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"query\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"LookupOrCreateOptions\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Place | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"discoverNearby\\\":{\\\"name\\\":\\\"discoverNearby\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"latitude\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"longitude\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"radiusMeters\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"DiscoverNearbyOptions\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"resolveTrackPlaces\\\":{\\\"name\\\":\\\"resolveTrackPlaces\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"points\\\",\\\"type\\\":\\\"ReadonlyArray<TrackPoint>\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"ResolveTrackPlacesOptions\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<TrackPlacesResult>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getChildren\\\":{\\\"name\\\":\\\"getChildren\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"parentId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getRootPlaces\\\":{\\\"name\\\":\\\"getRootPlaces\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getByType\\\":{\\\"name\\\":\\\"getByType\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"typeSlug\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getHierarchy\\\":{\\\"name\\\":\\\"getHierarchy\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"any\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAssets\\\":{\\\"name\\\":\\\"getAssets\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Asset[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"addAsset\\\":{\\\"name\\\":\\\"addAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"asset\\\",\\\"type\\\":\\\"Asset\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"default\\\":\\\"attachment\\\"},{\\\"name\\\":\\\"sortOrder\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"removeAsset\\\":{\\\"name\\\":\\\"removeAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"assetId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"searchByProximity\\\":{\\\"name\\\":\\\"searchByProximity\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"latitude\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"longitude\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"radiusKm\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByTenant\\\":{\\\"name\\\":\\\"findByTenant\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findGlobal\\\":{\\\"name\\\":\\\"findGlobal\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findWithGlobals\\\":{\\\"name\\\":\\\"findWithGlobals\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"Place\\\",\\\"exportName\\\":\\\"PlaceCollection\\\",\\\"collectionExportName\\\":\\\"PlaceCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"places\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"places\\\\\\\" (\\\\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 \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"type_id\\\\\\\" UUID,\\\\n \\\\\\\"name\\\\\\\" TEXT,\\\\n \\\\\\\"description\\\\\\\" TEXT,\\\\n \\\\\\\"latitude\\\\\\\" REAL,\\\\n \\\\\\\"longitude\\\\\\\" REAL,\\\\n \\\\\\\"street_number\\\\\\\" TEXT,\\\\n \\\\\\\"street_name\\\\\\\" TEXT,\\\\n \\\\\\\"city\\\\\\\" TEXT,\\\\n \\\\\\\"region\\\\\\\" TEXT,\\\\n \\\\\\\"country\\\\\\\" TEXT,\\\\n \\\\\\\"postal_code\\\\\\\" TEXT,\\\\n \\\\\\\"country_code\\\\\\\" TEXT,\\\\n \\\\\\\"timezone\\\\\\\" TEXT,\\\\n \\\\\\\"external_id\\\\\\\" TEXT,\\\\n \\\\\\\"source\\\\\\\" TEXT,\\\\n \\\\\\\"metadata\\\\\\\" 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\\\"},\\\"parent_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"places\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false},\\\"type_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"place_types\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"latitude\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false},\\\"longitude\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false},\\\"street_number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"street_name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"city\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"region\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"country\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"postal_code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"country_code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"timezone\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"external_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"source\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"metadata\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"places_slug_context_meta_type_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\",\\\"_meta_type\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"places_meta_type_idx\\\",\\\"columns\\\":[\\\"_meta_type\\\"]},{\\\"name\\\":\\\"places_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"places_parent_id_idx\\\",\\\"columns\\\":[\\\"parent_id\\\"]},{\\\"name\\\":\\\"places_type_id_idx\\\",\\\"columns\\\":[\\\"type_id\\\"]}],\\\"version\\\":\\\"f670088c\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-places\\\"},\\\"@happyvertical/smrt-places:PlaceTypeCollection\\\":{\\\"name\\\":\\\"placetypecollection\\\",\\\"className\\\":\\\"PlaceTypeCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-places:PlaceTypeCollection\\\",\\\"collection\\\":\\\"placetypes\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/places/src/collections/PlaceTypeCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"getOrCreate\\\":{\\\"name\\\":\\\"getOrCreate\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"slug\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"name\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<PlaceType>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getBySlug\\\":{\\\"name\\\":\\\"getBySlug\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"slug\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<PlaceType | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"initializeDefaults\\\":{\\\"name\\\":\\\"initializeDefaults\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<PlaceType[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"PlaceType\\\",\\\"exportName\\\":\\\"PlaceTypeCollection\\\",\\\"collectionExportName\\\":\\\"PlaceTypeCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"place_types\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"place_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 DEFAULT '',\\\\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,\\\"default\\\":\\\"\\\"},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"place_types_slug_context_meta_type_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\",\\\"_meta_type\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"place_types_meta_type_idx\\\",\\\"columns\\\":[\\\"_meta_type\\\"]},{\\\"name\\\":\\\"place_types_created_at_idx\\\",\\\"columns\\\":[\\\"created_at\\\"]}],\\\"version\\\":\\\"8c3bb691\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-places\\\"},\\\"@happyvertical/smrt-places:Place\\\":{\\\"name\\\":\\\"place\\\",\\\"className\\\":\\\"Place\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-places:Place\\\",\\\"collection\\\":\\\"places\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/places/src/models/Place.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"fields\\\":{\\\"created_at\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"updated_at\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"parentId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"Place\\\",\\\"_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}}},\\\"typeId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"PlaceType\\\",\\\"description\\\":\\\"What kind of place this is, such as a building, a room or a storage zone.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What kind of place this is, such as a building, a room or a storage zone.\\\"}},\\\"name\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"What the place is called, such as \\\\\\\"Main warehouse\\\\\\\" or \\\\\\\"Aisle 4\\\\\\\".\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What the place is called, such as \\\\\\\"Main warehouse\\\\\\\" or \\\\\\\"Aisle 4\\\\\\\".\\\"}},\\\"description\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"A few words about the place and what happens there.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"A few words about the place and what happens there.\\\"}},\\\"latitude\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"description\\\":\\\"How far north or south the place is on a map. Leave empty for a place that is not on a map.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"How far north or south the place is on a map. Leave empty for a place that is not on a map.\\\"}},\\\"longitude\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"description\\\":\\\"How far east or west the place is on a map. Leave empty for a place that is not on a map.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"How far east or west the place is on a map. Leave empty for a place that is not on a map.\\\"}},\\\"streetNumber\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The number of the building on its street.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The number of the building on its street.\\\"}},\\\"streetName\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The name of the street the place is on.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The name of the street the place is on.\\\"}},\\\"city\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The town or city the place is in.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The town or city the place is in.\\\"}},\\\"region\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The state, province or region the place is in.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The state, province or region the place is in.\\\"}},\\\"country\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The country the place is in.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The country the place is in.\\\"}},\\\"postalCode\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The postal or zip code of the address.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The postal or zip code of the address.\\\"}},\\\"countryCode\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The short two-letter code for the country, such as CA or US.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The short two-letter code for the country, such as CA or US.\\\"}},\\\"timezone\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The time zone the place keeps, such as America/Toronto.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The time zone the place keeps, such as America/Toronto.\\\"}},\\\"externalId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The reference the map provider uses for this place, filled in when the app looks it up.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The reference the map provider uses for this place, filled in when the app looks it up.\\\"}},\\\"source\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"Which map provider the place was looked up from, if any.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Which map provider the place was looked up from, if any.\\\"}},\\\"metadata\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"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},\\\"getGeoData\\\":{\\\"name\\\":\\\"getGeoData\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"GeoData\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"hasCoordinates\\\":{\\\"name\\\":\\\"hasCoordinates\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"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\\\":\\\"data\\\",\\\"type\\\":\\\"Record<string, unknown>\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"void\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"updateMetadata\\\":{\\\"name\\\":\\\"updateMetadata\\\",\\\"async\\\":false,\\\"parameters\\\":[{\\\"name\\\":\\\"updates\\\",\\\"type\\\":\\\"Record<string, unknown>\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"void\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getType\\\":{\\\"name\\\":\\\"getType\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"any\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAssets\\\":{\\\"name\\\":\\\"getAssets\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Asset[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"addAsset\\\":{\\\"name\\\":\\\"addAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"asset\\\",\\\"type\\\":\\\"Asset\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"default\\\":\\\"attachment\\\"},{\\\"name\\\":\\\"sortOrder\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getMainAsset\\\":{\\\"name\\\":\\\"getMainAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Asset | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"setMainAsset\\\":{\\\"name\\\":\\\"setMainAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"asset\\\",\\\"type\\\":\\\"Asset | null\\\",\\\"optional\\\":false,\\\"unionBranches\\\":[{\\\"type\\\":\\\"Asset\\\"},{\\\"type\\\":\\\"null\\\"}]}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"removeAsset\\\":{\\\"name\\\":\\\"removeAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"assetId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"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\\\":\\\"Place\\\",\\\"collectionExportName\\\":\\\"PlaceCollection\\\",\\\"displayLabelField\\\":\\\"name\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"places\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"places\\\\\\\" (\\\\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 \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"type_id\\\\\\\" UUID,\\\\n \\\\\\\"name\\\\\\\" TEXT,\\\\n \\\\\\\"description\\\\\\\" TEXT,\\\\n \\\\\\\"latitude\\\\\\\" REAL,\\\\n \\\\\\\"longitude\\\\\\\" REAL,\\\\n \\\\\\\"street_number\\\\\\\" TEXT,\\\\n \\\\\\\"street_name\\\\\\\" TEXT,\\\\n \\\\\\\"city\\\\\\\" TEXT,\\\\n \\\\\\\"region\\\\\\\" TEXT,\\\\n \\\\\\\"country\\\\\\\" TEXT,\\\\n \\\\\\\"postal_code\\\\\\\" TEXT,\\\\n \\\\\\\"country_code\\\\\\\" TEXT,\\\\n \\\\\\\"timezone\\\\\\\" TEXT,\\\\n \\\\\\\"external_id\\\\\\\" TEXT,\\\\n \\\\\\\"source\\\\\\\" TEXT,\\\\n \\\\\\\"metadata\\\\\\\" 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\\\"},\\\"parent_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"places\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false},\\\"type_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"place_types\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"latitude\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false},\\\"longitude\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false},\\\"street_number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"street_name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"city\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"region\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"country\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"postal_code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"country_code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"timezone\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"external_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"source\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"metadata\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"places_slug_context_meta_type_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\",\\\"_meta_type\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"places_meta_type_idx\\\",\\\"columns\\\":[\\\"_meta_type\\\"]},{\\\"name\\\":\\\"places_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"places_parent_id_idx\\\",\\\"columns\\\":[\\\"parent_id\\\"]},{\\\"name\\\":\\\"places_type_id_idx\\\",\\\"columns\\\":[\\\"type_id\\\"]}],\\\"version\\\":\\\"f670088c\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-places\\\"},\\\"@happyvertical/smrt-places:PlaceAsset\\\":{\\\"name\\\":\\\"placeasset\\\",\\\"className\\\":\\\"PlaceAsset\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-places:PlaceAsset\\\",\\\"collection\\\":\\\"placeassets\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/places/src/models/PlaceAsset.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"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}}},\\\"placeId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":true,\\\"related\\\":\\\"Place\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"onDelete\\\":\\\"CASCADE\\\"}},\\\"assetId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":true,\\\"related\\\":\\\"@happyvertical/smrt-assets:Asset\\\",\\\"_meta\\\":{\\\"onDelete\\\":\\\"CASCADE\\\"}},\\\"relationship\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"sortOrder\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":true,\\\"default\\\":0}},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"place_assets\\\",\\\"conflictColumns\\\":[\\\"place_id\\\",\\\"asset_id\\\",\\\"relationship\\\"],\\\"api\\\":false,\\\"mcp\\\":false,\\\"cli\\\":false,\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"PlaceAsset\\\",\\\"collectionExportName\\\":\\\"PlaceAssetCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"placeId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"foreignKey\\\"},{\\\"field\\\":\\\"assetId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"crossPackageRef\\\"},{\\\"field\\\":\\\"relationship\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"sortOrder\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"integer\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"place_assets\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"place_assets\\\\\\\" (\\\\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 \\\\\\\"place_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"asset_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"relationship\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"sort_order\\\\\\\" INTEGER NOT NULL DEFAULT 0\\\\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},\\\"place_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"places\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"CASCADE\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"asset_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"relationship\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"sort_order\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":0}},\\\"indexes\\\":[{\\\"name\\\":\\\"place_assets_place_id_asset_id_idx\\\",\\\"columns\\\":[\\\"place_id\\\",\\\"asset_id\\\",\\\"relationship\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"place_assets_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"place_assets_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"place_assets_asset_id_idx\\\",\\\"columns\\\":[\\\"asset_id\\\"]}],\\\"version\\\":\\\"adf47666\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-places\\\"},\\\"@happyvertical/smrt-places:PlaceType\\\":{\\\"name\\\":\\\"placetype\\\",\\\"className\\\":\\\"PlaceType\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-places:PlaceType\\\",\\\"collection\\\":\\\"placetypes\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/places/src/models/PlaceType.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"fields\\\":{\\\"created_at\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"updated_at\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"name\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The name of the kind of place, such as \\\\\\\"Building\\\\\\\", \\\\\\\"Room\\\\\\\" or \\\\\\\"Zone\\\\\\\".\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"The name of the kind of place, such as \\\\\\\"Building\\\\\\\", \\\\\\\"Room\\\\\\\" or \\\\\\\"Zone\\\\\\\".\\\"}},\\\"description\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"A few words about when to use this kind of place.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"A few words about when to use this kind of place.\\\"}},\\\"createdAt\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"updatedAt\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false}},\\\"methods\\\":{\\\"getBySlug\\\":{\\\"name\\\":\\\"getBySlug\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"_slug\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<PlaceType | 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\\\":\\\"PlaceType\\\",\\\"collectionExportName\\\":\\\"PlaceTypeCollection\\\",\\\"displayLabelField\\\":\\\"name\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"name\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"place_types\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"place_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 DEFAULT '',\\\\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,\\\"default\\\":\\\"\\\"},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"place_types_slug_context_meta_type_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\",\\\"_meta_type\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"place_types_meta_type_idx\\\",\\\"columns\\\":[\\\"_meta_type\\\"]},{\\\"name\\\":\\\"place_types_created_at_idx\\\",\\\"columns\\\":[\\\"created_at\\\"]}],\\\"version\\\":\\\"8c3bb691\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-places\\\"}},\\\"moduleType\\\":\\\"smrt\\\",\\\"recipes\\\":[{\\\"id\\\":\\\"places.locations\\\",\\\"className\\\":\\\"PlacesLocationsRecipe\\\",\\\"label\\\":\\\"Places\\\",\\\"summary\\\":\\\"Keep a list of the places your work happens, such as sites, buildings, rooms and storage zones, one inside another.\\\",\\\"synonyms\\\":[\\\"places\\\",\\\"locations\\\",\\\"sites\\\",\\\"buildings\\\",\\\"rooms\\\",\\\"addresses\\\",\\\"warehouses\\\"],\\\"models\\\":[\\\"@happyvertical/smrt-places:Place\\\",\\\"@happyvertical/smrt-places:PlaceType\\\"],\\\"nav\\\":[{\\\"label\\\":\\\"Places\\\",\\\"model\\\":\\\"@happyvertical/smrt-places:Place\\\",\\\"icon\\\":\\\"home\\\",\\\"description\\\":\\\"Every site, building, room and zone, with its address and what it is inside.\\\",\\\"noun\\\":\\\"place\\\"},{\\\"label\\\":\\\"Place types\\\",\\\"model\\\":\\\"@happyvertical/smrt-places:PlaceType\\\",\\\"icon\\\":\\\"tag\\\",\\\"description\\\":\\\"The kinds of place you keep, such as building or room.\\\",\\\"noun\\\":\\\"place type\\\"}],\\\"requires\\\":[],\\\"section\\\":{\\\"id\\\":\\\"places\\\",\\\"label\\\":\\\"Locations\\\",\\\"icon\\\":\\\"home\\\",\\\"description\\\":\\\"The places your work happens.\\\"},\\\"options\\\":{\\\"@happyvertical/smrt-places:Place\\\":{\\\"fields\\\":{\\\"name\\\":{\\\"order\\\":1},\\\"typeId\\\":{\\\"label\\\":\\\"Type\\\",\\\"order\\\":2},\\\"parentId\\\":{\\\"label\\\":\\\"Inside\\\",\\\"help\\\":\\\"The larger place this one is part of, such as the building a room is in.\\\",\\\"order\\\":3},\\\"description\\\":{\\\"order\\\":4},\\\"streetNumber\\\":{\\\"label\\\":\\\"Street number\\\",\\\"order\\\":5},\\\"streetName\\\":{\\\"label\\\":\\\"Street name\\\",\\\"order\\\":6},\\\"city\\\":{\\\"order\\\":7},\\\"region\\\":{\\\"order\\\":8},\\\"country\\\":{\\\"order\\\":9},\\\"postalCode\\\":{\\\"label\\\":\\\"Postal code\\\",\\\"order\\\":10},\\\"latitude\\\":{\\\"visibility\\\":\\\"advanced\\\"},\\\"longitude\\\":{\\\"visibility\\\":\\\"advanced\\\"},\\\"countryCode\\\":{\\\"label\\\":\\\"Country code\\\",\\\"visibility\\\":\\\"advanced\\\"},\\\"timezone\\\":{\\\"label\\\":\\\"Time zone\\\",\\\"visibility\\\":\\\"advanced\\\"},\\\"externalId\\\":{\\\"label\\\":\\\"Map reference\\\",\\\"visibility\\\":\\\"advanced\\\"},\\\"source\\\":{\\\"label\\\":\\\"Map provider\\\",\\\"visibility\\\":\\\"advanced\\\"},\\\"metadata\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"tenantId\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"createdAt\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"updatedAt\\\":{\\\"visibility\\\":\\\"hidden\\\"}}},\\\"@happyvertical/smrt-places:PlaceType\\\":{\\\"fields\\\":{\\\"name\\\":{\\\"order\\\":1},\\\"description\\\":{\\\"order\\\":2},\\\"createdAt\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"updatedAt\\\":{\\\"visibility\\\":\\\"hidden\\\"}}}},\\\"help\\\":{\\\"markdown\\\":\\\"## Overview\\\\n\\\\nPlaces is where you keep the sites, buildings, rooms and storage zones your\\\\nwork happens in. Each place has a name, a type and, when it is somewhere real,\\\\nan address. A place can sit inside a larger one, so a room belongs to a\\\\nbuilding and a shelf to a room, and you can follow that chain either way. A\\\\nplace does not have to be on a map: a storage zone or a work area with no\\\\naddress is fine.\\\\n\\\\n## Tasks\\\\n\\\\n### Add a place\\\\n\\\\n1. Open the list of places and choose **New**.\\\\n2. Type the **{field:Place.name}**, for example \\\\\\\"Main warehouse\\\\\\\".\\\\n3. Pick its **{field:Place.typeId}**, such as building or room. Add a type first if the one you need is missing.\\\\n4. Fill in the address: the **{field:Place.streetNumber}**, **{field:Place.streetName}**, **{field:Place.city}**, **{field:Place.region}**, **{field:Place.country}** and **{field:Place.postalCode}**. Leave these empty for a place that is not on a map.\\\\n5. Save. When your app searches a map for a place, it can add the place for you with the address filled in from the map provider.\\\\n\\\\n### Put a place inside another\\\\n\\\\n1. Open the place and choose to edit it.\\\\n2. In **{field:Place.parentId}**, pick the larger place it belongs to, such as the building a room is in.\\\\n3. Save. The place now shows up under the one you chose.\\\\n\\\\n### Change or remove a place\\\\n\\\\n1. Open the place and choose to edit it.\\\\n2. Change the **{field:Place.name}**, **{field:Place.description}** or address, then save.\\\\n3. To remove a place you no longer use, open it and choose to delete it. Move anything inside it first.\\\\n\\\\n### Add a place type\\\\n\\\\n1. Open the list of place types and choose **New**.\\\\n2. Type the **{field:PlaceType.name}**, for example \\\\\\\"Room\\\\\\\".\\\\n3. Add a **{field:PlaceType.description}** so others know when to use it.\\\\n4. Save. The type can now be picked when you add a place.\\\\n\\\",\\\"fieldRefs\\\":[\\\"Place.city\\\",\\\"Place.country\\\",\\\"Place.description\\\",\\\"Place.name\\\",\\\"Place.parentId\\\",\\\"Place.postalCode\\\",\\\"Place.region\\\",\\\"Place.streetName\\\",\\\"Place.streetNumber\\\",\\\"Place.typeId\\\",\\\"PlaceType.description\\\",\\\"PlaceType.name\\\"]},\\\"demo\\\":{\\\"mode\\\":\\\"server\\\",\\\"reasons\\\":[\\\"Needs a server because its package does not build for a browser: geo -> cache -> redis, node:zlib; url-signature node:crypto; and its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624, #3627).\\\"]}}],\\\"smrtDependencies\\\":[\\\"@happyvertical/smrt-assets\\\",\\\"@happyvertical/smrt-core\\\",\\\"@happyvertical/smrt-tenancy\\\"],\\\"browser\\\":{\\\"status\\\":\\\"server-only\\\",\\\"issues\\\":[\\\"#3624\\\",\\\"#3627\\\"],\\\"reason\\\":\\\"geo -> cache -> redis, node:zlib; url-signature node:crypto\\\",\\\"via\\\":[\\\"@happyvertical/smrt-tenancy\\\"]},\\\"stampsConstructors\\\":true}\"));\n","import type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\nexport interface PlaceAssetOptions extends SmrtObjectOptions {\n placeId?: string;\n assetId?: string;\n relationship?: string;\n sortOrder?: number;\n tenantId?: string | null;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'place_assets',\n conflictColumns: ['place_id', 'asset_id', 'relationship'],\n api: false,\n mcp: false,\n cli: false,\n})\nexport class PlaceAsset extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-places\";\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey('Place', { required: true, onDelete: 'CASCADE' })\n placeId = '';\n\n @crossPackageRef('@happyvertical/smrt-assets:Asset', {\n required: true,\n onDelete: 'CASCADE',\n })\n assetId = '';\n\n @field({ required: true })\n relationship = 'attachment';\n\n @field()\n sortOrder = 0;\n\n constructor(options: PlaceAssetOptions = {}) {\n super(options);\n if (options.placeId) this.placeId = options.placeId;\n if (options.assetId) this.assetId = options.assetId;\n if (options.relationship) this.relationship = options.relationship;\n if (options.sortOrder !== undefined) this.sortOrder = options.sortOrder;\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n }\n}\n","import type { Asset } from '@happyvertical/smrt-assets';\nimport {\n addOwnedAssetFromCollection,\n getOwnedAssetsFromCollection,\n removeOwnedAssetFromCollection,\n} from '@happyvertical/smrt-assets';\nimport type { SmrtCollectionOptions } from '@happyvertical/smrt-core';\nimport { SmrtJunction, smrt } from '@happyvertical/smrt-core';\nimport { PlaceAsset } from '../models/PlaceAsset';\nimport type { PlaceCollection } from './PlaceCollection';\n\nexport interface PlaceAssetCollectionOptions extends SmrtCollectionOptions {}\n\n@smrt({\n api: false,\n mcp: false,\n cli: false,\n})\nexport class PlaceAssetCollection extends SmrtJunction<PlaceAsset> { static __smrtPackage__ = \"@happyvertical/smrt-places\";\n static readonly _itemClass = PlaceAsset;\n protected leftField = 'placeId';\n protected rightField = 'assetId';\n\n private placeCollectionPromise: Promise<PlaceCollection> | null = null;\n\n private async getPlaceCollection(): Promise<PlaceCollection> {\n if (!this.placeCollectionPromise) {\n const { PlaceCollection } = await import('./PlaceCollection');\n this.placeCollectionPromise = PlaceCollection.create({ db: this.db });\n }\n\n return this.placeCollectionPromise;\n }\n\n async getAssets(placeId: string, relationship?: string): Promise<Asset[]> {\n return getOwnedAssetsFromCollection(\n await this.getPlaceCollection(),\n placeId,\n relationship,\n );\n }\n\n async addAsset(\n placeId: string,\n asset: Asset,\n relationship = 'attachment',\n sortOrder = 0,\n ): Promise<void> {\n await addOwnedAssetFromCollection(\n await this.getPlaceCollection(),\n 'Place',\n placeId,\n asset,\n relationship,\n sortOrder,\n );\n }\n\n async removeAsset(\n placeId: string,\n assetId: string,\n relationship?: string,\n ): Promise<void> {\n await removeOwnedAssetFromCollection(\n await this.getPlaceCollection(),\n 'Place',\n placeId,\n assetId,\n relationship,\n );\n }\n}\n","/**\n * Place model - Core entity for hierarchical place management\n *\n * Supports both real-world places with geo data and abstract places\n * (virtual worlds, game zones) by making all geo fields optional.\n *\n * Tenancy: Places are tenant-scoped with optional mode, allowing:\n * - Tenant-specific places (tenantId set)\n * - Global/shared places (tenantId null)\n */\n\nimport type { Asset } from '@happyvertical/smrt-assets';\nimport {\n assertAssetLinkable,\n assertValidOwnedAssetRelationship,\n assertValidOwnedAssetSortOrder,\n resolveOwnedAssetsById,\n} from '@happyvertical/smrt-assets';\nimport {\n field,\n foreignKey,\n SmrtHierarchical,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { GeoData, PlaceOptions } from '../types';\n\n/** `place_assets.relationship` of a place's main picture. */\nexport const PLACE_MAIN_ASSET_RELATIONSHIP = 'hero';\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n mcp: { include: ['list', 'get', 'create', 'update'] },\n cli: { skipApiCheck: true },\n})\nexport class Place extends SmrtHierarchical { static __smrtPackage__ = \"@happyvertical/smrt-places\";\n // id: UUID (auto-generated by SmrtObject)\n\n // Tenancy field - nullable for global/shared places\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n // Core fields\n @field({\n description:\n 'What kind of place this is, such as a building, a room or a storage zone.',\n })\n @foreignKey('PlaceType')\n typeId = ''; // FK to PlaceType\n // parentId inherited from SmrtHierarchical (nullable, self-reference)\n @field({\n description:\n 'What the place is called, such as \"Main warehouse\" or \"Aisle 4\".',\n })\n name = ''; // Place name/title\n @field({ description: 'A few words about the place and what happens there.' })\n description = ''; // Optional description\n\n // Optional geo fields (all nullable for abstract places)\n @field({\n type: 'decimal',\n description:\n 'How far north or south the place is on a map. Leave empty for a place that is not on a map.',\n })\n latitude: number | null = null;\n @field({\n type: 'decimal',\n description:\n 'How far east or west the place is on a map. Leave empty for a place that is not on a map.',\n })\n longitude: number | null = null;\n @field({ description: 'The number of the building on its street.' })\n streetNumber = '';\n @field({ description: 'The name of the street the place is on.' })\n streetName = '';\n @field({ description: 'The town or city the place is in.' })\n city = '';\n @field({ description: 'The state, province or region the place is in.' })\n region = '';\n @field({ description: 'The country the place is in.' })\n country = '';\n @field({ description: 'The postal or zip code of the address.' })\n postalCode = '';\n @field({\n description: 'The short two-letter code for the country, such as CA or US.',\n })\n countryCode = '';\n @field({\n description: 'The time zone the place keeps, such as America/Toronto.',\n })\n timezone = '';\n\n // Metadata\n @field({\n description:\n 'The reference the map provider uses for this place, filled in when the app looks it up.',\n })\n externalId = ''; // External system identifier\n @field({\n description: 'Which map provider the place was looked up from, if any.',\n })\n source = ''; // Where this place came from (e.g., 'google', 'osm')\n metadata = ''; // JSON metadata stored as text\n\n // Timestamps\n createdAt = new Date();\n updatedAt = new Date();\n\n constructor(options: PlaceOptions = {}) {\n super(options);\n\n // Tenancy field\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n\n // Core fields\n if (options.typeId) this.typeId = options.typeId;\n if (options.parentId !== undefined)\n this.parentId = options.parentId ?? null;\n if (options.name) this.name = options.name;\n if (options.description !== undefined)\n this.description = options.description;\n\n // Geo fields\n if (options.latitude !== undefined) this.latitude = options.latitude;\n if (options.longitude !== undefined) this.longitude = options.longitude;\n if (options.streetNumber !== undefined)\n this.streetNumber = options.streetNumber;\n if (options.streetName !== undefined) this.streetName = options.streetName;\n if (options.city !== undefined) this.city = options.city;\n if (options.region !== undefined) this.region = options.region;\n if (options.country !== undefined) this.country = options.country;\n if (options.postalCode !== undefined) this.postalCode = options.postalCode;\n if (options.countryCode !== undefined)\n this.countryCode = options.countryCode;\n if (options.timezone !== undefined) this.timezone = options.timezone;\n\n // Metadata\n if (options.externalId !== undefined) this.externalId = options.externalId;\n if (options.source !== undefined) this.source = options.source;\n\n // Handle metadata - can be object or JSON string\n if (options.metadata !== undefined) {\n if (typeof options.metadata === 'string') {\n this.metadata = options.metadata;\n } else {\n this.metadata = JSON.stringify(options.metadata);\n }\n }\n\n // Timestamps\n if (options.createdAt) this.createdAt = options.createdAt;\n if (options.updatedAt) this.updatedAt = options.updatedAt;\n }\n\n /**\n * Get geographic data for this place\n *\n * @returns GeoData object with all geo fields\n */\n getGeoData(): GeoData {\n return {\n latitude: this.latitude,\n longitude: this.longitude,\n streetNumber: this.streetNumber || undefined,\n streetName: this.streetName || undefined,\n city: this.city || undefined,\n region: this.region || undefined,\n country: this.country || undefined,\n postalCode: this.postalCode || undefined,\n countryCode: this.countryCode || undefined,\n timezone: this.timezone || undefined,\n };\n }\n\n /**\n * Check if this place has geographic coordinates\n *\n * @returns True if latitude and longitude are set\n */\n hasCoordinates(): boolean {\n return this.latitude !== null && this.longitude !== null;\n }\n\n /**\n * Get metadata as parsed object\n *\n * @returns Parsed metadata object or empty object if no metadata\n */\n getMetadata(): Record<string, unknown> {\n if (!this.metadata) return {};\n try {\n return JSON.parse(this.metadata);\n } catch {\n return {};\n }\n }\n\n /**\n * Set metadata from object\n *\n * @param data - Metadata object to store\n */\n setMetadata(data: Record<string, unknown>): void {\n this.metadata = JSON.stringify(data);\n }\n\n /**\n * Update metadata by merging with existing values\n *\n * @param updates - Partial metadata to merge\n */\n updateMetadata(updates: Record<string, unknown>): void {\n const current = this.getMetadata();\n this.setMetadata({ ...current, ...updates });\n }\n\n /**\n * Get the place type\n *\n * @returns PlaceType instance or null if not found\n */\n async getType() {\n if (!this.typeId) return null;\n\n const { PlaceTypeCollection } = await import(\n '../collections/PlaceTypeCollection'\n );\n const collection = await PlaceTypeCollection.create(this.options);\n\n return await collection.get({ id: this.typeId });\n }\n\n // Hierarchy traversal (getParent / getChildren / getAncestors /\n // getDescendants / getHierarchy / moveTo) provided by SmrtHierarchical.\n\n private async getPlaceAssetCollection() {\n const { PlaceAssetCollection } = await import(\n '../collections/PlaceAssetCollection'\n );\n return PlaceAssetCollection.create({ db: this.db });\n }\n async getAssets(relationship?: string): Promise<Asset[]> {\n if (!this.id) {\n return [];\n }\n\n const placeAssets = await this.getPlaceAssetCollection();\n const linkedAssets = await placeAssets.byLeft(\n this.id,\n relationship ? { relationship } : {},\n );\n\n return resolveOwnedAssetsById(\n this.db,\n linkedAssets.map((link) => link.assetId),\n this.tenantId,\n );\n }\n\n async addAsset(\n asset: Asset,\n relationship = 'attachment',\n sortOrder = 0,\n ): Promise<void> {\n if (!this.id || !asset.id) {\n throw new Error('Cannot associate unsaved place or asset');\n }\n // The asset's tenant comes from storage, not from the caller's object.\n await assertAssetLinkable(this.db, asset.id, this.tenantId, 'place');\n\n assertValidOwnedAssetRelationship(relationship);\n assertValidOwnedAssetSortOrder(sortOrder);\n\n const placeAssets = await this.getPlaceAssetCollection();\n await placeAssets.attach(this.id, asset.id, {\n relationship,\n sortOrder,\n tenantId: this.tenantId,\n });\n }\n\n /**\n * The place's main picture: its `hero` asset (see `ASSET_ROLES.HERO`), or\n * null when none is set.\n */\n async getMainAsset(): Promise<Asset | null> {\n const [main] = await this.getAssets(PLACE_MAIN_ASSET_RELATIONSHIP);\n return main ?? null;\n }\n\n /**\n * Make `asset` the place's one main picture: it becomes the only `hero`\n * link (any other is removed). Pass `null` to clear the main picture.\n * Other links of the asset (e.g. `depicts`) are left alone.\n */\n async setMainAsset(asset: Asset | null): Promise<void> {\n if (!this.id) {\n throw new Error('Cannot set the main asset of an unsaved place');\n }\n const placeAssets = await this.getPlaceAssetCollection();\n const current = await placeAssets.byLeft(this.id, {\n relationship: PLACE_MAIN_ASSET_RELATIONSHIP,\n });\n if (asset) await this.addAsset(asset, PLACE_MAIN_ASSET_RELATIONSHIP, 0);\n for (const link of current) {\n if (asset && link.assetId === asset.id) continue;\n await placeAssets.detach(this.id, link.assetId, {\n relationship: PLACE_MAIN_ASSET_RELATIONSHIP,\n });\n }\n }\n\n async removeAsset(assetId: string, relationship?: string): Promise<void> {\n if (!this.id) {\n return;\n }\n\n const placeAssets = await this.getPlaceAssetCollection();\n await placeAssets.detach(\n this.id,\n assetId,\n relationship ? { relationship } : {},\n );\n }\n}\n","/**\n * PlaceCollection - Collection manager for Place objects\n *\n * Provides hierarchy traversal and organic place database growth via\n * lookupOrCreate method that integrates with @happyvertical/geo.\n */\n\nimport type { GeoAdapter, Location } from '@happyvertical/geo';\nimport { getGeoAdapter } from '@happyvertical/geo';\nimport type { Asset } from '@happyvertical/smrt-assets';\nimport {\n addOwnedAssetFromCollection,\n getOwnedAssetsFromCollection,\n removeOwnedAssetFromCollection,\n} from '@happyvertical/smrt-assets';\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { Place } from '../models/Place';\nimport type {\n DiscoverNearbyOptions,\n LookupOrCreateOptions,\n ResolveTrackPlacesOptions,\n TrackPlacesResult,\n TrackPoint,\n} from '../types';\nimport { PlaceTypeCollection } from './PlaceTypeCollection';\n\ntype PoiSearchOptions = Pick<\n DiscoverNearbyOptions,\n 'types' | 'keyword' | 'limit' | 'language'\n>;\n\ntype GeoAdapterWithPoiSearch = GeoAdapter & {\n findPoisNear?: (\n latitude: number,\n longitude: number,\n radiusMeters: number,\n options?: PoiSearchOptions,\n ) => Promise<Location[]>;\n};\n\nexport class PlaceCollection extends SmrtCollection<Place> {\n static readonly _itemClass = Place;\n\n /**\n * Look up a place by query or coordinates, creating it if not found\n *\n * This is the key method for organic database growth:\n * 1. Search local database first\n * 2. If not found, query @happyvertical/geo\n * 3. Create place from geocoding result\n * 4. Return place\n *\n * @param query - Address or location query string\n * @param options - Lookup options (provider, type, parent, etc.)\n * @returns Place instance\n */\n async lookupOrCreate(\n query: string,\n options: LookupOrCreateOptions = {},\n ): Promise<Place | null> {\n const {\n geoProvider = 'openstreetmap',\n typeSlug,\n parentId,\n createIfNotFound = true,\n coords,\n } = options;\n\n // Step 1: Try to find existing place\n let existingPlace: Place | null = null;\n\n // Search by coordinates if provided\n if (coords) {\n existingPlace = await this.findByCoordinates(coords.lat, coords.lng);\n }\n\n // Search by query text if coordinates didn't match\n if (!existingPlace) {\n existingPlace = await this.findByQuery(query);\n }\n\n if (existingPlace) {\n return existingPlace;\n }\n\n // Step 2: If not found and createIfNotFound is false, return null\n if (!createIfNotFound) {\n return null;\n }\n\n // Step 3: Query @happyvertical/geo for location data\n const locations = await this.geocode(\n query,\n coords,\n geoProvider as 'google' | 'openstreetmap',\n );\n\n if (locations.length === 0) {\n return null;\n }\n\n // Use first result (most relevant)\n const location = locations[0];\n\n // Step 4: Create place from location data\n return await this.createFromLocation(location, typeSlug, parentId);\n }\n\n /**\n * Find place by coordinates (within small threshold)\n *\n * @param latitude - Latitude to search\n * @param longitude - Longitude to search\n * @param threshold - Max distance in degrees (default: 0.0001 ~11m)\n * @returns Place instance or null\n */\n private async findByCoordinates(\n latitude: number,\n longitude: number,\n threshold: number = 0.0001,\n ): Promise<Place | null> {\n // Get all places with coordinates\n const places = await this.list({\n where: {\n latitude: { $ne: null },\n longitude: { $ne: null },\n },\n });\n\n // Find closest match within threshold\n for (const place of places) {\n // Cast to access Place-specific properties\n const placeObj = place as Place;\n if (placeObj.latitude === null || placeObj.longitude === null) continue;\n\n const latDiff = Math.abs(placeObj.latitude - latitude);\n const lngDiff = Math.abs(placeObj.longitude - longitude);\n\n if (latDiff < threshold && lngDiff < threshold) {\n return place;\n }\n }\n\n return null;\n }\n\n /**\n * Find place by query text (matches name, city, region, country)\n *\n * @param query - Search query\n * @returns Place instance or null\n */\n private async findByQuery(query: string): Promise<Place | null> {\n const normalizedQuery = query.toLowerCase().trim();\n\n // Try exact match on name first\n const places = await this.list({});\n\n for (const place of places) {\n // Match on name\n if (place.name.toLowerCase().includes(normalizedQuery)) {\n return place;\n }\n\n // Match on full address components\n const addressParts = [\n place.streetNumber,\n place.streetName,\n place.city,\n place.region,\n place.country,\n ]\n .filter((p) => p)\n .join(' ')\n .toLowerCase();\n\n if (addressParts.includes(normalizedQuery)) {\n return place;\n }\n }\n\n return null;\n }\n\n /**\n * Geocode query or coordinates using @happyvertical/geo\n *\n * @param query - Address query\n * @param coords - Optional coordinates for reverse geocoding\n * @param provider - Geo provider to use\n * @returns Array of Location results\n */\n private async geocode(\n query: string,\n coords?: { lat: number; lng: number },\n provider: 'google' | 'openstreetmap' = 'openstreetmap',\n ): Promise<Location[]> {\n const geo = await this.getGeoAdapter(provider);\n\n // Use reverse geocode if coords provided, otherwise forward geocode\n if (coords) {\n return await geo.reverseGeocode(coords.lat, coords.lng);\n }\n\n return await geo.lookup(query);\n }\n\n /**\n * Find a place by the provider's native id (Google place_id, OSM\n * osm-node-N, etc.). Used as the primary idempotency key by\n * `discoverNearby` so repeat POI searches don't create duplicate rows.\n */\n private async findByExternalId(externalId: string): Promise<Place | null> {\n if (!externalId) return null;\n const matches = await this.list({\n where: { externalId },\n limit: 1,\n });\n return matches[0] ?? null;\n }\n\n /**\n * Idempotent \"find or create\" for a geo Location. Keyed purely on the\n * provider's externalId (Google place_id, osm-node-*, etc.), which is\n * stable per POI across repeat searches. The older `lookupOrCreate`\n * keeps its own fallback chain (name/address/coordinate matching) for\n * address-style workflows where externalId isn't reliable.\n *\n * Returns `{ place, created }` so callers can distinguish fresh rows\n * from reused ones without re-querying the table — this is how\n * `resolveTrackPlaces` derives its `cacheHitCount` without a full\n * scan per bucket.\n */\n private async ensureFromLocation(\n location: Location,\n typeSlug?: string,\n parentId?: string | null,\n ): Promise<{ place: Place; created: boolean }> {\n if (location.id) {\n const existing = await this.findByExternalId(location.id);\n if (existing) return { place: existing, created: false };\n }\n const place = await this.createFromLocation(location, typeSlug, parentId);\n return { place, created: true };\n }\n\n /**\n * Create place from @happyvertical/geo Location data\n *\n * @param location - Location from geocoding\n * @param typeSlug - Optional type slug override\n * @param parentId - Optional parent place ID\n * @returns Created Place instance\n */\n private async createFromLocation(\n location: Location,\n typeSlug?: string,\n parentId?: string | null,\n ): Promise<Place> {\n // Get or create place type\n const typeCollection = await PlaceTypeCollection.create(this.options);\n\n const slug = typeSlug || location.type || 'address';\n const placeType = await typeCollection.getOrCreate(slug);\n\n // Extract address components\n const components = location.addressComponents || {};\n\n // Create place\n return await this.create({\n typeId: placeType.id ?? undefined,\n parentId: parentId ?? null,\n name: location.name,\n description: '',\n\n // Geo fields from location\n latitude: location.latitude,\n longitude: location.longitude,\n streetNumber: components.streetNumber || '',\n streetName: components.streetName || '',\n city: components.city || '',\n region: components.region || '',\n country: components.country || '',\n postalCode: components.postalCode || '',\n countryCode: location.countryCode || '',\n timezone: location.timezone || '',\n\n // Metadata\n externalId: location.id,\n source: location.raw?.provider || 'unknown',\n metadata: JSON.stringify({ raw: location.raw ?? null }),\n });\n }\n\n /**\n * Discover POIs near a coordinate and persist them as Place rows.\n *\n * Composes `@happyvertical/geo`'s `findPoisNear` with `ensureFromLocation`\n * so every returned POI is either reused from the local DB (when the\n * provider returns an id matching an existing Place `externalId`) or\n * created fresh otherwise. The cache is effectively automatic because\n * the provider's own place_id becomes the Place row's `externalId`, so\n * calling `discoverNearby` twice for the same area on the same provider\n * is a no-op after the first run when the provider returns stable ids.\n *\n * Requires a geo provider that implements `findPoisNear`. Throws a clear\n * error otherwise so consumers can fall back to `lookupOrCreate` or\n * switch providers.\n */\n async discoverNearby(\n latitude: number,\n longitude: number,\n radiusMeters: number,\n options: DiscoverNearbyOptions = {},\n ): Promise<Place[]> {\n if (!(radiusMeters > 0)) {\n throw new Error(\n `discoverNearby: radiusMeters must be > 0 (got ${radiusMeters})`,\n );\n }\n const detailed = await this.discoverNearbyDetailed(\n latitude,\n longitude,\n radiusMeters,\n options,\n );\n return detailed.map((d) => d.place);\n }\n\n /**\n * Internal variant of `discoverNearby` that exposes whether each\n * returned Place was created during this call (`true`) or reused from\n * an earlier call (`false`). Used by `resolveTrackPlaces` to classify\n * buckets as cache hits without having to re-scan the Place table.\n */\n private async discoverNearbyDetailed(\n latitude: number,\n longitude: number,\n radiusMeters: number,\n options: DiscoverNearbyOptions = {},\n ): Promise<Array<{ place: Place; created: boolean }>> {\n const {\n geoProvider = 'openstreetmap',\n types,\n keyword,\n limit,\n language,\n typeSlug,\n parentId,\n } = options;\n\n const geo = await this.getGeoAdapter(geoProvider);\n if (typeof geo.findPoisNear !== 'function') {\n throw new Error(\n `Geo provider '${geoProvider}' does not implement findPoisNear`,\n );\n }\n\n const results = await geo.findPoisNear(latitude, longitude, radiusMeters, {\n types,\n keyword,\n limit,\n language,\n });\n\n const detailed: Array<{ place: Place; created: boolean }> = [];\n for (const result of results) {\n detailed.push(await this.ensureFromLocation(result, typeSlug, parentId));\n }\n return detailed;\n }\n\n /**\n * Resolve POIs along a GPS track (e.g. a video's per-frame path).\n *\n * Naively walking every point would hammer the provider with redundant\n * requests — consecutive samples are usually within a few meters. This\n * method buckets points into a `bucketMeters`-wide grid, calls\n * `discoverNearby` once per distinct bucket, and throttles requests per\n * `throttleMs` so free tiers (Overpass, Nominatim) stay inside their\n * community rate limits without the caller having to manage a queue.\n *\n * The returned `places` are deduped across buckets by Place id, so a\n * POI that falls within several overlapping search radii appears once.\n */\n async resolveTrackPlaces(\n points: ReadonlyArray<TrackPoint>,\n options: ResolveTrackPlacesOptions = {},\n ): Promise<TrackPlacesResult> {\n const radiusMeters = options.radiusMeters ?? 50;\n const bucketMeters = options.bucketMeters ?? 50;\n const throttleMs = options.throttleMs ?? 1100;\n\n if (!(radiusMeters > 0)) {\n throw new Error(\n `resolveTrackPlaces: radiusMeters must be > 0 (got ${radiusMeters})`,\n );\n }\n if (!(bucketMeters > 0)) {\n // Grid/greedy bucketing both divide by bucketMeters; a non-positive\n // value would either NaN the math or produce \"everything in one\n // bucket\", neither of which the caller likely meant.\n throw new Error(\n `resolveTrackPlaces: bucketMeters must be > 0 (got ${bucketMeters})`,\n );\n }\n if (throttleMs < 0 || !Number.isFinite(throttleMs)) {\n throw new Error(\n `resolveTrackPlaces: throttleMs must be a finite non-negative number (got ${throttleMs})`,\n );\n }\n\n // Greedy proximity-based bucketing: each new point joins the nearest\n // existing bucket within `bucketMeters` (Haversine), otherwise seeds a\n // new bucket with itself as the center. This matches the documented\n // semantic (\"points within bucketMeters of each other collapse into\n // one request\") more faithfully than a `Math.round`-on-grid scheme,\n // which can split two points ~0.2m apart if they straddle a cell\n // boundary and inflate requestCount exactly when the user was trying\n // to rate-limit.\n const bucketMetersKm = bucketMeters / 1000;\n const bucketCenters: TrackPoint[] = [];\n for (const point of points) {\n if (!Number.isFinite(point.lat) || !Number.isFinite(point.lng)) continue;\n let bestIdx = -1;\n let bestKm = Number.POSITIVE_INFINITY;\n for (let i = 0; i < bucketCenters.length; i += 1) {\n const c = bucketCenters[i];\n const km = this.calculateDistance(c.lat, c.lng, point.lat, point.lng);\n if (km <= bucketMetersKm && km < bestKm) {\n bestKm = km;\n bestIdx = i;\n }\n }\n if (bestIdx < 0) bucketCenters.push(point);\n }\n\n const result: TrackPlacesResult = {\n places: [],\n requestCount: 0,\n cacheHitCount: 0,\n bucketCount: bucketCenters.length,\n };\n const seen = new Map<string, Place>();\n\n let lastCallAt = 0;\n for (const center of bucketCenters) {\n const wait = lastCallAt + throttleMs - Date.now();\n if (wait > 0) {\n await new Promise((resolve) => setTimeout(resolve, wait));\n }\n\n const detailed = await this.discoverNearbyDetailed(\n center.lat,\n center.lng,\n radiusMeters,\n options,\n );\n lastCallAt = Date.now();\n result.requestCount += 1;\n\n // Cache hit = the provider returned results and every one of them\n // matched a Place that already existed (explicit `created === false`\n // from ensureFromLocation). No timestamp heuristics, no re-scan.\n if (detailed.length > 0 && detailed.every((d) => !d.created)) {\n result.cacheHitCount += 1;\n }\n\n for (const { place } of detailed) {\n if (place.id && !seen.has(place.id)) seen.set(place.id, place);\n }\n }\n\n result.places = [...seen.values()];\n return result;\n }\n\n /**\n * Provider wiring (env keys, user-agent string, etc.) that `geocode`\n * and `discoverNearby` share so the two code paths can't drift. Kept\n * separate from the adapter call itself so tests and future providers\n * can inspect or override the options before construction.\n */\n private getGeoAdapterOptions(\n provider: 'google' | 'openstreetmap',\n ):\n | { provider: 'google'; apiKey: string }\n | { provider: 'openstreetmap'; userAgent: string } {\n if (provider === 'google') {\n return {\n provider: 'google',\n apiKey: process.env.GOOGLE_MAPS_API_KEY || '',\n };\n }\n return { provider: 'openstreetmap', userAgent: '@have/places' };\n }\n\n /**\n * Build a geo adapter configured for this call. Single source of truth\n * for provider wiring — `geocode` and `discoverNearby` both come through\n * here.\n */\n private async getGeoAdapter(\n provider: 'google' | 'openstreetmap',\n ): Promise<GeoAdapterWithPoiSearch> {\n return getGeoAdapter(this.getGeoAdapterOptions(provider));\n }\n\n /**\n * Get immediate children of a parent place\n *\n * @param parentId - The parent place ID\n * @returns Array of child places\n */\n async getChildren(parentId: string): Promise<Place[]> {\n return await this.list({\n where: { parentId },\n });\n }\n\n /**\n * Get root places (no parent)\n *\n * @returns Array of root places\n */\n async getRootPlaces(): Promise<Place[]> {\n return await this.list({\n where: { parentId: null },\n });\n }\n\n /**\n * Get places by type\n *\n * @param typeSlug - PlaceType slug\n * @returns Array of places of that type\n */\n async getByType(typeSlug: string): Promise<Place[]> {\n // Get type ID\n const typeCollection = await PlaceTypeCollection.create(this.options);\n\n const placeType = await typeCollection.getBySlug(typeSlug);\n if (!placeType) return [];\n\n return await this.list({\n where: { typeId: placeType.id },\n });\n }\n\n /**\n * Get place hierarchy (all ancestors and descendants)\n *\n * @param placeId - The place ID\n * @returns Object with ancestors, current place, and descendants\n */\n async getHierarchy(placeId: string) {\n const place = await this.get({ id: placeId });\n if (!place) throw new Error(`Place '${placeId}' not found`);\n\n return await place.getHierarchy();\n }\n\n async getAssets(placeId: string, relationship?: string): Promise<Asset[]> {\n return getOwnedAssetsFromCollection(this, placeId, relationship);\n }\n\n async addAsset(\n placeId: string,\n asset: Asset,\n relationship = 'attachment',\n sortOrder = 0,\n ): Promise<void> {\n await addOwnedAssetFromCollection(\n this,\n 'Place',\n placeId,\n asset,\n relationship,\n sortOrder,\n );\n }\n\n async removeAsset(\n placeId: string,\n assetId: string,\n relationship?: string,\n ): Promise<void> {\n await removeOwnedAssetFromCollection(\n this,\n 'Place',\n placeId,\n assetId,\n relationship,\n );\n }\n\n /**\n * Search places by proximity to coordinates\n *\n * @param latitude - Center latitude\n * @param longitude - Center longitude\n * @param radiusKm - Search radius in kilometers\n * @returns Array of places within radius, sorted by distance\n */\n async searchByProximity(\n latitude: number,\n longitude: number,\n radiusKm: number = 10,\n ): Promise<Place[]> {\n // Get all places with coordinates\n const places = await this.list({\n where: {\n latitude: { $ne: null },\n longitude: { $ne: null },\n },\n });\n\n // Calculate distances and filter by radius\n const placesWithDistance = places\n .map((place) => {\n if (place.latitude === null || place.longitude === null) return null;\n\n const distance = this.calculateDistance(\n latitude,\n longitude,\n place.latitude,\n place.longitude,\n );\n\n return { place, distance };\n })\n .filter(\n (p): p is { place: Place; distance: number } =>\n p !== null && p.distance <= radiusKm,\n )\n .sort((a, b) => a.distance - b.distance);\n\n return placesWithDistance.map((p) => p.place);\n }\n\n /**\n * Calculate distance between two coordinates using Haversine formula\n *\n * @param lat1 - First latitude\n * @param lng1 - First longitude\n * @param lat2 - Second latitude\n * @param lng2 - Second longitude\n * @returns Distance in kilometers\n */\n private calculateDistance(\n lat1: number,\n lng1: number,\n lat2: number,\n lng2: number,\n ): number {\n const R = 6371; // Earth radius in km\n const dLat = this.toRad(lat2 - lat1);\n const dLng = this.toRad(lng2 - lng1);\n\n const a =\n Math.sin(dLat / 2) * Math.sin(dLat / 2) +\n Math.cos(this.toRad(lat1)) *\n Math.cos(this.toRad(lat2)) *\n Math.sin(dLng / 2) *\n Math.sin(dLng / 2);\n\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n return R * c;\n }\n\n /**\n * Convert degrees to radians\n */\n private toRad(degrees: number): number {\n return degrees * (Math.PI / 180);\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Find all places belonging to a specific tenant\n *\n * @param tenantId - The tenant ID to filter by\n * @returns Array of places for the tenant\n */\n async findByTenant(tenantId: string): Promise<Place[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global places (not associated with any tenant).\n *\n * Routes through the shared tenant-global helper so it does not throw under\n * an active tenant context (an explicit `tenant_id IS NULL` filter would be\n * flagged as an isolation violation). (#1600)\n *\n * @returns Array of global places\n */\n async findGlobal(): Promise<Place[]> {\n return queryGlobal<Place>(this);\n }\n\n /**\n * Find places for a tenant including global places.\n *\n * Fails closed if an active tenant context requests a different tenant's\n * rows; the admin/system path keeps the cross-tenant capability. (#1600)\n *\n * @param tenantId - The tenant ID to include\n * @returns Array of tenant-specific and global places\n */\n async findWithGlobals(tenantId: string): Promise<Place[]> {\n return queryWithGlobals<Place>(this, tenantId, 'Place.findWithGlobals');\n }\n}\n","/**\n * Declared recipes for smrt-places (#4409): user-facing units of\n * functionality an app or agent can pick instead of the whole package.\n * The scanner reads these statics into the `recipes` array of `manifest.json`\n * and `smrt-knowledge.json`; nothing here runs at that point.\n *\n * @packageDocumentation\n */\n\nimport { SmrtRecipe } from '@happyvertical/smrt-core';\nimport { Place } from './models/Place';\nimport { PlaceType } from './models/PlaceType';\n\n/**\n * Places: the buildings, rooms, zones and sites where work happens, one\n * inside another. `PlaceAsset` (the picture join) is closed to every surface\n * and stays out of the recipe.\n */\nexport class PlacesLocationsRecipe extends SmrtRecipe {\n static id = 'places.locations';\n static help = './locations.recipe.md';\n static label = 'Places';\n static summary =\n 'Keep a list of the places your work happens, such as sites, buildings, rooms and storage zones, one inside another.';\n static synonyms = [\n 'places',\n 'locations',\n 'sites',\n 'buildings',\n 'rooms',\n 'addresses',\n 'warehouses',\n ];\n static section = {\n id: 'places',\n label: 'Locations',\n icon: 'home',\n description: 'The places your work happens.',\n };\n static models = [Place, PlaceType];\n static nav = [\n {\n label: 'Places',\n model: Place,\n icon: 'home',\n description:\n 'Every site, building, room and zone, with its address and what it is inside.',\n noun: 'place',\n },\n {\n label: 'Place types',\n model: PlaceType,\n icon: 'tag',\n description: 'The kinds of place you keep, such as building or room.',\n noun: 'place type',\n },\n ];\n static options = {\n Place: {\n fields: {\n name: { order: 1 },\n typeId: { label: 'Type', order: 2 },\n parentId: {\n label: 'Inside',\n help: 'The larger place this one is part of, such as the building a room is in.',\n order: 3,\n },\n description: { order: 4 },\n streetNumber: { label: 'Street number', order: 5 },\n streetName: { label: 'Street name', order: 6 },\n city: { order: 7 },\n region: { order: 8 },\n country: { order: 9 },\n postalCode: { label: 'Postal code', order: 10 },\n latitude: { visibility: 'advanced' },\n longitude: { visibility: 'advanced' },\n countryCode: { label: 'Country code', visibility: 'advanced' },\n timezone: { label: 'Time zone', visibility: 'advanced' },\n externalId: { label: 'Map reference', visibility: 'advanced' },\n source: { label: 'Map provider', visibility: 'advanced' },\n metadata: { visibility: 'hidden' },\n tenantId: { visibility: 'hidden' },\n createdAt: { visibility: 'hidden' },\n updatedAt: { visibility: 'hidden' },\n },\n },\n PlaceType: {\n fields: {\n name: { order: 1 },\n description: { order: 2 },\n createdAt: { visibility: 'hidden' },\n updatedAt: { visibility: 'hidden' },\n },\n },\n } as const;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/__smrt-register__.ts","../src/models/PlaceAsset.ts","../src/collections/PlaceAssetCollection.ts","../src/models/Place.ts","../src/collections/PlaceCollection.ts","../src/recipes.ts"],"sourcesContent":["// Generated by @happyvertical/smrt-core smrtPlugin at library build time.\n// The package manifest is inlined so self-registration cannot miss when a\n// downstream bundler relocates this module away from dist/manifest.json\n// (https://github.com/happyvertical/smrt/issues/1506,\n// https://github.com/happyvertical/smrt/issues/1507).\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(JSON.parse(\"{\\\"version\\\":\\\"1.0.0\\\",\\\"timestamp\\\":0,\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"packageVersion\\\":\\\"0.57.47\\\",\\\"objects\\\":{\\\"@happyvertical/smrt-places:PlaceAssetCollection\\\":{\\\"name\\\":\\\"placeassetcollection\\\",\\\"className\\\":\\\"PlaceAssetCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-places:PlaceAssetCollection\\\",\\\"collection\\\":\\\"placeassets\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/places/src/collections/PlaceAssetCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"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,\\\"resolvedType\\\":\\\"Record<string, unknown>\\\"}],\\\"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,\\\"resolvedType\\\":\\\"Record<string, unknown>\\\"}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAssets\\\":{\\\"name\\\":\\\"getAssets\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Asset[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"addAsset\\\":{\\\"name\\\":\\\"addAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"asset\\\",\\\"type\\\":\\\"Asset\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"default\\\":\\\"attachment\\\"},{\\\"name\\\":\\\"sortOrder\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"removeAsset\\\":{\\\"name\\\":\\\"removeAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"assetId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":false,\\\"mcp\\\":false,\\\"cli\\\":false,\\\"tableName\\\":\\\"place_assets\\\"},\\\"extends\\\":\\\"SmrtJunction\\\",\\\"extendsTypeArg\\\":\\\"PlaceAsset\\\",\\\"exportName\\\":\\\"PlaceAssetCollection\\\",\\\"collectionExportName\\\":\\\"PlaceAssetCollectionCollection\\\",\\\"collectionOf\\\":\\\"@happyvertical/smrt-places:PlaceAsset\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"place_assets\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"place_assets\\\\\\\" (\\\\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 \\\\\\\"place_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"asset_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"relationship\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"sort_order\\\\\\\" INTEGER NOT NULL DEFAULT 0\\\\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},\\\"place_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"places\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"CASCADE\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"asset_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"relationship\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"sort_order\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":0}},\\\"indexes\\\":[{\\\"name\\\":\\\"place_assets_place_id_asset_id_idx\\\",\\\"columns\\\":[\\\"place_id\\\",\\\"asset_id\\\",\\\"relationship\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"place_assets_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"place_assets_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"place_assets_asset_id_idx\\\",\\\"columns\\\":[\\\"asset_id\\\"]}],\\\"version\\\":\\\"adf47666\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-places\\\"},\\\"@happyvertical/smrt-places:PlaceCollection\\\":{\\\"name\\\":\\\"placecollection\\\",\\\"className\\\":\\\"PlaceCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-places:PlaceCollection\\\",\\\"collection\\\":\\\"places\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/places/src/collections/PlaceCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"lookupOrCreate\\\":{\\\"name\\\":\\\"lookupOrCreate\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"query\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"LookupOrCreateOptions\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Place | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"discoverNearby\\\":{\\\"name\\\":\\\"discoverNearby\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"latitude\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"longitude\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"radiusMeters\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"DiscoverNearbyOptions\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"resolveTrackPlaces\\\":{\\\"name\\\":\\\"resolveTrackPlaces\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"points\\\",\\\"type\\\":\\\"ReadonlyArray<TrackPoint>\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"ResolveTrackPlacesOptions\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<TrackPlacesResult>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getChildren\\\":{\\\"name\\\":\\\"getChildren\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"parentId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getRootPlaces\\\":{\\\"name\\\":\\\"getRootPlaces\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getByType\\\":{\\\"name\\\":\\\"getByType\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"typeSlug\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getHierarchy\\\":{\\\"name\\\":\\\"getHierarchy\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"any\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAssets\\\":{\\\"name\\\":\\\"getAssets\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Asset[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"addAsset\\\":{\\\"name\\\":\\\"addAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"asset\\\",\\\"type\\\":\\\"Asset\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"default\\\":\\\"attachment\\\"},{\\\"name\\\":\\\"sortOrder\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"removeAsset\\\":{\\\"name\\\":\\\"removeAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"assetId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"searchByProximity\\\":{\\\"name\\\":\\\"searchByProximity\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"latitude\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"longitude\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"radiusKm\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByTenant\\\":{\\\"name\\\":\\\"findByTenant\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findGlobal\\\":{\\\"name\\\":\\\"findGlobal\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findWithGlobals\\\":{\\\"name\\\":\\\"findWithGlobals\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Place[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"Place\\\",\\\"exportName\\\":\\\"PlaceCollection\\\",\\\"collectionExportName\\\":\\\"PlaceCollectionCollection\\\",\\\"collectionOf\\\":\\\"@happyvertical/smrt-places:Place\\\",\\\"inheritedExposure\\\":[\\\"api\\\",\\\"mcp\\\"],\\\"schema\\\":{\\\"tableName\\\":\\\"places\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"places\\\\\\\" (\\\\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 \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"type_id\\\\\\\" UUID,\\\\n \\\\\\\"name\\\\\\\" TEXT,\\\\n \\\\\\\"description\\\\\\\" TEXT,\\\\n \\\\\\\"latitude\\\\\\\" REAL,\\\\n \\\\\\\"longitude\\\\\\\" REAL,\\\\n \\\\\\\"street_number\\\\\\\" TEXT,\\\\n \\\\\\\"street_name\\\\\\\" TEXT,\\\\n \\\\\\\"city\\\\\\\" TEXT,\\\\n \\\\\\\"region\\\\\\\" TEXT,\\\\n \\\\\\\"country\\\\\\\" TEXT,\\\\n \\\\\\\"postal_code\\\\\\\" TEXT,\\\\n \\\\\\\"country_code\\\\\\\" TEXT,\\\\n \\\\\\\"timezone\\\\\\\" TEXT,\\\\n \\\\\\\"external_id\\\\\\\" TEXT,\\\\n \\\\\\\"source\\\\\\\" TEXT,\\\\n \\\\\\\"metadata\\\\\\\" 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\\\"},\\\"parent_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"places\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false},\\\"type_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"place_types\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"latitude\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false},\\\"longitude\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false},\\\"street_number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"street_name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"city\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"region\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"country\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"postal_code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"country_code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"timezone\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"external_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"source\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"metadata\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"places_slug_context_meta_type_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\",\\\"_meta_type\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"places_meta_type_idx\\\",\\\"columns\\\":[\\\"_meta_type\\\"]},{\\\"name\\\":\\\"places_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"places_parent_id_idx\\\",\\\"columns\\\":[\\\"parent_id\\\"]},{\\\"name\\\":\\\"places_type_id_idx\\\",\\\"columns\\\":[\\\"type_id\\\"]}],\\\"version\\\":\\\"f670088c\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-places\\\"},\\\"@happyvertical/smrt-places:PlaceTypeCollection\\\":{\\\"name\\\":\\\"placetypecollection\\\",\\\"className\\\":\\\"PlaceTypeCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-places:PlaceTypeCollection\\\",\\\"collection\\\":\\\"placetypes\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/places/src/collections/PlaceTypeCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"getOrCreate\\\":{\\\"name\\\":\\\"getOrCreate\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"slug\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"name\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<PlaceType>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getBySlug\\\":{\\\"name\\\":\\\"getBySlug\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"slug\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<PlaceType | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"initializeDefaults\\\":{\\\"name\\\":\\\"initializeDefaults\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<PlaceType[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"PlaceType\\\",\\\"exportName\\\":\\\"PlaceTypeCollection\\\",\\\"collectionExportName\\\":\\\"PlaceTypeCollectionCollection\\\",\\\"collectionOf\\\":\\\"@happyvertical/smrt-places:PlaceType\\\",\\\"inheritedExposure\\\":[\\\"api\\\",\\\"mcp\\\"],\\\"schema\\\":{\\\"tableName\\\":\\\"place_types\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"place_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 DEFAULT '',\\\\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,\\\"default\\\":\\\"\\\"},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"place_types_slug_context_meta_type_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\",\\\"_meta_type\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"place_types_meta_type_idx\\\",\\\"columns\\\":[\\\"_meta_type\\\"]},{\\\"name\\\":\\\"place_types_created_at_idx\\\",\\\"columns\\\":[\\\"created_at\\\"]}],\\\"version\\\":\\\"8c3bb691\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-places\\\"},\\\"@happyvertical/smrt-places:Place\\\":{\\\"name\\\":\\\"place\\\",\\\"className\\\":\\\"Place\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-places:Place\\\",\\\"collection\\\":\\\"places\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/places/src/models/Place.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"fields\\\":{\\\"created_at\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"updated_at\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"parentId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"Place\\\",\\\"_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}}},\\\"typeId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"PlaceType\\\",\\\"description\\\":\\\"What kind of place this is, such as a building, a room or a storage zone.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What kind of place this is, such as a building, a room or a storage zone.\\\"}},\\\"name\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"What the place is called, such as \\\\\\\"Main warehouse\\\\\\\" or \\\\\\\"Aisle 4\\\\\\\".\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What the place is called, such as \\\\\\\"Main warehouse\\\\\\\" or \\\\\\\"Aisle 4\\\\\\\".\\\"}},\\\"description\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"A few words about the place and what happens there.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"A few words about the place and what happens there.\\\"}},\\\"latitude\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"description\\\":\\\"How far north or south the place is on a map. Leave empty for a place that is not on a map.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"How far north or south the place is on a map. Leave empty for a place that is not on a map.\\\"}},\\\"longitude\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"description\\\":\\\"How far east or west the place is on a map. Leave empty for a place that is not on a map.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"How far east or west the place is on a map. Leave empty for a place that is not on a map.\\\"}},\\\"streetNumber\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The number of the building on its street.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The number of the building on its street.\\\"}},\\\"streetName\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The name of the street the place is on.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The name of the street the place is on.\\\"}},\\\"city\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The town or city the place is in.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The town or city the place is in.\\\"}},\\\"region\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The state, province or region the place is in.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The state, province or region the place is in.\\\"}},\\\"country\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The country the place is in.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The country the place is in.\\\"}},\\\"postalCode\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The postal or zip code of the address.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The postal or zip code of the address.\\\"}},\\\"countryCode\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The short two-letter code for the country, such as CA or US.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The short two-letter code for the country, such as CA or US.\\\"}},\\\"timezone\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The time zone the place keeps, such as America/Toronto.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The time zone the place keeps, such as America/Toronto.\\\"}},\\\"externalId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The reference the map provider uses for this place, filled in when the app looks it up.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The reference the map provider uses for this place, filled in when the app looks it up.\\\"}},\\\"source\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"Which map provider the place was looked up from, if any.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Which map provider the place was looked up from, if any.\\\"}},\\\"metadata\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"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},\\\"getGeoData\\\":{\\\"name\\\":\\\"getGeoData\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"GeoData\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"hasCoordinates\\\":{\\\"name\\\":\\\"hasCoordinates\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"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\\\":\\\"data\\\",\\\"type\\\":\\\"Record<string, unknown>\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"void\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"updateMetadata\\\":{\\\"name\\\":\\\"updateMetadata\\\",\\\"async\\\":false,\\\"parameters\\\":[{\\\"name\\\":\\\"updates\\\",\\\"type\\\":\\\"Record<string, unknown>\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"void\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getType\\\":{\\\"name\\\":\\\"getType\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"any\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAssets\\\":{\\\"name\\\":\\\"getAssets\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Asset[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"addAsset\\\":{\\\"name\\\":\\\"addAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"asset\\\",\\\"type\\\":\\\"Asset\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"default\\\":\\\"attachment\\\"},{\\\"name\\\":\\\"sortOrder\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getMainAsset\\\":{\\\"name\\\":\\\"getMainAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Asset | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"setMainAsset\\\":{\\\"name\\\":\\\"setMainAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"asset\\\",\\\"type\\\":\\\"Asset | null\\\",\\\"optional\\\":false,\\\"unionBranches\\\":[{\\\"type\\\":\\\"Asset\\\"},{\\\"type\\\":\\\"null\\\"}]}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"removeAsset\\\":{\\\"name\\\":\\\"removeAsset\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"assetId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"relationship\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"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\\\":\\\"Place\\\",\\\"collectionExportName\\\":\\\"PlaceCollection\\\",\\\"displayLabelField\\\":\\\"name\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"places\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"places\\\\\\\" (\\\\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 \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"type_id\\\\\\\" UUID,\\\\n \\\\\\\"name\\\\\\\" TEXT,\\\\n \\\\\\\"description\\\\\\\" TEXT,\\\\n \\\\\\\"latitude\\\\\\\" REAL,\\\\n \\\\\\\"longitude\\\\\\\" REAL,\\\\n \\\\\\\"street_number\\\\\\\" TEXT,\\\\n \\\\\\\"street_name\\\\\\\" TEXT,\\\\n \\\\\\\"city\\\\\\\" TEXT,\\\\n \\\\\\\"region\\\\\\\" TEXT,\\\\n \\\\\\\"country\\\\\\\" TEXT,\\\\n \\\\\\\"postal_code\\\\\\\" TEXT,\\\\n \\\\\\\"country_code\\\\\\\" TEXT,\\\\n \\\\\\\"timezone\\\\\\\" TEXT,\\\\n \\\\\\\"external_id\\\\\\\" TEXT,\\\\n \\\\\\\"source\\\\\\\" TEXT,\\\\n \\\\\\\"metadata\\\\\\\" 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\\\"},\\\"parent_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"places\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false},\\\"type_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"place_types\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"latitude\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false},\\\"longitude\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false},\\\"street_number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"street_name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"city\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"region\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"country\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"postal_code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"country_code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"timezone\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"external_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"source\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false},\\\"metadata\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"places_slug_context_meta_type_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\",\\\"_meta_type\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"places_meta_type_idx\\\",\\\"columns\\\":[\\\"_meta_type\\\"]},{\\\"name\\\":\\\"places_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"places_parent_id_idx\\\",\\\"columns\\\":[\\\"parent_id\\\"]},{\\\"name\\\":\\\"places_type_id_idx\\\",\\\"columns\\\":[\\\"type_id\\\"]}],\\\"version\\\":\\\"f670088c\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-places\\\"},\\\"@happyvertical/smrt-places:PlaceAsset\\\":{\\\"name\\\":\\\"placeasset\\\",\\\"className\\\":\\\"PlaceAsset\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-places:PlaceAsset\\\",\\\"collection\\\":\\\"placeassets\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/places/src/models/PlaceAsset.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"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}}},\\\"placeId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":true,\\\"related\\\":\\\"Place\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"onDelete\\\":\\\"CASCADE\\\"}},\\\"assetId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":true,\\\"related\\\":\\\"@happyvertical/smrt-assets:Asset\\\",\\\"_meta\\\":{\\\"onDelete\\\":\\\"CASCADE\\\"}},\\\"relationship\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"sortOrder\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":true,\\\"default\\\":0}},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"place_assets\\\",\\\"conflictColumns\\\":[\\\"place_id\\\",\\\"asset_id\\\",\\\"relationship\\\"],\\\"api\\\":false,\\\"mcp\\\":false,\\\"cli\\\":false,\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"PlaceAsset\\\",\\\"collectionExportName\\\":\\\"PlaceAssetCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"placeId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"foreignKey\\\"},{\\\"field\\\":\\\"assetId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"crossPackageRef\\\"},{\\\"field\\\":\\\"relationship\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"sortOrder\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"integer\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"place_assets\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"place_assets\\\\\\\" (\\\\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 \\\\\\\"place_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"asset_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"relationship\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"sort_order\\\\\\\" INTEGER NOT NULL DEFAULT 0\\\\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},\\\"place_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"places\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"CASCADE\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"asset_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"relationship\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"sort_order\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":0}},\\\"indexes\\\":[{\\\"name\\\":\\\"place_assets_place_id_asset_id_idx\\\",\\\"columns\\\":[\\\"place_id\\\",\\\"asset_id\\\",\\\"relationship\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"place_assets_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"place_assets_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"place_assets_asset_id_idx\\\",\\\"columns\\\":[\\\"asset_id\\\"]}],\\\"version\\\":\\\"adf47666\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-places\\\"},\\\"@happyvertical/smrt-places:PlaceType\\\":{\\\"name\\\":\\\"placetype\\\",\\\"className\\\":\\\"PlaceType\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-places:PlaceType\\\",\\\"collection\\\":\\\"placetypes\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/places/src/models/PlaceType.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-places\\\",\\\"fields\\\":{\\\"created_at\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"updated_at\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"name\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The name of the kind of place, such as \\\\\\\"Building\\\\\\\", \\\\\\\"Room\\\\\\\" or \\\\\\\"Zone\\\\\\\".\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"The name of the kind of place, such as \\\\\\\"Building\\\\\\\", \\\\\\\"Room\\\\\\\" or \\\\\\\"Zone\\\\\\\".\\\"}},\\\"description\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"A few words about when to use this kind of place.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"A few words about when to use this kind of place.\\\"}},\\\"createdAt\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"updatedAt\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false}},\\\"methods\\\":{\\\"getBySlug\\\":{\\\"name\\\":\\\"getBySlug\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"_slug\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<PlaceType | 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\\\":\\\"PlaceType\\\",\\\"collectionExportName\\\":\\\"PlaceTypeCollection\\\",\\\"displayLabelField\\\":\\\"name\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"name\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"place_types\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"place_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 DEFAULT '',\\\\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,\\\"default\\\":\\\"\\\"},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"place_types_slug_context_meta_type_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\",\\\"_meta_type\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"place_types_meta_type_idx\\\",\\\"columns\\\":[\\\"_meta_type\\\"]},{\\\"name\\\":\\\"place_types_created_at_idx\\\",\\\"columns\\\":[\\\"created_at\\\"]}],\\\"version\\\":\\\"8c3bb691\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-places\\\"}},\\\"moduleType\\\":\\\"smrt\\\",\\\"recipes\\\":[{\\\"id\\\":\\\"places.locations\\\",\\\"className\\\":\\\"PlacesLocationsRecipe\\\",\\\"label\\\":\\\"Places\\\",\\\"summary\\\":\\\"Keep a list of the places your work happens, such as sites, buildings, rooms and storage zones, one inside another.\\\",\\\"synonyms\\\":[\\\"places\\\",\\\"locations\\\",\\\"sites\\\",\\\"buildings\\\",\\\"rooms\\\",\\\"addresses\\\",\\\"warehouses\\\"],\\\"models\\\":[\\\"@happyvertical/smrt-places:Place\\\",\\\"@happyvertical/smrt-places:PlaceType\\\"],\\\"nav\\\":[{\\\"label\\\":\\\"Places\\\",\\\"model\\\":\\\"@happyvertical/smrt-places:Place\\\",\\\"icon\\\":\\\"home\\\",\\\"description\\\":\\\"Every site, building, room and zone, with its address and what it is inside.\\\",\\\"noun\\\":\\\"place\\\"},{\\\"label\\\":\\\"Place types\\\",\\\"model\\\":\\\"@happyvertical/smrt-places:PlaceType\\\",\\\"icon\\\":\\\"tag\\\",\\\"description\\\":\\\"The kinds of place you keep, such as building or room.\\\",\\\"noun\\\":\\\"place type\\\"}],\\\"requires\\\":[],\\\"section\\\":{\\\"id\\\":\\\"places\\\",\\\"label\\\":\\\"Locations\\\",\\\"icon\\\":\\\"home\\\",\\\"description\\\":\\\"The places your work happens.\\\"},\\\"options\\\":{\\\"@happyvertical/smrt-places:Place\\\":{\\\"fields\\\":{\\\"name\\\":{\\\"order\\\":1},\\\"typeId\\\":{\\\"label\\\":\\\"Type\\\",\\\"order\\\":2},\\\"parentId\\\":{\\\"label\\\":\\\"Inside\\\",\\\"help\\\":\\\"The larger place this one is part of, such as the building a room is in.\\\",\\\"order\\\":3},\\\"description\\\":{\\\"order\\\":4},\\\"streetNumber\\\":{\\\"label\\\":\\\"Street number\\\",\\\"order\\\":5},\\\"streetName\\\":{\\\"label\\\":\\\"Street name\\\",\\\"order\\\":6},\\\"city\\\":{\\\"order\\\":7},\\\"region\\\":{\\\"order\\\":8},\\\"country\\\":{\\\"order\\\":9},\\\"postalCode\\\":{\\\"label\\\":\\\"Postal code\\\",\\\"order\\\":10},\\\"latitude\\\":{\\\"visibility\\\":\\\"advanced\\\"},\\\"longitude\\\":{\\\"visibility\\\":\\\"advanced\\\"},\\\"countryCode\\\":{\\\"label\\\":\\\"Country code\\\",\\\"visibility\\\":\\\"advanced\\\"},\\\"timezone\\\":{\\\"label\\\":\\\"Time zone\\\",\\\"visibility\\\":\\\"advanced\\\"},\\\"externalId\\\":{\\\"label\\\":\\\"Map reference\\\",\\\"visibility\\\":\\\"advanced\\\"},\\\"source\\\":{\\\"label\\\":\\\"Map provider\\\",\\\"visibility\\\":\\\"advanced\\\"},\\\"metadata\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"tenantId\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"createdAt\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"updatedAt\\\":{\\\"visibility\\\":\\\"hidden\\\"}}},\\\"@happyvertical/smrt-places:PlaceType\\\":{\\\"fields\\\":{\\\"name\\\":{\\\"order\\\":1},\\\"description\\\":{\\\"order\\\":2},\\\"createdAt\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"updatedAt\\\":{\\\"visibility\\\":\\\"hidden\\\"}}}},\\\"help\\\":{\\\"markdown\\\":\\\"## Overview\\\\n\\\\nPlaces is where you keep the sites, buildings, rooms and storage zones your\\\\nwork happens in. Each place has a name, a type and, when it is somewhere real,\\\\nan address. A place can sit inside a larger one, so a room belongs to a\\\\nbuilding and a shelf to a room, and you can follow that chain either way. A\\\\nplace does not have to be on a map: a storage zone or a work area with no\\\\naddress is fine.\\\\n\\\\n## Tasks\\\\n\\\\n### Add a place\\\\n\\\\n1. Open the list of places and choose **New**.\\\\n2. Type the **{field:Place.name}**, for example \\\\\\\"Main warehouse\\\\\\\".\\\\n3. Pick its **{field:Place.typeId}**, such as building or room. Add a type first if the one you need is missing.\\\\n4. Fill in the address: the **{field:Place.streetNumber}**, **{field:Place.streetName}**, **{field:Place.city}**, **{field:Place.region}**, **{field:Place.country}** and **{field:Place.postalCode}**. Leave these empty for a place that is not on a map.\\\\n5. Save. When your app searches a map for a place, it can add the place for you with the address filled in from the map provider.\\\\n\\\\n### Put a place inside another\\\\n\\\\n1. Open the place and choose to edit it.\\\\n2. In **{field:Place.parentId}**, pick the larger place it belongs to, such as the building a room is in.\\\\n3. Save. The place now shows up under the one you chose.\\\\n\\\\n### Change or remove a place\\\\n\\\\n1. Open the place and choose to edit it.\\\\n2. Change the **{field:Place.name}**, **{field:Place.description}** or address, then save.\\\\n3. To remove a place you no longer use, open it and choose to delete it. Move anything inside it first.\\\\n\\\\n### Add a place type\\\\n\\\\n1. Open the list of place types and choose **New**.\\\\n2. Type the **{field:PlaceType.name}**, for example \\\\\\\"Room\\\\\\\".\\\\n3. Add a **{field:PlaceType.description}** so others know when to use it.\\\\n4. Save. The type can now be picked when you add a place.\\\\n\\\",\\\"fieldRefs\\\":[\\\"Place.city\\\",\\\"Place.country\\\",\\\"Place.description\\\",\\\"Place.name\\\",\\\"Place.parentId\\\",\\\"Place.postalCode\\\",\\\"Place.region\\\",\\\"Place.streetName\\\",\\\"Place.streetNumber\\\",\\\"Place.typeId\\\",\\\"PlaceType.description\\\",\\\"PlaceType.name\\\"]},\\\"demo\\\":{\\\"mode\\\":\\\"server\\\",\\\"reasons\\\":[\\\"Needs a server because its package does not build for a browser: geo -> cache -> redis, node:zlib; url-signature node:crypto; and its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624, #3627).\\\"]}}],\\\"smrtDependencies\\\":[\\\"@happyvertical/smrt-assets\\\",\\\"@happyvertical/smrt-core\\\",\\\"@happyvertical/smrt-tenancy\\\"],\\\"browser\\\":{\\\"status\\\":\\\"server-only\\\",\\\"issues\\\":[\\\"#3624\\\",\\\"#3627\\\"],\\\"reason\\\":\\\"geo -> cache -> redis, node:zlib; url-signature node:crypto\\\",\\\"via\\\":[\\\"@happyvertical/smrt-tenancy\\\"]},\\\"stampsConstructors\\\":true}\"));\n","import type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\nexport interface PlaceAssetOptions extends SmrtObjectOptions {\n placeId?: string;\n assetId?: string;\n relationship?: string;\n sortOrder?: number;\n tenantId?: string | null;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'place_assets',\n conflictColumns: ['place_id', 'asset_id', 'relationship'],\n api: false,\n mcp: false,\n cli: false,\n})\nexport class PlaceAsset extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-places\";\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey('Place', { required: true, onDelete: 'CASCADE' })\n placeId = '';\n\n @crossPackageRef('@happyvertical/smrt-assets:Asset', {\n required: true,\n onDelete: 'CASCADE',\n })\n assetId = '';\n\n @field({ required: true })\n relationship = 'attachment';\n\n @field()\n sortOrder = 0;\n\n constructor(options: PlaceAssetOptions = {}) {\n super(options);\n if (options.placeId) this.placeId = options.placeId;\n if (options.assetId) this.assetId = options.assetId;\n if (options.relationship) this.relationship = options.relationship;\n if (options.sortOrder !== undefined) this.sortOrder = options.sortOrder;\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n }\n}\n","import type { Asset } from '@happyvertical/smrt-assets';\nimport {\n addOwnedAssetFromCollection,\n getOwnedAssetsFromCollection,\n removeOwnedAssetFromCollection,\n} from '@happyvertical/smrt-assets';\nimport type { SmrtCollectionOptions } from '@happyvertical/smrt-core';\nimport { SmrtJunction, smrt } from '@happyvertical/smrt-core';\nimport { PlaceAsset } from '../models/PlaceAsset';\nimport type { PlaceCollection } from './PlaceCollection';\n\nexport interface PlaceAssetCollectionOptions extends SmrtCollectionOptions {}\n\n@smrt({\n api: false,\n mcp: false,\n cli: false,\n})\nexport class PlaceAssetCollection extends SmrtJunction<PlaceAsset> { static __smrtPackage__ = \"@happyvertical/smrt-places\";\n static readonly _itemClass = PlaceAsset;\n protected leftField = 'placeId';\n protected rightField = 'assetId';\n\n private placeCollectionPromise: Promise<PlaceCollection> | null = null;\n\n private async getPlaceCollection(): Promise<PlaceCollection> {\n if (!this.placeCollectionPromise) {\n const { PlaceCollection } = await import('./PlaceCollection');\n this.placeCollectionPromise = PlaceCollection.create({ db: this.db });\n }\n\n return this.placeCollectionPromise;\n }\n\n async getAssets(placeId: string, relationship?: string): Promise<Asset[]> {\n return getOwnedAssetsFromCollection(\n await this.getPlaceCollection(),\n placeId,\n relationship,\n );\n }\n\n async addAsset(\n placeId: string,\n asset: Asset,\n relationship = 'attachment',\n sortOrder = 0,\n ): Promise<void> {\n await addOwnedAssetFromCollection(\n await this.getPlaceCollection(),\n 'Place',\n placeId,\n asset,\n relationship,\n sortOrder,\n );\n }\n\n async removeAsset(\n placeId: string,\n assetId: string,\n relationship?: string,\n ): Promise<void> {\n await removeOwnedAssetFromCollection(\n await this.getPlaceCollection(),\n 'Place',\n placeId,\n assetId,\n relationship,\n );\n }\n}\n","/**\n * Place model - Core entity for hierarchical place management\n *\n * Supports both real-world places with geo data and abstract places\n * (virtual worlds, game zones) by making all geo fields optional.\n *\n * Tenancy: Places are tenant-scoped with optional mode, allowing:\n * - Tenant-specific places (tenantId set)\n * - Global/shared places (tenantId null)\n */\n\nimport type { Asset } from '@happyvertical/smrt-assets';\nimport {\n assertAssetLinkable,\n assertValidOwnedAssetRelationship,\n assertValidOwnedAssetSortOrder,\n resolveOwnedAssetsById,\n} from '@happyvertical/smrt-assets';\nimport {\n field,\n foreignKey,\n SmrtHierarchical,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { GeoData, PlaceOptions } from '../types';\n\n/** `place_assets.relationship` of a place's main picture. */\nexport const PLACE_MAIN_ASSET_RELATIONSHIP = 'hero';\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableStrategy: 'sti',\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n mcp: { include: ['list', 'get', 'create', 'update'] },\n cli: { skipApiCheck: true },\n})\nexport class Place extends SmrtHierarchical { static __smrtPackage__ = \"@happyvertical/smrt-places\";\n // id: UUID (auto-generated by SmrtObject)\n\n // Tenancy field - nullable for global/shared places\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n // Core fields\n @field({\n description:\n 'What kind of place this is, such as a building, a room or a storage zone.',\n })\n @foreignKey('PlaceType')\n typeId = ''; // FK to PlaceType\n // parentId inherited from SmrtHierarchical (nullable, self-reference)\n @field({\n description:\n 'What the place is called, such as \"Main warehouse\" or \"Aisle 4\".',\n })\n name = ''; // Place name/title\n @field({ description: 'A few words about the place and what happens there.' })\n description = ''; // Optional description\n\n // Optional geo fields (all nullable for abstract places)\n @field({\n type: 'decimal',\n description:\n 'How far north or south the place is on a map. Leave empty for a place that is not on a map.',\n })\n latitude: number | null = null;\n @field({\n type: 'decimal',\n description:\n 'How far east or west the place is on a map. Leave empty for a place that is not on a map.',\n })\n longitude: number | null = null;\n @field({ description: 'The number of the building on its street.' })\n streetNumber = '';\n @field({ description: 'The name of the street the place is on.' })\n streetName = '';\n @field({ description: 'The town or city the place is in.' })\n city = '';\n @field({ description: 'The state, province or region the place is in.' })\n region = '';\n @field({ description: 'The country the place is in.' })\n country = '';\n @field({ description: 'The postal or zip code of the address.' })\n postalCode = '';\n @field({\n description: 'The short two-letter code for the country, such as CA or US.',\n })\n countryCode = '';\n @field({\n description: 'The time zone the place keeps, such as America/Toronto.',\n })\n timezone = '';\n\n // Metadata\n @field({\n description:\n 'The reference the map provider uses for this place, filled in when the app looks it up.',\n })\n externalId = ''; // External system identifier\n @field({\n description: 'Which map provider the place was looked up from, if any.',\n })\n source = ''; // Where this place came from (e.g., 'google', 'osm')\n metadata = ''; // JSON metadata stored as text\n\n // Timestamps\n createdAt = new Date();\n updatedAt = new Date();\n\n constructor(options: PlaceOptions = {}) {\n super(options);\n\n // Tenancy field\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n\n // Core fields\n if (options.typeId) this.typeId = options.typeId;\n if (options.parentId !== undefined)\n this.parentId = options.parentId ?? null;\n if (options.name) this.name = options.name;\n if (options.description !== undefined)\n this.description = options.description;\n\n // Geo fields\n if (options.latitude !== undefined) this.latitude = options.latitude;\n if (options.longitude !== undefined) this.longitude = options.longitude;\n if (options.streetNumber !== undefined)\n this.streetNumber = options.streetNumber;\n if (options.streetName !== undefined) this.streetName = options.streetName;\n if (options.city !== undefined) this.city = options.city;\n if (options.region !== undefined) this.region = options.region;\n if (options.country !== undefined) this.country = options.country;\n if (options.postalCode !== undefined) this.postalCode = options.postalCode;\n if (options.countryCode !== undefined)\n this.countryCode = options.countryCode;\n if (options.timezone !== undefined) this.timezone = options.timezone;\n\n // Metadata\n if (options.externalId !== undefined) this.externalId = options.externalId;\n if (options.source !== undefined) this.source = options.source;\n\n // Handle metadata - can be object or JSON string\n if (options.metadata !== undefined) {\n if (typeof options.metadata === 'string') {\n this.metadata = options.metadata;\n } else {\n this.metadata = JSON.stringify(options.metadata);\n }\n }\n\n // Timestamps\n if (options.createdAt) this.createdAt = options.createdAt;\n if (options.updatedAt) this.updatedAt = options.updatedAt;\n }\n\n /**\n * Get geographic data for this place\n *\n * @returns GeoData object with all geo fields\n */\n getGeoData(): GeoData {\n return {\n latitude: this.latitude,\n longitude: this.longitude,\n streetNumber: this.streetNumber || undefined,\n streetName: this.streetName || undefined,\n city: this.city || undefined,\n region: this.region || undefined,\n country: this.country || undefined,\n postalCode: this.postalCode || undefined,\n countryCode: this.countryCode || undefined,\n timezone: this.timezone || undefined,\n };\n }\n\n /**\n * Check if this place has geographic coordinates\n *\n * @returns True if latitude and longitude are set\n */\n hasCoordinates(): boolean {\n return this.latitude !== null && this.longitude !== null;\n }\n\n /**\n * Get metadata as parsed object\n *\n * @returns Parsed metadata object or empty object if no metadata\n */\n getMetadata(): Record<string, unknown> {\n if (!this.metadata) return {};\n try {\n return JSON.parse(this.metadata);\n } catch {\n return {};\n }\n }\n\n /**\n * Set metadata from object\n *\n * @param data - Metadata object to store\n */\n setMetadata(data: Record<string, unknown>): void {\n this.metadata = JSON.stringify(data);\n }\n\n /**\n * Update metadata by merging with existing values\n *\n * @param updates - Partial metadata to merge\n */\n updateMetadata(updates: Record<string, unknown>): void {\n const current = this.getMetadata();\n this.setMetadata({ ...current, ...updates });\n }\n\n /**\n * Get the place type\n *\n * @returns PlaceType instance or null if not found\n */\n async getType() {\n if (!this.typeId) return null;\n\n const { PlaceTypeCollection } = await import(\n '../collections/PlaceTypeCollection'\n );\n const collection = await PlaceTypeCollection.create(this.options);\n\n return await collection.get({ id: this.typeId });\n }\n\n // Hierarchy traversal (getParent / getChildren / getAncestors /\n // getDescendants / getHierarchy / moveTo) provided by SmrtHierarchical.\n\n private async getPlaceAssetCollection() {\n const { PlaceAssetCollection } = await import(\n '../collections/PlaceAssetCollection'\n );\n return PlaceAssetCollection.create({ db: this.db });\n }\n async getAssets(relationship?: string): Promise<Asset[]> {\n if (!this.id) {\n return [];\n }\n\n const placeAssets = await this.getPlaceAssetCollection();\n const linkedAssets = await placeAssets.byLeft(\n this.id,\n relationship ? { relationship } : {},\n );\n\n return resolveOwnedAssetsById(\n this.db,\n linkedAssets.map((link) => link.assetId),\n this.tenantId,\n );\n }\n\n async addAsset(\n asset: Asset,\n relationship = 'attachment',\n sortOrder = 0,\n ): Promise<void> {\n if (!this.id || !asset.id) {\n throw new Error('Cannot associate unsaved place or asset');\n }\n // The asset's tenant comes from storage, not from the caller's object.\n await assertAssetLinkable(this.db, asset.id, this.tenantId, 'place');\n\n assertValidOwnedAssetRelationship(relationship);\n assertValidOwnedAssetSortOrder(sortOrder);\n\n const placeAssets = await this.getPlaceAssetCollection();\n await placeAssets.attach(this.id, asset.id, {\n relationship,\n sortOrder,\n tenantId: this.tenantId,\n });\n }\n\n /**\n * The place's main picture: its `hero` asset (see `ASSET_ROLES.HERO`), or\n * null when none is set.\n */\n async getMainAsset(): Promise<Asset | null> {\n const [main] = await this.getAssets(PLACE_MAIN_ASSET_RELATIONSHIP);\n return main ?? null;\n }\n\n /**\n * Make `asset` the place's one main picture: it becomes the only `hero`\n * link (any other is removed). Pass `null` to clear the main picture.\n * Other links of the asset (e.g. `depicts`) are left alone.\n */\n async setMainAsset(asset: Asset | null): Promise<void> {\n if (!this.id) {\n throw new Error('Cannot set the main asset of an unsaved place');\n }\n const placeAssets = await this.getPlaceAssetCollection();\n const current = await placeAssets.byLeft(this.id, {\n relationship: PLACE_MAIN_ASSET_RELATIONSHIP,\n });\n if (asset) await this.addAsset(asset, PLACE_MAIN_ASSET_RELATIONSHIP, 0);\n for (const link of current) {\n if (asset && link.assetId === asset.id) continue;\n await placeAssets.detach(this.id, link.assetId, {\n relationship: PLACE_MAIN_ASSET_RELATIONSHIP,\n });\n }\n }\n\n async removeAsset(assetId: string, relationship?: string): Promise<void> {\n if (!this.id) {\n return;\n }\n\n const placeAssets = await this.getPlaceAssetCollection();\n await placeAssets.detach(\n this.id,\n assetId,\n relationship ? { relationship } : {},\n );\n }\n}\n","/**\n * PlaceCollection - Collection manager for Place objects\n *\n * Provides hierarchy traversal and organic place database growth via\n * lookupOrCreate method that integrates with @happyvertical/geo.\n */\n\nimport type { GeoAdapter, Location } from '@happyvertical/geo';\nimport { getGeoAdapter } from '@happyvertical/geo';\nimport type { Asset } from '@happyvertical/smrt-assets';\nimport {\n addOwnedAssetFromCollection,\n getOwnedAssetsFromCollection,\n removeOwnedAssetFromCollection,\n} from '@happyvertical/smrt-assets';\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { Place } from '../models/Place';\nimport type {\n DiscoverNearbyOptions,\n LookupOrCreateOptions,\n ResolveTrackPlacesOptions,\n TrackPlacesResult,\n TrackPoint,\n} from '../types';\nimport { PlaceTypeCollection } from './PlaceTypeCollection';\n\ntype PoiSearchOptions = Pick<\n DiscoverNearbyOptions,\n 'types' | 'keyword' | 'limit' | 'language'\n>;\n\ntype GeoAdapterWithPoiSearch = GeoAdapter & {\n findPoisNear?: (\n latitude: number,\n longitude: number,\n radiusMeters: number,\n options?: PoiSearchOptions,\n ) => Promise<Location[]>;\n};\n\nexport class PlaceCollection extends SmrtCollection<Place> {\n static readonly _itemClass = Place;\n\n /**\n * Look up a place by query or coordinates, creating it if not found\n *\n * This is the key method for organic database growth:\n * 1. Search local database first\n * 2. If not found, query @happyvertical/geo\n * 3. Create place from geocoding result\n * 4. Return place\n *\n * @param query - Address or location query string\n * @param options - Lookup options (provider, type, parent, etc.)\n * @returns Place instance\n */\n async lookupOrCreate(\n query: string,\n options: LookupOrCreateOptions = {},\n ): Promise<Place | null> {\n const {\n geoProvider = 'openstreetmap',\n typeSlug,\n parentId,\n createIfNotFound = true,\n coords,\n } = options;\n\n // Step 1: Try to find existing place\n let existingPlace: Place | null = null;\n\n // Search by coordinates if provided\n if (coords) {\n existingPlace = await this.findByCoordinates(coords.lat, coords.lng);\n }\n\n // Search by query text if coordinates didn't match\n if (!existingPlace) {\n existingPlace = await this.findByQuery(query);\n }\n\n if (existingPlace) {\n return existingPlace;\n }\n\n // Step 2: If not found and createIfNotFound is false, return null\n if (!createIfNotFound) {\n return null;\n }\n\n // Step 3: Query @happyvertical/geo for location data\n const locations = await this.geocode(\n query,\n coords,\n geoProvider as 'google' | 'openstreetmap',\n );\n\n if (locations.length === 0) {\n return null;\n }\n\n // Use first result (most relevant)\n const location = locations[0];\n\n // Step 4: Create place from location data\n return await this.createFromLocation(location, typeSlug, parentId);\n }\n\n /**\n * Find place by coordinates (within small threshold)\n *\n * @param latitude - Latitude to search\n * @param longitude - Longitude to search\n * @param threshold - Max distance in degrees (default: 0.0001 ~11m)\n * @returns Place instance or null\n */\n private async findByCoordinates(\n latitude: number,\n longitude: number,\n threshold: number = 0.0001,\n ): Promise<Place | null> {\n // Get all places with coordinates\n const places = await this.list({\n where: {\n latitude: { $ne: null },\n longitude: { $ne: null },\n },\n });\n\n // Find closest match within threshold\n for (const place of places) {\n // Cast to access Place-specific properties\n const placeObj = place as Place;\n if (placeObj.latitude === null || placeObj.longitude === null) continue;\n\n const latDiff = Math.abs(placeObj.latitude - latitude);\n const lngDiff = Math.abs(placeObj.longitude - longitude);\n\n if (latDiff < threshold && lngDiff < threshold) {\n return place;\n }\n }\n\n return null;\n }\n\n /**\n * Find place by query text (matches name, city, region, country)\n *\n * @param query - Search query\n * @returns Place instance or null\n */\n private async findByQuery(query: string): Promise<Place | null> {\n const normalizedQuery = query.toLowerCase().trim();\n\n // Try exact match on name first\n const places = await this.list({});\n\n for (const place of places) {\n // Match on name\n if (place.name.toLowerCase().includes(normalizedQuery)) {\n return place;\n }\n\n // Match on full address components\n const addressParts = [\n place.streetNumber,\n place.streetName,\n place.city,\n place.region,\n place.country,\n ]\n .filter((p) => p)\n .join(' ')\n .toLowerCase();\n\n if (addressParts.includes(normalizedQuery)) {\n return place;\n }\n }\n\n return null;\n }\n\n /**\n * Geocode query or coordinates using @happyvertical/geo\n *\n * @param query - Address query\n * @param coords - Optional coordinates for reverse geocoding\n * @param provider - Geo provider to use\n * @returns Array of Location results\n */\n private async geocode(\n query: string,\n coords?: { lat: number; lng: number },\n provider: 'google' | 'openstreetmap' = 'openstreetmap',\n ): Promise<Location[]> {\n const geo = await this.getGeoAdapter(provider);\n\n // Use reverse geocode if coords provided, otherwise forward geocode\n if (coords) {\n return await geo.reverseGeocode(coords.lat, coords.lng);\n }\n\n return await geo.lookup(query);\n }\n\n /**\n * Find a place by the provider's native id (Google place_id, OSM\n * osm-node-N, etc.). Used as the primary idempotency key by\n * `discoverNearby` so repeat POI searches don't create duplicate rows.\n */\n private async findByExternalId(externalId: string): Promise<Place | null> {\n if (!externalId) return null;\n const matches = await this.list({\n where: { externalId },\n limit: 1,\n });\n return matches[0] ?? null;\n }\n\n /**\n * Idempotent \"find or create\" for a geo Location. Keyed purely on the\n * provider's externalId (Google place_id, osm-node-*, etc.), which is\n * stable per POI across repeat searches. The older `lookupOrCreate`\n * keeps its own fallback chain (name/address/coordinate matching) for\n * address-style workflows where externalId isn't reliable.\n *\n * Returns `{ place, created }` so callers can distinguish fresh rows\n * from reused ones without re-querying the table — this is how\n * `resolveTrackPlaces` derives its `cacheHitCount` without a full\n * scan per bucket.\n */\n private async ensureFromLocation(\n location: Location,\n typeSlug?: string,\n parentId?: string | null,\n ): Promise<{ place: Place; created: boolean }> {\n if (location.id) {\n const existing = await this.findByExternalId(location.id);\n if (existing) return { place: existing, created: false };\n }\n const place = await this.createFromLocation(location, typeSlug, parentId);\n return { place, created: true };\n }\n\n /**\n * Create place from @happyvertical/geo Location data\n *\n * @param location - Location from geocoding\n * @param typeSlug - Optional type slug override\n * @param parentId - Optional parent place ID\n * @returns Created Place instance\n */\n private async createFromLocation(\n location: Location,\n typeSlug?: string,\n parentId?: string | null,\n ): Promise<Place> {\n // Get or create place type\n const typeCollection = await PlaceTypeCollection.create(this.options);\n\n const slug = typeSlug || location.type || 'address';\n const placeType = await typeCollection.getOrCreate(slug);\n\n // Extract address components\n const components = location.addressComponents || {};\n\n // Create place\n return await this.create({\n typeId: placeType.id ?? undefined,\n parentId: parentId ?? null,\n name: location.name,\n description: '',\n\n // Geo fields from location\n latitude: location.latitude,\n longitude: location.longitude,\n streetNumber: components.streetNumber || '',\n streetName: components.streetName || '',\n city: components.city || '',\n region: components.region || '',\n country: components.country || '',\n postalCode: components.postalCode || '',\n countryCode: location.countryCode || '',\n timezone: location.timezone || '',\n\n // Metadata\n externalId: location.id,\n source: location.raw?.provider || 'unknown',\n metadata: JSON.stringify({ raw: location.raw ?? null }),\n });\n }\n\n /**\n * Discover POIs near a coordinate and persist them as Place rows.\n *\n * Composes `@happyvertical/geo`'s `findPoisNear` with `ensureFromLocation`\n * so every returned POI is either reused from the local DB (when the\n * provider returns an id matching an existing Place `externalId`) or\n * created fresh otherwise. The cache is effectively automatic because\n * the provider's own place_id becomes the Place row's `externalId`, so\n * calling `discoverNearby` twice for the same area on the same provider\n * is a no-op after the first run when the provider returns stable ids.\n *\n * Requires a geo provider that implements `findPoisNear`. Throws a clear\n * error otherwise so consumers can fall back to `lookupOrCreate` or\n * switch providers.\n */\n async discoverNearby(\n latitude: number,\n longitude: number,\n radiusMeters: number,\n options: DiscoverNearbyOptions = {},\n ): Promise<Place[]> {\n if (!(radiusMeters > 0)) {\n throw new Error(\n `discoverNearby: radiusMeters must be > 0 (got ${radiusMeters})`,\n );\n }\n const detailed = await this.discoverNearbyDetailed(\n latitude,\n longitude,\n radiusMeters,\n options,\n );\n return detailed.map((d) => d.place);\n }\n\n /**\n * Internal variant of `discoverNearby` that exposes whether each\n * returned Place was created during this call (`true`) or reused from\n * an earlier call (`false`). Used by `resolveTrackPlaces` to classify\n * buckets as cache hits without having to re-scan the Place table.\n */\n private async discoverNearbyDetailed(\n latitude: number,\n longitude: number,\n radiusMeters: number,\n options: DiscoverNearbyOptions = {},\n ): Promise<Array<{ place: Place; created: boolean }>> {\n const {\n geoProvider = 'openstreetmap',\n types,\n keyword,\n limit,\n language,\n typeSlug,\n parentId,\n } = options;\n\n const geo = await this.getGeoAdapter(geoProvider);\n if (typeof geo.findPoisNear !== 'function') {\n throw new Error(\n `Geo provider '${geoProvider}' does not implement findPoisNear`,\n );\n }\n\n const results = await geo.findPoisNear(latitude, longitude, radiusMeters, {\n types,\n keyword,\n limit,\n language,\n });\n\n const detailed: Array<{ place: Place; created: boolean }> = [];\n for (const result of results) {\n detailed.push(await this.ensureFromLocation(result, typeSlug, parentId));\n }\n return detailed;\n }\n\n /**\n * Resolve POIs along a GPS track (e.g. a video's per-frame path).\n *\n * Naively walking every point would hammer the provider with redundant\n * requests — consecutive samples are usually within a few meters. This\n * method buckets points into a `bucketMeters`-wide grid, calls\n * `discoverNearby` once per distinct bucket, and throttles requests per\n * `throttleMs` so free tiers (Overpass, Nominatim) stay inside their\n * community rate limits without the caller having to manage a queue.\n *\n * The returned `places` are deduped across buckets by Place id, so a\n * POI that falls within several overlapping search radii appears once.\n */\n async resolveTrackPlaces(\n points: ReadonlyArray<TrackPoint>,\n options: ResolveTrackPlacesOptions = {},\n ): Promise<TrackPlacesResult> {\n const radiusMeters = options.radiusMeters ?? 50;\n const bucketMeters = options.bucketMeters ?? 50;\n const throttleMs = options.throttleMs ?? 1100;\n\n if (!(radiusMeters > 0)) {\n throw new Error(\n `resolveTrackPlaces: radiusMeters must be > 0 (got ${radiusMeters})`,\n );\n }\n if (!(bucketMeters > 0)) {\n // Grid/greedy bucketing both divide by bucketMeters; a non-positive\n // value would either NaN the math or produce \"everything in one\n // bucket\", neither of which the caller likely meant.\n throw new Error(\n `resolveTrackPlaces: bucketMeters must be > 0 (got ${bucketMeters})`,\n );\n }\n if (throttleMs < 0 || !Number.isFinite(throttleMs)) {\n throw new Error(\n `resolveTrackPlaces: throttleMs must be a finite non-negative number (got ${throttleMs})`,\n );\n }\n\n // Greedy proximity-based bucketing: each new point joins the nearest\n // existing bucket within `bucketMeters` (Haversine), otherwise seeds a\n // new bucket with itself as the center. This matches the documented\n // semantic (\"points within bucketMeters of each other collapse into\n // one request\") more faithfully than a `Math.round`-on-grid scheme,\n // which can split two points ~0.2m apart if they straddle a cell\n // boundary and inflate requestCount exactly when the user was trying\n // to rate-limit.\n const bucketMetersKm = bucketMeters / 1000;\n const bucketCenters: TrackPoint[] = [];\n for (const point of points) {\n if (!Number.isFinite(point.lat) || !Number.isFinite(point.lng)) continue;\n let bestIdx = -1;\n let bestKm = Number.POSITIVE_INFINITY;\n for (let i = 0; i < bucketCenters.length; i += 1) {\n const c = bucketCenters[i];\n const km = this.calculateDistance(c.lat, c.lng, point.lat, point.lng);\n if (km <= bucketMetersKm && km < bestKm) {\n bestKm = km;\n bestIdx = i;\n }\n }\n if (bestIdx < 0) bucketCenters.push(point);\n }\n\n const result: TrackPlacesResult = {\n places: [],\n requestCount: 0,\n cacheHitCount: 0,\n bucketCount: bucketCenters.length,\n };\n const seen = new Map<string, Place>();\n\n let lastCallAt = 0;\n for (const center of bucketCenters) {\n const wait = lastCallAt + throttleMs - Date.now();\n if (wait > 0) {\n await new Promise((resolve) => setTimeout(resolve, wait));\n }\n\n const detailed = await this.discoverNearbyDetailed(\n center.lat,\n center.lng,\n radiusMeters,\n options,\n );\n lastCallAt = Date.now();\n result.requestCount += 1;\n\n // Cache hit = the provider returned results and every one of them\n // matched a Place that already existed (explicit `created === false`\n // from ensureFromLocation). No timestamp heuristics, no re-scan.\n if (detailed.length > 0 && detailed.every((d) => !d.created)) {\n result.cacheHitCount += 1;\n }\n\n for (const { place } of detailed) {\n if (place.id && !seen.has(place.id)) seen.set(place.id, place);\n }\n }\n\n result.places = [...seen.values()];\n return result;\n }\n\n /**\n * Provider wiring (env keys, user-agent string, etc.) that `geocode`\n * and `discoverNearby` share so the two code paths can't drift. Kept\n * separate from the adapter call itself so tests and future providers\n * can inspect or override the options before construction.\n */\n private getGeoAdapterOptions(\n provider: 'google' | 'openstreetmap',\n ):\n | { provider: 'google'; apiKey: string }\n | { provider: 'openstreetmap'; userAgent: string } {\n if (provider === 'google') {\n return {\n provider: 'google',\n apiKey: process.env.GOOGLE_MAPS_API_KEY || '',\n };\n }\n return { provider: 'openstreetmap', userAgent: '@have/places' };\n }\n\n /**\n * Build a geo adapter configured for this call. Single source of truth\n * for provider wiring — `geocode` and `discoverNearby` both come through\n * here.\n */\n private async getGeoAdapter(\n provider: 'google' | 'openstreetmap',\n ): Promise<GeoAdapterWithPoiSearch> {\n return getGeoAdapter(this.getGeoAdapterOptions(provider));\n }\n\n /**\n * Get immediate children of a parent place\n *\n * @param parentId - The parent place ID\n * @returns Array of child places\n */\n async getChildren(parentId: string): Promise<Place[]> {\n return await this.list({\n where: { parentId },\n });\n }\n\n /**\n * Get root places (no parent)\n *\n * @returns Array of root places\n */\n async getRootPlaces(): Promise<Place[]> {\n return await this.list({\n where: { parentId: null },\n });\n }\n\n /**\n * Get places by type\n *\n * @param typeSlug - PlaceType slug\n * @returns Array of places of that type\n */\n async getByType(typeSlug: string): Promise<Place[]> {\n // Get type ID\n const typeCollection = await PlaceTypeCollection.create(this.options);\n\n const placeType = await typeCollection.getBySlug(typeSlug);\n if (!placeType) return [];\n\n return await this.list({\n where: { typeId: placeType.id },\n });\n }\n\n /**\n * Get place hierarchy (all ancestors and descendants)\n *\n * @param placeId - The place ID\n * @returns Object with ancestors, current place, and descendants\n */\n async getHierarchy(placeId: string) {\n const place = await this.get({ id: placeId });\n if (!place) throw new Error(`Place '${placeId}' not found`);\n\n return await place.getHierarchy();\n }\n\n async getAssets(placeId: string, relationship?: string): Promise<Asset[]> {\n return getOwnedAssetsFromCollection(this, placeId, relationship);\n }\n\n async addAsset(\n placeId: string,\n asset: Asset,\n relationship = 'attachment',\n sortOrder = 0,\n ): Promise<void> {\n await addOwnedAssetFromCollection(\n this,\n 'Place',\n placeId,\n asset,\n relationship,\n sortOrder,\n );\n }\n\n async removeAsset(\n placeId: string,\n assetId: string,\n relationship?: string,\n ): Promise<void> {\n await removeOwnedAssetFromCollection(\n this,\n 'Place',\n placeId,\n assetId,\n relationship,\n );\n }\n\n /**\n * Search places by proximity to coordinates\n *\n * @param latitude - Center latitude\n * @param longitude - Center longitude\n * @param radiusKm - Search radius in kilometers\n * @returns Array of places within radius, sorted by distance\n */\n async searchByProximity(\n latitude: number,\n longitude: number,\n radiusKm: number = 10,\n ): Promise<Place[]> {\n // Get all places with coordinates\n const places = await this.list({\n where: {\n latitude: { $ne: null },\n longitude: { $ne: null },\n },\n });\n\n // Calculate distances and filter by radius\n const placesWithDistance = places\n .map((place) => {\n if (place.latitude === null || place.longitude === null) return null;\n\n const distance = this.calculateDistance(\n latitude,\n longitude,\n place.latitude,\n place.longitude,\n );\n\n return { place, distance };\n })\n .filter(\n (p): p is { place: Place; distance: number } =>\n p !== null && p.distance <= radiusKm,\n )\n .sort((a, b) => a.distance - b.distance);\n\n return placesWithDistance.map((p) => p.place);\n }\n\n /**\n * Calculate distance between two coordinates using Haversine formula\n *\n * @param lat1 - First latitude\n * @param lng1 - First longitude\n * @param lat2 - Second latitude\n * @param lng2 - Second longitude\n * @returns Distance in kilometers\n */\n private calculateDistance(\n lat1: number,\n lng1: number,\n lat2: number,\n lng2: number,\n ): number {\n const R = 6371; // Earth radius in km\n const dLat = this.toRad(lat2 - lat1);\n const dLng = this.toRad(lng2 - lng1);\n\n const a =\n Math.sin(dLat / 2) * Math.sin(dLat / 2) +\n Math.cos(this.toRad(lat1)) *\n Math.cos(this.toRad(lat2)) *\n Math.sin(dLng / 2) *\n Math.sin(dLng / 2);\n\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n return R * c;\n }\n\n /**\n * Convert degrees to radians\n */\n private toRad(degrees: number): number {\n return degrees * (Math.PI / 180);\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Find all places belonging to a specific tenant\n *\n * @param tenantId - The tenant ID to filter by\n * @returns Array of places for the tenant\n */\n async findByTenant(tenantId: string): Promise<Place[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global places (not associated with any tenant).\n *\n * Routes through the shared tenant-global helper so it does not throw under\n * an active tenant context (an explicit `tenant_id IS NULL` filter would be\n * flagged as an isolation violation). (#1600)\n *\n * @returns Array of global places\n */\n async findGlobal(): Promise<Place[]> {\n return queryGlobal<Place>(this);\n }\n\n /**\n * Find places for a tenant including global places.\n *\n * Fails closed if an active tenant context requests a different tenant's\n * rows; the admin/system path keeps the cross-tenant capability. (#1600)\n *\n * @param tenantId - The tenant ID to include\n * @returns Array of tenant-specific and global places\n */\n async findWithGlobals(tenantId: string): Promise<Place[]> {\n return queryWithGlobals<Place>(this, tenantId, 'Place.findWithGlobals');\n }\n}\n","/**\n * Declared recipes for smrt-places (#4409): user-facing units of\n * functionality an app or agent can pick instead of the whole package.\n * The scanner reads these statics into the `recipes` array of `manifest.json`\n * and `smrt-knowledge.json`; nothing here runs at that point.\n *\n * @packageDocumentation\n */\n\nimport { SmrtRecipe } from '@happyvertical/smrt-core';\nimport { Place } from './models/Place';\nimport { PlaceType } from './models/PlaceType';\n\n/**\n * Places: the buildings, rooms, zones and sites where work happens, one\n * inside another. `PlaceAsset` (the picture join) is closed to every surface\n * and stays out of the recipe.\n */\nexport class PlacesLocationsRecipe extends SmrtRecipe {\n static id = 'places.locations';\n static help = './locations.recipe.md';\n static label = 'Places';\n static summary =\n 'Keep a list of the places your work happens, such as sites, buildings, rooms and storage zones, one inside another.';\n static synonyms = [\n 'places',\n 'locations',\n 'sites',\n 'buildings',\n 'rooms',\n 'addresses',\n 'warehouses',\n ];\n static section = {\n id: 'places',\n label: 'Locations',\n icon: 'home',\n description: 'The places your work happens.',\n };\n static models = [Place, PlaceType];\n static nav = [\n {\n label: 'Places',\n model: Place,\n icon: 'home',\n description:\n 'Every site, building, room and zone, with its address and what it is inside.',\n noun: 'place',\n },\n {\n label: 'Place types',\n model: PlaceType,\n icon: 'tag',\n description: 'The kinds of place you keep, such as building or room.',\n noun: 'place type',\n },\n ];\n static options = {\n Place: {\n fields: {\n name: { order: 1 },\n typeId: { label: 'Type', order: 2 },\n parentId: {\n label: 'Inside',\n help: 'The larger place this one is part of, such as the building a room is in.',\n order: 3,\n },\n description: { order: 4 },\n streetNumber: { label: 'Street number', order: 5 },\n streetName: { label: 'Street name', order: 6 },\n city: { order: 7 },\n region: { order: 8 },\n country: { order: 9 },\n postalCode: { label: 'Postal code', order: 10 },\n latitude: { visibility: 'advanced' },\n longitude: { visibility: 'advanced' },\n countryCode: { label: 'Country code', visibility: 'advanced' },\n timezone: { label: 'Time zone', visibility: 'advanced' },\n externalId: { label: 'Map reference', visibility: 'advanced' },\n source: { label: 'Map provider', visibility: 'advanced' },\n metadata: { visibility: 'hidden' },\n tenantId: { visibility: 'hidden' },\n createdAt: { visibility: 'hidden' },\n updatedAt: { visibility: 'hidden' },\n },\n },\n PlaceType: {\n fields: {\n name: { order: 1 },\n description: { order: 2 },\n createdAt: { visibility: 'hidden' },\n updatedAt: { visibility: 'hidden' },\n },\n },\n } as const;\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-places",
5
- "packageVersion": "0.57.46",
5
+ "packageVersion": "0.57.47",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-places:PlaceAssetCollection": {
8
8
  "name": "placeassetcollection",
@@ -68,7 +68,8 @@
68
68
  {
69
69
  "name": "opts",
70
70
  "type": "JunctionAttachOptions",
71
- "optional": true
71
+ "optional": true,
72
+ "resolvedType": "Record<string, unknown>"
72
73
  }
73
74
  ],
74
75
  "returnType": "Promise<TItem>",
@@ -116,7 +117,8 @@
116
117
  {
117
118
  "name": "opts",
118
119
  "type": "JunctionAttachOptions",
119
- "optional": true
120
+ "optional": true,
121
+ "resolvedType": "Record<string, unknown>"
120
122
  }
121
123
  ],
122
124
  "returnType": "Promise<void>",
@@ -207,6 +209,7 @@
207
209
  "extendsTypeArg": "PlaceAsset",
208
210
  "exportName": "PlaceAssetCollection",
209
211
  "collectionExportName": "PlaceAssetCollectionCollection",
212
+ "collectionOf": "@happyvertical/smrt-places:PlaceAsset",
210
213
  "schema": {
211
214
  "tableName": "place_assets",
212
215
  "ddl": "CREATE TABLE IF NOT EXISTS \"place_assets\" (\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 \"place_id\" UUID NOT NULL,\n \"asset_id\" UUID NOT NULL,\n \"relationship\" TEXT NOT NULL,\n \"sort_order\" INTEGER NOT NULL DEFAULT 0\n);",
@@ -590,6 +593,11 @@
590
593
  "extendsTypeArg": "Place",
591
594
  "exportName": "PlaceCollection",
592
595
  "collectionExportName": "PlaceCollectionCollection",
596
+ "collectionOf": "@happyvertical/smrt-places:Place",
597
+ "inheritedExposure": [
598
+ "api",
599
+ "mcp"
600
+ ],
593
601
  "schema": {
594
602
  "tableName": "places",
595
603
  "ddl": "CREATE TABLE IF NOT EXISTS \"places\" (\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 \"tenant_id\" UUID,\n \"type_id\" UUID,\n \"name\" TEXT,\n \"description\" TEXT,\n \"latitude\" REAL,\n \"longitude\" REAL,\n \"street_number\" TEXT,\n \"street_name\" TEXT,\n \"city\" TEXT,\n \"region\" TEXT,\n \"country\" TEXT,\n \"postal_code\" TEXT,\n \"country_code\" TEXT,\n \"timezone\" TEXT,\n \"external_id\" TEXT,\n \"source\" TEXT,\n \"metadata\" TEXT\n);",
@@ -830,6 +838,11 @@
830
838
  "extendsTypeArg": "PlaceType",
831
839
  "exportName": "PlaceTypeCollection",
832
840
  "collectionExportName": "PlaceTypeCollectionCollection",
841
+ "collectionOf": "@happyvertical/smrt-places:PlaceType",
842
+ "inheritedExposure": [
843
+ "api",
844
+ "mcp"
845
+ ],
833
846
  "schema": {
834
847
  "tableName": "place_types",
835
848
  "ddl": "CREATE TABLE IF NOT EXISTS \"place_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 DEFAULT '',\n \"description\" TEXT\n);",
@@ -3,12 +3,12 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-places",
6
- "packageVersion": "0.57.46",
6
+ "packageVersion": "0.57.47",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "2f5c7dfc4ea8589e44d0a77f6fec01eca9aa294f7670c0755e7aa028126ac35f",
11
- "packageJson": "78a8b3472eddde93cfa8b1607ece68a7993ecbb6736c04b0823364c84fa12f48",
10
+ "manifest": "e599ae7a568fb3fab56541ed1d664fb87016fbdd2d4e88f3d801a4b2e7a6648d",
11
+ "packageJson": "5a59f70b897733eed2d77fe5540142600ef86f5200790d88f964343355d36220",
12
12
  "agents": "8b7e9c23fd1311b3d04afe693969c1caaaa5d166e436f48e70c3504efbbadce9"
13
13
  },
14
14
  "exports": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-places",
3
- "version": "0.57.46",
3
+ "version": "0.57.47",
4
4
  "description": "Hierarchical place management with geo integration and SMRT framework support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -23,19 +23,19 @@
23
23
  "./manifest.json": "./dist/manifest.json"
24
24
  },
25
25
  "dependencies": {
26
- "@happyvertical/ai": "^0.111.0",
27
- "@happyvertical/cache": "^0.111.0",
28
- "@happyvertical/files": "^0.111.0",
29
- "@happyvertical/geo": "^0.111.0",
30
- "@happyvertical/logger": "^0.111.0",
31
- "@happyvertical/smrt-assets": "0.57.46",
32
- "@happyvertical/smrt-core": "0.57.46",
33
- "@happyvertical/smrt-tenancy": "0.57.46",
34
- "@happyvertical/sql": "^0.111.0",
35
- "@happyvertical/utils": "^0.111.0"
26
+ "@happyvertical/ai": "^0.111.3",
27
+ "@happyvertical/cache": "^0.111.3",
28
+ "@happyvertical/files": "^0.111.3",
29
+ "@happyvertical/geo": "^0.111.3",
30
+ "@happyvertical/logger": "^0.111.3",
31
+ "@happyvertical/smrt-assets": "0.57.47",
32
+ "@happyvertical/smrt-core": "0.57.47",
33
+ "@happyvertical/smrt-tenancy": "0.57.47",
34
+ "@happyvertical/sql": "^0.111.3",
35
+ "@happyvertical/utils": "^0.111.3"
36
36
  },
37
37
  "devDependencies": {
38
- "@happyvertical/smrt-vitest": "0.57.46",
38
+ "@happyvertical/smrt-vitest": "0.57.47",
39
39
  "@types/node": "24.13.6",
40
40
  "typescript": "6.0.3",
41
41
  "vite": "8.1.6",