| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 |
- import fs from 'node:fs'
- import path from 'node:path'
- import assert from 'node:assert/strict'
- import { createHash } from 'node:crypto'
- import { execFileSync } from 'node:child_process'
- async function download(url) {
- assert.ok(url.startsWith('https://registry.npmjs.org/') || url.startsWith('https://codeload.github.com/') || url.startsWith('https://code.haverbeke.berlin/'), 'Unexpected source host')
- const response = await fetch(url, { signal: AbortSignal.timeout(120000) })
- if (!response.ok) throw new Error(`Source download failed (${response.status}): ${url}`)
- return Buffer.from(await response.arrayBuffer())
- }
- /** Publish package distributions and pinned upstream sources, never local paths. */
- export async function collectDependencySources(root, output) {
- const components = new Map()
- for (const pkg of ['bundle', 'embedding-provider']) {
- const entries = JSON.parse(fs.readFileSync(path.join(root, 'packages', pkg, 'lib/third-party-inputs.json'), 'utf8'))
- for (const entry of entries) components.set(`${entry.name}@${entry.version}`, entry)
- }
- const directory = path.join(output, 'third-party-sources')
- fs.mkdirSync(directory)
- const upstream = new Map()
- const report = []
- const pinned = JSON.parse(fs.readFileSync(path.join(root, 'scripts/release/upstream-sources.json'), 'utf8'))
- for (const entry of components.values()) {
- const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(entry.name)}/${encodeURIComponent(entry.version)}`, { signal: AbortSignal.timeout(30000) })
- if (!response.ok) throw new Error(`Package source metadata unavailable: ${entry.name}@${entry.version}`)
- const metadata = await response.json()
- const tarball = await download(metadata.dist.tarball)
- const integrity = metadata.dist.integrity
- if (integrity) {
- const [algorithm, value] = integrity.split(' ')[0].split('-')
- assert.ok(['sha512', 'sha256', 'sha1'].includes(algorithm))
- assert.equal(createHash(algorithm).update(tarball).digest('base64'), value, 'Registry source integrity mismatch')
- } else assert.equal(createHash('sha1').update(tarball).digest('hex'), metadata.dist.shasum)
- const filename = `${entry.name.replaceAll('@', '').replaceAll('/', '__')}--${entry.version}.tgz`
- fs.writeFileSync(path.join(directory, filename), tarball)
- const repository = typeof metadata.repository === 'string' ? metadata.repository : metadata.repository?.url
- const github = /github\.com[/:]([\w.-]+)\/([\w.-]+?)(?:\.git)?(?:#.*)?$/.exec(repository ?? '')
- const haverbeke = /code\.haverbeke\.berlin\/([\w.-]+)\/([\w.-]+?)(?:\.git)?$/.exec(repository ?? '')
- const override = pinned[`${entry.name}@${entry.version}`]
- const commit = override?.commit ?? metadata.gitHead
- assert.match(commit ?? '', /^[a-f0-9]{40}$/, `Pin upstream source for ${entry.name}@${entry.version}`)
- let upstreamFile = null, sourceUrl = null
- const upstreamRepo = override?.repository ?? (github ? `${github[1]}/${github[2]}` : null)
- if (upstreamRepo || haverbeke) {
- const key = `${upstreamRepo ?? `${haverbeke[1]}/${haverbeke[2]}`}-${commit}`.replaceAll('/', '-')
- sourceUrl = upstreamRepo ? `https://codeload.github.com/${upstreamRepo}/tar.gz/${commit}`
- : `https://code.haverbeke.berlin/${haverbeke[1]}/${haverbeke[2]}/archive/${commit}.tar.gz`
- if (!upstream.has(key)) {
- upstreamFile = `${key}.tar.gz`
- fs.writeFileSync(path.join(directory, upstreamFile), await download(sourceUrl))
- upstream.set(key, upstreamFile)
- } else upstreamFile = upstream.get(key)
- }
- assert.ok(upstreamFile, `No corresponding upstream source for ${entry.name}@${entry.version}`)
- report.push({ name: entry.name, version: entry.version, license: entry.license, repository,
- packageArchive: filename, packageIntegrity: integrity ?? `sha1:${metadata.dist.shasum}`,
- upstreamArchive: upstreamFile, upstreamUrl: sourceUrl, upstreamCommit: commit,
- upstreamSha256: createHash('sha256').update(fs.readFileSync(path.join(directory, upstreamFile))).digest('hex'),
- note: 'Pinned upstream source and registry distribution included.' })
- console.log(`[source] ${entry.name}@${entry.version}: package${upstreamFile ? ' + upstream' : ''}`)
- }
- fs.writeFileSync(path.join(directory, 'manifest.json'), JSON.stringify(report, null, 2) + '\n')
- fs.writeFileSync(path.join(directory, 'README.txt'), 'Corresponding third-party source materials for this release. See manifest.json for exact versions, original integrity and pinned upstream archives. Original licenses are also shipped with the application.\n')
- execFileSync('tar', ['-czf', 'third-party-sources.tar.gz', 'third-party-sources'], { cwd: output, windowsHide: true })
- return report
- }
|