Files
hy 1eedabb914 feat: add support for language and service route preferences
- Updated ModelSource type to include 'huggingface'.
- Enhanced MODEL_SOURCE_LABELS for better clarity.
- Introduced defaultModelSource function to determine default source based on service route.
- Modified AppSettings to include language and serviceRoute.
- Created end-to-end tests for language and service route settings.
- Added unit tests for application language and service preferences.
- Updated free models test to reflect new catalog naming conventions.
- Enhanced official API tests to ensure correct handling of service regions.
- Adjusted release artifact tests to accommodate internationalization.
- Updated SQLite migration and storage tests to include new preferences.
2026-10-21 10:05:42 +08:00

114 lines
3.9 KiB
JavaScript

import { assertDistribution, distributionName } from '../shared/distribution.mjs'
import { createHash } from 'node:crypto'
import { readFile, stat, writeFile } from 'node:fs/promises'
import path from 'node:path'
import process from 'node:process'
import {
assertPackageAudit,
assertReleaseFragment,
resolveReleaseAssetPath
} from './fragment-contract.mjs'
import { parseReleaseTag } from '../tag.mjs'
const [
inputDirectory = '',
outputPath = '',
releaseTag = '',
platform = '',
distribution = 'domestic'
] = process.argv.slice(2)
assertDistribution(distribution)
const name = distributionName(distribution)
const definitions = {
'windows-x64': {
metadata: 'latest.yml',
signature: undefined,
assets: (version) => [
[`${name}-${version}-Windows-x64.exe`, 'Ncurator-windows-x64.exe', 'installer'],
[`${name}-${version}-Windows-x64.exe.blockmap`, 'Ncurator-windows-x64.exe.blockmap', 'update']
]
},
'macos-arm64': {
metadata: 'latest-mac.yml',
signature: 'mac-update-signature.txt',
assets: (version) => [
[`${name}-${version}-macos-arm64.dmg`, 'Ncurator-mac-arm64.dmg', 'installer'],
['Ncurator-mac-arm64.dmg.blockmap', 'Ncurator-mac-arm64.dmg.blockmap', 'update'],
['Ncurator-mac-arm64.zip', 'Ncurator-mac-arm64.zip', 'update'],
['Ncurator-mac-arm64.zip.blockmap', 'Ncurator-mac-arm64.zip.blockmap', 'update']
]
}
}
if (!inputDirectory || !outputPath || !releaseTag) {
throw new Error(
'usage: node scripts/release/r2/create-fragment.mjs <input-dir> <output-json> <platform-v1.2.3> <platform>'
)
}
const definition = definitions[platform]
if (!definition) throw new Error(`unsupported release platform: ${platform}`)
const { version } = parseReleaseTag(releaseTag, platform)
const auditPath = path.join(inputDirectory, 'package-audit.json')
const audit = JSON.parse(await readFile(auditPath, 'utf8'))
assertPackageAudit(audit, platform, `package security audit ${auditPath}`)
if ((audit.distribution || 'domestic') !== distribution) {
throw new Error(`package audit distribution does not match ${distribution}: ${auditPath}`)
}
if (platform.startsWith('macos-') && !['passed', 'warning'].includes(audit.sizeBudget?.status)) {
throw new Error(`macOS package size budget is missing or failed: ${auditPath}`)
}
const sha512 = async (filePath) =>
createHash('sha512')
.update(await readFile(filePath))
.digest('base64')
const files = []
for (const [name, storageName, role] of definition.assets(version)) {
const filePath = await resolveReleaseAssetPath(inputDirectory, { name, storageName })
const fileStat = await stat(filePath)
files.push({ name, storageName, role, size: fileStat.size, sha512: await sha512(filePath) })
}
const metadata = await readFile(path.join(inputDirectory, definition.metadata), 'utf8')
if (!new RegExp(`^version:\\s*${version.replaceAll('.', '\\.')}\\s*$`, 'mu').test(metadata)) {
throw new Error(`${definition.metadata} does not declare version ${version}`)
}
const signature = definition.signature
? (await readFile(path.join(inputDirectory, definition.signature), 'utf8')).trim()
: undefined
const fragment = {
schemaVersion: 3,
tag: releaseTag,
version,
platform,
distribution,
sharedAppHash: audit.sharedAppHash,
createdAt: new Date().toISOString(),
files,
metadata,
audit: {
schemaVersion: audit.schemaVersion,
generatedAt: audit.generatedAt,
platform: audit.platform,
distribution,
sharedAppHash: audit.sharedAppHash,
arch: audit.arch,
applications: audit.applications.map((application) => ({
root: application.root,
totalBytes: application.totalBytes,
archiveBytes: application.archiveBytes,
archiveFileCount: application.archiveFileCount
})),
...(audit.sizeBudget ? { sizeBudget: audit.sizeBudget } : {})
},
...(signature ? { signature } : {})
}
assertReleaseFragment(fragment, { tag: releaseTag, platform })
await writeFile(outputPath, `${JSON.stringify(fragment, null, 2)}\n`, 'utf8')