@mxfb/tools 1.0.0 → 1.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.
Files changed (67) hide show
  1. package/TODO.md +1 -0
  2. package/agnostic/@publisher/index.d.ts +47 -0
  3. package/agnostic/@publisher/index.js +361 -0
  4. package/agnostic/elo/index.d.ts +23 -0
  5. package/agnostic/elo/index.js +28 -0
  6. package/agnostic/elo/index.test.js +67 -0
  7. package/agnostic/index.d.ts +5 -0
  8. package/agnostic/index.js +5 -0
  9. package/agnostic/poetry/generate-rhymes/index.d.ts +1 -0
  10. package/agnostic/poetry/generate-rhymes/index.js +125 -0
  11. package/agnostic/poetry/index.d.ts +1 -0
  12. package/agnostic/poetry/index.js +1 -0
  13. package/agnostic/scrapers/@meteociel/index.js +240 -186
  14. package/agnostic/scrapers/@meteociel/index.test.js +43 -0
  15. package/agnostic/scrapers/@meteociel/locations/index.js +9 -5
  16. package/agnostic/scrapers/@meteociel/types.js +1 -0
  17. package/agnostic/scrapers/@tumblr/blogs/delabienbonnemusique/index.d.ts +22 -0
  18. package/agnostic/scrapers/@tumblr/blogs/delabienbonnemusique/index.js +124 -0
  19. package/agnostic/scrapers/@tumblr/blogs/delabienbonnemusique/index.test.d.ts +1 -0
  20. package/agnostic/scrapers/@tumblr/blogs/delabienbonnemusique/index.test.js +107 -0
  21. package/agnostic/scrapers/@tumblr/blogs/index.d.ts +8 -0
  22. package/agnostic/scrapers/@tumblr/blogs/index.js +23 -0
  23. package/agnostic/scrapers/@tumblr/index.d.ts +73 -0
  24. package/agnostic/scrapers/@tumblr/index.js +180 -0
  25. package/agnostic/scrapers/@tumblr/index.test.d.ts +1 -0
  26. package/agnostic/scrapers/@tumblr/index.test.js +319 -0
  27. package/agnostic/scrapers/@tumblr/types.d.ts +238 -0
  28. package/agnostic/scrapers/@tumblr/types.js +38 -0
  29. package/agnostic/scrapers/@tumblr/utils.d.ts +12 -0
  30. package/agnostic/scrapers/@tumblr/utils.js +407 -0
  31. package/agnostic/scrapers/index.d.ts +2 -0
  32. package/agnostic/scrapers/index.js +2 -0
  33. package/agnostic/weather/index.d.ts +1 -0
  34. package/agnostic/weather/index.js +1 -0
  35. package/agnostic/weather/types.d.ts +2 -2
  36. package/agnostic/weather/types.js +8 -0
  37. package/components/index.d.ts +1 -0
  38. package/components/index.js +1 -0
  39. package/components/public-classnames.d.ts +5 -0
  40. package/components/public-classnames.js +5 -0
  41. package/components/utils/index.d.ts +1 -0
  42. package/components/utils/index.js +12 -0
  43. package/components/utils/types.d.ts +3 -0
  44. package/components/utils/types.js +1 -0
  45. package/index.d.ts +3 -0
  46. package/index.js +3 -0
  47. package/node/headless-browser/index.d.ts +37 -0
  48. package/node/headless-browser/index.js +126 -0
  49. package/node/headless-browser/types.d.ts +47 -0
  50. package/node/headless-browser/types.js +5 -0
  51. package/node/index.js +1 -0
  52. package/node/index.test.d.ts +1 -0
  53. package/node/index.test.js +6 -0
  54. package/node/scrapers/@tumblr/index.d.ts +61 -0
  55. package/node/scrapers/@tumblr/index.js +182 -0
  56. package/node/scrapers/@tumblr/index.test.d.ts +1 -0
  57. package/node/scrapers/@tumblr/index.test.js +185 -0
  58. package/node/scrapers/@tumblr/types.d.ts +91 -0
  59. package/node/scrapers/@tumblr/types.js +1 -0
  60. package/node/scrapers/@tumblr/utils.d.ts +23 -0
  61. package/node/scrapers/@tumblr/utils.js +328 -0
  62. package/node/scrapers/index.d.ts +1 -0
  63. package/node/scrapers/index.js +1 -0
  64. package/package.json +197 -31
  65. package/chunks/chunk-JQLUR5LO.js +0 -12
  66. package/components/Comp/index.js +0 -0
  67. /package/{components/Comp/index.d.ts → agnostic/elo/index.test.d.ts} +0 -0
@@ -0,0 +1,328 @@
1
+ import { createHash, randomBytes } from 'node:crypto';
2
+ import { createReadStream, promises as fs } from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { createInterface } from 'node:readline';
6
+ import { parseRobots, parseSitemap } from '../../../agnostic/scrapers/@tumblr/index.js';
7
+ const PAGES_FILE_NAME = 'pages.ndjson';
8
+ const STATE_FILE_NAME = 'state.json';
9
+ const RAW_DIR_NAME = 'raw';
10
+ const DEFAULT_SITEMAP_PATHNAME = '/sitemap.xml';
11
+ const LISTING_PAGE_KINDS = ['index', 'archive', 'tagged'];
12
+ export function toOriginOrNull(rawUrl) {
13
+ try {
14
+ return new URL(rawUrl).origin;
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ export function normalizeUrl(rawUrl, baseUrl) {
21
+ try {
22
+ const url = new URL(rawUrl, baseUrl ?? undefined);
23
+ url.hash = '';
24
+ if (url.pathname !== '/' && url.pathname.endsWith('/')) {
25
+ url.pathname = url.pathname.slice(0, -1);
26
+ }
27
+ return url.href;
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ export function isListingKind(kind) {
34
+ return LISTING_PAGE_KINDS.includes(kind);
35
+ }
36
+ export function buildListingPageUrls(baseUrl, from, to) {
37
+ const urls = [];
38
+ for (let pageNumber = from; pageNumber <= to; pageNumber = pageNumber + 1) {
39
+ urls.push(`${baseUrl}/page/${pageNumber}`);
40
+ }
41
+ return urls;
42
+ }
43
+ export function toErrorMessage(error) {
44
+ return error instanceof Error ? error.message : 'unknown-error';
45
+ }
46
+ export async function fetchRobots(baseUrl, fetcher) {
47
+ const content = await fetchOrNull(fetcher, `${baseUrl}/robots.txt`);
48
+ if (content === null)
49
+ return null;
50
+ try {
51
+ return parseRobots(content);
52
+ }
53
+ catch {
54
+ return null;
55
+ }
56
+ }
57
+ export async function collectSitemapLocations(baseUrl, robots, fetcher) {
58
+ const advertisedUrls = robots?.sitemapUrls ?? [];
59
+ const rootSitemapUrls = advertisedUrls.length > 0
60
+ ? advertisedUrls
61
+ : [`${baseUrl}${DEFAULT_SITEMAP_PATHNAME}`];
62
+ const lastModifiedByUrl = new Map();
63
+ const visitedSitemapUrls = new Set();
64
+ const pendingSitemapUrls = [...rootSitemapUrls];
65
+ while (pendingSitemapUrls.length > 0) {
66
+ const sitemapUrl = pendingSitemapUrls.shift();
67
+ if (sitemapUrl === undefined || visitedSitemapUrls.has(sitemapUrl))
68
+ continue;
69
+ visitedSitemapUrls.add(sitemapUrl);
70
+ const sitemap = await readSitemapOrNull(sitemapUrl, fetcher);
71
+ if (sitemap === null)
72
+ continue;
73
+ for (const childUrl of sitemap.childSitemapUrls)
74
+ pendingSitemapUrls.push(childUrl);
75
+ for (const location of sitemap.locations) {
76
+ const normalizedUrl = normalizeUrl(location.url, baseUrl);
77
+ if (normalizedUrl === null || lastModifiedByUrl.has(normalizedUrl))
78
+ continue;
79
+ lastModifiedByUrl.set(normalizedUrl, location.lastModifiedOn);
80
+ }
81
+ }
82
+ return lastModifiedByUrl;
83
+ }
84
+ export function fillLastModifiedFromSitemap(page, lastModifiedByUrl, baseUrl) {
85
+ if (lastModifiedByUrl.size === 0)
86
+ return page;
87
+ return {
88
+ ...page,
89
+ posts: page.posts.map(post => {
90
+ if (post.url === null || post.lastModifiedOn !== null)
91
+ return post;
92
+ const normalizedUrl = normalizeUrl(post.url, baseUrl);
93
+ const lastModifiedOn = normalizedUrl === null
94
+ ? null
95
+ : lastModifiedByUrl.get(normalizedUrl) ?? null;
96
+ return lastModifiedOn === null ? post : { ...post, lastModifiedOn };
97
+ })
98
+ };
99
+ }
100
+ export async function createTemporaryDataDir() {
101
+ const dirPath = path.join(os.tmpdir(), randomBytes(8).toString('hex'));
102
+ await fs.mkdir(dirPath, { recursive: true });
103
+ return dirPath;
104
+ }
105
+ export async function ensureDataDirectories(dataDirPath, saveRawPages) {
106
+ await fs.mkdir(dataDirPath, { recursive: true });
107
+ if (saveRawPages)
108
+ await fs.mkdir(path.join(dataDirPath, RAW_DIR_NAME), { recursive: true });
109
+ }
110
+ export async function appendPageRecord(dataDirPath, page) {
111
+ const line = `${JSON.stringify(page)}\n`;
112
+ await fs.appendFile(path.join(dataDirPath, PAGES_FILE_NAME), line, { encoding: 'utf-8' });
113
+ }
114
+ export async function writeRawPage(dataDirPath, url, pageContent) {
115
+ const filePath = path.join(dataDirPath, RAW_DIR_NAME, toRawFileName(url));
116
+ await fs.writeFile(filePath, pageContent, { encoding: 'utf-8' });
117
+ }
118
+ export async function writeCrawlState(dataDirPath, state) {
119
+ const line = JSON.stringify(state, null, 2);
120
+ await fs.writeFile(path.join(dataDirPath, STATE_FILE_NAME), line, { encoding: 'utf-8' });
121
+ }
122
+ export async function readCrawlState(dataDirPath, baseUrl) {
123
+ const stateContent = await readFileOrNull(path.join(dataDirPath, STATE_FILE_NAME));
124
+ const parsedState = stateContent === null ? null : toCrawlStateOrNull(parseJson(stateContent));
125
+ if (parsedState !== null)
126
+ return parsedState;
127
+ return await rebuildCrawlStateFromRecords(dataDirPath, baseUrl);
128
+ }
129
+ export async function rebuildCrawlStateFromRecords(dataDirPath, baseUrl) {
130
+ const recordsContent = await readFileOrNull(path.join(dataDirPath, PAGES_FILE_NAME));
131
+ if (recordsContent === null)
132
+ return null;
133
+ const processedUrls = new Set();
134
+ const knownPostIds = new Set();
135
+ for (const line of recordsContent.split('\n')) {
136
+ if (line.trim() === '')
137
+ continue;
138
+ const record = toPageRecordDigest(parseJson(line));
139
+ if (record.url !== null)
140
+ processedUrls.add(record.url);
141
+ for (const postId of record.postIds)
142
+ knownPostIds.add(postId);
143
+ }
144
+ return {
145
+ baseUrl,
146
+ processedUrls: Array.from(processedUrls),
147
+ waitlistUrls: [],
148
+ knownPostIds: Array.from(knownPostIds)
149
+ };
150
+ }
151
+ export async function* readPageRecords(dataDirPath) {
152
+ const filePath = path.join(dataDirPath, PAGES_FILE_NAME);
153
+ const lines = createInterface({
154
+ input: createReadStream(filePath, { encoding: 'utf-8' }),
155
+ crlfDelay: Number.POSITIVE_INFINITY
156
+ });
157
+ for await (const line of lines) {
158
+ if (line.trim() === '')
159
+ continue;
160
+ const page = toArchivedPage(parseJson(line));
161
+ if (page !== null)
162
+ yield page;
163
+ }
164
+ }
165
+ export function mergeArchivedPosts(existing, incoming) {
166
+ const incomingWins = incoming.rawHtmlSource === 'permalink'
167
+ && existing.rawHtmlSource !== 'permalink';
168
+ const [preferred, other] = incomingWins ? [incoming, existing] : [existing, incoming];
169
+ return {
170
+ id: preferred.id ?? other.id,
171
+ url: preferred.url ?? other.url,
172
+ type: preferred.type === 'unknown' ? other.type : preferred.type,
173
+ publishedOn: preferred.publishedOn ?? other.publishedOn,
174
+ title: preferred.title ?? other.title,
175
+ contentHtml: preferred.contentHtml ?? other.contentHtml,
176
+ rawHtml: preferred.rawHtml ?? other.rawHtml,
177
+ rawHtmlSource: preferred.rawHtml === null ? other.rawHtmlSource : preferred.rawHtmlSource,
178
+ detail: preferred.detail ?? other.detail,
179
+ tags: preferred.tags.length > 0 ? preferred.tags : other.tags,
180
+ media: preferred.media.length > 0 ? preferred.media : other.media,
181
+ notesCount: preferred.notesCount ?? other.notesCount,
182
+ reblogOfUrl: preferred.reblogOfUrl ?? other.reblogOfUrl,
183
+ lastModifiedOn: preferred.lastModifiedOn ?? other.lastModifiedOn
184
+ };
185
+ }
186
+ export function resolveDelayMs(robots, defaultDelayMs) {
187
+ const requestedDelayMs = (robots?.crawlDelaySeconds ?? 0) * 1000;
188
+ return Math.max(defaultDelayMs, requestedDelayMs);
189
+ }
190
+ export function discoverUrlsToFollow(page, followedKinds, newPostCount, baseUrl) {
191
+ const urls = [];
192
+ if (!isListingKind(page.kind))
193
+ return urls;
194
+ if (followedKinds.includes('permalink')) {
195
+ for (const post of page.posts) {
196
+ const postUrl = post.url === null ? null : normalizeUrl(post.url, baseUrl);
197
+ if (postUrl !== null)
198
+ urls.push(postUrl);
199
+ }
200
+ }
201
+ const keepsWalking = followedKinds.includes(page.kind)
202
+ && newPostCount > 0
203
+ && page.pagination.nextPageUrl !== null;
204
+ if (keepsWalking) {
205
+ const nextPageUrl = normalizeUrl(page.pagination.nextPageUrl ?? '', baseUrl);
206
+ if (nextPageUrl !== null)
207
+ urls.push(nextPageUrl);
208
+ }
209
+ return urls;
210
+ }
211
+ async function readSitemapOrNull(sitemapUrl, fetcher) {
212
+ const content = await fetchOrNull(fetcher, sitemapUrl);
213
+ if (content === null)
214
+ return null;
215
+ try {
216
+ return parseSitemap(content);
217
+ }
218
+ catch {
219
+ return null;
220
+ }
221
+ }
222
+ async function fetchOrNull(fetcher, url) {
223
+ try {
224
+ return await fetcher(url);
225
+ }
226
+ catch {
227
+ return null;
228
+ }
229
+ }
230
+ async function readFileOrNull(filePath) {
231
+ try {
232
+ return await fs.readFile(filePath, { encoding: 'utf-8' });
233
+ }
234
+ catch {
235
+ return null;
236
+ }
237
+ }
238
+ function parseJson(raw) {
239
+ try {
240
+ return JSON.parse(raw);
241
+ }
242
+ catch {
243
+ return null;
244
+ }
245
+ }
246
+ function toStringArray(value) {
247
+ if (!Array.isArray(value))
248
+ return [];
249
+ return value.filter((item) => typeof item === 'string');
250
+ }
251
+ function toCrawlStateOrNull(value) {
252
+ if (typeof value !== 'object' || value === null)
253
+ return null;
254
+ /* eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion */
255
+ const record = value;
256
+ const baseUrl = record.baseUrl;
257
+ if (typeof baseUrl !== 'string')
258
+ return null;
259
+ return {
260
+ baseUrl,
261
+ processedUrls: toStringArray(record.processedUrls),
262
+ waitlistUrls: toStringArray(record.waitlistUrls),
263
+ knownPostIds: toStringArray(record.knownPostIds)
264
+ };
265
+ }
266
+ function toPageRecordDigest(value) {
267
+ if (typeof value !== 'object' || value === null)
268
+ return { url: null, postIds: [] };
269
+ /* eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion */
270
+ const record = value;
271
+ const pageUrl = record.url;
272
+ const posts = Array.isArray(record.posts) ? record.posts : [];
273
+ const postIds = [];
274
+ for (const post of posts) {
275
+ if (typeof post !== 'object' || post === null)
276
+ continue;
277
+ /* eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion */
278
+ const postRecord = post;
279
+ const postId = postRecord.id;
280
+ if (typeof postId === 'string')
281
+ postIds.push(postId);
282
+ }
283
+ return {
284
+ url: typeof pageUrl === 'string' ? pageUrl : null,
285
+ postIds
286
+ };
287
+ }
288
+ function toDateOrNull(value) {
289
+ if (typeof value !== 'string')
290
+ return null;
291
+ const parsed = new Date(value);
292
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
293
+ }
294
+ // JSON knows no dates, so what a record holds are the strings `JSON.stringify` wrote.
295
+ function toArchivedPage(value) {
296
+ if (typeof value !== 'object' || value === null)
297
+ return null;
298
+ /* eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion */
299
+ const record = value;
300
+ const collectedOn = toDateOrNull(record.collectedOn);
301
+ if (typeof record.url !== 'string' || !Array.isArray(record.posts))
302
+ return null;
303
+ if (collectedOn === null)
304
+ return null;
305
+ /* eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion */
306
+ const page = value;
307
+ return {
308
+ ...page,
309
+ collectedOn,
310
+ posts: page.posts.map(post => ({
311
+ ...post,
312
+ publishedOn: toDateOrNull(post.publishedOn),
313
+ lastModifiedOn: toDateOrNull(post.lastModifiedOn)
314
+ }))
315
+ };
316
+ }
317
+ function toRawFileName(url) {
318
+ const digest = createHash('sha1').update(url).digest('hex').slice(0, 6);
319
+ let pathname;
320
+ try {
321
+ pathname = new URL(url).pathname;
322
+ }
323
+ catch {
324
+ pathname = url;
325
+ }
326
+ const slug = pathname.replace(/[^a-zA-Z0-9]+/gv, '-').replace(/^-+|-+$/gv, '');
327
+ return `${slug === '' ? 'home' : slug}-${digest}.html`;
328
+ }
@@ -0,0 +1 @@
1
+ export * as tumblr from './@tumblr/index.js'
@@ -0,0 +1 @@
1
+ export * as tumblr from './@tumblr/index.js'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mxfb/tools",
3
- "version": "1.0.0",
3
+ "version": "1.0.3",
4
4
  "description": "",
5
5
  "author": "Maxime Fabas",
6
6
  "license": "ISC",
@@ -11,54 +11,220 @@
11
11
  "type": "module",
12
12
  "main": "index.js",
13
13
  "module": "index.js",
14
+ "exports": {
15
+ ".": {
16
+ "import": "./index.js",
17
+ "types": "./index.d.ts"
18
+ },
19
+ "./agnostic": {
20
+ "import": "./agnostic/index.js",
21
+ "types": "./agnostic/index.d.ts"
22
+ },
23
+ "./agnostic/@publisher": {
24
+ "import": "./agnostic/@publisher/index.js",
25
+ "types": "./agnostic/@publisher/index.d.ts"
26
+ },
27
+ "./agnostic/@publisher/index.js": {
28
+ "import": "./agnostic/@publisher/index.js"
29
+ },
30
+ "./agnostic/elo": {
31
+ "import": "./agnostic/elo/index.js",
32
+ "types": "./agnostic/elo/index.d.ts"
33
+ },
34
+ "./agnostic/elo/index.js": {
35
+ "import": "./agnostic/elo/index.js"
36
+ },
37
+ "./agnostic/index.js": {
38
+ "import": "./agnostic/index.js"
39
+ },
40
+ "./agnostic/poetry": {
41
+ "import": "./agnostic/poetry/index.js",
42
+ "types": "./agnostic/poetry/index.d.ts"
43
+ },
44
+ "./agnostic/poetry/generate-rhymes": {
45
+ "import": "./agnostic/poetry/generate-rhymes/index.js",
46
+ "types": "./agnostic/poetry/generate-rhymes/index.d.ts"
47
+ },
48
+ "./agnostic/poetry/generate-rhymes/index.js": {
49
+ "import": "./agnostic/poetry/generate-rhymes/index.js"
50
+ },
51
+ "./agnostic/poetry/index.js": {
52
+ "import": "./agnostic/poetry/index.js"
53
+ },
54
+ "./agnostic/scrapers": {
55
+ "import": "./agnostic/scrapers/index.js",
56
+ "types": "./agnostic/scrapers/index.d.ts"
57
+ },
58
+ "./agnostic/scrapers/@meteociel": {
59
+ "import": "./agnostic/scrapers/@meteociel/index.js",
60
+ "types": "./agnostic/scrapers/@meteociel/index.d.ts"
61
+ },
62
+ "./agnostic/scrapers/@meteociel/index.js": {
63
+ "import": "./agnostic/scrapers/@meteociel/index.js"
64
+ },
65
+ "./agnostic/scrapers/@meteociel/locations": {
66
+ "import": "./agnostic/scrapers/@meteociel/locations/index.js",
67
+ "types": "./agnostic/scrapers/@meteociel/locations/index.d.ts"
68
+ },
69
+ "./agnostic/scrapers/@meteociel/locations/index.js": {
70
+ "import": "./agnostic/scrapers/@meteociel/locations/index.js"
71
+ },
72
+ "./agnostic/scrapers/@meteociel/types.js": {
73
+ "import": "./agnostic/scrapers/@meteociel/types.js",
74
+ "types": "./agnostic/scrapers/@meteociel/types.d.ts"
75
+ },
76
+ "./agnostic/scrapers/@tumblr": {
77
+ "import": "./agnostic/scrapers/@tumblr/index.js",
78
+ "types": "./agnostic/scrapers/@tumblr/index.d.ts"
79
+ },
80
+ "./agnostic/scrapers/@tumblr/blogs": {
81
+ "import": "./agnostic/scrapers/@tumblr/blogs/index.js",
82
+ "types": "./agnostic/scrapers/@tumblr/blogs/index.d.ts"
83
+ },
84
+ "./agnostic/scrapers/@tumblr/blogs/delabienbonnemusique": {
85
+ "import": "./agnostic/scrapers/@tumblr/blogs/delabienbonnemusique/index.js",
86
+ "types": "./agnostic/scrapers/@tumblr/blogs/delabienbonnemusique/index.d.ts"
87
+ },
88
+ "./agnostic/scrapers/@tumblr/blogs/delabienbonnemusique/index.js": {
89
+ "import": "./agnostic/scrapers/@tumblr/blogs/delabienbonnemusique/index.js"
90
+ },
91
+ "./agnostic/scrapers/@tumblr/blogs/index.js": {
92
+ "import": "./agnostic/scrapers/@tumblr/blogs/index.js"
93
+ },
94
+ "./agnostic/scrapers/@tumblr/index.js": {
95
+ "import": "./agnostic/scrapers/@tumblr/index.js"
96
+ },
97
+ "./agnostic/scrapers/@tumblr/types.js": {
98
+ "import": "./agnostic/scrapers/@tumblr/types.js",
99
+ "types": "./agnostic/scrapers/@tumblr/types.d.ts"
100
+ },
101
+ "./agnostic/scrapers/index.js": {
102
+ "import": "./agnostic/scrapers/index.js"
103
+ },
104
+ "./agnostic/weather": {
105
+ "import": "./agnostic/weather/index.js",
106
+ "types": "./agnostic/weather/index.d.ts"
107
+ },
108
+ "./agnostic/weather/index.js": {
109
+ "import": "./agnostic/weather/index.js"
110
+ },
111
+ "./agnostic/weather/types.js": {
112
+ "import": "./agnostic/weather/types.js",
113
+ "types": "./agnostic/weather/types.d.ts"
114
+ },
115
+ "./components": {
116
+ "import": "./components/index.js",
117
+ "types": "./components/index.d.ts"
118
+ },
119
+ "./components/index.js": {
120
+ "import": "./components/index.js"
121
+ },
122
+ "./components/utils": {
123
+ "import": "./components/utils/index.js",
124
+ "types": "./components/utils/index.d.ts"
125
+ },
126
+ "./components/utils/index.js": {
127
+ "import": "./components/utils/index.js"
128
+ },
129
+ "./components/utils/types.js": {
130
+ "import": "./components/utils/types.js",
131
+ "types": "./components/utils/types.d.ts"
132
+ },
133
+ "./index.js": {
134
+ "import": "./index.js"
135
+ },
136
+ "./node": {
137
+ "import": "./node/index.js",
138
+ "types": "./node/index.d.ts"
139
+ },
140
+ "./node/headless-browser": {
141
+ "import": "./node/headless-browser/index.js",
142
+ "types": "./node/headless-browser/index.d.ts"
143
+ },
144
+ "./node/headless-browser/index.js": {
145
+ "import": "./node/headless-browser/index.js"
146
+ },
147
+ "./node/headless-browser/types.js": {
148
+ "import": "./node/headless-browser/types.js",
149
+ "types": "./node/headless-browser/types.d.ts"
150
+ },
151
+ "./node/index.js": {
152
+ "import": "./node/index.js"
153
+ },
154
+ "./node/scrapers": {
155
+ "import": "./node/scrapers/index.js",
156
+ "types": "./node/scrapers/index.d.ts"
157
+ },
158
+ "./node/scrapers/@tumblr": {
159
+ "import": "./node/scrapers/@tumblr/index.js",
160
+ "types": "./node/scrapers/@tumblr/index.d.ts"
161
+ },
162
+ "./node/scrapers/@tumblr/index.js": {
163
+ "import": "./node/scrapers/@tumblr/index.js"
164
+ },
165
+ "./node/scrapers/@tumblr/types.js": {
166
+ "import": "./node/scrapers/@tumblr/types.js",
167
+ "types": "./node/scrapers/@tumblr/types.d.ts"
168
+ },
169
+ "./node/scrapers/index.js": {
170
+ "import": "./node/scrapers/index.js"
171
+ }
172
+ },
14
173
  "dependencies": {
15
- "@aws-sdk/client-s3": "^3.907.0",
16
- "@aws-sdk/lib-storage": "^3.907.0",
17
- "@design-edito/tools": "^0.2.41",
18
- "@google-cloud/storage": "^7.17.2",
19
- "@inquirer/prompts": "^8.2.0",
174
+ "@aws-sdk/client-s3": "^3.999.0",
175
+ "@aws-sdk/lib-storage": "^3.1008.0",
176
+ "@design-edito/publisher": "^0.1.17",
177
+ "@design-edito/tools": "^0.5.39",
178
+ "@google-cloud/storage": "^7.19.0",
179
+ "@inquirer/prompts": "^8.3.0",
20
180
  "ansi-regex": "^6.2.2",
21
181
  "archiver": "^7.0.1",
22
- "basic-ftp": "^5.0.5",
182
+ "basic-ftp": "^5.1.0",
23
183
  "chalk": "^5.6.2",
24
- "express": "^5.1.0",
184
+ "express": "^5.2.1",
185
+ "jsdom": "^28.1.0",
25
186
  "multer": "^2.0.0",
187
+ "preact-render-to-string": "^6.6.6",
188
+ "puppeteer": "^24.39.0",
26
189
  "quantize": "^1.0.2",
27
- "react": "^19.2.0",
28
- "react-dom": "^19.2.0",
29
- "sharp": "^0.34.4",
190
+ "react": "^19.2.4",
191
+ "react-dom": "^19.2.4",
192
+ "sharp": "^0.34.5",
30
193
  "ssh2": "^1.17.0",
31
- "ssh2-sftp-client": "^12.0.0",
194
+ "ssh2-sftp-client": "^12.1.0",
32
195
  "xss": "^1.0.15",
33
- "zod": "^4.1.12"
196
+ "zod": "^4.3.6"
34
197
  },
35
198
  "devDependencies": {
36
- "@preact/preset-vite": "^2.10.2",
199
+ "@preact/preset-vite": "^2.10.3",
37
200
  "@testing-library/jest-dom": "^6.9.1",
38
201
  "@testing-library/preact": "^3.2.4",
39
- "@testing-library/react": "^16.3.1",
40
- "@types/archiver": "^6.0.3",
41
- "@types/express": "^5.0.2",
42
- "@types/jsdom": "^27.0.0",
43
- "@types/multer": "^2.0.0",
44
- "@types/node": "^24.7.1",
202
+ "@testing-library/react": "^16.3.2",
203
+ "@types/archiver": "^7.0.0",
204
+ "@types/express": "^5.0.6",
205
+ "@types/jsdom": "^28.0.0",
206
+ "@types/multer": "^2.1.0",
207
+ "@types/node": "^25.5.0",
45
208
  "@types/prompts": "^2.4.9",
46
209
  "@types/quantize": "^1.0.2",
47
- "@types/react": "^19.2.2",
48
- "@types/react-dom": "^19.2.1",
210
+ "@types/react": "^19.2.14",
211
+ "@types/react-dom": "^19.2.3",
49
212
  "@types/semver": "^7.7.1",
50
213
  "@types/sharp": "^0.31.1",
51
- "@types/ssh2-sftp-client": "^9.0.4",
52
- "@vitejs/plugin-react": "^5.1.2",
214
+ "@types/ssh2-sftp-client": "^9.0.6",
215
+ "@vitejs/plugin-react": "^5.1.3",
216
+ "change-case": "^5.4.4",
53
217
  "chokidar-cli": "^3.0.0",
54
218
  "concurrently": "^9.2.1",
55
- "esbuild": "^0.25.10",
56
- "jsdom": "^27.4.0",
219
+ "esbuild": "^0.27.4",
220
+ "eslint": "^9.39.5",
221
+ "eslint-config-love": "^154.1.0",
222
+ "globals": "^17.11.0",
57
223
  "prompts": "^2.4.2",
58
- "puppeteer": "^24.23.1",
59
- "semver": "^7.7.3",
60
- "simple-git": "^3.27.0",
61
- "typescript": "^5.9.3",
62
- "vitest": "^4.0.17"
224
+ "semver": "^7.7.4",
225
+ "simple-git": "^3.33.0",
226
+ "typescript": "^5.3.3",
227
+ "vite": "^6.4.1",
228
+ "vitest": "^4.1.0"
63
229
  }
64
230
  }
@@ -1,12 +0,0 @@
1
- // src/agnostic/scrapers/@meteociel/locations/index.ts
2
- var citiesData = {
3
- // Paris 11e
4
- "paris11": {
5
- id: 27827,
6
- urlSuffix: "paris_11eme_arrondissement"
7
- }
8
- };
9
-
10
- export {
11
- citiesData
12
- };
File without changes