vinmonopolet-ts 2.1.0 → 3.0.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/CHANGELOG.md +23 -0
- package/dist/cjs/index.js +1 -3
- package/dist/cjs/models/Facet.js +4 -1
- package/dist/cjs/models/Store.js +11 -66
- package/dist/cjs/retrievers/getStore.js +11 -1
- package/dist/cjs/retrievers/getStores.js +45 -19
- package/dist/esm/index.js +0 -1
- package/dist/esm/models/Facet.js +4 -1
- package/dist/esm/models/Store.js +14 -140
- package/dist/esm/retrievers/getStore.js +11 -1
- package/dist/esm/retrievers/getStores.js +45 -19
- package/dist/types/index.d.ts +0 -1
- package/dist/types/models/Facet.d.ts +1 -1
- package/dist/types/models/Store.d.ts +9 -79
- package/dist/types/retrievers/getStores.d.ts +17 -2
- package/dist/types/util/request.d.ts +1 -3
- package/package.json +1 -1
- package/dist/cjs/csvUrls.js +0 -5
- package/dist/cjs/stream.js +0 -38
- package/dist/esm/csvUrls.js +0 -3
- package/dist/esm/stream.js +0 -33
- package/dist/types/csvUrls.d.ts +0 -5
- package/dist/types/stream.d.ts +0 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
#Changelog
|
|
2
2
|
|
|
3
|
+
## [3.0.0]
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- getAllStores now uses the vinmonopolet api instead of the stream api.
|
|
8
|
+
- Adjusted BaseStore and PopulatedStore to match the new api.
|
|
9
|
+
|
|
10
|
+
### Breaking changes
|
|
11
|
+
|
|
12
|
+
- Removed stream package. Vinmonopolet no longer maintains a csv of products and stores.
|
|
13
|
+
- getStores now returns BaseStore instead of PopulatedStore. You will need to call .populate() on the BaseStore if you want a PopulatedStore.
|
|
14
|
+
- Adjusted BaseStore and PopulatedStore:
|
|
15
|
+
- StreetZip is now called zip
|
|
16
|
+
- StreetCity is now called city
|
|
17
|
+
- Removed phoneNumber, weekNumber, weekNumberNext postalAddress postalZip and postalCity
|
|
18
|
+
- openingHours are now in an array called openingHours instead of individual properties.
|
|
19
|
+
|
|
20
|
+
## [2.1.1]
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Made UpcomingProduct a FacetValue object
|
|
25
|
+
|
|
3
26
|
## [2.1.0]
|
|
4
27
|
|
|
5
28
|
#### Added
|
package/dist/cjs/index.js
CHANGED
|
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.
|
|
29
|
+
exports.getProductReleases = exports.getStore = exports.searchProducts = exports.searchStores = exports.getAllStores = exports.getProductsByIds = exports.getProductsByStore = exports.getProductByBarcode = exports.getFacets = exports.getProduct = exports.getProductCount = exports.getProducts = exports.BaseStore = exports.PopulatedStore = exports.RawMaterial = exports.ProductStatus = exports.ProductImage = exports.StreamProduct = exports.PopulatedProduct = exports.BaseProduct = exports.Pagination = exports.FoodPairing = exports.FacetCategory = exports.FacetValue = exports.Facet = void 0;
|
|
30
30
|
require("reflect-metadata");
|
|
31
31
|
var Facet_1 = require("./models/Facet");
|
|
32
32
|
Object.defineProperty(exports, "Facet", { enumerable: true, get: function () { return __importDefault(Facet_1).default; } });
|
|
@@ -72,5 +72,3 @@ var getStore_1 = require("./retrievers/getStore");
|
|
|
72
72
|
Object.defineProperty(exports, "getStore", { enumerable: true, get: function () { return __importDefault(getStore_1).default; } });
|
|
73
73
|
var getProductReleases_1 = require("./retrievers/getProductReleases");
|
|
74
74
|
Object.defineProperty(exports, "getProductReleases", { enumerable: true, get: function () { return __importDefault(getProductReleases_1).default; } });
|
|
75
|
-
var stream_1 = require("./stream");
|
|
76
|
-
Object.defineProperty(exports, "stream", { enumerable: true, get: function () { return __importDefault(stream_1).default; } });
|
package/dist/cjs/models/Facet.js
CHANGED
|
@@ -118,5 +118,8 @@ class Facet {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
Facet.Category = (0, exports.FacetCategoryMapping)();
|
|
121
|
-
Facet.UpcomingProduct =
|
|
121
|
+
Facet.UpcomingProduct = new FacetValue_1.default({
|
|
122
|
+
name: "Upcoming product",
|
|
123
|
+
query: { query: { value: "upcomingProduct:true" } },
|
|
124
|
+
});
|
|
122
125
|
exports.default = Facet;
|
package/dist/cjs/models/Store.js
CHANGED
|
@@ -24,56 +24,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.BaseStore = void 0;
|
|
27
|
-
const getOpeningHours = (weekday, store) => {
|
|
28
|
-
try {
|
|
29
|
-
let weekDayOpening = store["Apn_" + weekday.toLowerCase().replace("ø", "o")];
|
|
30
|
-
weekDayOpening = weekDayOpening ?? store.openingTimes;
|
|
31
|
-
if (Array.isArray(weekDayOpening)) {
|
|
32
|
-
const weekDayEntry = weekDayOpening.find((entry) => entry.weekDay.toLowerCase() === weekday.toLowerCase());
|
|
33
|
-
if (weekDayEntry.closed || !weekDayEntry)
|
|
34
|
-
return null;
|
|
35
|
-
return {
|
|
36
|
-
opens: weekDayEntry?.openingTime,
|
|
37
|
-
closes: weekDayEntry?.closingTime,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
if (weekDayOpening && weekDayOpening != "Stengt") {
|
|
41
|
-
weekDayOpening = weekDayOpening;
|
|
42
|
-
let [opening, closing] = weekDayOpening.split("-");
|
|
43
|
-
opening = opening.trim();
|
|
44
|
-
closing = closing.trim();
|
|
45
|
-
return {
|
|
46
|
-
opens: {
|
|
47
|
-
hour: Number(opening?.slice(0, 3)),
|
|
48
|
-
minute: Number(opening?.slice(2, opening.length)),
|
|
49
|
-
},
|
|
50
|
-
closes: {
|
|
51
|
-
hour: Number(closing?.slice(0, 3)),
|
|
52
|
-
minute: Number(closing?.slice(2, opening.length)),
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
catch (e) {
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
27
|
class BaseStore {
|
|
63
|
-
constructor(
|
|
64
|
-
this.
|
|
65
|
-
this.
|
|
66
|
-
this.
|
|
67
|
-
this.
|
|
68
|
-
this.
|
|
69
|
-
this.
|
|
70
|
-
this.postalCity = store?.Post_poststed ?? store.address.town;
|
|
71
|
-
this.phoneNumber = store?.Telefonnummer ?? store.address.phone;
|
|
72
|
-
this.gpsCoordinates = [
|
|
73
|
-
store?.GPS_breddegrad ?? store?.geoPoint.latitude,
|
|
74
|
-
store?.GPS_lengdegrad ?? store?.geoPoint.longitude,
|
|
75
|
-
];
|
|
76
|
-
this.storeNumber = store?.Butikknummer ?? store?.name;
|
|
28
|
+
constructor(storeNumber, name, streetAddress, zip, city, latitude, longitude) {
|
|
29
|
+
this.storeNumber = storeNumber;
|
|
30
|
+
this.name = name;
|
|
31
|
+
this.streetAddress = streetAddress;
|
|
32
|
+
this.zip = zip;
|
|
33
|
+
this.city = city;
|
|
34
|
+
this.gpsCoordinates = [latitude, longitude];
|
|
77
35
|
}
|
|
78
36
|
/**
|
|
79
37
|
* Returns a new instance of PopulatedStore, with more fields.
|
|
@@ -90,23 +48,10 @@ class BaseStore {
|
|
|
90
48
|
}
|
|
91
49
|
exports.BaseStore = BaseStore;
|
|
92
50
|
class PopulatedStore extends BaseStore {
|
|
93
|
-
constructor(
|
|
94
|
-
super(
|
|
95
|
-
this.category =
|
|
96
|
-
this.
|
|
97
|
-
this.openingHoursMonday = getOpeningHours("mandag", store);
|
|
98
|
-
this.openingHoursTuesday = getOpeningHours("tirsdag", store);
|
|
99
|
-
this.openingHoursWednesday = getOpeningHours("onsdag", store);
|
|
100
|
-
this.openingHoursThursday = getOpeningHours("torsdag", store);
|
|
101
|
-
this.openingHoursFriday = getOpeningHours("fredag", store);
|
|
102
|
-
this.openingHoursSaturday = getOpeningHours("lørdag", store);
|
|
103
|
-
this.weekNumberNext = store?.Ukenummer_neste;
|
|
104
|
-
this.openingHoursNextMonday = store?.Apn_neste_mandag;
|
|
105
|
-
this.openingHoursNextTuesday = store?.Apn_neste_tirsdag;
|
|
106
|
-
this.openingHoursNextWednesday = store?.Apn_neste_onsdag;
|
|
107
|
-
this.openingHoursNextThursday = store?.Apn_neste_torsdag;
|
|
108
|
-
this.openingHoursNextFriday = store?.Apn_neste_fredag;
|
|
109
|
-
this.openingHoursNextSaturday = store?.Apn_neste_lordag;
|
|
51
|
+
constructor(storeNumber, name, streetAddress, zip, city, latitude, longitude, category, openingHours) {
|
|
52
|
+
super(storeNumber, name, streetAddress, zip, city, latitude, longitude);
|
|
53
|
+
this.category = category;
|
|
54
|
+
this.openingHours = openingHours;
|
|
110
55
|
}
|
|
111
56
|
populate() {
|
|
112
57
|
return Promise.resolve(this);
|
|
@@ -10,6 +10,16 @@ const getStore = async (store_id) => {
|
|
|
10
10
|
baseUrl: "https://www.vinmonopolet.no",
|
|
11
11
|
query: { fields: "FULL" },
|
|
12
12
|
});
|
|
13
|
-
return
|
|
13
|
+
return toPopulatedStore(res);
|
|
14
14
|
};
|
|
15
|
+
function toPopulatedStore(storeDTO) {
|
|
16
|
+
return new Store_1.default(storeDTO.name, storeDTO.displayName, storeDTO.address.line1, storeDTO.address.postalCode, storeDTO.address.town, storeDTO.geoPoint.latitude, storeDTO.geoPoint.longitude, storeDTO.assortment, storeDTO.openingTimes.map(toOpeningHours));
|
|
17
|
+
}
|
|
18
|
+
function toOpeningHours(openingTimeDTO) {
|
|
19
|
+
return {
|
|
20
|
+
closes: openingTimeDTO.closingTime,
|
|
21
|
+
opens: openingTimeDTO.openingTime,
|
|
22
|
+
weekDay: openingTimeDTO.weekDay,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
15
25
|
exports.default = getStore;
|
|
@@ -7,7 +7,6 @@ exports.searchStores = void 0;
|
|
|
7
7
|
const Store_1 = require("../models/Store");
|
|
8
8
|
const Pagination_1 = __importDefault(require("../models/Pagination"));
|
|
9
9
|
const request_1 = __importDefault(require("../util/request"));
|
|
10
|
-
const stream_1 = __importDefault(require("../stream"));
|
|
11
10
|
const defaults = {
|
|
12
11
|
latitude: 59.9126054,
|
|
13
12
|
longitude: 10.7515334,
|
|
@@ -30,7 +29,7 @@ function searchByQuery(querystring) {
|
|
|
30
29
|
query,
|
|
31
30
|
});
|
|
32
31
|
return req.then((res) => ({
|
|
33
|
-
stores:
|
|
32
|
+
stores: res.stores.map(toBaseStore),
|
|
34
33
|
}));
|
|
35
34
|
}
|
|
36
35
|
function searchByLocation(lat, lon, currentPage = 1, pageSize = 10) {
|
|
@@ -46,7 +45,7 @@ function searchByLocation(lat, lon, currentPage = 1, pageSize = 10) {
|
|
|
46
45
|
query,
|
|
47
46
|
});
|
|
48
47
|
return req.then((res) => ({
|
|
49
|
-
stores: (res.stores || []).map(
|
|
48
|
+
stores: (res.stores || []).map(toBaseStore),
|
|
50
49
|
pagination: new Pagination_1.default(getPagination(query.currentPage, pageSize, res.pagination), { nearLocation: { lat, lon } }, searchStores),
|
|
51
50
|
}));
|
|
52
51
|
}
|
|
@@ -59,22 +58,49 @@ function getPagination(currentPage, pageSize, res) {
|
|
|
59
58
|
};
|
|
60
59
|
}
|
|
61
60
|
async function getAllStores() {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
61
|
+
let allStores = [];
|
|
62
|
+
let currentPage = 0;
|
|
63
|
+
let numPages = 2;
|
|
64
|
+
while (currentPage < numPages) {
|
|
65
|
+
const { totalPages, stores } = await getPaginatedStores(currentPage);
|
|
66
|
+
currentPage += 1;
|
|
67
|
+
numPages = totalPages;
|
|
68
|
+
allStores = [...allStores, ...stores];
|
|
69
|
+
}
|
|
70
|
+
return allStores;
|
|
71
|
+
}
|
|
72
|
+
async function getPaginatedStores(page) {
|
|
73
|
+
const query = {
|
|
74
|
+
fields: "BASIC",
|
|
75
|
+
currentPage: page,
|
|
76
|
+
pageSize: 50,
|
|
77
|
+
};
|
|
78
|
+
const res = await request_1.default.get("/vmpws/v2/vmp/stores", {
|
|
79
|
+
baseUrl: "https://www.vinmonopolet.no",
|
|
80
|
+
query,
|
|
77
81
|
});
|
|
78
|
-
|
|
82
|
+
const stores = await Promise.all(res.stores.map(toBaseStore));
|
|
83
|
+
return {
|
|
84
|
+
totalPages: res.pagination.totalPages,
|
|
85
|
+
stores,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function toBaseStore(store) {
|
|
89
|
+
const address = getZipAndCityFromFormattedString(store.address.formattedAddress);
|
|
90
|
+
return new Store_1.BaseStore(store.id, store.displayName, store.address.line1, address?.zip, address?.city, store.geoPoint.latitude, store.geoPoint.longitude);
|
|
91
|
+
}
|
|
92
|
+
function getZipAndCityFromFormattedString(formattedAddressString) {
|
|
93
|
+
try {
|
|
94
|
+
const splitAddress = formattedAddressString.split(",");
|
|
95
|
+
const city = splitAddress[splitAddress.length - 1].trim();
|
|
96
|
+
const zip = splitAddress[splitAddress.length - 2].trim();
|
|
97
|
+
return {
|
|
98
|
+
zip,
|
|
99
|
+
city,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
console.warn("Unable to get zip and city from string: " + formattedAddressString);
|
|
104
|
+
}
|
|
79
105
|
}
|
|
80
106
|
exports.default = getAllStores;
|
package/dist/esm/index.js
CHANGED
|
@@ -19,4 +19,3 @@ export { default as getAllStores, searchStores } from "./retrievers/getStores";
|
|
|
19
19
|
export { default as searchProducts } from "./retrievers/searchProducts";
|
|
20
20
|
export { default as getStore } from "./retrievers/getStore";
|
|
21
21
|
export { default as getProductReleases } from "./retrievers/getProductReleases";
|
|
22
|
-
export { default as stream } from "./stream";
|
package/dist/esm/models/Facet.js
CHANGED
|
@@ -93,6 +93,9 @@ class Facet {
|
|
|
93
93
|
this.values = facet.values.map((val) => new FacetValue(val, valueFilter));
|
|
94
94
|
}
|
|
95
95
|
static Category = FacetCategoryMapping();
|
|
96
|
-
static UpcomingProduct =
|
|
96
|
+
static UpcomingProduct = new FacetValue({
|
|
97
|
+
name: "Upcoming product",
|
|
98
|
+
query: { query: { value: "upcomingProduct:true" } },
|
|
99
|
+
});
|
|
97
100
|
}
|
|
98
101
|
export default Facet;
|
package/dist/esm/models/Store.js
CHANGED
|
@@ -1,38 +1,3 @@
|
|
|
1
|
-
const getOpeningHours = (weekday, store) => {
|
|
2
|
-
try {
|
|
3
|
-
let weekDayOpening = store["Apn_" + weekday.toLowerCase().replace("ø", "o")];
|
|
4
|
-
weekDayOpening = weekDayOpening ?? store.openingTimes;
|
|
5
|
-
if (Array.isArray(weekDayOpening)) {
|
|
6
|
-
const weekDayEntry = weekDayOpening.find((entry) => entry.weekDay.toLowerCase() === weekday.toLowerCase());
|
|
7
|
-
if (weekDayEntry.closed || !weekDayEntry)
|
|
8
|
-
return null;
|
|
9
|
-
return {
|
|
10
|
-
opens: weekDayEntry?.openingTime,
|
|
11
|
-
closes: weekDayEntry?.closingTime,
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
if (weekDayOpening && weekDayOpening != "Stengt") {
|
|
15
|
-
weekDayOpening = weekDayOpening;
|
|
16
|
-
let [opening, closing] = weekDayOpening.split("-");
|
|
17
|
-
opening = opening.trim();
|
|
18
|
-
closing = closing.trim();
|
|
19
|
-
return {
|
|
20
|
-
opens: {
|
|
21
|
-
hour: Number(opening?.slice(0, 3)),
|
|
22
|
-
minute: Number(opening?.slice(2, opening.length)),
|
|
23
|
-
},
|
|
24
|
-
closes: {
|
|
25
|
-
hour: Number(closing?.slice(0, 3)),
|
|
26
|
-
minute: Number(closing?.slice(2, opening.length)),
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
catch (e) {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
1
|
export class BaseStore {
|
|
37
2
|
/**
|
|
38
3
|
* Unique ID for the store.
|
|
@@ -49,45 +14,22 @@ export class BaseStore {
|
|
|
49
14
|
/**
|
|
50
15
|
* The zip code of the store.
|
|
51
16
|
*/
|
|
52
|
-
|
|
17
|
+
zip;
|
|
53
18
|
/**
|
|
54
19
|
* The city the store is located in.
|
|
55
20
|
*/
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* The postal address. Usually just the same as streetAddress.
|
|
59
|
-
*/
|
|
60
|
-
postalAddress;
|
|
61
|
-
/**
|
|
62
|
-
* The zip code of the stores postal address. Usually just the same as streetZip.
|
|
63
|
-
*/
|
|
64
|
-
postalZip;
|
|
65
|
-
/**
|
|
66
|
-
* The postal city of the store. Usually just the same as the streetCity property.
|
|
67
|
-
*/
|
|
68
|
-
postalCity;
|
|
69
|
-
/**
|
|
70
|
-
* The phone number for the store.
|
|
71
|
-
*/
|
|
72
|
-
phoneNumber;
|
|
21
|
+
city;
|
|
73
22
|
/**
|
|
74
23
|
* GPS coordinates of the store given as a [lat, lon] array.
|
|
75
24
|
*/
|
|
76
25
|
gpsCoordinates;
|
|
77
|
-
constructor(
|
|
78
|
-
this.
|
|
79
|
-
this.
|
|
80
|
-
this.
|
|
81
|
-
this.
|
|
82
|
-
this.
|
|
83
|
-
this.
|
|
84
|
-
this.postalCity = store?.Post_poststed ?? store.address.town;
|
|
85
|
-
this.phoneNumber = store?.Telefonnummer ?? store.address.phone;
|
|
86
|
-
this.gpsCoordinates = [
|
|
87
|
-
store?.GPS_breddegrad ?? store?.geoPoint.latitude,
|
|
88
|
-
store?.GPS_lengdegrad ?? store?.geoPoint.longitude,
|
|
89
|
-
];
|
|
90
|
-
this.storeNumber = store?.Butikknummer ?? store?.name;
|
|
26
|
+
constructor(storeNumber, name, streetAddress, zip, city, latitude, longitude) {
|
|
27
|
+
this.storeNumber = storeNumber;
|
|
28
|
+
this.name = name;
|
|
29
|
+
this.streetAddress = streetAddress;
|
|
30
|
+
this.zip = zip;
|
|
31
|
+
this.city = city;
|
|
32
|
+
this.gpsCoordinates = [latitude, longitude];
|
|
91
33
|
}
|
|
92
34
|
/**
|
|
93
35
|
* Returns a new instance of PopulatedStore, with more fields.
|
|
@@ -107,79 +49,11 @@ class PopulatedStore extends BaseStore {
|
|
|
107
49
|
* The category of the store. The category ranges from 1 to 7, where 1 is the lowest possible product selection and 7 is the best possible product selection.
|
|
108
50
|
*/
|
|
109
51
|
category;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
* An oject representing the opening and closing times of the store on monday this week. Is null if the store is not open that day.
|
|
116
|
-
*/
|
|
117
|
-
openingHoursMonday;
|
|
118
|
-
/**
|
|
119
|
-
* An oject representing the opening and closing times of the store on tuesday this week. Is null if the store is not open that day.
|
|
120
|
-
*/
|
|
121
|
-
openingHoursTuesday;
|
|
122
|
-
/**
|
|
123
|
-
* An oject representing the opening and closing times of the store on wednesday this week. Is null if the store is not open that day.
|
|
124
|
-
*/
|
|
125
|
-
openingHoursWednesday;
|
|
126
|
-
/**
|
|
127
|
-
* An oject representing the opening and closing times of the store on thursday this week. Is null if the store is not open that day.
|
|
128
|
-
*/
|
|
129
|
-
openingHoursThursday;
|
|
130
|
-
/**
|
|
131
|
-
* An oject representing the opening and closing times of the store on friday this week. Is null if the store is not open that day.
|
|
132
|
-
*/
|
|
133
|
-
openingHoursFriday;
|
|
134
|
-
/**
|
|
135
|
-
* An oject representing the opening and closing times of the store on saturday this week. Is null if the store is not open that day.
|
|
136
|
-
*/
|
|
137
|
-
openingHoursSaturday;
|
|
138
|
-
/**
|
|
139
|
-
* The next weeks number.
|
|
140
|
-
*/
|
|
141
|
-
weekNumberNext;
|
|
142
|
-
/**
|
|
143
|
-
* An oject representing the opening and closing times of the store on monday next week. Is null if the store is not open that day.
|
|
144
|
-
*/
|
|
145
|
-
openingHoursNextMonday;
|
|
146
|
-
/**
|
|
147
|
-
* An oject representing the opening and closing times of the store on tuesday next week. Is null if the store is not open that day.
|
|
148
|
-
*/
|
|
149
|
-
openingHoursNextTuesday;
|
|
150
|
-
/**
|
|
151
|
-
* An oject representing the opening and closing times of the store on wendesday next week. Is null if the store is not open that day.
|
|
152
|
-
*/
|
|
153
|
-
openingHoursNextWednesday;
|
|
154
|
-
/**
|
|
155
|
-
* An oject representing the opening and closing times of the store on thursday next week. Is null if the store is not open that day.
|
|
156
|
-
*/
|
|
157
|
-
openingHoursNextThursday;
|
|
158
|
-
/**
|
|
159
|
-
* An oject representing the opening and closing times of the store on friday next week. Is null if the store is not open that day.
|
|
160
|
-
*/
|
|
161
|
-
openingHoursNextFriday;
|
|
162
|
-
/**
|
|
163
|
-
* An oject representing the opening and closing times of the store on saturday next week. Is null if the store is not open that day.
|
|
164
|
-
*/
|
|
165
|
-
openingHoursNextSaturday;
|
|
166
|
-
constructor(store) {
|
|
167
|
-
super(store);
|
|
168
|
-
this.category = store?.Kategori ?? store?.assortment;
|
|
169
|
-
this.weekNumber = store?.Ukenummer;
|
|
170
|
-
this.openingHoursMonday = getOpeningHours("mandag", store);
|
|
171
|
-
this.openingHoursTuesday = getOpeningHours("tirsdag", store);
|
|
172
|
-
this.openingHoursWednesday = getOpeningHours("onsdag", store);
|
|
173
|
-
this.openingHoursThursday = getOpeningHours("torsdag", store);
|
|
174
|
-
this.openingHoursFriday = getOpeningHours("fredag", store);
|
|
175
|
-
this.openingHoursSaturday = getOpeningHours("lørdag", store);
|
|
176
|
-
this.weekNumberNext = store?.Ukenummer_neste;
|
|
177
|
-
this.openingHoursNextMonday = store?.Apn_neste_mandag;
|
|
178
|
-
this.openingHoursNextTuesday = store?.Apn_neste_tirsdag;
|
|
179
|
-
this.openingHoursNextWednesday = store?.Apn_neste_onsdag;
|
|
180
|
-
this.openingHoursNextThursday = store?.Apn_neste_torsdag;
|
|
181
|
-
this.openingHoursNextFriday = store?.Apn_neste_fredag;
|
|
182
|
-
this.openingHoursNextSaturday = store?.Apn_neste_lordag;
|
|
52
|
+
openingHours;
|
|
53
|
+
constructor(storeNumber, name, streetAddress, zip, city, latitude, longitude, category, openingHours) {
|
|
54
|
+
super(storeNumber, name, streetAddress, zip, city, latitude, longitude);
|
|
55
|
+
this.category = category;
|
|
56
|
+
this.openingHours = openingHours;
|
|
183
57
|
}
|
|
184
58
|
populate() {
|
|
185
59
|
return Promise.resolve(this);
|
|
@@ -5,6 +5,16 @@ const getStore = async (store_id) => {
|
|
|
5
5
|
baseUrl: "https://www.vinmonopolet.no",
|
|
6
6
|
query: { fields: "FULL" },
|
|
7
7
|
});
|
|
8
|
-
return
|
|
8
|
+
return toPopulatedStore(res);
|
|
9
9
|
};
|
|
10
|
+
function toPopulatedStore(storeDTO) {
|
|
11
|
+
return new PopulatedStore(storeDTO.name, storeDTO.displayName, storeDTO.address.line1, storeDTO.address.postalCode, storeDTO.address.town, storeDTO.geoPoint.latitude, storeDTO.geoPoint.longitude, storeDTO.assortment, storeDTO.openingTimes.map(toOpeningHours));
|
|
12
|
+
}
|
|
13
|
+
function toOpeningHours(openingTimeDTO) {
|
|
14
|
+
return {
|
|
15
|
+
closes: openingTimeDTO.closingTime,
|
|
16
|
+
opens: openingTimeDTO.openingTime,
|
|
17
|
+
weekDay: openingTimeDTO.weekDay,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
10
20
|
export default getStore;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { BaseStore } from "../models/Store";
|
|
2
2
|
import Pagination from "../models/Pagination";
|
|
3
3
|
import request from "../util/request";
|
|
4
|
-
import stream from "../stream";
|
|
5
4
|
const defaults = {
|
|
6
5
|
latitude: 59.9126054,
|
|
7
6
|
longitude: 10.7515334,
|
|
@@ -23,7 +22,7 @@ function searchByQuery(querystring) {
|
|
|
23
22
|
query,
|
|
24
23
|
});
|
|
25
24
|
return req.then((res) => ({
|
|
26
|
-
stores:
|
|
25
|
+
stores: res.stores.map(toBaseStore),
|
|
27
26
|
}));
|
|
28
27
|
}
|
|
29
28
|
function searchByLocation(lat, lon, currentPage = 1, pageSize = 10) {
|
|
@@ -39,7 +38,7 @@ function searchByLocation(lat, lon, currentPage = 1, pageSize = 10) {
|
|
|
39
38
|
query,
|
|
40
39
|
});
|
|
41
40
|
return req.then((res) => ({
|
|
42
|
-
stores: (res.stores || []).map(
|
|
41
|
+
stores: (res.stores || []).map(toBaseStore),
|
|
43
42
|
pagination: new Pagination(getPagination(query.currentPage, pageSize, res.pagination), { nearLocation: { lat, lon } }, searchStores),
|
|
44
43
|
}));
|
|
45
44
|
}
|
|
@@ -52,22 +51,49 @@ function getPagination(currentPage, pageSize, res) {
|
|
|
52
51
|
};
|
|
53
52
|
}
|
|
54
53
|
async function getAllStores() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
54
|
+
let allStores = [];
|
|
55
|
+
let currentPage = 0;
|
|
56
|
+
let numPages = 2;
|
|
57
|
+
while (currentPage < numPages) {
|
|
58
|
+
const { totalPages, stores } = await getPaginatedStores(currentPage);
|
|
59
|
+
currentPage += 1;
|
|
60
|
+
numPages = totalPages;
|
|
61
|
+
allStores = [...allStores, ...stores];
|
|
62
|
+
}
|
|
63
|
+
return allStores;
|
|
64
|
+
}
|
|
65
|
+
async function getPaginatedStores(page) {
|
|
66
|
+
const query = {
|
|
67
|
+
fields: "BASIC",
|
|
68
|
+
currentPage: page,
|
|
69
|
+
pageSize: 50,
|
|
70
|
+
};
|
|
71
|
+
const res = await request.get("/vmpws/v2/vmp/stores", {
|
|
72
|
+
baseUrl: "https://www.vinmonopolet.no",
|
|
73
|
+
query,
|
|
70
74
|
});
|
|
71
|
-
|
|
75
|
+
const stores = await Promise.all(res.stores.map(toBaseStore));
|
|
76
|
+
return {
|
|
77
|
+
totalPages: res.pagination.totalPages,
|
|
78
|
+
stores,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function toBaseStore(store) {
|
|
82
|
+
const address = getZipAndCityFromFormattedString(store.address.formattedAddress);
|
|
83
|
+
return new BaseStore(store.id, store.displayName, store.address.line1, address?.zip, address?.city, store.geoPoint.latitude, store.geoPoint.longitude);
|
|
84
|
+
}
|
|
85
|
+
function getZipAndCityFromFormattedString(formattedAddressString) {
|
|
86
|
+
try {
|
|
87
|
+
const splitAddress = formattedAddressString.split(",");
|
|
88
|
+
const city = splitAddress[splitAddress.length - 1].trim();
|
|
89
|
+
const zip = splitAddress[splitAddress.length - 2].trim();
|
|
90
|
+
return {
|
|
91
|
+
zip,
|
|
92
|
+
city,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
console.warn("Unable to get zip and city from string: " + formattedAddressString);
|
|
97
|
+
}
|
|
72
98
|
}
|
|
73
99
|
export default getAllStores;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -19,4 +19,3 @@ export { default as getAllStores, searchStores } from "./retrievers/getStores";
|
|
|
19
19
|
export { default as searchProducts } from "./retrievers/searchProducts";
|
|
20
20
|
export { default as getStore } from "./retrievers/getStore";
|
|
21
21
|
export { default as getProductReleases } from "./retrievers/getProductReleases";
|
|
22
|
-
export { default as stream } from "./stream";
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
interface IOpeningHours {
|
|
2
|
-
|
|
1
|
+
export interface IOpeningHours {
|
|
2
|
+
weekDay: string;
|
|
3
|
+
opens?: {
|
|
3
4
|
hour: number;
|
|
4
5
|
minute: number;
|
|
5
6
|
};
|
|
6
|
-
closes
|
|
7
|
+
closes?: {
|
|
7
8
|
hour: number;
|
|
8
9
|
minute: number;
|
|
9
10
|
};
|
|
@@ -24,32 +25,16 @@ export declare class BaseStore {
|
|
|
24
25
|
/**
|
|
25
26
|
* The zip code of the store.
|
|
26
27
|
*/
|
|
27
|
-
|
|
28
|
+
zip?: string;
|
|
28
29
|
/**
|
|
29
30
|
* The city the store is located in.
|
|
30
31
|
*/
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* The postal address. Usually just the same as streetAddress.
|
|
34
|
-
*/
|
|
35
|
-
postalAddress: string;
|
|
36
|
-
/**
|
|
37
|
-
* The zip code of the stores postal address. Usually just the same as streetZip.
|
|
38
|
-
*/
|
|
39
|
-
postalZip: string;
|
|
40
|
-
/**
|
|
41
|
-
* The postal city of the store. Usually just the same as the streetCity property.
|
|
42
|
-
*/
|
|
43
|
-
postalCity: string;
|
|
44
|
-
/**
|
|
45
|
-
* The phone number for the store.
|
|
46
|
-
*/
|
|
47
|
-
phoneNumber: string;
|
|
32
|
+
city?: string;
|
|
48
33
|
/**
|
|
49
34
|
* GPS coordinates of the store given as a [lat, lon] array.
|
|
50
35
|
*/
|
|
51
36
|
gpsCoordinates: [number, number];
|
|
52
|
-
constructor(
|
|
37
|
+
constructor(storeNumber: string, name: string, streetAddress: string, zip: string | undefined, city: string | undefined, latitude: number, longitude: number);
|
|
53
38
|
/**
|
|
54
39
|
* Returns a new instance of PopulatedStore, with more fields.
|
|
55
40
|
* @returns Promise<PopulatedStore>
|
|
@@ -61,63 +46,8 @@ declare class PopulatedStore extends BaseStore {
|
|
|
61
46
|
* The category of the store. The category ranges from 1 to 7, where 1 is the lowest possible product selection and 7 is the best possible product selection.
|
|
62
47
|
*/
|
|
63
48
|
category: string;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
*/
|
|
67
|
-
weekNumber: number | undefined;
|
|
68
|
-
/**
|
|
69
|
-
* An oject representing the opening and closing times of the store on monday this week. Is null if the store is not open that day.
|
|
70
|
-
*/
|
|
71
|
-
openingHoursMonday: IOpeningHours | null;
|
|
72
|
-
/**
|
|
73
|
-
* An oject representing the opening and closing times of the store on tuesday this week. Is null if the store is not open that day.
|
|
74
|
-
*/
|
|
75
|
-
openingHoursTuesday: IOpeningHours | null;
|
|
76
|
-
/**
|
|
77
|
-
* An oject representing the opening and closing times of the store on wednesday this week. Is null if the store is not open that day.
|
|
78
|
-
*/
|
|
79
|
-
openingHoursWednesday: IOpeningHours | null;
|
|
80
|
-
/**
|
|
81
|
-
* An oject representing the opening and closing times of the store on thursday this week. Is null if the store is not open that day.
|
|
82
|
-
*/
|
|
83
|
-
openingHoursThursday: IOpeningHours | null;
|
|
84
|
-
/**
|
|
85
|
-
* An oject representing the opening and closing times of the store on friday this week. Is null if the store is not open that day.
|
|
86
|
-
*/
|
|
87
|
-
openingHoursFriday: IOpeningHours | null;
|
|
88
|
-
/**
|
|
89
|
-
* An oject representing the opening and closing times of the store on saturday this week. Is null if the store is not open that day.
|
|
90
|
-
*/
|
|
91
|
-
openingHoursSaturday: IOpeningHours | null;
|
|
92
|
-
/**
|
|
93
|
-
* The next weeks number.
|
|
94
|
-
*/
|
|
95
|
-
weekNumberNext: number;
|
|
96
|
-
/**
|
|
97
|
-
* An oject representing the opening and closing times of the store on monday next week. Is null if the store is not open that day.
|
|
98
|
-
*/
|
|
99
|
-
openingHoursNextMonday: IOpeningHours | null;
|
|
100
|
-
/**
|
|
101
|
-
* An oject representing the opening and closing times of the store on tuesday next week. Is null if the store is not open that day.
|
|
102
|
-
*/
|
|
103
|
-
openingHoursNextTuesday: IOpeningHours | null;
|
|
104
|
-
/**
|
|
105
|
-
* An oject representing the opening and closing times of the store on wendesday next week. Is null if the store is not open that day.
|
|
106
|
-
*/
|
|
107
|
-
openingHoursNextWednesday: IOpeningHours | null;
|
|
108
|
-
/**
|
|
109
|
-
* An oject representing the opening and closing times of the store on thursday next week. Is null if the store is not open that day.
|
|
110
|
-
*/
|
|
111
|
-
openingHoursNextThursday: IOpeningHours | null;
|
|
112
|
-
/**
|
|
113
|
-
* An oject representing the opening and closing times of the store on friday next week. Is null if the store is not open that day.
|
|
114
|
-
*/
|
|
115
|
-
openingHoursNextFriday: IOpeningHours | null;
|
|
116
|
-
/**
|
|
117
|
-
* An oject representing the opening and closing times of the store on saturday next week. Is null if the store is not open that day.
|
|
118
|
-
*/
|
|
119
|
-
openingHoursNextSaturday: IOpeningHours | null;
|
|
120
|
-
constructor(store: any);
|
|
49
|
+
openingHours: IOpeningHours[];
|
|
50
|
+
constructor(storeNumber: string, name: string, streetAddress: string, zip: string, city: string, latitude: number, longitude: number, category: string, openingHours: IOpeningHours[]);
|
|
121
51
|
populate(): Promise<PopulatedStore>;
|
|
122
52
|
}
|
|
123
53
|
export default PopulatedStore;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { BaseStore } from "../models/Store";
|
|
2
2
|
import Pagination from "../models/Pagination";
|
|
3
3
|
export interface ISearchStoresOptions {
|
|
4
4
|
/**
|
|
@@ -31,6 +31,21 @@ export interface ISearchStoreResult {
|
|
|
31
31
|
*/
|
|
32
32
|
pagination?: Pagination<ISearchStoreResult>;
|
|
33
33
|
}
|
|
34
|
+
export interface IStoreDTO {
|
|
35
|
+
displayName: string;
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
formattedDistance: string;
|
|
39
|
+
geoPoint: {
|
|
40
|
+
latitude: number;
|
|
41
|
+
longitude: number;
|
|
42
|
+
};
|
|
43
|
+
address: {
|
|
44
|
+
formattedAddress: string;
|
|
45
|
+
id: string;
|
|
46
|
+
line1: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
34
49
|
export declare function searchStores(opts?: ISearchStoresOptions): Promise<ISearchStoreResult>;
|
|
35
|
-
declare function getAllStores(): Promise<
|
|
50
|
+
declare function getAllStores(): Promise<BaseStore[]>;
|
|
36
51
|
export default getAllStores;
|
|
@@ -8,9 +8,7 @@ export interface IRequestOptions {
|
|
|
8
8
|
}
|
|
9
9
|
declare function sendRequest(path: string, options?: IRequestOptions): Promise<Response>;
|
|
10
10
|
declare namespace sendRequest {
|
|
11
|
-
var get: (path: string, options: IRequestOptions) => Promise<
|
|
12
|
-
[prop: string]: any;
|
|
13
|
-
}>;
|
|
11
|
+
var get: <T>(path: string, options: IRequestOptions) => Promise<T>;
|
|
14
12
|
var head: (path: any, options: any) => Promise<Response>;
|
|
15
13
|
var raw: (url: string) => Promise<Response>;
|
|
16
14
|
}
|
package/package.json
CHANGED
package/dist/cjs/csvUrls.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const products = "https://www.vinmonopolet.no/medias/sys_master/products/products/hbc/hb0/8834253127710/produkter.csv";
|
|
4
|
-
const stores = "https://www.vinmonopolet.no/medias/sys_master/locations/locations/h3c/h4a/8834253946910/8834253946910.csv";
|
|
5
|
-
exports.default = { products, stores };
|
package/dist/cjs/stream.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const csvUrls_1 = __importDefault(require("./csvUrls"));
|
|
7
|
-
const csv_parser_1 = __importDefault(require("csv-parser"));
|
|
8
|
-
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
9
|
-
const Store_1 = __importDefault(require("./models/Store"));
|
|
10
|
-
const Product_1 = require("./models/Product");
|
|
11
|
-
const stream_1 = require("stream");
|
|
12
|
-
async function getCsvStream(url, transformer) {
|
|
13
|
-
const { body } = await (0, node_fetch_1.default)(url);
|
|
14
|
-
return body.pipe((0, csv_parser_1.default)({ separator: ";" })).pipe(transformer);
|
|
15
|
-
}
|
|
16
|
-
const getProducts = () => {
|
|
17
|
-
const transformProduct = new stream_1.Transform({
|
|
18
|
-
objectMode: true,
|
|
19
|
-
transform(chunk, enc, cb) {
|
|
20
|
-
const product = new Product_1.StreamProduct(chunk);
|
|
21
|
-
this.push(product);
|
|
22
|
-
cb();
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
return getCsvStream(csvUrls_1.default.products, transformProduct);
|
|
26
|
-
};
|
|
27
|
-
const getStores = () => {
|
|
28
|
-
const transformStore = new stream_1.Transform({
|
|
29
|
-
objectMode: true,
|
|
30
|
-
transform(chunk, enc, cb) {
|
|
31
|
-
const store = new Store_1.default(chunk);
|
|
32
|
-
this.push(store);
|
|
33
|
-
cb();
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
return getCsvStream(csvUrls_1.default.stores, transformStore);
|
|
37
|
-
};
|
|
38
|
-
exports.default = { getProducts, getStores };
|
package/dist/esm/csvUrls.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
const products = "https://www.vinmonopolet.no/medias/sys_master/products/products/hbc/hb0/8834253127710/produkter.csv";
|
|
2
|
-
const stores = "https://www.vinmonopolet.no/medias/sys_master/locations/locations/h3c/h4a/8834253946910/8834253946910.csv";
|
|
3
|
-
export default { products, stores };
|
package/dist/esm/stream.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import csvUrls from "./csvUrls";
|
|
2
|
-
import csv from "csv-parser";
|
|
3
|
-
import fetch from "node-fetch";
|
|
4
|
-
import Store from "./models/Store";
|
|
5
|
-
import { StreamProduct } from "./models/Product";
|
|
6
|
-
import { Transform } from "stream";
|
|
7
|
-
async function getCsvStream(url, transformer) {
|
|
8
|
-
const { body } = await fetch(url);
|
|
9
|
-
return body.pipe(csv({ separator: ";" })).pipe(transformer);
|
|
10
|
-
}
|
|
11
|
-
const getProducts = () => {
|
|
12
|
-
const transformProduct = new Transform({
|
|
13
|
-
objectMode: true,
|
|
14
|
-
transform(chunk, enc, cb) {
|
|
15
|
-
const product = new StreamProduct(chunk);
|
|
16
|
-
this.push(product);
|
|
17
|
-
cb();
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
return getCsvStream(csvUrls.products, transformProduct);
|
|
21
|
-
};
|
|
22
|
-
const getStores = () => {
|
|
23
|
-
const transformStore = new Transform({
|
|
24
|
-
objectMode: true,
|
|
25
|
-
transform(chunk, enc, cb) {
|
|
26
|
-
const store = new Store(chunk);
|
|
27
|
-
this.push(store);
|
|
28
|
-
cb();
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
return getCsvStream(csvUrls.stores, transformStore);
|
|
32
|
-
};
|
|
33
|
-
export default { getProducts, getStores };
|
package/dist/types/csvUrls.d.ts
DELETED