@happyvertical/smrt-places 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,172 @@
1
+ import { SmrtObjectOptions } from '@happyvertical/smrt-core';
2
+
3
+ /**
4
+ * Options for `PlaceCollection.discoverNearby`. Mirrors the inputs to
5
+ * `@happyvertical/geo`'s `findPoisNear` plus a couple of persistence knobs
6
+ * (PlaceType override, parent linkage) to match `lookupOrCreate`'s shape.
7
+ */
8
+ export declare interface DiscoverNearbyOptions {
9
+ /** Which geo provider to use. Defaults to openstreetmap. */
10
+ geoProvider?: 'google' | 'openstreetmap';
11
+ /**
12
+ * POI category filter, forwarded to the provider. See
13
+ * `@happyvertical/geo`'s `PoiSearchOptions.types` for provider-specific
14
+ * interpretation.
15
+ */
16
+ types?: string[];
17
+ /** Free-text keyword filter (provider-dependent; Google only). */
18
+ keyword?: string;
19
+ /** Max results per provider call. Default 20. */
20
+ limit?: number;
21
+ /** Preferred language for place names (Google only). */
22
+ language?: string;
23
+ /** Override the PlaceType slug assigned to created rows. */
24
+ typeSlug?: string;
25
+ /** Set parent place on created rows. */
26
+ parentId?: string | null;
27
+ }
28
+
29
+ /**
30
+ * Geographic data structure
31
+ * All fields optional to support both real-world and abstract places
32
+ */
33
+ export declare interface GeoData {
34
+ latitude: number | null;
35
+ longitude: number | null;
36
+ streetNumber?: string;
37
+ streetName?: string;
38
+ city?: string;
39
+ region?: string;
40
+ country?: string;
41
+ postalCode?: string;
42
+ countryCode?: string;
43
+ timezone?: string;
44
+ }
45
+
46
+ /**
47
+ * Options for lookupOrCreate method
48
+ */
49
+ export declare interface LookupOrCreateOptions {
50
+ /**
51
+ * Which geo provider to use for lookups
52
+ */
53
+ geoProvider?: 'google' | 'openstreetmap';
54
+ /**
55
+ * Force a specific place type
56
+ */
57
+ typeSlug?: string;
58
+ /**
59
+ * Set parent place if known
60
+ */
61
+ parentId?: string | null;
62
+ /**
63
+ * Whether to create if not found (default: true)
64
+ */
65
+ createIfNotFound?: boolean;
66
+ /**
67
+ * Coordinates for reverse geocoding
68
+ */
69
+ coords?: {
70
+ lat: number;
71
+ lng: number;
72
+ };
73
+ }
74
+
75
+ /**
76
+ * Place hierarchy structure
77
+ */
78
+ export declare interface PlaceHierarchy {
79
+ ancestors: any[];
80
+ current: any;
81
+ descendants: any[];
82
+ }
83
+
84
+ /**
85
+ * Options for creating/updating a Place
86
+ */
87
+ export declare interface PlaceOptions extends SmrtObjectOptions {
88
+ id?: string;
89
+ tenantId?: string | null;
90
+ typeId?: string;
91
+ parentId?: string | null;
92
+ name?: string;
93
+ description?: string;
94
+ latitude?: number | null;
95
+ longitude?: number | null;
96
+ streetNumber?: string;
97
+ streetName?: string;
98
+ city?: string;
99
+ region?: string;
100
+ country?: string;
101
+ postalCode?: string;
102
+ countryCode?: string;
103
+ timezone?: string;
104
+ externalId?: string;
105
+ source?: string;
106
+ metadata?: Record<string, any> | string;
107
+ createdAt?: Date;
108
+ updatedAt?: Date;
109
+ }
110
+
111
+ /**
112
+ * Options for creating/updating a PlaceType
113
+ */
114
+ export declare interface PlaceTypeOptions extends SmrtObjectOptions {
115
+ id?: string;
116
+ slug?: string;
117
+ name?: string;
118
+ description?: string;
119
+ createdAt?: Date;
120
+ updatedAt?: Date;
121
+ }
122
+
123
+ /**
124
+ * Options for `PlaceCollection.resolveTrackPlaces`. Extends
125
+ * `DiscoverNearbyOptions` with per-track knobs that control how the track
126
+ * is bucketed + throttled before hitting the geo provider.
127
+ */
128
+ export declare interface ResolveTrackPlacesOptions extends DiscoverNearbyOptions {
129
+ /**
130
+ * Per-point POI search radius in meters. Default 50.
131
+ */
132
+ radiusMeters?: number;
133
+ /**
134
+ * Collapse points within this distance (m) into a single bucket so we
135
+ * don't re-query the same ~50m area dozens of times for a slow drive-by.
136
+ * Default 50.
137
+ */
138
+ bucketMeters?: number;
139
+ /**
140
+ * Minimum delay between provider requests. Default 1100ms — safely above
141
+ * OSM's 1 req/sec community limit. Google can usually handle faster; set
142
+ * to 100ms or less for paid tiers.
143
+ */
144
+ throttleMs?: number;
145
+ }
146
+
147
+ /**
148
+ * Result of `PlaceCollection.resolveTrackPlaces`. Tracks are typically
149
+ * long-running operations so the return payload includes counters that let
150
+ * callers surface progress or estimate cost without re-walking.
151
+ */
152
+ export declare interface TrackPlacesResult {
153
+ /** De-duplicated Place rows touched during resolution. */
154
+ places: any[];
155
+ /** Number of provider requests issued. */
156
+ requestCount: number;
157
+ /** Number of bucketed points that reused existing Place rows. */
158
+ cacheHitCount: number;
159
+ /** Number of distinct geographic buckets walked. */
160
+ bucketCount: number;
161
+ }
162
+
163
+ /**
164
+ * A single point along a track. Matches the `{ lat, lng }` convention used
165
+ * by `LookupOrCreateOptions.coords` so callers don't have to shuffle shapes.
166
+ */
167
+ export declare interface TrackPoint {
168
+ lat: number;
169
+ lng: number;
170
+ }
171
+
172
+ export { }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,113 @@
1
+ import { Location } from '@happyvertical/geo';
2
+
3
+ /**
4
+ * Check if two coordinates are within a threshold distance
5
+ *
6
+ * @param lat1 - First latitude
7
+ * @param lng1 - First longitude
8
+ * @param lat2 - Second latitude
9
+ * @param lng2 - Second longitude
10
+ * @param thresholdKm - Distance threshold in kilometers
11
+ * @returns True if coordinates are within threshold
12
+ */
13
+ export declare function areCoordinatesNear(lat1: number, lng1: number, lat2: number, lng2: number, thresholdKm?: number): boolean;
14
+
15
+ /**
16
+ * Calculate distance between two coordinates using Haversine formula
17
+ *
18
+ * @param lat1 - First latitude
19
+ * @param lng1 - First longitude
20
+ * @param lat2 - Second latitude
21
+ * @param lng2 - Second longitude
22
+ * @returns Distance in kilometers
23
+ */
24
+ export declare function calculateDistance(lat1: number, lng1: number, lat2: number, lng2: number): number;
25
+
26
+ /**
27
+ * Format coordinates as string
28
+ *
29
+ * @param latitude - Latitude value
30
+ * @param longitude - Longitude value
31
+ * @param precision - Number of decimal places (default: 6)
32
+ * @returns Formatted coordinate string
33
+ */
34
+ export declare function formatCoordinates(latitude: number, longitude: number, precision?: number): string;
35
+
36
+ /**
37
+ * Generate a display name from address components
38
+ *
39
+ * @param components - Address components
40
+ * @returns Formatted display name
41
+ */
42
+ export declare function generateDisplayName(components: Partial<GeoData>): string;
43
+
44
+ /**
45
+ * Geographic data structure
46
+ * All fields optional to support both real-world and abstract places
47
+ */
48
+ declare interface GeoData {
49
+ latitude: number | null;
50
+ longitude: number | null;
51
+ streetNumber?: string;
52
+ streetName?: string;
53
+ city?: string;
54
+ region?: string;
55
+ country?: string;
56
+ postalCode?: string;
57
+ countryCode?: string;
58
+ timezone?: string;
59
+ }
60
+
61
+ /**
62
+ * Convert Location from @happyvertical/geo to GeoData
63
+ *
64
+ * @param location - Location from geocoding
65
+ * @returns GeoData object
66
+ */
67
+ export declare function locationToGeoData(location: Location): GeoData;
68
+
69
+ /**
70
+ * Map Location type from @happyvertical/geo to PlaceType slug
71
+ *
72
+ * @param locationType - Location type from geocoding provider
73
+ * @returns PlaceType slug
74
+ */
75
+ export declare function mapLocationTypeToPlaceType(locationType: string): string;
76
+
77
+ /**
78
+ * Normalize address components by trimming and removing empty values
79
+ *
80
+ * @param components - Address components
81
+ * @returns Normalized components
82
+ */
83
+ export declare function normalizeAddressComponents(components: Partial<GeoData>): Partial<GeoData>;
84
+
85
+ /**
86
+ * Parse coordinate string to lat/lng
87
+ *
88
+ * Supports formats:
89
+ * - "lat, lng"
90
+ * - "lat,lng"
91
+ * - "lat lng"
92
+ *
93
+ * @param coordString - Coordinate string
94
+ * @returns Object with lat and lng, or null if invalid
95
+ */
96
+ export declare function parseCoordinates(coordString: string): {
97
+ lat: number;
98
+ lng: number;
99
+ } | null;
100
+
101
+ /**
102
+ * Validate geographic coordinates
103
+ *
104
+ * @param latitude - Latitude value
105
+ * @param longitude - Longitude value
106
+ * @returns Object with valid flag and optional error message
107
+ */
108
+ export declare function validateCoordinates(latitude: number, longitude: number): {
109
+ valid: boolean;
110
+ error?: string;
111
+ };
112
+
113
+ export { }
package/dist/utils.js ADDED
@@ -0,0 +1,110 @@
1
+ function mapLocationTypeToPlaceType(locationType) {
2
+ const typeMap = {
3
+ // Standard types
4
+ country: "country",
5
+ region: "region",
6
+ city: "city",
7
+ address: "address",
8
+ point_of_interest: "point_of_interest",
9
+ // Additional mappings
10
+ state: "region",
11
+ province: "region",
12
+ town: "city",
13
+ village: "city",
14
+ building: "building",
15
+ room: "room",
16
+ zone: "zone"
17
+ };
18
+ return typeMap[locationType.toLowerCase()] || "address";
19
+ }
20
+ function locationToGeoData(location) {
21
+ const components = location.addressComponents || {};
22
+ return {
23
+ latitude: location.latitude,
24
+ longitude: location.longitude,
25
+ streetNumber: components.streetNumber,
26
+ streetName: components.streetName,
27
+ city: components.city,
28
+ region: components.region,
29
+ country: components.country,
30
+ postalCode: components.postalCode,
31
+ countryCode: location.countryCode,
32
+ timezone: location.timezone
33
+ };
34
+ }
35
+ function validateCoordinates(latitude, longitude) {
36
+ if (latitude < -90 || latitude > 90) {
37
+ return { valid: false, error: "Invalid latitude (must be -90 to 90)" };
38
+ }
39
+ if (longitude < -180 || longitude > 180) {
40
+ return { valid: false, error: "Invalid longitude (must be -180 to 180)" };
41
+ }
42
+ return { valid: true };
43
+ }
44
+ function calculateDistance(lat1, lng1, lat2, lng2) {
45
+ const R = 6371;
46
+ const dLat = toRad(lat2 - lat1);
47
+ const dLng = toRad(lng2 - lng1);
48
+ const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
49
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
50
+ return R * c;
51
+ }
52
+ function toRad(degrees) {
53
+ return degrees * (Math.PI / 180);
54
+ }
55
+ function formatCoordinates(latitude, longitude, precision = 6) {
56
+ return `${latitude.toFixed(precision)}, ${longitude.toFixed(precision)}`;
57
+ }
58
+ function parseCoordinates(coordString) {
59
+ const parts = coordString.trim().replace(/\s+/g, " ").replace(/,\s*/g, ",").split(/[,\s]+/);
60
+ if (parts.length !== 2) return null;
61
+ const lat = parseFloat(parts[0]);
62
+ const lng = parseFloat(parts[1]);
63
+ if (Number.isNaN(lat) || Number.isNaN(lng)) return null;
64
+ const validation = validateCoordinates(lat, lng);
65
+ if (!validation.valid) return null;
66
+ return { lat, lng };
67
+ }
68
+ function normalizeAddressComponents(components) {
69
+ const normalized = {};
70
+ for (const [key, value] of Object.entries(components)) {
71
+ if (value === null || value === void 0) continue;
72
+ if (typeof value === "string") {
73
+ const trimmed = value.trim();
74
+ if (trimmed) {
75
+ normalized[key] = trimmed;
76
+ }
77
+ } else {
78
+ normalized[key] = value;
79
+ }
80
+ }
81
+ return normalized;
82
+ }
83
+ function generateDisplayName(components) {
84
+ const parts = [];
85
+ if (components.streetNumber && components.streetName) {
86
+ parts.push(`${components.streetNumber} ${components.streetName}`);
87
+ } else if (components.streetName) {
88
+ parts.push(components.streetName);
89
+ }
90
+ if (components.city) parts.push(components.city);
91
+ if (components.region) parts.push(components.region);
92
+ if (components.country) parts.push(components.country);
93
+ return parts.join(", ");
94
+ }
95
+ function areCoordinatesNear(lat1, lng1, lat2, lng2, thresholdKm = 0.1) {
96
+ const distance = calculateDistance(lat1, lng1, lat2, lng2);
97
+ return distance <= thresholdKm;
98
+ }
99
+ export {
100
+ areCoordinatesNear,
101
+ calculateDistance,
102
+ formatCoordinates,
103
+ generateDisplayName,
104
+ locationToGeoData,
105
+ mapLocationTypeToPlaceType,
106
+ normalizeAddressComponents,
107
+ parseCoordinates,
108
+ validateCoordinates
109
+ };
110
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["/**\n * Utility functions for @have/places package\n */\n\nimport type { Location } from '@happyvertical/geo';\nimport type { GeoData } from './types';\n\n/**\n * Map Location type from @happyvertical/geo to PlaceType slug\n *\n * @param locationType - Location type from geocoding provider\n * @returns PlaceType slug\n */\nexport function mapLocationTypeToPlaceType(locationType: string): string {\n const typeMap: Record<string, string> = {\n // Standard types\n country: 'country',\n region: 'region',\n city: 'city',\n address: 'address',\n point_of_interest: 'point_of_interest',\n\n // Additional mappings\n state: 'region',\n province: 'region',\n town: 'city',\n village: 'city',\n building: 'building',\n room: 'room',\n zone: 'zone',\n };\n\n return typeMap[locationType.toLowerCase()] || 'address';\n}\n\n/**\n * Convert Location from @happyvertical/geo to GeoData\n *\n * @param location - Location from geocoding\n * @returns GeoData object\n */\nexport function locationToGeoData(location: Location): GeoData {\n const components = location.addressComponents || {};\n\n return {\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}\n\n/**\n * Validate geographic coordinates\n *\n * @param latitude - Latitude value\n * @param longitude - Longitude value\n * @returns Object with valid flag and optional error message\n */\nexport function validateCoordinates(\n latitude: number,\n longitude: number,\n): { valid: boolean; error?: string } {\n if (latitude < -90 || latitude > 90) {\n return { valid: false, error: 'Invalid latitude (must be -90 to 90)' };\n }\n\n if (longitude < -180 || longitude > 180) {\n return { valid: false, error: 'Invalid longitude (must be -180 to 180)' };\n }\n\n return { valid: true };\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 */\nexport function 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 = toRad(lat2 - lat1);\n const dLng = toRad(lng2 - lng1);\n\n const a =\n Math.sin(dLat / 2) * Math.sin(dLat / 2) +\n Math.cos(toRad(lat1)) *\n Math.cos(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 */\nfunction toRad(degrees: number): number {\n return degrees * (Math.PI / 180);\n}\n\n/**\n * Format coordinates as string\n *\n * @param latitude - Latitude value\n * @param longitude - Longitude value\n * @param precision - Number of decimal places (default: 6)\n * @returns Formatted coordinate string\n */\nexport function formatCoordinates(\n latitude: number,\n longitude: number,\n precision: number = 6,\n): string {\n return `${latitude.toFixed(precision)}, ${longitude.toFixed(precision)}`;\n}\n\n/**\n * Parse coordinate string to lat/lng\n *\n * Supports formats:\n * - \"lat, lng\"\n * - \"lat,lng\"\n * - \"lat lng\"\n *\n * @param coordString - Coordinate string\n * @returns Object with lat and lng, or null if invalid\n */\nexport function parseCoordinates(\n coordString: string,\n): { lat: number; lng: number } | null {\n // Remove extra whitespace and split\n const parts = coordString\n .trim()\n .replace(/\\s+/g, ' ')\n .replace(/,\\s*/g, ',')\n .split(/[,\\s]+/);\n\n if (parts.length !== 2) return null;\n\n const lat = parseFloat(parts[0]);\n const lng = parseFloat(parts[1]);\n\n if (Number.isNaN(lat) || Number.isNaN(lng)) return null;\n\n const validation = validateCoordinates(lat, lng);\n if (!validation.valid) return null;\n\n return { lat, lng };\n}\n\n/**\n * Normalize address components by trimming and removing empty values\n *\n * @param components - Address components\n * @returns Normalized components\n */\nexport function normalizeAddressComponents(\n components: Partial<GeoData>,\n): Partial<GeoData> {\n const normalized: Partial<GeoData> = {};\n\n for (const [key, value] of Object.entries(components)) {\n if (value === null || value === undefined) continue;\n\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed) {\n normalized[key as keyof GeoData] = trimmed as any;\n }\n } else {\n normalized[key as keyof GeoData] = value as any;\n }\n }\n\n return normalized;\n}\n\n/**\n * Generate a display name from address components\n *\n * @param components - Address components\n * @returns Formatted display name\n */\nexport function generateDisplayName(components: Partial<GeoData>): string {\n const parts: string[] = [];\n\n if (components.streetNumber && components.streetName) {\n parts.push(`${components.streetNumber} ${components.streetName}`);\n } else if (components.streetName) {\n parts.push(components.streetName);\n }\n\n if (components.city) parts.push(components.city);\n if (components.region) parts.push(components.region);\n if (components.country) parts.push(components.country);\n\n return parts.join(', ');\n}\n\n/**\n * Check if two coordinates are within a threshold distance\n *\n * @param lat1 - First latitude\n * @param lng1 - First longitude\n * @param lat2 - Second latitude\n * @param lng2 - Second longitude\n * @param thresholdKm - Distance threshold in kilometers\n * @returns True if coordinates are within threshold\n */\nexport function areCoordinatesNear(\n lat1: number,\n lng1: number,\n lat2: number,\n lng2: number,\n thresholdKm: number = 0.1,\n): boolean {\n const distance = calculateDistance(lat1, lng1, lat2, lng2);\n return distance <= thresholdKm;\n}\n"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@happyvertical/smrt-places",
3
+ "version": "0.30.0",
4
+ "description": "Hierarchical place management with geo integration and SMRT framework support",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "CLAUDE.md",
11
+ "AGENTS.md"
12
+ ],
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js"
17
+ },
18
+ "./utils": {
19
+ "types": "./dist/utils.d.ts",
20
+ "import": "./dist/utils.js"
21
+ },
22
+ "./manifest": "./dist/manifest.json",
23
+ "./manifest.json": "./dist/manifest.json"
24
+ },
25
+ "dependencies": {
26
+ "@happyvertical/ai": "^0.74.7",
27
+ "@happyvertical/cache": "^0.74.7",
28
+ "@happyvertical/files": "^0.74.7",
29
+ "@happyvertical/geo": "^0.74.7",
30
+ "@happyvertical/logger": "^0.74.7",
31
+ "@happyvertical/sql": "^0.74.7",
32
+ "@happyvertical/utils": "^0.74.7",
33
+ "@happyvertical/smrt-assets": "0.30.0",
34
+ "@happyvertical/smrt-core": "0.30.0",
35
+ "@happyvertical/smrt-tenancy": "0.30.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "25.0.9",
39
+ "fast-glob": "3.3.3",
40
+ "typescript": "^5.9.3",
41
+ "vite": "^7.3.1",
42
+ "vitest": "^4.0.17",
43
+ "@happyvertical/smrt-vitest": "0.30.0"
44
+ },
45
+ "keywords": [
46
+ "ai",
47
+ "agents",
48
+ "places",
49
+ "locations",
50
+ "geocoding",
51
+ "geography",
52
+ "hierarchy",
53
+ "smrt"
54
+ ],
55
+ "author": "HappyVertical",
56
+ "license": "MIT",
57
+ "publishConfig": {
58
+ "registry": "https://registry.npmjs.org",
59
+ "access": "public"
60
+ },
61
+ "repository": {
62
+ "type": "git",
63
+ "url": "https://github.com/happyvertical/smrt.git",
64
+ "directory": "packages/places"
65
+ },
66
+ "scripts": {
67
+ "build": "vite build --mode library",
68
+ "build:fresh": "npm run clean && npm run build",
69
+ "build:watch": "vite build --mode library --watch",
70
+ "clean": "rm -rf dist",
71
+ "dev": "vite dev",
72
+ "test": "vitest run",
73
+ "test:watch": "vitest",
74
+ "typecheck": "tsc --noEmit -p tsconfig.json"
75
+ }
76
+ }