@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 +96 -0
- package/lib/GooglePlacesService.d.ts +23 -0
- package/lib/GooglePlacesService.js +68 -0
- package/lib/GooglePlacesService.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +20 -0
- package/lib/index.js.map +1 -0
- package/lib/models.d.ts +79 -0
- package/lib/models.js +4 -0
- package/lib/models.js.map +1 -0
- package/package.json +40 -0
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
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
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oCAAoC;AACpC,wDAAsC;AACtC,2CAAyB"}
|
package/lib/models.d.ts
ADDED
|
@@ -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 @@
|
|
|
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
|
+
}
|