tablefacts 0.1.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/.env.example +14 -0
- package/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/README.md +313 -0
- package/bin/tablefacts.mjs +28 -0
- package/package.json +77 -0
- package/src/index.mjs +52 -0
- package/src/instagram/README.md +135 -0
- package/src/instagram/download.mjs +62 -0
- package/src/instagram/index.mjs +355 -0
- package/src/instagram/links.mjs +55 -0
- package/src/instagram/record.mjs +18 -0
- package/src/lib/edge.mjs +49 -0
- package/src/lib/env.mjs +35 -0
- package/src/lib/errors.mjs +39 -0
- package/src/lib/files.mjs +10 -0
- package/src/lib/images.mjs +20 -0
- package/src/lib/log.mjs +17 -0
- package/src/lib/photos.mjs +42 -0
- package/src/lib/playwright.mjs +13 -0
- package/src/lib/project.mjs +42 -0
- package/src/lib/text.mjs +7 -0
- package/src/lib/types.mjs +247 -0
- package/src/menu/README.md +97 -0
- package/src/menu/cluvi/config.mjs +33 -0
- package/src/menu/cluvi/extract.mjs +24 -0
- package/src/menu/cluvi/import.mjs +30 -0
- package/src/menu/cluvi/source.mjs +156 -0
- package/src/menu/index.mjs +9 -0
- package/src/menu/lib/db.mjs +119 -0
- package/src/menu/lib/import.mjs +126 -0
- package/src/menu/lib/menu.mjs +95 -0
- package/src/menu/lib/run.mjs +83 -0
- package/src/menu/raw/config.mjs +38 -0
- package/src/menu/raw/extract.mjs +72 -0
- package/src/menu/raw/import.mjs +99 -0
- package/src/menu/raw/normalize.mjs +120 -0
- package/src/menu/raw/source.mjs +116 -0
- package/src/menu/raw/vision.mjs +252 -0
- package/src/research/README.md +69 -0
- package/src/research/index.mjs +147 -0
- package/src/research/lib/google.mjs +93 -0
- package/src/research/lib/hours.mjs +109 -0
- package/src/research/lib/merge.mjs +119 -0
- package/src/research/lib/osm.mjs +49 -0
- package/src/research/lib/report.mjs +118 -0
- package/src/research/lib/social.mjs +49 -0
- package/src/research/lib/util.mjs +104 -0
- package/src/research/lib/website.mjs +285 -0
- package/src/research/research.mjs +67 -0
- package/src/tripadvisor/README.md +78 -0
- package/src/tripadvisor/index.mjs +178 -0
- package/src/tripadvisor/links.mjs +78 -0
- package/src/tripadvisor/photos.mjs +55 -0
- package/types/index.d.mts +65 -0
- package/types/instagram/download.d.mts +1 -0
- package/types/instagram/index.d.mts +13 -0
- package/types/instagram/links.d.mts +14 -0
- package/types/instagram/record.d.mts +1 -0
- package/types/lib/edge.d.mts +14 -0
- package/types/lib/env.d.mts +12 -0
- package/types/lib/errors.d.mts +25 -0
- package/types/lib/files.d.mts +1 -0
- package/types/lib/images.d.mts +6 -0
- package/types/lib/log.d.mts +5 -0
- package/types/lib/photos.d.mts +30 -0
- package/types/lib/playwright.d.mts +1677 -0
- package/types/lib/project.d.mts +32 -0
- package/types/lib/text.d.mts +4 -0
- package/types/lib/types.d.mts +668 -0
- package/types/menu/cluvi/config.d.mts +13 -0
- package/types/menu/cluvi/extract.d.mts +2 -0
- package/types/menu/cluvi/import.d.mts +35 -0
- package/types/menu/cluvi/source.d.mts +37 -0
- package/types/menu/index.d.mts +6 -0
- package/types/menu/lib/db.d.mts +23 -0
- package/types/menu/lib/import.d.mts +11 -0
- package/types/menu/lib/menu.d.mts +24 -0
- package/types/menu/lib/run.d.mts +27 -0
- package/types/menu/raw/config.d.mts +18 -0
- package/types/menu/raw/extract.d.mts +2 -0
- package/types/menu/raw/import.d.mts +64 -0
- package/types/menu/raw/normalize.d.mts +29 -0
- package/types/menu/raw/source.d.mts +19 -0
- package/types/menu/raw/vision.d.mts +13 -0
- package/types/research/index.d.mts +9 -0
- package/types/research/lib/google.d.mts +12 -0
- package/types/research/lib/hours.d.mts +22 -0
- package/types/research/lib/merge.d.mts +87 -0
- package/types/research/lib/osm.d.mts +36 -0
- package/types/research/lib/report.d.mts +6 -0
- package/types/research/lib/social.d.mts +118 -0
- package/types/research/lib/util.d.mts +45 -0
- package/types/research/lib/website.d.mts +283 -0
- package/types/research/research.d.mts +1 -0
- package/types/tripadvisor/index.d.mts +11 -0
- package/types/tripadvisor/links.d.mts +13 -0
- package/types/tripadvisor/photos.d.mts +1 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dir` when given, else TABLEFACTS_PROJECT, else the current folder.
|
|
3
|
+
* @param {string} [dir]
|
|
4
|
+
* @returns {string}
|
|
5
|
+
*/
|
|
6
|
+
export declare const projectRoot: (dir?: string) => string;
|
|
7
|
+
/**
|
|
8
|
+
* A path under <root>/.tablefacts, where output, caches and browser profiles go (git-ignore it).
|
|
9
|
+
* @param {string | undefined} root project folder (see projectRoot)
|
|
10
|
+
* @param {...string} parts
|
|
11
|
+
* @returns {string}
|
|
12
|
+
*/
|
|
13
|
+
export declare const workDirIn: (root: string | undefined, ...parts: string[]) => string;
|
|
14
|
+
/**
|
|
15
|
+
* A path under <project>/.tablefacts for the project in TABLEFACTS_PROJECT or the current folder.
|
|
16
|
+
* @param {...string} parts
|
|
17
|
+
* @returns {string}
|
|
18
|
+
*/
|
|
19
|
+
export declare const workDir: (...parts: string[]) => string;
|
|
20
|
+
/**
|
|
21
|
+
* The env files read, first one wins: <root>/.env, then <root>/data/.env (older templates).
|
|
22
|
+
* @param {string} [root] project folder (see projectRoot)
|
|
23
|
+
* @returns {string[]}
|
|
24
|
+
*/
|
|
25
|
+
export declare const envFiles: (root?: string) => string[];
|
|
26
|
+
/**
|
|
27
|
+
* An absolute path: relative paths resolve against the project (`projectDir`) when given, else the current folder.
|
|
28
|
+
* @param {string | undefined} projectDir
|
|
29
|
+
* @param {string} path
|
|
30
|
+
* @returns {string}
|
|
31
|
+
*/
|
|
32
|
+
export declare const resolveIn: (projectDir: string | undefined, path: string) => string;
|
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
export type Log = (message: string, level?: 'info' | 'warn' | 'error') => void;
|
|
2
|
+
export type Env = Record<string, string | undefined>;
|
|
3
|
+
export type ResearchOptions = {
|
|
4
|
+
/**
|
|
5
|
+
* Restaurant name. Required.
|
|
6
|
+
*/
|
|
7
|
+
name: string;
|
|
8
|
+
/**
|
|
9
|
+
* "City, Country".
|
|
10
|
+
*/
|
|
11
|
+
location?: string;
|
|
12
|
+
/**
|
|
13
|
+
* ISO country code, narrows the search (CO, MX, US...).
|
|
14
|
+
*/
|
|
15
|
+
country?: string;
|
|
16
|
+
website?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Handle or URL.
|
|
19
|
+
*/
|
|
20
|
+
instagram?: string;
|
|
21
|
+
/**
|
|
22
|
+
* TripAdvisor page URL.
|
|
23
|
+
*/
|
|
24
|
+
tripadvisor?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Linktree or other link-in-bio page.
|
|
27
|
+
*/
|
|
28
|
+
linktree?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Also download up to n Google and n website photos (reference only).
|
|
31
|
+
*/
|
|
32
|
+
photos?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Render the website with Playwright (sites built in JavaScript).
|
|
35
|
+
*/
|
|
36
|
+
render?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Set false to skip Google even if a key is available. Default true.
|
|
39
|
+
*/
|
|
40
|
+
google?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Default: env.GOOGLE_PLACES_API_KEY.
|
|
43
|
+
*/
|
|
44
|
+
googleKey?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Environment the keys are read from. Default process.env.
|
|
47
|
+
*/
|
|
48
|
+
env?: Env;
|
|
49
|
+
/**
|
|
50
|
+
* Output folder; relative paths resolve against projectDir. Default <project>/.tablefacts/research/<slug>.
|
|
51
|
+
*/
|
|
52
|
+
out?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Project folder. Default: TABLEFACTS_PROJECT or the current folder.
|
|
55
|
+
*/
|
|
56
|
+
projectDir?: string;
|
|
57
|
+
log?: Log;
|
|
58
|
+
};
|
|
59
|
+
export type ResearchPhoto = {
|
|
60
|
+
/**
|
|
61
|
+
* File name inside <outDir>/photos.
|
|
62
|
+
*/
|
|
63
|
+
file: string;
|
|
64
|
+
/**
|
|
65
|
+
* Where it was downloaded from.
|
|
66
|
+
*/
|
|
67
|
+
source: string;
|
|
68
|
+
alt?: string;
|
|
69
|
+
};
|
|
70
|
+
export type ResearchProfile = {
|
|
71
|
+
/**
|
|
72
|
+
* Each field carries value, source and confidence.
|
|
73
|
+
*/
|
|
74
|
+
fields: Record<string, any>;
|
|
75
|
+
warnings?: string[];
|
|
76
|
+
};
|
|
77
|
+
export type ResearchResult = {
|
|
78
|
+
/**
|
|
79
|
+
* The merged profile.
|
|
80
|
+
*/
|
|
81
|
+
profile: ResearchProfile;
|
|
82
|
+
/**
|
|
83
|
+
* What each source found or failed to find.
|
|
84
|
+
*/
|
|
85
|
+
notes: string[];
|
|
86
|
+
photos: ResearchPhoto[];
|
|
87
|
+
/**
|
|
88
|
+
* Absolute output folder.
|
|
89
|
+
*/
|
|
90
|
+
outDir: string;
|
|
91
|
+
/**
|
|
92
|
+
* Absolute paths of the written files.
|
|
93
|
+
*/
|
|
94
|
+
files: {
|
|
95
|
+
profile: string;
|
|
96
|
+
report: string;
|
|
97
|
+
setupAnswers: string;
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
export type PhotoFailure = {
|
|
101
|
+
/**
|
|
102
|
+
* The post, profile or page that failed.
|
|
103
|
+
*/
|
|
104
|
+
item: string;
|
|
105
|
+
reason: string;
|
|
106
|
+
};
|
|
107
|
+
export type PhotoSummary = {
|
|
108
|
+
saved: number;
|
|
109
|
+
/**
|
|
110
|
+
* Files that were already there.
|
|
111
|
+
*/
|
|
112
|
+
skipped: number;
|
|
113
|
+
failed: PhotoFailure[];
|
|
114
|
+
/**
|
|
115
|
+
* Only present when dryRun is true.
|
|
116
|
+
*/
|
|
117
|
+
found?: {
|
|
118
|
+
name: string;
|
|
119
|
+
url: string;
|
|
120
|
+
}[];
|
|
121
|
+
};
|
|
122
|
+
export type InstagramOptions = {
|
|
123
|
+
/**
|
|
124
|
+
* Post links.
|
|
125
|
+
*/
|
|
126
|
+
links?: string[];
|
|
127
|
+
/**
|
|
128
|
+
* Text file with one link per line (resolved against projectDir).
|
|
129
|
+
*/
|
|
130
|
+
file?: string;
|
|
131
|
+
/**
|
|
132
|
+
* Folder the images are saved to (resolved against projectDir). Required.
|
|
133
|
+
*/
|
|
134
|
+
out: string;
|
|
135
|
+
/**
|
|
136
|
+
* Profile link or handle (with or without the at sign): download a whole profile (videos skipped).
|
|
137
|
+
*/
|
|
138
|
+
profile?: string;
|
|
139
|
+
/**
|
|
140
|
+
* With `profile`, batches of posts to load. Default 1.
|
|
141
|
+
*/
|
|
142
|
+
pages?: number | 'all';
|
|
143
|
+
/**
|
|
144
|
+
* Edge debugging address, e.g. http://localhost:9222. Started if nothing listens.
|
|
145
|
+
*/
|
|
146
|
+
cdp?: string;
|
|
147
|
+
/**
|
|
148
|
+
* Profile folder for the Edge that is started.
|
|
149
|
+
*/
|
|
150
|
+
edgeDir?: string;
|
|
151
|
+
/**
|
|
152
|
+
* Reach toolzu through a Google search (CLI: --google). Default false.
|
|
153
|
+
*/
|
|
154
|
+
viaGoogle?: boolean;
|
|
155
|
+
/**
|
|
156
|
+
* Installed browser channel: 'msedge' or 'chrome'.
|
|
157
|
+
*/
|
|
158
|
+
browser?: string;
|
|
159
|
+
/**
|
|
160
|
+
* Persistent browser profile (resolved against projectDir).
|
|
161
|
+
*/
|
|
162
|
+
userDataDir?: string;
|
|
163
|
+
/**
|
|
164
|
+
* Project folder. Default: TABLEFACTS_PROJECT or the current folder.
|
|
165
|
+
*/
|
|
166
|
+
projectDir?: string;
|
|
167
|
+
/**
|
|
168
|
+
* Show the browser window.
|
|
169
|
+
*/
|
|
170
|
+
headed?: boolean;
|
|
171
|
+
/**
|
|
172
|
+
* List what would be saved without saving.
|
|
173
|
+
*/
|
|
174
|
+
dryRun?: boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Keep screenshots in <out>/_debug.
|
|
177
|
+
*/
|
|
178
|
+
debug?: boolean;
|
|
179
|
+
log?: Log;
|
|
180
|
+
};
|
|
181
|
+
export type TripadvisorOptions = {
|
|
182
|
+
/**
|
|
183
|
+
* Restaurant page links. At least one valid link is required.
|
|
184
|
+
*/
|
|
185
|
+
links: string[];
|
|
186
|
+
/**
|
|
187
|
+
* Folder the images are saved to (resolved against projectDir). Required.
|
|
188
|
+
*/
|
|
189
|
+
out: string;
|
|
190
|
+
/**
|
|
191
|
+
* Edge debugging address. Default http://localhost:9222.
|
|
192
|
+
*/
|
|
193
|
+
cdp?: string;
|
|
194
|
+
/**
|
|
195
|
+
* Profile folder for the Edge that is started.
|
|
196
|
+
*/
|
|
197
|
+
edgeDir?: string;
|
|
198
|
+
/**
|
|
199
|
+
* Stop after n photos per restaurant.
|
|
200
|
+
*/
|
|
201
|
+
max?: number;
|
|
202
|
+
/**
|
|
203
|
+
* Project folder. Default: TABLEFACTS_PROJECT or the current folder.
|
|
204
|
+
*/
|
|
205
|
+
projectDir?: string;
|
|
206
|
+
dryRun?: boolean;
|
|
207
|
+
debug?: boolean;
|
|
208
|
+
log?: Log;
|
|
209
|
+
};
|
|
210
|
+
export type MenuProduct = {
|
|
211
|
+
name: string;
|
|
212
|
+
description?: string | null;
|
|
213
|
+
/**
|
|
214
|
+
* Finite and not negative.
|
|
215
|
+
*/
|
|
216
|
+
price: number;
|
|
217
|
+
/**
|
|
218
|
+
* ISO 4217 code, e.g. COP.
|
|
219
|
+
*/
|
|
220
|
+
currency: string;
|
|
221
|
+
/**
|
|
222
|
+
* An https URL.
|
|
223
|
+
*/
|
|
224
|
+
image_url?: string | null;
|
|
225
|
+
recommended?: boolean;
|
|
226
|
+
};
|
|
227
|
+
export type MenuSection = {
|
|
228
|
+
name: string;
|
|
229
|
+
products: MenuProduct[];
|
|
230
|
+
};
|
|
231
|
+
export type MenuCategory = {
|
|
232
|
+
/**
|
|
233
|
+
* The key the site's dictionaries use.
|
|
234
|
+
*/
|
|
235
|
+
slug: string;
|
|
236
|
+
name: string;
|
|
237
|
+
sections: MenuSection[];
|
|
238
|
+
};
|
|
239
|
+
export type Menu = MenuCategory[];
|
|
240
|
+
export type MenuTotals = {
|
|
241
|
+
categories: number;
|
|
242
|
+
sections: number;
|
|
243
|
+
products: number;
|
|
244
|
+
withImage: number;
|
|
245
|
+
};
|
|
246
|
+
export type ImportOptions = {
|
|
247
|
+
/**
|
|
248
|
+
* Check and report, write nothing.
|
|
249
|
+
*/
|
|
250
|
+
dryRun?: boolean;
|
|
251
|
+
/**
|
|
252
|
+
* Also save the extracted menu as JSON at this path (resolved against projectDir).
|
|
253
|
+
*/
|
|
254
|
+
json?: string;
|
|
255
|
+
/**
|
|
256
|
+
* Replace the whole menu, not only the categories in this import.
|
|
257
|
+
*/
|
|
258
|
+
replaceAll?: boolean;
|
|
259
|
+
/**
|
|
260
|
+
* Write even if the import has far fewer products than it replaces.
|
|
261
|
+
*/
|
|
262
|
+
force?: boolean;
|
|
263
|
+
/**
|
|
264
|
+
* Default: env.SUPABASE_DB_URL.
|
|
265
|
+
*/
|
|
266
|
+
databaseUrl?: string;
|
|
267
|
+
/**
|
|
268
|
+
* Environment the database URL and keys are read from. Default process.env.
|
|
269
|
+
*/
|
|
270
|
+
env?: Env;
|
|
271
|
+
/**
|
|
272
|
+
* Project folder. Default: TABLEFACTS_PROJECT or the current folder.
|
|
273
|
+
*/
|
|
274
|
+
projectDir?: string;
|
|
275
|
+
log?: Log;
|
|
276
|
+
};
|
|
277
|
+
export type ImportResult = {
|
|
278
|
+
totals: MenuTotals;
|
|
279
|
+
notes: string[];
|
|
280
|
+
written: boolean;
|
|
281
|
+
dryRun: boolean;
|
|
282
|
+
/**
|
|
283
|
+
* Null when the database was not reached.
|
|
284
|
+
*/
|
|
285
|
+
database: {
|
|
286
|
+
label: string;
|
|
287
|
+
current: {
|
|
288
|
+
categories: number;
|
|
289
|
+
products: number;
|
|
290
|
+
kept: string[];
|
|
291
|
+
};
|
|
292
|
+
} | null;
|
|
293
|
+
};
|
|
294
|
+
export type ImportMenuOptions = ImportOptions & {
|
|
295
|
+
menu: Menu;
|
|
296
|
+
notes?: string[];
|
|
297
|
+
title?: string;
|
|
298
|
+
};
|
|
299
|
+
export type CluviConfig = {
|
|
300
|
+
/**
|
|
301
|
+
* Any page of the restaurant's Cluvi menu.
|
|
302
|
+
*/
|
|
303
|
+
url?: string;
|
|
304
|
+
/**
|
|
305
|
+
* Cluvi main categories folded into each site category.
|
|
306
|
+
*/
|
|
307
|
+
categories?: {
|
|
308
|
+
slug: string;
|
|
309
|
+
name: string;
|
|
310
|
+
from: string[];
|
|
311
|
+
}[];
|
|
312
|
+
/**
|
|
313
|
+
* Cluvi subcategory to section name.
|
|
314
|
+
*/
|
|
315
|
+
sections?: Record<string, string>;
|
|
316
|
+
};
|
|
317
|
+
export type RawConfig = {
|
|
318
|
+
/**
|
|
319
|
+
* Page with the menu pictures, or a direct image URL.
|
|
320
|
+
*/
|
|
321
|
+
url?: string;
|
|
322
|
+
/**
|
|
323
|
+
* ISO code of the prices.
|
|
324
|
+
*/
|
|
325
|
+
currency: string;
|
|
326
|
+
/**
|
|
327
|
+
* Thousands separator the menu prints. Default ".".
|
|
328
|
+
*/
|
|
329
|
+
thousands?: string;
|
|
330
|
+
/**
|
|
331
|
+
* Decimal separator the menu prints. Default ",".
|
|
332
|
+
*/
|
|
333
|
+
decimal?: string;
|
|
334
|
+
/**
|
|
335
|
+
* Multiplies every price. Default 1.
|
|
336
|
+
*/
|
|
337
|
+
scale?: number;
|
|
338
|
+
/**
|
|
339
|
+
* Category that lists each group.
|
|
340
|
+
*/
|
|
341
|
+
categories?: {
|
|
342
|
+
slug: string;
|
|
343
|
+
name: string;
|
|
344
|
+
groups?: ('food' | 'drink')[];
|
|
345
|
+
}[];
|
|
346
|
+
/**
|
|
347
|
+
* Section title to category slug.
|
|
348
|
+
*/
|
|
349
|
+
placeIn?: Record<string, string>;
|
|
350
|
+
/**
|
|
351
|
+
* Section title to the name stored.
|
|
352
|
+
*/
|
|
353
|
+
sections?: Record<string, string>;
|
|
354
|
+
/**
|
|
355
|
+
* Section titles to leave out.
|
|
356
|
+
*/
|
|
357
|
+
skipSections?: string[];
|
|
358
|
+
};
|
|
359
|
+
export type MenuSourceConfig = CluviConfig | RawConfig;
|
|
360
|
+
export type CluviMenuOptions = {
|
|
361
|
+
/**
|
|
362
|
+
* Default: the config's.
|
|
363
|
+
*/
|
|
364
|
+
url?: string;
|
|
365
|
+
service?: 'on_table' | 'delivery' | 'take_away';
|
|
366
|
+
lang?: string;
|
|
367
|
+
/**
|
|
368
|
+
* Default: the cluvi config.mjs.
|
|
369
|
+
*/
|
|
370
|
+
config?: CluviConfig;
|
|
371
|
+
};
|
|
372
|
+
export type ImportCluviOptions = ImportOptions & CluviMenuOptions;
|
|
373
|
+
export type ImageMenuReadOptions = {
|
|
374
|
+
/**
|
|
375
|
+
* Pages or image URLs. Default: the config's url.
|
|
376
|
+
*/
|
|
377
|
+
urls?: string[];
|
|
378
|
+
/**
|
|
379
|
+
* Pages to read, e.g. '1,3-5' or [1, 3, 4, 5].
|
|
380
|
+
*/
|
|
381
|
+
only?: string | number[];
|
|
382
|
+
/**
|
|
383
|
+
* Vision provider, see `providers`. Default MENU_VISION_PROVIDER or `defaultProvider`.
|
|
384
|
+
*/
|
|
385
|
+
provider?: string;
|
|
386
|
+
model?: string;
|
|
387
|
+
/**
|
|
388
|
+
* Ignore images declaring a smaller width. Default 500.
|
|
389
|
+
*/
|
|
390
|
+
minWidth?: number;
|
|
391
|
+
/**
|
|
392
|
+
* Default: the provider's key in env.
|
|
393
|
+
*/
|
|
394
|
+
apiKey?: string;
|
|
395
|
+
/**
|
|
396
|
+
* Read the pages again instead of using the saved transcriptions.
|
|
397
|
+
*/
|
|
398
|
+
refresh?: boolean;
|
|
399
|
+
/**
|
|
400
|
+
* Default: the raw config.mjs.
|
|
401
|
+
*/
|
|
402
|
+
config?: RawConfig;
|
|
403
|
+
};
|
|
404
|
+
export type ImportImageMenuOptions = ImportOptions & ImageMenuReadOptions;
|
|
405
|
+
export type ListMenuImagesOptions = {
|
|
406
|
+
urls?: string[];
|
|
407
|
+
only?: string | number[];
|
|
408
|
+
minWidth?: number;
|
|
409
|
+
config?: RawConfig;
|
|
410
|
+
};
|
|
411
|
+
export type MenuImage = {
|
|
412
|
+
/**
|
|
413
|
+
* Position as the CLI's --list numbers it.
|
|
414
|
+
*/
|
|
415
|
+
number: number;
|
|
416
|
+
url: string;
|
|
417
|
+
alt: string;
|
|
418
|
+
};
|
|
419
|
+
export type PriceFormat = {
|
|
420
|
+
/**
|
|
421
|
+
* Default ".".
|
|
422
|
+
*/
|
|
423
|
+
thousands?: string;
|
|
424
|
+
/**
|
|
425
|
+
* Default ",".
|
|
426
|
+
*/
|
|
427
|
+
decimal?: string;
|
|
428
|
+
/**
|
|
429
|
+
* Default 1.
|
|
430
|
+
*/
|
|
431
|
+
scale?: number;
|
|
432
|
+
};
|
|
433
|
+
export type VisionProvider = {
|
|
434
|
+
label: string;
|
|
435
|
+
/**
|
|
436
|
+
* Environment variable holding the API key.
|
|
437
|
+
*/
|
|
438
|
+
keyName: string;
|
|
439
|
+
defaultModel: string;
|
|
440
|
+
};
|
|
441
|
+
export type LoadEnvOptions = {
|
|
442
|
+
/**
|
|
443
|
+
* Project folder whose .env files are read.
|
|
444
|
+
*/
|
|
445
|
+
projectDir?: string;
|
|
446
|
+
/**
|
|
447
|
+
* Exactly these files instead of the project's.
|
|
448
|
+
*/
|
|
449
|
+
files?: string[];
|
|
450
|
+
/**
|
|
451
|
+
* Object the variables are set on. Default process.env.
|
|
452
|
+
*/
|
|
453
|
+
env?: Env;
|
|
454
|
+
};
|
|
455
|
+
export type TablefactsErrorCode = 'EUSAGE' | 'ECONFIG' | 'EDEPENDENCY' | 'EFAILED';
|
|
456
|
+
/**
|
|
457
|
+
* Progress callback. `level` is 'info' by default; 'warn' for problems the run goes on from,
|
|
458
|
+
* 'error' for failures. Every tool is silent unless given one.
|
|
459
|
+
* @typedef {(message: string, level?: 'info' | 'warn' | 'error') => void} Log
|
|
460
|
+
*/
|
|
461
|
+
/**
|
|
462
|
+
* An environment object such as process.env.
|
|
463
|
+
* @typedef {Record<string, string | undefined>} Env
|
|
464
|
+
*/
|
|
465
|
+
/**
|
|
466
|
+
* @typedef {object} ResearchOptions
|
|
467
|
+
* @property {string} name Restaurant name. Required.
|
|
468
|
+
* @property {string} [location] "City, Country".
|
|
469
|
+
* @property {string} [country] ISO country code, narrows the search (CO, MX, US...).
|
|
470
|
+
* @property {string} [website]
|
|
471
|
+
* @property {string} [instagram] Handle or URL.
|
|
472
|
+
* @property {string} [tripadvisor] TripAdvisor page URL.
|
|
473
|
+
* @property {string} [linktree] Linktree or other link-in-bio page.
|
|
474
|
+
* @property {number} [photos] Also download up to n Google and n website photos (reference only).
|
|
475
|
+
* @property {boolean} [render] Render the website with Playwright (sites built in JavaScript).
|
|
476
|
+
* @property {boolean} [google] Set false to skip Google even if a key is available. Default true.
|
|
477
|
+
* @property {string} [googleKey] Default: env.GOOGLE_PLACES_API_KEY.
|
|
478
|
+
* @property {Env} [env] Environment the keys are read from. Default process.env.
|
|
479
|
+
* @property {string} [out] Output folder; relative paths resolve against projectDir. Default <project>/.tablefacts/research/<slug>.
|
|
480
|
+
* @property {string} [projectDir] Project folder. Default: TABLEFACTS_PROJECT or the current folder.
|
|
481
|
+
* @property {Log} [log]
|
|
482
|
+
*/
|
|
483
|
+
/**
|
|
484
|
+
* @typedef {object} ResearchPhoto
|
|
485
|
+
* @property {string} file File name inside <outDir>/photos.
|
|
486
|
+
* @property {string} source Where it was downloaded from.
|
|
487
|
+
* @property {string} [alt]
|
|
488
|
+
*/
|
|
489
|
+
/**
|
|
490
|
+
* @typedef {object} ResearchProfile
|
|
491
|
+
* @property {Record<string, any>} fields Each field carries value, source and confidence.
|
|
492
|
+
* @property {string[]} [warnings]
|
|
493
|
+
*/
|
|
494
|
+
/**
|
|
495
|
+
* @typedef {object} ResearchResult
|
|
496
|
+
* @property {ResearchProfile} profile The merged profile.
|
|
497
|
+
* @property {string[]} notes What each source found or failed to find.
|
|
498
|
+
* @property {ResearchPhoto[]} photos
|
|
499
|
+
* @property {string} outDir Absolute output folder.
|
|
500
|
+
* @property {{ profile: string, report: string, setupAnswers: string }} files Absolute paths of the written files.
|
|
501
|
+
*/
|
|
502
|
+
/**
|
|
503
|
+
* @typedef {object} PhotoFailure
|
|
504
|
+
* @property {string} item The post, profile or page that failed.
|
|
505
|
+
* @property {string} reason
|
|
506
|
+
*/
|
|
507
|
+
/**
|
|
508
|
+
* @typedef {object} PhotoSummary
|
|
509
|
+
* @property {number} saved
|
|
510
|
+
* @property {number} skipped Files that were already there.
|
|
511
|
+
* @property {PhotoFailure[]} failed
|
|
512
|
+
* @property {{ name: string, url: string }[]} [found] Only present when dryRun is true.
|
|
513
|
+
*/
|
|
514
|
+
/**
|
|
515
|
+
* At least one of `links`, `file` or `profile` is required.
|
|
516
|
+
* @typedef {object} InstagramOptions
|
|
517
|
+
* @property {string[]} [links] Post links.
|
|
518
|
+
* @property {string} [file] Text file with one link per line (resolved against projectDir).
|
|
519
|
+
* @property {string} out Folder the images are saved to (resolved against projectDir). Required.
|
|
520
|
+
* @property {string} [profile] Profile link or handle (with or without the at sign): download a whole profile (videos skipped).
|
|
521
|
+
* @property {number | 'all'} [pages] With `profile`, batches of posts to load. Default 1.
|
|
522
|
+
* @property {string} [cdp] Edge debugging address, e.g. http://localhost:9222. Started if nothing listens.
|
|
523
|
+
* @property {string} [edgeDir] Profile folder for the Edge that is started.
|
|
524
|
+
* @property {boolean} [viaGoogle] Reach toolzu through a Google search (CLI: --google). Default false.
|
|
525
|
+
* @property {string} [browser] Installed browser channel: 'msedge' or 'chrome'.
|
|
526
|
+
* @property {string} [userDataDir] Persistent browser profile (resolved against projectDir).
|
|
527
|
+
* @property {string} [projectDir] Project folder. Default: TABLEFACTS_PROJECT or the current folder.
|
|
528
|
+
* @property {boolean} [headed] Show the browser window.
|
|
529
|
+
* @property {boolean} [dryRun] List what would be saved without saving.
|
|
530
|
+
* @property {boolean} [debug] Keep screenshots in <out>/_debug.
|
|
531
|
+
* @property {Log} [log]
|
|
532
|
+
*/
|
|
533
|
+
/**
|
|
534
|
+
* @typedef {object} TripadvisorOptions
|
|
535
|
+
* @property {string[]} links Restaurant page links. At least one valid link is required.
|
|
536
|
+
* @property {string} out Folder the images are saved to (resolved against projectDir). Required.
|
|
537
|
+
* @property {string} [cdp] Edge debugging address. Default http://localhost:9222.
|
|
538
|
+
* @property {string} [edgeDir] Profile folder for the Edge that is started.
|
|
539
|
+
* @property {number} [max] Stop after n photos per restaurant.
|
|
540
|
+
* @property {string} [projectDir] Project folder. Default: TABLEFACTS_PROJECT or the current folder.
|
|
541
|
+
* @property {boolean} [dryRun]
|
|
542
|
+
* @property {boolean} [debug]
|
|
543
|
+
* @property {Log} [log]
|
|
544
|
+
*/
|
|
545
|
+
/**
|
|
546
|
+
* @typedef {object} MenuProduct
|
|
547
|
+
* @property {string} name
|
|
548
|
+
* @property {string | null} [description]
|
|
549
|
+
* @property {number} price Finite and not negative.
|
|
550
|
+
* @property {string} currency ISO 4217 code, e.g. COP.
|
|
551
|
+
* @property {string | null} [image_url] An https URL.
|
|
552
|
+
* @property {boolean} [recommended]
|
|
553
|
+
*/
|
|
554
|
+
/**
|
|
555
|
+
* @typedef {object} MenuSection
|
|
556
|
+
* @property {string} name
|
|
557
|
+
* @property {MenuProduct[]} products
|
|
558
|
+
*/
|
|
559
|
+
/**
|
|
560
|
+
* @typedef {object} MenuCategory
|
|
561
|
+
* @property {string} slug The key the site's dictionaries use.
|
|
562
|
+
* @property {string} name
|
|
563
|
+
* @property {MenuSection[]} sections
|
|
564
|
+
*/
|
|
565
|
+
/** @typedef {MenuCategory[]} Menu */
|
|
566
|
+
/**
|
|
567
|
+
* @typedef {object} MenuTotals
|
|
568
|
+
* @property {number} categories
|
|
569
|
+
* @property {number} sections
|
|
570
|
+
* @property {number} products
|
|
571
|
+
* @property {number} withImage
|
|
572
|
+
*/
|
|
573
|
+
/**
|
|
574
|
+
* @typedef {object} ImportOptions
|
|
575
|
+
* @property {boolean} [dryRun] Check and report, write nothing.
|
|
576
|
+
* @property {string} [json] Also save the extracted menu as JSON at this path (resolved against projectDir).
|
|
577
|
+
* @property {boolean} [replaceAll] Replace the whole menu, not only the categories in this import.
|
|
578
|
+
* @property {boolean} [force] Write even if the import has far fewer products than it replaces.
|
|
579
|
+
* @property {string} [databaseUrl] Default: env.SUPABASE_DB_URL.
|
|
580
|
+
* @property {Env} [env] Environment the database URL and keys are read from. Default process.env.
|
|
581
|
+
* @property {string} [projectDir] Project folder. Default: TABLEFACTS_PROJECT or the current folder.
|
|
582
|
+
* @property {Log} [log]
|
|
583
|
+
*/
|
|
584
|
+
/**
|
|
585
|
+
* @typedef {object} ImportResult
|
|
586
|
+
* @property {MenuTotals} totals
|
|
587
|
+
* @property {string[]} notes
|
|
588
|
+
* @property {boolean} written
|
|
589
|
+
* @property {boolean} dryRun
|
|
590
|
+
* @property {{ label: string, current: { categories: number, products: number, kept: string[] } } | null} database Null when the database was not reached.
|
|
591
|
+
*/
|
|
592
|
+
/**
|
|
593
|
+
* @typedef {ImportOptions & { menu: Menu, notes?: string[], title?: string }} ImportMenuOptions
|
|
594
|
+
*/
|
|
595
|
+
/**
|
|
596
|
+
* Restaurant-specific part of the Cluvi source (src/menu/cluvi/config.mjs).
|
|
597
|
+
* @typedef {object} CluviConfig
|
|
598
|
+
* @property {string} [url] Any page of the restaurant's Cluvi menu.
|
|
599
|
+
* @property {{ slug: string, name: string, from: string[] }[]} [categories] Cluvi main categories folded into each site category.
|
|
600
|
+
* @property {Record<string, string>} [sections] Cluvi subcategory to section name.
|
|
601
|
+
*/
|
|
602
|
+
/**
|
|
603
|
+
* Restaurant-specific part of the picture-menu source (src/menu/raw/config.mjs).
|
|
604
|
+
* @typedef {object} RawConfig
|
|
605
|
+
* @property {string} [url] Page with the menu pictures, or a direct image URL.
|
|
606
|
+
* @property {string} currency ISO code of the prices.
|
|
607
|
+
* @property {string} [thousands] Thousands separator the menu prints. Default ".".
|
|
608
|
+
* @property {string} [decimal] Decimal separator the menu prints. Default ",".
|
|
609
|
+
* @property {number} [scale] Multiplies every price. Default 1.
|
|
610
|
+
* @property {{ slug: string, name: string, groups?: ('food' | 'drink')[] }[]} [categories] Category that lists each group.
|
|
611
|
+
* @property {Record<string, string>} [placeIn] Section title to category slug.
|
|
612
|
+
* @property {Record<string, string>} [sections] Section title to the name stored.
|
|
613
|
+
* @property {string[]} [skipSections] Section titles to leave out.
|
|
614
|
+
*/
|
|
615
|
+
/** @typedef {CluviConfig | RawConfig} MenuSourceConfig */
|
|
616
|
+
/**
|
|
617
|
+
* @typedef {object} CluviMenuOptions
|
|
618
|
+
* @property {string} [url] Default: the config's.
|
|
619
|
+
* @property {'on_table' | 'delivery' | 'take_away'} [service]
|
|
620
|
+
* @property {string} [lang]
|
|
621
|
+
* @property {CluviConfig} [config] Default: the cluvi config.mjs.
|
|
622
|
+
*/
|
|
623
|
+
/** @typedef {ImportOptions & CluviMenuOptions} ImportCluviOptions */
|
|
624
|
+
/**
|
|
625
|
+
* @typedef {object} ImageMenuReadOptions
|
|
626
|
+
* @property {string[]} [urls] Pages or image URLs. Default: the config's url.
|
|
627
|
+
* @property {string | number[]} [only] Pages to read, e.g. '1,3-5' or [1, 3, 4, 5].
|
|
628
|
+
* @property {string} [provider] Vision provider, see `providers`. Default MENU_VISION_PROVIDER or `defaultProvider`.
|
|
629
|
+
* @property {string} [model]
|
|
630
|
+
* @property {number} [minWidth] Ignore images declaring a smaller width. Default 500.
|
|
631
|
+
* @property {string} [apiKey] Default: the provider's key in env.
|
|
632
|
+
* @property {boolean} [refresh] Read the pages again instead of using the saved transcriptions.
|
|
633
|
+
* @property {RawConfig} [config] Default: the raw config.mjs.
|
|
634
|
+
*/
|
|
635
|
+
/** @typedef {ImportOptions & ImageMenuReadOptions} ImportImageMenuOptions */
|
|
636
|
+
/**
|
|
637
|
+
* @typedef {object} ListMenuImagesOptions
|
|
638
|
+
* @property {string[]} [urls]
|
|
639
|
+
* @property {string | number[]} [only]
|
|
640
|
+
* @property {number} [minWidth]
|
|
641
|
+
* @property {RawConfig} [config]
|
|
642
|
+
*/
|
|
643
|
+
/**
|
|
644
|
+
* @typedef {object} MenuImage
|
|
645
|
+
* @property {number} number Position as the CLI's --list numbers it.
|
|
646
|
+
* @property {string} url
|
|
647
|
+
* @property {string} alt
|
|
648
|
+
*/
|
|
649
|
+
/**
|
|
650
|
+
* @typedef {object} PriceFormat
|
|
651
|
+
* @property {string} [thousands] Default ".".
|
|
652
|
+
* @property {string} [decimal] Default ",".
|
|
653
|
+
* @property {number} [scale] Default 1.
|
|
654
|
+
*/
|
|
655
|
+
/**
|
|
656
|
+
* @typedef {object} VisionProvider
|
|
657
|
+
* @property {string} label
|
|
658
|
+
* @property {string} keyName Environment variable holding the API key.
|
|
659
|
+
* @property {string} defaultModel
|
|
660
|
+
*/
|
|
661
|
+
/**
|
|
662
|
+
* @typedef {object} LoadEnvOptions
|
|
663
|
+
* @property {string} [projectDir] Project folder whose .env files are read.
|
|
664
|
+
* @property {string[]} [files] Exactly these files instead of the project's.
|
|
665
|
+
* @property {Env} [env] Object the variables are set on. Default process.env.
|
|
666
|
+
*/
|
|
667
|
+
/** @typedef {'EUSAGE' | 'ECONFIG' | 'EDEPENDENCY' | 'EFAILED'} TablefactsErrorCode */
|
|
668
|
+
export {};
|