106 行
3.7 KiB
JavaScript
106 行
3.7 KiB
JavaScript
import { createHash } from 'node:crypto'
|
|
import { readFileSync } from 'node:fs'
|
|
import { strFromU8, unzipSync } from 'fflate'
|
|
|
|
function requiredString(manifest, key) {
|
|
const value = manifest?.[key]
|
|
if (typeof value !== 'string' || value.trim() === '') {
|
|
throw new Error(`plugin package manifest ${key} is missing`)
|
|
}
|
|
return value
|
|
}
|
|
|
|
/**
|
|
* 发布身份只能来自即将上传的 ZIP,不能根据环境变量或缓存再次推导。这样 Bundle、
|
|
* Source Map 和服务端登记始终使用同一个构建产生的精确身份。
|
|
*/
|
|
export function readReleasePackageIdentity(packageFile, expected) {
|
|
const archive = unzipSync(new Uint8Array(readFileSync(packageFile)))
|
|
const manifestBytes = archive['rn-manifest.json']
|
|
if (!manifestBytes) throw new Error('plugin package manifest is missing')
|
|
|
|
let manifest
|
|
try {
|
|
manifest = JSON.parse(strFromU8(manifestBytes))
|
|
} catch {
|
|
throw new Error('plugin package manifest is invalid JSON')
|
|
}
|
|
|
|
const packageName = requiredString(manifest, 'packageName')
|
|
const moduleId = requiredString(manifest, 'moduleId')
|
|
const platform = requiredString(manifest, 'platform')
|
|
const moduleVersion = requiredString(manifest, 'version')
|
|
const appVersion = requiredString(manifest, 'appVersion')
|
|
const buildId = requiredString(manifest, 'buildId')
|
|
const bundleFile = requiredString(manifest, 'bundleFile')
|
|
const bundleHash = requiredString(manifest, 'bundleSha256')
|
|
const bundleFormat = requiredString(manifest, 'bundleFormat')
|
|
const nativeBaselineId = requiredString(manifest, 'builtAgainstNativeBaselineId')
|
|
const appVersionRange = requiredString(manifest, 'appVersionRange')
|
|
const minNativeApiLevel = manifest.minNativeApiLevel
|
|
|
|
if (buildId === 'development') {
|
|
throw new Error('plugin package was built without a release buildId; rebuild before publishing')
|
|
}
|
|
if (expected.packageName !== packageName) {
|
|
throw new Error(
|
|
`plugin package packageName mismatch: expected ${expected.packageName}, got ${packageName}`,
|
|
)
|
|
}
|
|
if (expected.moduleId !== moduleId) {
|
|
throw new Error(
|
|
`plugin package moduleId mismatch: expected ${expected.moduleId}, got ${moduleId}`,
|
|
)
|
|
}
|
|
if (expected.platform !== platform) {
|
|
throw new Error(
|
|
`plugin package platform mismatch: expected ${expected.platform}, got ${platform}`,
|
|
)
|
|
}
|
|
if (expected.moduleVersion !== moduleVersion) {
|
|
throw new Error(
|
|
`plugin package version mismatch: expected ${expected.moduleVersion}, got ${moduleVersion}`,
|
|
)
|
|
}
|
|
if (expected.appVersion !== appVersion) {
|
|
throw new Error(
|
|
`plugin package appVersion mismatch: expected ${expected.appVersion}, got ${appVersion}`,
|
|
)
|
|
}
|
|
if (!/^[a-f0-9]{64}$/i.test(bundleHash)) {
|
|
throw new Error('plugin package bundleSha256 is invalid')
|
|
}
|
|
if (!Number.isInteger(minNativeApiLevel) || minNativeApiLevel < 1) {
|
|
throw new Error('plugin package minNativeApiLevel is invalid')
|
|
}
|
|
if (
|
|
manifest.commonVersionRange !== undefined &&
|
|
(typeof manifest.commonVersionRange !== 'string' || !manifest.commonVersionRange.trim())
|
|
) {
|
|
throw new Error('plugin package commonVersionRange is invalid')
|
|
}
|
|
|
|
const bundleBytes = archive[bundleFile]
|
|
if (!bundleBytes) throw new Error(`plugin package bundle is missing: ${bundleFile}`)
|
|
const actualBundleHash = createHash('sha256').update(bundleBytes).digest('hex')
|
|
if (actualBundleHash !== bundleHash.toLowerCase()) {
|
|
throw new Error('plugin package bundleSha256 does not match bundle content')
|
|
}
|
|
|
|
return {
|
|
manifest,
|
|
packageName,
|
|
moduleId,
|
|
platform,
|
|
moduleVersion,
|
|
appVersion,
|
|
buildId,
|
|
bundleHash: actualBundleHash,
|
|
bundleFormat,
|
|
nativeBaselineId,
|
|
appVersionRange,
|
|
commonVersionRange: manifest.commonVersionRange,
|
|
minNativeApiLevel,
|
|
}
|
|
}
|