wetherspoons-api 0.0.1 → 0.0.3

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,226 @@
1
+ # Wetherspoons API
2
+
3
+ A TypeScript package for accessing JD Wetherspoon's venue and menu data, including drink information with pricing and alcohol unit calculations.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/wetherspoons-api.svg)](https://www.npmjs.com/package/wetherspoons-api)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install wetherspoons-api
12
+ ```
13
+
14
+ ## Features
15
+
16
+ - 🏪 Fetch all Wetherspoons venues
17
+ - 📍 Get detailed venue information
18
+ - 🍺 Access venue menus and drinks
19
+ - 💰 Calculate price per unit (PPU) for alcoholic beverages
20
+ - ✅ Type-safe with TypeScript and Zod validation
21
+ - 🔄 Automatic handling of different portion sizes
22
+
23
+ ## Usage
24
+
25
+ ### Get All Venues
26
+
27
+ ```typescript
28
+ import { venues } from 'wetherspoons-api';
29
+
30
+ const allVenues = await venues();
31
+ console.log(allVenues);
32
+ // [
33
+ // {
34
+ // franchise: 'lloyds',
35
+ // id: 123,
36
+ // isClosed: false,
37
+ // name: 'The Moon Under Water',
38
+ // venueRef: 456
39
+ // },
40
+ // ...
41
+ // ]
42
+ ```
43
+
44
+ ### Get Venue Details
45
+
46
+ ```typescript
47
+ import { venues, getVenue } from 'wetherspoons-api';
48
+
49
+ const allVenues = await venues();
50
+ const venue = allVenues[0];
51
+ const details = await getVenue(venue);
52
+
53
+ console.log(details);
54
+ // {
55
+ // canPlaceOrder: true,
56
+ // franchise: 'lloyds',
57
+ // id: 123,
58
+ // name: 'The Moon Under Water',
59
+ // salesAreas: [{ id: 789 }],
60
+ // venueCanOrder: true,
61
+ // venueRef: 456
62
+ // }
63
+ ```
64
+
65
+ ### Get Drinks with Price Analysis
66
+
67
+ ```typescript
68
+ import { venues, getDrinks } from 'wetherspoons-api';
69
+
70
+ const allVenues = await venues();
71
+ const venue = allVenues[0];
72
+ const drinks = await getDrinks(venue);
73
+
74
+ console.log(drinks);
75
+ // [
76
+ // {
77
+ // name: 'Ruddles Best',
78
+ // units: 2.27,
79
+ // productId: 12345,
80
+ // price: 249, // in pence
81
+ // ppu: 109.69 // price per unit in pence
82
+ // },
83
+ // ...
84
+ // ]
85
+ // Sorted by best value (lowest price per unit first)
86
+ ```
87
+
88
+ ### Get Menus
89
+
90
+ ```typescript
91
+ import { venues, getVenue, getMenus, getMenu } from 'wetherspoons-api';
92
+
93
+ const allVenues = await venues();
94
+ const venue = allVenues[0];
95
+ const details = await getVenue(venue);
96
+
97
+ // Get all menus for a sales area
98
+ const menus = await getMenus({
99
+ venue: details,
100
+ salesAreaId: details.salesAreas[0].id
101
+ });
102
+
103
+ // Get detailed menu information
104
+ const drinksMenu = menus.find(m => m.name === 'Drinks');
105
+ if (drinksMenu) {
106
+ const detailedMenu = await getMenu(drinksMenu);
107
+ console.log(detailedMenu.data.categories);
108
+ }
109
+ ```
110
+
111
+ ## API Reference
112
+
113
+ ### Functions
114
+
115
+ #### `venues(): Promise<HighLevelVenue[]>`
116
+ Fetches all Wetherspoons venues.
117
+
118
+ **Returns:** Array of venue objects with basic information.
119
+
120
+ #### `getVenue(venue: HighLevelVenue): Promise<DetailedVenue>`
121
+ Gets detailed information about a specific venue.
122
+
123
+ **Parameters:**
124
+ - `venue`: A venue object from [`venues()`](src/index.ts:28)
125
+
126
+ **Returns:** Detailed venue information including sales areas and ordering capabilities.
127
+
128
+ #### `getMenus({ venue, salesAreaId }): Promise<HighLevelMenu[]>`
129
+ Fetches all menus for a specific sales area in a venue.
130
+
131
+ **Parameters:**
132
+ - `venue`: A detailed venue object from [`getVenue()`](src/index.ts:49)
133
+ - `salesAreaId`: The ID of the sales area
134
+
135
+ **Returns:** Array of menu objects.
136
+
137
+ #### `getMenu(highLevelMenu: HighLevelMenu): Promise<DetailedMenu>`
138
+ Gets detailed menu information including all products and categories.
139
+
140
+ **Parameters:**
141
+ - `highLevelMenu`: A menu object from [`getMenus()`](src/index.ts:66)
142
+
143
+ **Returns:** Detailed menu with categories, item groups, and products.
144
+
145
+ #### `getDrinks(highLevelVenue: HighLevelVenue): Promise<Drink[]>`
146
+ Fetches all drinks from a venue's drinks menu, calculates alcohol units and price per unit, then sorts by best value.
147
+
148
+ **Parameters:**
149
+ - `highLevelVenue`: A venue object from [`venues()`](src/index.ts:28)
150
+
151
+ **Returns:** Array of drinks sorted by price per unit (best value first).
152
+
153
+ ### Types
154
+
155
+ #### `HighLevelVenue`
156
+ ```typescript
157
+ {
158
+ franchise: string;
159
+ id: number;
160
+ isClosed: boolean;
161
+ name: string;
162
+ venueRef: number;
163
+ }
164
+ ```
165
+
166
+ #### `DetailedVenue`
167
+ ```typescript
168
+ {
169
+ canPlaceOrder: boolean;
170
+ franchise: string;
171
+ id: number;
172
+ isClosed?: boolean;
173
+ name: string;
174
+ salesAreas: Array<{ id: number }>;
175
+ venueCanOrder: boolean;
176
+ venueRef: string | number;
177
+ }
178
+ ```
179
+
180
+ #### `Drink`
181
+ ```typescript
182
+ {
183
+ name: string;
184
+ units: number; // Alcohol units
185
+ productId: number;
186
+ price: number; // Price in pence
187
+ ppu: number; // Price per unit in pence
188
+ }
189
+ ```
190
+
191
+ ## How It Works
192
+
193
+ The package:
194
+ 1. Connects to the JD Wetherspoon API
195
+ 2. Validates all responses using Zod schemas for type safety
196
+ 3. Calculates alcohol units based on ABV and volume information
197
+ 4. Determines the best value portion size for each drink
198
+ 5. Sorts drinks by price per unit to help find the best deals
199
+
200
+ ## Development
201
+
202
+ ```bash
203
+ # Install dependencies
204
+ npm install
205
+
206
+ # Build the package
207
+ npm run build
208
+
209
+ # Lint code
210
+ npm run lint
211
+
212
+ # Fix linting issues
213
+ npm run lint:fix
214
+ ```
215
+
216
+ ## License
217
+
218
+ MIT © [Joss Bird](https://github.com/slack2450)
219
+
220
+ ## Contributing
221
+
222
+ Contributions are welcome! Please feel free to submit a Pull Request.
223
+
224
+ ## Issues
225
+
226
+ Report bugs and feature requests at [https://github.com/slack2450/wetherspoons-api/issues](https://github.com/slack2450/wetherspoons-api/issues)
package/dist/index.d.ts CHANGED
@@ -1,2 +1,116 @@
1
+ import { z } from 'zod';
2
+ export declare const highLevelVenueSchema: z.ZodObject<{
3
+ franchise: z.ZodString;
4
+ id: z.ZodNumber;
5
+ isClosed: z.ZodBoolean;
6
+ name: z.ZodString;
7
+ venueRef: z.ZodNumber;
8
+ }, z.core.$strip>;
9
+ export type HighLevelVenue = z.infer<typeof highLevelVenueSchema>;
10
+ export declare function venues(): Promise<HighLevelVenue[]>;
11
+ declare const detailedVenueSchema: z.ZodObject<{
12
+ canPlaceOrder: z.ZodBoolean;
13
+ franchise: z.ZodString;
14
+ id: z.ZodNumber;
15
+ isClosed: z.ZodOptional<z.ZodBoolean>;
16
+ name: z.ZodString;
17
+ salesAreas: z.ZodArray<z.ZodObject<{
18
+ id: z.ZodNumber;
19
+ }, z.core.$strip>>;
20
+ venueCanOrder: z.ZodBoolean;
21
+ venueRef: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
22
+ }, z.core.$strip>;
23
+ export type DetailedVenue = z.infer<typeof detailedVenueSchema>;
24
+ export declare function getVenue(venue: HighLevelVenue): Promise<DetailedVenue>;
25
+ export declare const highLevelMenuSchema: z.ZodObject<{
26
+ canOrder: z.ZodBoolean;
27
+ franchise: z.ZodString;
28
+ id: z.ZodNumber;
29
+ name: z.ZodString;
30
+ salesAreaId: z.ZodNumber;
31
+ venueRef: z.ZodNumber;
32
+ }, z.core.$strip>;
33
+ export type HighLevelMenu = z.infer<typeof highLevelMenuSchema>;
34
+ export declare function getMenus({ venue, salesAreaId }: {
35
+ venue: DetailedVenue;
36
+ salesAreaId: number;
37
+ }): Promise<HighLevelMenu[]>;
38
+ declare const detailedMenuProductSchema: z.ZodObject<{
39
+ id: z.ZodNumber;
40
+ isOutOfStock: z.ZodBoolean;
41
+ itemType: z.ZodLiteral<"product">;
42
+ name: z.ZodString;
43
+ description: z.ZodString;
44
+ options: z.ZodObject<{
45
+ portion: z.ZodObject<{
46
+ options: z.ZodArray<z.ZodObject<{
47
+ label: z.ZodString;
48
+ value: z.ZodObject<{
49
+ price: z.ZodObject<{
50
+ currency: z.ZodString;
51
+ discount: z.ZodNumber;
52
+ initialValue: z.ZodNumber;
53
+ value: z.ZodNumber;
54
+ }, z.core.$strip>;
55
+ }, z.core.$strip>;
56
+ }, z.core.$strip>>;
57
+ }, z.core.$strip>;
58
+ }, z.core.$strip>;
59
+ }, z.core.$strip>;
60
+ export type DetailedMenuProduct = z.infer<typeof detailedMenuProductSchema>;
61
+ declare const detailedMenuSchema: z.ZodObject<{
62
+ data: z.ZodObject<{
63
+ canOrder: z.ZodBoolean;
64
+ categories: z.ZodArray<z.ZodObject<{
65
+ itemGroups: z.ZodArray<z.ZodObject<{
66
+ items: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
67
+ itemType: z.ZodLiteral<"text">;
68
+ text: z.ZodString;
69
+ }, z.core.$strip>, z.ZodObject<{
70
+ itemType: z.ZodLiteral<"divider">;
71
+ }, z.core.$strip>, z.ZodObject<{
72
+ itemType: z.ZodLiteral<"ale">;
73
+ }, z.core.$strip>, z.ZodObject<{
74
+ id: z.ZodNumber;
75
+ isOutOfStock: z.ZodBoolean;
76
+ itemType: z.ZodLiteral<"product">;
77
+ name: z.ZodString;
78
+ description: z.ZodString;
79
+ options: z.ZodObject<{
80
+ portion: z.ZodObject<{
81
+ options: z.ZodArray<z.ZodObject<{
82
+ label: z.ZodString;
83
+ value: z.ZodObject<{
84
+ price: z.ZodObject<{
85
+ currency: z.ZodString;
86
+ discount: z.ZodNumber;
87
+ initialValue: z.ZodNumber;
88
+ value: z.ZodNumber;
89
+ }, z.core.$strip>;
90
+ }, z.core.$strip>;
91
+ }, z.core.$strip>>;
92
+ }, z.core.$strip>;
93
+ }, z.core.$strip>;
94
+ }, z.core.$strip>]>>;
95
+ name: z.ZodNullable<z.ZodString>;
96
+ }, z.core.$strip>>;
97
+ name: z.ZodString;
98
+ }, z.core.$strip>>;
99
+ franchise: z.ZodString;
100
+ id: z.ZodNumber;
101
+ salesAreaId: z.ZodNumber;
102
+ venueRef: z.ZodNumber;
103
+ }, z.core.$strip>;
104
+ }, z.core.$strip>;
105
+ export type DetailedMenu = z.infer<typeof detailedMenuSchema>;
106
+ export declare function getMenu(highLevelMenu: HighLevelMenu): Promise<DetailedMenu>;
107
+ export interface Drink {
108
+ name: string;
109
+ units: number;
110
+ productId: number;
111
+ price: number;
112
+ ppu: number;
113
+ }
114
+ export declare function getDrinks(highLevelVenue: HighLevelVenue): Promise<Drink[]>;
1
115
  export {};
2
116
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAiBxB,eAAO,MAAM,oBAAoB;;;;;;iBAM/B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,wBAAsB,MAAM,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAIxD;AAED,QAAA,MAAM,mBAAmB;;;;;;;;;;;iBAWvB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,wBAAsB,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAI5E;AAED,eAAO,MAAM,mBAAmB;;;;;;;iBAO9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,wBAAsB,QAAQ,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAI9H;AAED,QAAA,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;iBAqB7B,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA2BtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,wBAAsB,OAAO,CAAC,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAIjF;AAMD,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,wBAAsB,SAAS,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CA+GhF"}
package/dist/index.js CHANGED
@@ -1,3 +1,210 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ import { z } from 'zod';
2
+ const API_ENDPOINT = 'https://ca.jdw-apps.net/api/v0.1';
3
+ const API_HEADERS = {
4
+ Authorization: 'Bearer 1|SFS9MMnn5deflq0BMcUTSijwSMBB4mc7NSG2rOhqb2765466',
5
+ };
6
+ async function request(path) {
7
+ const response = await fetch(`${API_ENDPOINT}${path}`, {
8
+ headers: API_HEADERS,
9
+ });
10
+ const json = await response.json();
11
+ return json;
12
+ }
13
+ export const highLevelVenueSchema = z.object({
14
+ franchise: z.string(),
15
+ id: z.number(),
16
+ isClosed: z.boolean(),
17
+ name: z.string(),
18
+ venueRef: z.number(),
19
+ });
20
+ export async function venues() {
21
+ const response = await request('/venues');
22
+ const venues = z.object({ data: z.array(highLevelVenueSchema) }).parse(response);
23
+ return venues.data;
24
+ }
25
+ const detailedVenueSchema = z.object({
26
+ canPlaceOrder: z.boolean(),
27
+ franchise: z.string(),
28
+ id: z.number(),
29
+ isClosed: z.boolean().optional(),
30
+ name: z.string(),
31
+ salesAreas: z.array(z.object({
32
+ id: z.number(),
33
+ })),
34
+ venueCanOrder: z.boolean(),
35
+ venueRef: z.union([z.string(), z.number()]),
36
+ });
37
+ export async function getVenue(venue) {
38
+ const response = await request(`/venues/${venue.venueRef}`);
39
+ const venueDetails = z.object({ data: detailedVenueSchema }).parse(response);
40
+ return venueDetails.data;
41
+ }
42
+ export const highLevelMenuSchema = z.object({
43
+ canOrder: z.boolean(),
44
+ franchise: z.string(),
45
+ id: z.number(),
46
+ name: z.string(),
47
+ salesAreaId: z.number(),
48
+ venueRef: z.number(),
49
+ });
50
+ export async function getMenus({ venue, salesAreaId }) {
51
+ const response = await request(`/${venue.franchise}/venues/${venue.venueRef}/sales-areas/${salesAreaId}/menus`);
52
+ const menus = z.object({ data: z.array(highLevelMenuSchema) }).parse(response);
53
+ return menus.data;
54
+ }
55
+ const detailedMenuProductSchema = z.object({
56
+ id: z.number(),
57
+ isOutOfStock: z.boolean(),
58
+ itemType: z.literal('product'),
59
+ name: z.string(),
60
+ description: z.string(),
61
+ options: z.object({
62
+ portion: z.object({
63
+ options: z.array(z.object({
64
+ label: z.string(),
65
+ value: z.object({
66
+ price: z.object({
67
+ currency: z.string(),
68
+ discount: z.number(),
69
+ initialValue: z.number(),
70
+ value: z.number(),
71
+ }),
72
+ }),
73
+ })),
74
+ }),
75
+ }),
76
+ });
77
+ const detailedMenuSchema = z.object({
78
+ data: z.object({
79
+ canOrder: z.boolean(),
80
+ categories: z.array(z.object({
81
+ itemGroups: z.array(z.object({
82
+ items: z.array(z.union([
83
+ z.object({
84
+ itemType: z.literal('text'),
85
+ text: z.string(),
86
+ }),
87
+ z.object({
88
+ itemType: z.literal('divider'),
89
+ }),
90
+ z.object({
91
+ itemType: z.literal('ale'),
92
+ }),
93
+ detailedMenuProductSchema,
94
+ ])),
95
+ name: z.string().nullable(),
96
+ })),
97
+ name: z.string(),
98
+ })),
99
+ franchise: z.string(),
100
+ id: z.number(),
101
+ salesAreaId: z.number(),
102
+ venueRef: z.number(),
103
+ }),
104
+ });
105
+ export async function getMenu(highLevelMenu) {
106
+ const response = await request(`/${highLevelMenu.franchise}/venues/${highLevelMenu.venueRef}/sales-areas/${highLevelMenu.salesAreaId}/menus/${highLevelMenu.id}`);
107
+ const detailedMenu = detailedMenuSchema.parse(response);
108
+ return detailedMenu;
109
+ }
110
+ function strengthAndVolumeToUnits(strength, volume) {
111
+ return (strength * volume) / 1000;
112
+ }
113
+ export async function getDrinks(highLevelVenue) {
114
+ const detailedVenue = await getVenue(highLevelVenue);
115
+ const salesArea = detailedVenue.salesAreas[0];
116
+ if (!salesArea)
117
+ return [];
118
+ const menus = await getMenus({ venue: detailedVenue, salesAreaId: salesArea.id });
119
+ let drinksMenu;
120
+ for (const menu of menus) {
121
+ if (menu.name === 'Drinks') {
122
+ drinksMenu = menu;
123
+ break;
124
+ }
125
+ }
126
+ if (!drinksMenu)
127
+ return [];
128
+ const res = await getMenu(drinksMenu);
129
+ // Convert menu to flat array of drinks
130
+ const hash_map = new Map();
131
+ for (const categories of res.data.categories) {
132
+ for (const itemGroup of categories.itemGroups) {
133
+ for (const item of itemGroup.items) {
134
+ if (item.itemType == 'product') {
135
+ // Skip out of stock
136
+ if (item.isOutOfStock) {
137
+ continue;
138
+ }
139
+ hash_map.set(item.id, item);
140
+ }
141
+ }
142
+ }
143
+ }
144
+ const drinks = [];
145
+ for (const product of hash_map.values()) {
146
+ const strengthMatches = product.description.match(/(\d?\d?\.?\d?\d%)\s?ABV/);
147
+ const volumeDescriptionMatches = product.description.match(/(\d?\d\d)ml/);
148
+ let strength;
149
+ if (strengthMatches) {
150
+ strength = parseFloat(strengthMatches[0]);
151
+ }
152
+ let volumeDescription;
153
+ if (volumeDescriptionMatches) {
154
+ volumeDescription = parseFloat(volumeDescriptionMatches[0]);
155
+ }
156
+ let bestPortion;
157
+ let bestPPU = Infinity;
158
+ let bestUnits = 0;
159
+ for (const portion of product.options.portion.options) {
160
+ let units;
161
+ const volumeMatches = portion.label.match(/(\d?\d\d)ml/);
162
+ let volume;
163
+ if (volumeMatches && volumeMatches[1])
164
+ volume = parseFloat(volumeMatches[1]);
165
+ const unitsMatches = portion.label.match(/(\d?\.?\d?\d) unit/);
166
+ if (unitsMatches && unitsMatches[1])
167
+ units = parseFloat(unitsMatches[1]);
168
+ if (portion.label === 'Pint' && strength) {
169
+ units = strengthAndVolumeToUnits(strength, 568);
170
+ }
171
+ else if (['Half pint', 'Half Pint', 'Half'].includes(portion.label) && typeof strength !== 'undefined') {
172
+ units = strengthAndVolumeToUnits(strength, 284);
173
+ }
174
+ else if (typeof strength !== 'undefined' && volume) {
175
+ units = strengthAndVolumeToUnits(strength, volume);
176
+ }
177
+ else if (typeof strength !== 'undefined' && volumeDescription) {
178
+ units = strengthAndVolumeToUnits(strength, volumeDescription);
179
+ }
180
+ else if (typeof strength !== 'undefined' && portion.label === 'Single') {
181
+ units = strengthAndVolumeToUnits(strength, 25);
182
+ }
183
+ else if (typeof strength !== 'undefined' && portion.label === 'Double') {
184
+ units = strengthAndVolumeToUnits(strength, 50);
185
+ }
186
+ if (typeof units !== 'undefined') {
187
+ const ppu = portion.value.price.value / units;
188
+ if (ppu < bestPPU) {
189
+ bestPPU = ppu;
190
+ bestPortion = portion;
191
+ bestUnits = units;
192
+ }
193
+ }
194
+ }
195
+ if (typeof bestPortion !== 'undefined') {
196
+ drinks.push({
197
+ name: product.name,
198
+ units: bestUnits,
199
+ ppu: bestPPU,
200
+ productId: product.id,
201
+ price: bestPortion?.value.price.value,
202
+ });
203
+ }
204
+ }
205
+ drinks.sort((a, b) => {
206
+ return a.ppu - b.ppu;
207
+ });
208
+ return drinks;
209
+ }
3
210
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "wetherspoons-api",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "A simple package to get data from the JD Wetherspoons API",
5
5
  "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
6
7
  "type": "module",
8
+ "files": [
9
+ "dist"
10
+ ],
7
11
  "scripts": {
8
12
  "build": "tsc",
9
13
  "lint": "eslint .",
File without changes
@@ -1,3 +0,0 @@
1
- declare const _default: import("@eslint/core", { with: { "resolution-mode": "require" } }).ConfigObject<import("@eslint/core", { with: { "resolution-mode": "require" } }).RulesConfig>[];
2
- export default _default;
3
- //# sourceMappingURL=eslint.config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"eslint.config.d.ts","sourceRoot":"","sources":["../eslint.config.ts"],"names":[],"mappings":";AAMA,wBAaG"}
@@ -1,20 +0,0 @@
1
- import js from '@eslint/js';
2
- import globals from 'globals';
3
- import tseslint from 'typescript-eslint';
4
- import { defineConfig } from 'eslint/config';
5
- import stylistic from '@stylistic/eslint-plugin';
6
- export default defineConfig([
7
- {
8
- ignores: ['dist/**', 'node_modules/**'],
9
- },
10
- { files: ['**/*.{js,mjs,cjs,ts,mts,cts}'], plugins: { js, '@stylistic': stylistic }, extends: ['js/recommended'], languageOptions: { globals: { ...globals.browser, ...globals.node } } },
11
- tseslint.configs.recommended,
12
- stylistic.configs['recommended'],
13
- {
14
- rules: {
15
- '@stylistic/semi': ['error', 'always'],
16
- '@stylistic/brace-style': ['error', '1tbs'],
17
- },
18
- },
19
- ]);
20
- //# sourceMappingURL=eslint.config.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"eslint.config.js","sourceRoot":"","sources":["../eslint.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,QAAQ,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,SAAS,MAAM,0BAA0B,CAAC;AAEjD,eAAe,YAAY,CAAC;IAC1B;QACE,OAAO,EAAE,CAAC,SAAS,EAAE,iBAAiB,CAAC;KACxC;IACD,EAAE,KAAK,EAAE,CAAC,8BAA8B,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,eAAe,EAAE,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE;IACzL,QAAQ,CAAC,OAAO,CAAC,WAAW;IAC5B,SAAS,CAAC,OAAO,CAAC,aAAa,CAAC;IAChC;QACE,KAAK,EAAE;YACL,iBAAiB,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC;YACtC,wBAAwB,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC;SAC5C;KACF;CACF,CAAC,CAAC"}
@@ -1,116 +0,0 @@
1
- import { z } from 'zod';
2
- export declare const highLevelVenueSchema: z.ZodObject<{
3
- franchise: z.ZodString;
4
- id: z.ZodNumber;
5
- isClosed: z.ZodBoolean;
6
- name: z.ZodString;
7
- venueRef: z.ZodNumber;
8
- }, z.core.$strip>;
9
- export type HighLevelVenue = z.infer<typeof highLevelVenueSchema>;
10
- export declare function venues(): Promise<HighLevelVenue[]>;
11
- declare const detailedVenueSchema: z.ZodObject<{
12
- canPlaceOrder: z.ZodBoolean;
13
- franchise: z.ZodString;
14
- id: z.ZodNumber;
15
- isClosed: z.ZodOptional<z.ZodBoolean>;
16
- name: z.ZodString;
17
- salesAreas: z.ZodArray<z.ZodObject<{
18
- id: z.ZodNumber;
19
- }, z.core.$strip>>;
20
- venueCanOrder: z.ZodBoolean;
21
- venueRef: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
22
- }, z.core.$strip>;
23
- export type DetailedVenue = z.infer<typeof detailedVenueSchema>;
24
- export declare function getVenue(venue: HighLevelVenue): Promise<DetailedVenue>;
25
- export declare const highLevelMenuSchema: z.ZodObject<{
26
- canOrder: z.ZodBoolean;
27
- franchise: z.ZodString;
28
- id: z.ZodNumber;
29
- name: z.ZodString;
30
- salesAreaId: z.ZodNumber;
31
- venueRef: z.ZodNumber;
32
- }, z.core.$strip>;
33
- export type HighLevelMenu = z.infer<typeof highLevelMenuSchema>;
34
- export declare function getMenus({ venue, salesAreaId }: {
35
- venue: DetailedVenue;
36
- salesAreaId: number;
37
- }): Promise<HighLevelMenu[]>;
38
- declare const detailedMenuProductSchema: z.ZodObject<{
39
- id: z.ZodNumber;
40
- isOutOfStock: z.ZodBoolean;
41
- itemType: z.ZodLiteral<"product">;
42
- name: z.ZodString;
43
- description: z.ZodString;
44
- options: z.ZodObject<{
45
- portion: z.ZodObject<{
46
- options: z.ZodArray<z.ZodObject<{
47
- label: z.ZodString;
48
- value: z.ZodObject<{
49
- price: z.ZodObject<{
50
- currency: z.ZodString;
51
- discount: z.ZodNumber;
52
- initialValue: z.ZodNumber;
53
- value: z.ZodNumber;
54
- }, z.core.$strip>;
55
- }, z.core.$strip>;
56
- }, z.core.$strip>>;
57
- }, z.core.$strip>;
58
- }, z.core.$strip>;
59
- }, z.core.$strip>;
60
- export type DetailedMenuProduct = z.infer<typeof detailedMenuProductSchema>;
61
- declare const detailedMenuSchema: z.ZodObject<{
62
- data: z.ZodObject<{
63
- canOrder: z.ZodBoolean;
64
- categories: z.ZodArray<z.ZodObject<{
65
- itemGroups: z.ZodArray<z.ZodObject<{
66
- items: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
67
- itemType: z.ZodLiteral<"text">;
68
- text: z.ZodString;
69
- }, z.core.$strip>, z.ZodObject<{
70
- itemType: z.ZodLiteral<"divider">;
71
- }, z.core.$strip>, z.ZodObject<{
72
- itemType: z.ZodLiteral<"ale">;
73
- }, z.core.$strip>, z.ZodObject<{
74
- id: z.ZodNumber;
75
- isOutOfStock: z.ZodBoolean;
76
- itemType: z.ZodLiteral<"product">;
77
- name: z.ZodString;
78
- description: z.ZodString;
79
- options: z.ZodObject<{
80
- portion: z.ZodObject<{
81
- options: z.ZodArray<z.ZodObject<{
82
- label: z.ZodString;
83
- value: z.ZodObject<{
84
- price: z.ZodObject<{
85
- currency: z.ZodString;
86
- discount: z.ZodNumber;
87
- initialValue: z.ZodNumber;
88
- value: z.ZodNumber;
89
- }, z.core.$strip>;
90
- }, z.core.$strip>;
91
- }, z.core.$strip>>;
92
- }, z.core.$strip>;
93
- }, z.core.$strip>;
94
- }, z.core.$strip>]>>;
95
- name: z.ZodNullable<z.ZodString>;
96
- }, z.core.$strip>>;
97
- name: z.ZodString;
98
- }, z.core.$strip>>;
99
- franchise: z.ZodString;
100
- id: z.ZodNumber;
101
- salesAreaId: z.ZodNumber;
102
- venueRef: z.ZodNumber;
103
- }, z.core.$strip>;
104
- }, z.core.$strip>;
105
- export type DetailedMenu = z.infer<typeof detailedMenuSchema>;
106
- export declare function getMenu(highLevelMenu: HighLevelMenu): Promise<DetailedMenu>;
107
- export interface Drink {
108
- name: string;
109
- units: number;
110
- productId: number;
111
- price: number;
112
- ppu: number;
113
- }
114
- export declare function getDrinks(highLevelVenue: HighLevelVenue): Promise<Drink[]>;
115
- export {};
116
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAiBxB,eAAO,MAAM,oBAAoB;;;;;;iBAM/B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,wBAAsB,MAAM,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAIxD;AAED,QAAA,MAAM,mBAAmB;;;;;;;;;;;iBAWvB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,wBAAsB,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAI5E;AAED,eAAO,MAAM,mBAAmB;;;;;;;iBAO9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,wBAAsB,QAAQ,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAI9H;AAED,QAAA,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;iBAqB7B,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA2BtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,wBAAsB,OAAO,CAAC,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAIjF;AAMD,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,wBAAsB,SAAS,CAAC,cAAc,EAAE,cAAc,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CA+GhF"}
package/dist/src/index.js DELETED
@@ -1,210 +0,0 @@
1
- import { z } from 'zod';
2
- const API_ENDPOINT = 'https://ca.jdw-apps.net/api/v0.1';
3
- const API_HEADERS = {
4
- Authorization: 'Bearer 1|SFS9MMnn5deflq0BMcUTSijwSMBB4mc7NSG2rOhqb2765466',
5
- };
6
- async function request(path) {
7
- const response = await fetch(`${API_ENDPOINT}${path}`, {
8
- headers: API_HEADERS,
9
- });
10
- const json = await response.json();
11
- return json;
12
- }
13
- export const highLevelVenueSchema = z.object({
14
- franchise: z.string(),
15
- id: z.number(),
16
- isClosed: z.boolean(),
17
- name: z.string(),
18
- venueRef: z.number(),
19
- });
20
- export async function venues() {
21
- const response = await request('/venues');
22
- const venues = z.object({ data: z.array(highLevelVenueSchema) }).parse(response);
23
- return venues.data;
24
- }
25
- const detailedVenueSchema = z.object({
26
- canPlaceOrder: z.boolean(),
27
- franchise: z.string(),
28
- id: z.number(),
29
- isClosed: z.boolean().optional(),
30
- name: z.string(),
31
- salesAreas: z.array(z.object({
32
- id: z.number(),
33
- })),
34
- venueCanOrder: z.boolean(),
35
- venueRef: z.union([z.string(), z.number()]),
36
- });
37
- export async function getVenue(venue) {
38
- const response = await request(`/venues/${venue.venueRef}`);
39
- const venueDetails = z.object({ data: detailedVenueSchema }).parse(response);
40
- return venueDetails.data;
41
- }
42
- export const highLevelMenuSchema = z.object({
43
- canOrder: z.boolean(),
44
- franchise: z.string(),
45
- id: z.number(),
46
- name: z.string(),
47
- salesAreaId: z.number(),
48
- venueRef: z.number(),
49
- });
50
- export async function getMenus({ venue, salesAreaId }) {
51
- const response = await request(`/${venue.franchise}/venues/${venue.venueRef}/sales-areas/${salesAreaId}/menus`);
52
- const menus = z.object({ data: z.array(highLevelMenuSchema) }).parse(response);
53
- return menus.data;
54
- }
55
- const detailedMenuProductSchema = z.object({
56
- id: z.number(),
57
- isOutOfStock: z.boolean(),
58
- itemType: z.literal('product'),
59
- name: z.string(),
60
- description: z.string(),
61
- options: z.object({
62
- portion: z.object({
63
- options: z.array(z.object({
64
- label: z.string(),
65
- value: z.object({
66
- price: z.object({
67
- currency: z.string(),
68
- discount: z.number(),
69
- initialValue: z.number(),
70
- value: z.number(),
71
- }),
72
- }),
73
- })),
74
- }),
75
- }),
76
- });
77
- const detailedMenuSchema = z.object({
78
- data: z.object({
79
- canOrder: z.boolean(),
80
- categories: z.array(z.object({
81
- itemGroups: z.array(z.object({
82
- items: z.array(z.union([
83
- z.object({
84
- itemType: z.literal('text'),
85
- text: z.string(),
86
- }),
87
- z.object({
88
- itemType: z.literal('divider'),
89
- }),
90
- z.object({
91
- itemType: z.literal('ale'),
92
- }),
93
- detailedMenuProductSchema,
94
- ])),
95
- name: z.string().nullable(),
96
- })),
97
- name: z.string(),
98
- })),
99
- franchise: z.string(),
100
- id: z.number(),
101
- salesAreaId: z.number(),
102
- venueRef: z.number(),
103
- }),
104
- });
105
- export async function getMenu(highLevelMenu) {
106
- const response = await request(`/${highLevelMenu.franchise}/venues/${highLevelMenu.venueRef}/sales-areas/${highLevelMenu.salesAreaId}/menus/${highLevelMenu.id}`);
107
- const detailedMenu = detailedMenuSchema.parse(response);
108
- return detailedMenu;
109
- }
110
- function strengthAndVolumeToUnits(strength, volume) {
111
- return (strength * volume) / 1000;
112
- }
113
- export async function getDrinks(highLevelVenue) {
114
- const detailedVenue = await getVenue(highLevelVenue);
115
- const salesArea = detailedVenue.salesAreas[0];
116
- if (!salesArea)
117
- return [];
118
- const menus = await getMenus({ venue: detailedVenue, salesAreaId: salesArea.id });
119
- let drinksMenu;
120
- for (const menu of menus) {
121
- if (menu.name === 'Drinks') {
122
- drinksMenu = menu;
123
- break;
124
- }
125
- }
126
- if (!drinksMenu)
127
- return [];
128
- const res = await getMenu(drinksMenu);
129
- // Convert menu to flat array of drinks
130
- const hash_map = new Map();
131
- for (const categories of res.data.categories) {
132
- for (const itemGroup of categories.itemGroups) {
133
- for (const item of itemGroup.items) {
134
- if (item.itemType == 'product') {
135
- // Skip out of stock
136
- if (item.isOutOfStock) {
137
- continue;
138
- }
139
- hash_map.set(item.id, item);
140
- }
141
- }
142
- }
143
- }
144
- const drinks = [];
145
- for (const product of hash_map.values()) {
146
- const strengthMatches = product.description.match(/(\d?\d?\.?\d?\d%)\s?ABV/);
147
- const volumeDescriptionMatches = product.description.match(/(\d?\d\d)ml/);
148
- let strength;
149
- if (strengthMatches) {
150
- strength = parseFloat(strengthMatches[0]);
151
- }
152
- let volumeDescription;
153
- if (volumeDescriptionMatches) {
154
- volumeDescription = parseFloat(volumeDescriptionMatches[0]);
155
- }
156
- let bestPortion;
157
- let bestPPU = Infinity;
158
- let bestUnits = 0;
159
- for (const portion of product.options.portion.options) {
160
- let units;
161
- const volumeMatches = portion.label.match(/(\d?\d\d)ml/);
162
- let volume;
163
- if (volumeMatches && volumeMatches[1])
164
- volume = parseFloat(volumeMatches[1]);
165
- const unitsMatches = portion.label.match(/(\d?\.?\d?\d) unit/);
166
- if (unitsMatches && unitsMatches[1])
167
- units = parseFloat(unitsMatches[1]);
168
- if (portion.label === 'Pint' && strength) {
169
- units = strengthAndVolumeToUnits(strength, 568);
170
- }
171
- else if (['Half pint', 'Half Pint', 'Half'].includes(portion.label) && typeof strength !== 'undefined') {
172
- units = strengthAndVolumeToUnits(strength, 284);
173
- }
174
- else if (typeof strength !== 'undefined' && volume) {
175
- units = strengthAndVolumeToUnits(strength, volume);
176
- }
177
- else if (typeof strength !== 'undefined' && volumeDescription) {
178
- units = strengthAndVolumeToUnits(strength, volumeDescription);
179
- }
180
- else if (typeof strength !== 'undefined' && portion.label === 'Single') {
181
- units = strengthAndVolumeToUnits(strength, 25);
182
- }
183
- else if (typeof strength !== 'undefined' && portion.label === 'Double') {
184
- units = strengthAndVolumeToUnits(strength, 50);
185
- }
186
- if (typeof units !== 'undefined') {
187
- const ppu = portion.value.price.value / units;
188
- if (ppu < bestPPU) {
189
- bestPPU = ppu;
190
- bestPortion = portion;
191
- bestUnits = units;
192
- }
193
- }
194
- }
195
- if (typeof bestPortion !== 'undefined') {
196
- drinks.push({
197
- name: product.name,
198
- units: bestUnits,
199
- ppu: bestPPU,
200
- productId: product.id,
201
- price: bestPortion?.value.price.value,
202
- });
203
- }
204
- }
205
- drinks.sort((a, b) => {
206
- return a.ppu - b.ppu;
207
- });
208
- return drinks;
209
- }
210
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
package/eslint.config.ts DELETED
@@ -1,20 +0,0 @@
1
- import js from '@eslint/js';
2
- import globals from 'globals';
3
- import tseslint from 'typescript-eslint';
4
- import { defineConfig } from 'eslint/config';
5
- import stylistic from '@stylistic/eslint-plugin';
6
-
7
- export default defineConfig([
8
- {
9
- ignores: ['dist/**', 'node_modules/**'],
10
- },
11
- { files: ['**/*.{js,mjs,cjs,ts,mts,cts}'], plugins: { js, '@stylistic': stylistic }, extends: ['js/recommended'], languageOptions: { globals: { ...globals.browser, ...globals.node } } },
12
- tseslint.configs.recommended,
13
- stylistic.configs['recommended'],
14
- {
15
- rules: {
16
- '@stylistic/semi': ['error', 'always'],
17
- '@stylistic/brace-style': ['error', '1tbs'],
18
- },
19
- },
20
- ]);
package/src/index.ts DELETED
@@ -1,257 +0,0 @@
1
- import { z } from 'zod';
2
-
3
- const API_ENDPOINT = 'https://ca.jdw-apps.net/api/v0.1';
4
- const API_HEADERS = {
5
- Authorization: 'Bearer 1|SFS9MMnn5deflq0BMcUTSijwSMBB4mc7NSG2rOhqb2765466',
6
- };
7
-
8
- async function request(path: string): Promise<unknown> {
9
- const response = await fetch(`${API_ENDPOINT}${path}`,
10
- {
11
- headers: API_HEADERS,
12
- },
13
- );
14
- const json = await response.json();
15
- return json;
16
- }
17
-
18
- export const highLevelVenueSchema = z.object({
19
- franchise: z.string(),
20
- id: z.number(),
21
- isClosed: z.boolean(),
22
- name: z.string(),
23
- venueRef: z.number(),
24
- });
25
-
26
- export type HighLevelVenue = z.infer<typeof highLevelVenueSchema>;
27
-
28
- export async function venues(): Promise<HighLevelVenue[]> {
29
- const response = await request('/venues');
30
- const venues = z.object({ data: z.array(highLevelVenueSchema) }).parse(response);
31
- return venues.data;
32
- }
33
-
34
- const detailedVenueSchema = z.object({
35
- canPlaceOrder: z.boolean(),
36
- franchise: z.string(),
37
- id: z.number(),
38
- isClosed: z.boolean().optional(),
39
- name: z.string(),
40
- salesAreas: z.array(z.object({
41
- id: z.number(),
42
- })),
43
- venueCanOrder: z.boolean(),
44
- venueRef: z.union([z.string(), z.number()]),
45
- });
46
-
47
- export type DetailedVenue = z.infer<typeof detailedVenueSchema>;
48
-
49
- export async function getVenue(venue: HighLevelVenue): Promise<DetailedVenue> {
50
- const response = await request(`/venues/${venue.venueRef}`);
51
- const venueDetails = z.object({ data: detailedVenueSchema }).parse(response);
52
- return venueDetails.data;
53
- }
54
-
55
- export const highLevelMenuSchema = z.object({
56
- canOrder: z.boolean(),
57
- franchise: z.string(),
58
- id: z.number(),
59
- name: z.string(),
60
- salesAreaId: z.number(),
61
- venueRef: z.number(),
62
- });
63
-
64
- export type HighLevelMenu = z.infer<typeof highLevelMenuSchema>;
65
-
66
- export async function getMenus({ venue, salesAreaId }: { venue: DetailedVenue, salesAreaId: number }): Promise<HighLevelMenu[]> {
67
- const response = await request(`/${venue.franchise}/venues/${venue.venueRef}/sales-areas/${salesAreaId}/menus`);
68
- const menus = z.object({ data: z.array(highLevelMenuSchema) }).parse(response);
69
- return menus.data;
70
- }
71
-
72
- const detailedMenuProductSchema = z.object({
73
- id: z.number(),
74
- isOutOfStock: z.boolean(),
75
- itemType: z.literal('product'),
76
- name: z.string(),
77
- description: z.string(),
78
- options: z.object({
79
- portion: z.object({
80
- options: z.array(z.object({
81
- label: z.string(),
82
- value: z.object({
83
- price: z.object({
84
- currency: z.string(),
85
- discount: z.number(),
86
- initialValue: z.number(),
87
- value: z.number(),
88
- }),
89
- }),
90
- })),
91
- }),
92
- }),
93
- });
94
-
95
- export type DetailedMenuProduct = z.infer<typeof detailedMenuProductSchema>;
96
-
97
- const detailedMenuSchema = z.object({
98
- data: z.object({
99
- canOrder: z.boolean(),
100
- categories: z.array(z.object({
101
- itemGroups: z.array(z.object({
102
- items: z.array(z.union([
103
- z.object({
104
- itemType: z.literal('text'),
105
- text: z.string(),
106
- }),
107
- z.object({
108
- itemType: z.literal('divider'),
109
- }),
110
- z.object({
111
- itemType: z.literal('ale'),
112
- }),
113
- detailedMenuProductSchema,
114
- ])),
115
- name: z.string().nullable(),
116
- })),
117
- name: z.string(),
118
- })),
119
- franchise: z.string(),
120
- id: z.number(),
121
- salesAreaId: z.number(),
122
- venueRef: z.number(),
123
- }),
124
- });
125
-
126
- export type DetailedMenu = z.infer<typeof detailedMenuSchema>;
127
-
128
- export async function getMenu(highLevelMenu: HighLevelMenu): Promise<DetailedMenu> {
129
- const response = await request(`/${highLevelMenu.franchise}/venues/${highLevelMenu.venueRef}/sales-areas/${highLevelMenu.salesAreaId}/menus/${highLevelMenu.id}`);
130
- const detailedMenu = detailedMenuSchema.parse(response);
131
- return detailedMenu;
132
- }
133
-
134
- function strengthAndVolumeToUnits(strength: number, volume: number) {
135
- return (strength * volume) / 1000;
136
- }
137
-
138
- export interface Drink {
139
- name: string
140
- units: number
141
- productId: number
142
- price: number
143
- ppu: number
144
- }
145
-
146
- export async function getDrinks(highLevelVenue: HighLevelVenue): Promise<Drink[]> {
147
- const detailedVenue = await getVenue(highLevelVenue);
148
-
149
- const salesArea = detailedVenue.salesAreas[0];
150
-
151
- if (!salesArea) return [];
152
-
153
- const menus = await getMenus({ venue: detailedVenue, salesAreaId: salesArea.id });
154
-
155
- let drinksMenu;
156
- for (const menu of menus) {
157
- if (menu.name === 'Drinks') {
158
- drinksMenu = menu;
159
- break;
160
- }
161
- }
162
-
163
- if (!drinksMenu) return [];
164
- const res = await getMenu(drinksMenu);
165
-
166
- // Convert menu to flat array of drinks
167
- const hash_map = new Map<number, DetailedMenuProduct>();
168
-
169
- for (const categories of res.data.categories) {
170
- for (const itemGroup of categories.itemGroups) {
171
- for (const item of itemGroup.items) {
172
- if (item.itemType == 'product') {
173
- // Skip out of stock
174
- if (item.isOutOfStock) {
175
- continue;
176
- }
177
- hash_map.set(item.id, item);
178
- }
179
- }
180
- }
181
- }
182
-
183
- const drinks: Drink[] = [];
184
-
185
- for (const product of hash_map.values()) {
186
- const strengthMatches = product.description.match(/(\d?\d?\.?\d?\d%)\s?ABV/);
187
- const volumeDescriptionMatches = product.description.match(/(\d?\d\d)ml/);
188
-
189
- let strength;
190
- if (strengthMatches) {
191
- strength = parseFloat(strengthMatches[0]);
192
- }
193
-
194
- let volumeDescription;
195
- if (volumeDescriptionMatches) {
196
- volumeDescription = parseFloat(volumeDescriptionMatches[0]);
197
- }
198
-
199
- let bestPortion;
200
- let bestPPU = Infinity;
201
- let bestUnits = 0;
202
-
203
- for (const portion of product.options.portion.options) {
204
- let units;
205
-
206
- const volumeMatches = portion.label.match(/(\d?\d\d)ml/);
207
-
208
- let volume;
209
- if (volumeMatches && volumeMatches[1])
210
- volume = parseFloat(volumeMatches[1]);
211
-
212
- const unitsMatches = portion.label.match(/(\d?\.?\d?\d) unit/);
213
- if (unitsMatches && unitsMatches[1])
214
- units = parseFloat(unitsMatches[1]);
215
-
216
- if (portion.label === 'Pint' && strength) {
217
- units = strengthAndVolumeToUnits(strength, 568);
218
- } else if (['Half pint', 'Half Pint', 'Half'].includes(portion.label) && typeof strength !== 'undefined') {
219
- units = strengthAndVolumeToUnits(strength, 284);
220
- } else if (typeof strength !== 'undefined' && volume) {
221
- units = strengthAndVolumeToUnits(strength, volume);
222
- } else if (typeof strength !== 'undefined' && volumeDescription) {
223
- units = strengthAndVolumeToUnits(strength, volumeDescription);
224
- } else if (typeof strength !== 'undefined' && portion.label === 'Single') {
225
- units = strengthAndVolumeToUnits(strength, 25);
226
- } else if (typeof strength !== 'undefined' && portion.label === 'Double') {
227
- units = strengthAndVolumeToUnits(strength, 50);
228
- }
229
-
230
- if (typeof units !== 'undefined') {
231
- const ppu = portion.value.price.value / units;
232
-
233
- if (ppu < bestPPU) {
234
- bestPPU = ppu;
235
- bestPortion = portion;
236
- bestUnits = units;
237
- }
238
- }
239
- }
240
-
241
- if (typeof bestPortion !== 'undefined') {
242
- drinks.push({
243
- name: product.name,
244
- units: bestUnits,
245
- ppu: bestPPU,
246
- productId: product.id,
247
- price: bestPortion?.value.price.value,
248
- });
249
- }
250
- }
251
-
252
- drinks.sort((a, b) => {
253
- return a.ppu - b.ppu;
254
- });
255
-
256
- return drinks;
257
- }
package/tsconfig.json DELETED
@@ -1,43 +0,0 @@
1
- {
2
- // Visit https://aka.ms/tsconfig to read more about this file
3
- "compilerOptions": {
4
- // File Layout
5
- "outDir": "./dist",
6
-
7
- // Environment Settings
8
- // See also https://aka.ms/tsconfig/module
9
- "module": "node20",
10
- "target": "es2024",
11
- "types": [],
12
- // For nodejs:
13
- // "lib": ["esnext"],
14
- // "types": ["node"],
15
- // and npm install -D @types/node
16
-
17
- // Other Outputs
18
- "sourceMap": true,
19
- "declaration": true,
20
- "declarationMap": true,
21
-
22
- // Stricter Typechecking Options
23
- "noUncheckedIndexedAccess": true,
24
- "exactOptionalPropertyTypes": true,
25
-
26
- // Style Options
27
- // "noImplicitReturns": true,
28
- // "noImplicitOverride": true,
29
- // "noUnusedLocals": true,
30
- // "noUnusedParameters": true,
31
- // "noFallthroughCasesInSwitch": true,
32
- // "noPropertyAccessFromIndexSignature": true,
33
-
34
- // Recommended Options
35
- "strict": true,
36
- "jsx": "react-jsx",
37
- "verbatimModuleSyntax": true,
38
- "isolatedModules": true,
39
- "noUncheckedSideEffectImports": true,
40
- "moduleDetection": "force",
41
- "skipLibCheck": true,
42
- }
43
- }