@xapp/stentor-service-google-places 1.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # Google Places Service
2
+
3
+ Service for integrating with Google Places API, built on Stentor's FetchService.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @xapp/stentor-service-google-places
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Basic Setup with API Key
14
+
15
+ ```typescript
16
+ import { GooglePlacesService } from "@xapp/stentor-service-google-places";
17
+
18
+ const service = new GooglePlacesService({
19
+ apiKey: "your-google-places-api-key"
20
+ });
21
+ ```
22
+
23
+ ### Setup with Authentication Function
24
+
25
+ ```typescript
26
+ import { GooglePlacesService } from "@xapp/stentor-service-google-places";
27
+
28
+ const service = new GooglePlacesService({
29
+ authenticate: async () => {
30
+ // Your authentication logic here
31
+ return { apiKey: await getApiKeyFromSomewhere() };
32
+ }
33
+ });
34
+ ```
35
+
36
+ ### Get Place Details
37
+
38
+ ```typescript
39
+ // Get basic place details
40
+ const placeDetails = await service.getPlaceDetails("ChIJN1t_tDeuEmsRUsoyG83frY4");
41
+
42
+ // Get specific fields only
43
+ const placeDetails = await service.getPlaceDetails(
44
+ "ChIJN1t_tDeuEmsRUsoyG83frY4",
45
+ ["name", "formatted_address", "geometry", "photos"]
46
+ );
47
+ ```
48
+
49
+ ## API Reference
50
+
51
+ ### GooglePlacesService
52
+
53
+ #### Constructor Options
54
+
55
+ - `apiKey?: string` - Google Places API key
56
+ - `authenticate?: () => Promise<{ apiKey: string }>` - Function that returns API key
57
+ - `urlBase?: string` - Custom API base URL (defaults to Google Places API)
58
+
59
+ #### Methods
60
+
61
+ ##### `getPlaceDetails(placeId: string, fields?: string[]): Promise<GooglePlaceDetails>`
62
+
63
+ Retrieves detailed information about a place.
64
+
65
+ **Parameters:**
66
+ - `placeId` - The unique identifier for a place
67
+ - `fields` - Optional array of fields to return (reduces API cost)
68
+
69
+ **Returns:** Promise resolving to place details
70
+
71
+ **Available Fields:**
72
+ - Basic: `place_id`, `name`, `formatted_address`, `geometry`
73
+ - Contact: `formatted_phone_number`, `international_phone_number`, `website`
74
+ - Atmosphere: `photos`, `rating`, `user_ratings_total`, `reviews`, `price_level`
75
+ - Details: `opening_hours`, `business_status`, `types`, `vicinity`
76
+
77
+ ## Error Handling
78
+
79
+ The service throws descriptive errors for:
80
+ - Missing API key or authentication function
81
+ - HTTP errors (4xx/5xx status codes)
82
+ - Google Places API errors (INVALID_REQUEST, OVER_QUERY_LIMIT, etc.)
83
+
84
+ ## Types
85
+
86
+ All TypeScript interfaces are exported for use in your application:
87
+
88
+ ```typescript
89
+ import {
90
+ GooglePlaceDetails,
91
+ GooglePlaceDetailsResponse,
92
+ GooglePlacesGeometry,
93
+ GooglePlacesPhoto,
94
+ GooglePlacesReview
95
+ } from "@xapp/stentor-service-google-places";
96
+ ```
@@ -0,0 +1,23 @@
1
+ import { FetchService } from "stentor-service-fetch";
2
+ import { GooglePlaceDetails } from "./models";
3
+ export interface GooglePlacesAuthenticator {
4
+ (): Promise<{
5
+ apiKey: string;
6
+ }>;
7
+ }
8
+ export interface GooglePlacesServiceOptions {
9
+ apiKey?: string;
10
+ authenticate?: GooglePlacesAuthenticator;
11
+ urlBase?: string;
12
+ }
13
+ export interface GooglePlacesServiceInterface {
14
+ getPlaceDetails(placeId: string, fields?: string[]): Promise<GooglePlaceDetails>;
15
+ }
16
+ export declare class GooglePlacesService extends FetchService implements GooglePlacesServiceInterface {
17
+ private readonly apiKey?;
18
+ private readonly authenticate?;
19
+ private readonly urlBase;
20
+ constructor(options: GooglePlacesServiceOptions);
21
+ getPlaceDetails(placeId: string, fields?: string[]): Promise<GooglePlaceDetails>;
22
+ private getApiKey;
23
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.GooglePlacesService = void 0;
13
+ /*! Copyright (c) 2025, XAPPmedia */
14
+ const stentor_constants_1 = require("stentor-constants");
15
+ const stentor_service_fetch_1 = require("stentor-service-fetch");
16
+ class GooglePlacesService extends stentor_service_fetch_1.FetchService {
17
+ constructor(options) {
18
+ super();
19
+ if (!options.apiKey && !options.authenticate) {
20
+ throw new Error("GooglePlacesService requires either apiKey or authenticate function");
21
+ }
22
+ this.apiKey = options.apiKey;
23
+ this.authenticate = options.authenticate;
24
+ this.urlBase = options.urlBase || "https://maps.googleapis.com/maps/api/place/details/json";
25
+ }
26
+ getPlaceDetails(placeId, fields) {
27
+ return __awaiter(this, void 0, void 0, function* () {
28
+ const apiKey = yield this.getApiKey();
29
+ const url = new URL(this.urlBase);
30
+ url.searchParams.set("place_id", placeId);
31
+ url.searchParams.set("key", apiKey);
32
+ if (fields && fields.length > 0) {
33
+ url.searchParams.set("fields", fields.join(","));
34
+ }
35
+ let status;
36
+ return this.fetch(url.toString(), {
37
+ method: "GET"
38
+ })
39
+ .then(response => {
40
+ status = response.status;
41
+ if (status >= stentor_constants_1.HTTP_400_BAD_REQUEST) {
42
+ throw new Error(`Google Places API request to ${url.toString()} returned status code ${status}`);
43
+ }
44
+ return response.json();
45
+ })
46
+ .then((response) => {
47
+ if (response.status !== "OK") {
48
+ throw new Error(`Google Places API error: ${response.status}${response.error_message ? ` - ${response.error_message}` : ""}`);
49
+ }
50
+ return response.result;
51
+ });
52
+ });
53
+ }
54
+ getApiKey() {
55
+ return __awaiter(this, void 0, void 0, function* () {
56
+ if (this.apiKey) {
57
+ return this.apiKey;
58
+ }
59
+ if (this.authenticate) {
60
+ const auth = yield this.authenticate();
61
+ return auth.apiKey;
62
+ }
63
+ throw new Error("No API key available");
64
+ });
65
+ }
66
+ }
67
+ exports.GooglePlacesService = GooglePlacesService;
68
+ //# sourceMappingURL=GooglePlacesService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GooglePlacesService.js","sourceRoot":"","sources":["../src/GooglePlacesService.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oCAAoC;AACpC,yDAAyD;AACzD,iEAAqD;AAiBrD,MAAa,mBAAoB,SAAQ,oCAAY;IAKjD,YAAY,OAAmC;QAC3C,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;QAC3F,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;QACzC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,yDAAyD,CAAC;IAChG,CAAC;IAEK,eAAe,CAAC,OAAe,EAAE,MAAiB;;YACpD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;YAEtC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC1C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAEpC,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YACrD,CAAC;YAED,IAAI,MAAc,CAAC;YAEnB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;gBAC9B,MAAM,EAAE,KAAK;aAChB,CAAC;iBACG,IAAI,CAAC,QAAQ,CAAC,EAAE;gBACb,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;gBAEzB,IAAI,MAAM,IAAI,wCAAoB,EAAE,CAAC;oBACjC,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,CAAC,QAAQ,EAAE,yBAAyB,MAAM,EAAE,CAAC,CAAC;gBACrG,CAAC;gBAED,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC3B,CAAC,CAAC;iBACD,IAAI,CAAqB,CAAC,QAAoC,EAAE,EAAE;gBAC/D,IAAI,QAAQ,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;oBAC3B,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAClI,CAAC;gBAED,OAAO,QAAQ,CAAC,MAAM,CAAC;YAC3B,CAAC,CAAC,CAAC;QACX,CAAC;KAAA;IAEa,SAAS;;YACnB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBACd,OAAO,IAAI,CAAC,MAAM,CAAC;YACvB,CAAC;YAED,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;gBACvC,OAAO,IAAI,CAAC,MAAM,CAAC;YACvB,CAAC;YAED,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC5C,CAAC;KAAA;CACJ;AA/DD,kDA+DC"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ /*! Copyright (c) 2025, XAPPmedia */
2
+ export * from "./GooglePlacesService";
3
+ export * from "./models";
package/lib/index.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /*! Copyright (c) 2025, XAPPmedia */
18
+ __exportStar(require("./GooglePlacesService"), exports);
19
+ __exportStar(require("./models"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oCAAoC;AACpC,wDAAsC;AACtC,2CAAyB"}
@@ -0,0 +1,79 @@
1
+ /*! Copyright (c) 2025, XAPPmedia */
2
+ export interface GooglePlacesGeometry {
3
+ location: {
4
+ lat: number;
5
+ lng: number;
6
+ };
7
+ viewport: {
8
+ northeast: {
9
+ lat: number;
10
+ lng: number;
11
+ };
12
+ southwest: {
13
+ lat: number;
14
+ lng: number;
15
+ };
16
+ };
17
+ }
18
+ export interface GooglePlacesAddressComponent {
19
+ long_name: string;
20
+ short_name: string;
21
+ types: string[];
22
+ }
23
+ export interface GooglePlacesPhoto {
24
+ height: number;
25
+ html_attributions: string[];
26
+ photo_reference: string;
27
+ width: number;
28
+ }
29
+ export interface GooglePlacesOpeningHours {
30
+ open_now: boolean;
31
+ periods?: Array<{
32
+ close?: {
33
+ day: number;
34
+ time: string;
35
+ };
36
+ open: {
37
+ day: number;
38
+ time: string;
39
+ };
40
+ }>;
41
+ weekday_text?: string[];
42
+ }
43
+ export interface GooglePlacesReview {
44
+ author_name: string;
45
+ author_url?: string;
46
+ language: string;
47
+ profile_photo_url: string;
48
+ rating: number;
49
+ relative_time_description: string;
50
+ text: string;
51
+ time: number;
52
+ }
53
+ export interface GooglePlaceDetails {
54
+ place_id: string;
55
+ name?: string;
56
+ formatted_address?: string;
57
+ formatted_phone_number?: string;
58
+ international_phone_number?: string;
59
+ geometry?: GooglePlacesGeometry;
60
+ address_components?: GooglePlacesAddressComponent[];
61
+ photos?: GooglePlacesPhoto[];
62
+ rating?: number;
63
+ user_ratings_total?: number;
64
+ reviews?: GooglePlacesReview[];
65
+ opening_hours?: GooglePlacesOpeningHours;
66
+ website?: string;
67
+ url?: string;
68
+ business_status?: string;
69
+ price_level?: number;
70
+ types?: string[];
71
+ vicinity?: string;
72
+ }
73
+ export interface GooglePlaceDetailsResponse {
74
+ result: GooglePlaceDetails;
75
+ status: string;
76
+ error_message?: string;
77
+ info_messages?: string[];
78
+ html_attributions: string[];
79
+ }
package/lib/models.js ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ /*! Copyright (c) 2025, XAPPmedia */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":";AAAA,oCAAoC"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@xapp/stentor-service-google-places",
3
+ "license": "Apache-2.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "version": "1.70.0",
8
+ "description": "Service to integrate with Google Places API",
9
+ "types": "lib/index",
10
+ "main": "lib/index",
11
+ "files": [
12
+ "lib"
13
+ ],
14
+ "engines": {
15
+ "node": "^10 || ^12 || ^14 || ^16 || ^18 || ^20 || ^22"
16
+ },
17
+ "devDependencies": {
18
+ "@types/chai": "5.2.2",
19
+ "@xapp/config": "0.2.3",
20
+ "chai": "4.5.0",
21
+ "mocha": "11.7.1",
22
+ "stentor-logger": "1.61.10",
23
+ "stentor-models": "1.61.9",
24
+ "stentor-service-fetch": "1.61.9",
25
+ "ts-node": "10.9.2",
26
+ "typescript": "5.9.2"
27
+ },
28
+ "peerDependencies": {
29
+ "stentor-constants": "1.x",
30
+ "stentor-logger": "1.x",
31
+ "stentor-models": "1.x",
32
+ "stentor-service-fetch": "1.x"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc -d true -p .",
36
+ "clean": "rm -rf ./lib/*",
37
+ "test": "exit 0"
38
+ },
39
+ "gitHead": "55afa51e5b8d8875d3e5f6ef23e57d4687dce2b8"
40
+ }