@ecosyste-ms/critical 1.0.20260328 → 1.1.20260514

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/bin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { build, databasePath } from './lib/index.js'
3
- import Database from 'better-sqlite3'
3
+ import { DatabaseSync } from 'node:sqlite'
4
4
  import { existsSync } from 'fs'
5
5
 
6
6
  const args = process.argv.slice(2)
@@ -40,7 +40,7 @@ if (args.includes('--stats')) {
40
40
  console.error(`Database not found: ${path}`)
41
41
  process.exit(1)
42
42
  }
43
- const db = new Database(path, { readonly: true })
43
+ const db = new DatabaseSync(path, { readOnly: true })
44
44
  const info = db.prepare('SELECT * FROM build_info WHERE id = 1').get()
45
45
  const packageCount = db.prepare('SELECT COUNT(*) as count FROM packages').get().count
46
46
  const versionCount = db.prepare('SELECT COUNT(*) as count FROM versions').get().count
Binary file
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import Database from 'better-sqlite3'
1
+ import { DatabaseSync } from 'node:sqlite'
2
2
  import { createReadStream, createWriteStream, existsSync } from 'fs'
3
3
  import { mkdir, unlink, readFile } from 'fs/promises'
4
4
  import { dirname, join } from 'path'
@@ -21,22 +21,39 @@ if (!existsSync(databasePath) && existsSync(gzPath)) {
21
21
  }
22
22
 
23
23
  const API_BASE = 'https://packages.ecosyste.ms/api/v1'
24
- const PER_PAGE = 1000
24
+ const PER_PAGE = 100
25
25
  const RATE_LIMIT_MS = 50
26
26
  const CONCURRENCY = 10
27
+ const MAX_RETRIES = 5
28
+ const RETRY_BASE_MS = 1000
27
29
 
28
30
  function sleep(ms) {
29
31
  return new Promise(resolve => setTimeout(resolve, ms))
30
32
  }
31
33
 
32
34
  async function fetchJson(url) {
33
- const response = await fetch(url, {
34
- headers: { 'User-Agent': USER_AGENT }
35
- })
36
- if (!response.ok) {
37
- throw new Error(`HTTP ${response.status}: ${url}`)
35
+ let lastErr
36
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
37
+ try {
38
+ const response = await fetch(url, {
39
+ headers: { 'User-Agent': USER_AGENT }
40
+ })
41
+ if (response.ok) return response.json()
42
+ // 4xx is a client error — don't retry. 5xx is server-side; retry.
43
+ if (response.status < 500) {
44
+ throw new Error(`HTTP ${response.status}: ${url}`)
45
+ }
46
+ lastErr = new Error(`HTTP ${response.status}: ${url}`)
47
+ } catch (err) {
48
+ // Network errors (fetch throws TypeError) are retryable.
49
+ if (err.message?.startsWith('HTTP ') && !err.message.match(/HTTP 5\d\d/)) throw err
50
+ lastErr = err
51
+ }
52
+ if (attempt < MAX_RETRIES) {
53
+ await sleep(RETRY_BASE_MS * Math.pow(2, attempt))
54
+ }
38
55
  }
39
- return response.json()
56
+ throw lastErr
40
57
  }
41
58
 
42
59
  async function fetchAllCriticalPackages(onProgress) {
@@ -96,8 +113,8 @@ function ecosystemToRegistry(ecosystem) {
96
113
  }
97
114
 
98
115
  function createDatabase(dbPath) {
99
- const db = new Database(dbPath)
100
- db.pragma('journal_mode = WAL')
116
+ const db = new DatabaseSync(dbPath)
117
+ db.exec('PRAGMA journal_mode = WAL')
101
118
 
102
119
  db.exec(`
103
120
  CREATE TABLE packages (
@@ -263,14 +280,14 @@ function insertRepoMetadata(db, packageId, repoMetadata, host) {
263
280
 
264
281
  stmt.run(
265
282
  packageId,
266
- repoMetadata.owner,
267
- repoMetadata.name,
268
- repoMetadata.full_name,
269
- host?.name,
270
- repoMetadata.language,
271
- repoMetadata.stargazers_count,
272
- repoMetadata.forks_count,
273
- repoMetadata.open_issues_count,
283
+ repoMetadata.owner ?? null,
284
+ repoMetadata.name ?? null,
285
+ repoMetadata.full_name ?? null,
286
+ host?.name ?? null,
287
+ repoMetadata.language ?? null,
288
+ repoMetadata.stargazers_count ?? null,
289
+ repoMetadata.forks_count ?? null,
290
+ repoMetadata.open_issues_count ?? null,
274
291
  repoMetadata.archived ? 1 : 0,
275
292
  repoMetadata.fork ? 1 : 0
276
293
  )
@@ -342,16 +359,19 @@ async function build(options = {}) {
342
359
  const packages = await fetchAllCriticalPackages(onProgress)
343
360
  onProgress(`Found ${packages.length} critical packages`)
344
361
 
345
- const insertAll = db.transaction((pkgs) => {
346
- for (const pkg of pkgs) {
362
+ onProgress('Inserting packages...')
363
+ db.exec('BEGIN')
364
+ try {
365
+ for (const pkg of packages) {
347
366
  insertPackage(db, pkg)
348
367
  insertRepoMetadata(db, pkg.id, pkg.repo_metadata, pkg.host)
349
368
  insertAdvisories(db, pkg.id, pkg.advisories)
350
369
  }
351
- })
352
-
353
- onProgress('Inserting packages...')
354
- insertAll(packages)
370
+ db.exec('COMMIT')
371
+ } catch (err) {
372
+ db.exec('ROLLBACK')
373
+ throw err
374
+ }
355
375
 
356
376
  if (fetchVersionsData) {
357
377
  onProgress('Fetching versions...')
@@ -369,13 +389,18 @@ async function build(options = {}) {
369
389
  const batch = packages.slice(i, i + CONCURRENCY)
370
390
  const results = await Promise.all(batch.map(processPackage))
371
391
 
372
- db.transaction(() => {
392
+ db.exec('BEGIN')
393
+ try {
373
394
  for (const { pkg, versions } of results) {
374
395
  if (versions.length > 0) {
375
396
  insertVersions(db, pkg.id, versions)
376
397
  }
377
398
  }
378
- })()
399
+ db.exec('COMMIT')
400
+ } catch (err) {
401
+ db.exec('ROLLBACK')
402
+ throw err
403
+ }
379
404
 
380
405
  completed += batch.length
381
406
  onProgress(`Fetched versions for ${completed}/${total} packages`)
@@ -391,4 +416,4 @@ async function build(options = {}) {
391
416
  return info
392
417
  }
393
418
 
394
- export { build, createDatabase, fetchAllCriticalPackages, fetchVersionNumbers, databasePath }
419
+ export { build, createDatabase, fetchAllCriticalPackages, fetchVersionNumbers, databasePath, insertRepoMetadata }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecosyste-ms/critical",
3
- "version": "1.0.20260328",
3
+ "version": "1.1.20260514",
4
4
  "description": "SQLite database of critical packages from ecosyste.ms",
5
5
  "main": "./lib/index.js",
6
6
  "type": "module",
@@ -35,9 +35,6 @@
35
35
  "access": "public"
36
36
  },
37
37
  "engines": {
38
- "node": ">=18.0.0"
39
- },
40
- "dependencies": {
41
- "better-sqlite3": "^12.5.0"
38
+ "node": ">=22.5.0"
42
39
  }
43
40
  }