Add publisher release versions to plugins

This commit is contained in:
2026-09-18 01:16:45 -04:00
parent 166f039ae6
commit a718efc9e7
15 changed files with 167 additions and 29 deletions
+1
View File
@@ -65,6 +65,7 @@ const SCRIPTS_COLUMNS: Array<{ name: string; ddl: string }> = [
];
const SCRIPT_VERSIONS_COLUMNS: Array<{ name: string; ddl: string }> = [
{ name: 'release_version', ddl: 'ALTER TABLE script_versions ADD COLUMN release_version TEXT' },
// state was added post-launch to make untested/tested/test-failed visible
// in the UI. Existing rows default to 'untested' — this is safe because
// any real promoted version's script has current_version_id set (which is
+1
View File
@@ -72,6 +72,7 @@ CREATE TABLE IF NOT EXISTS script_versions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
script_id INTEGER NOT NULL REFERENCES scripts(id) ON DELETE CASCADE,
version INTEGER NOT NULL,
release_version TEXT, -- publisher's version/tag, independent of upload order
sha256 TEXT NOT NULL,
size INTEGER NOT NULL,
content BLOB NOT NULL,
+21 -7
View File
@@ -29,6 +29,7 @@ export interface ScriptVersionRow {
id: number;
script_id: number;
version: number;
release_version: string | null;
sha256: string;
size: number;
content: Buffer;
@@ -66,6 +67,7 @@ export class ScriptError extends Error {
| 'baseline-requires-scope'
| 'baseline-exists'
| 'empty-overlay'
| 'invalid-release-version'
) {
super(message);
}
@@ -75,6 +77,14 @@ function sha256(buf: Buffer): string {
return createHash('sha256').update(buf).digest('hex');
}
function normalizeReleaseVersion(value: string | null | undefined): string | null {
if (value == null) return null;
if (typeof value !== 'string' || value.length > 80 || /[\u0000-\u001f\u007f]/.test(value)) {
throw new ScriptError('release version must be a single line of at most 80 characters', 'invalid-release-version');
}
return value.trim() || null;
}
export function getScript(id: number): ScriptRow | undefined {
return db().prepare('SELECT * FROM scripts WHERE id = ?').get(id) as ScriptRow | undefined;
}
@@ -157,6 +167,8 @@ export interface CreateScriptInput {
scopeValue?: string | null;
content: Buffer;
notes?: string;
/** Publisher's release tag, e.g. v3.1.0. Upload numbering stays independent. */
releaseVersion?: string;
/** Defaults to 'script' for back-compat with existing callers. */
kind?: ArtifactKind;
}
@@ -206,6 +218,7 @@ export function createScript(input: CreateScriptInput): { script: ScriptRow; ver
if (getScriptByName(input.name)) throw new ScriptError(`script "${input.name}" already exists`, 'name-taken');
const sha = sha256(input.content);
const releaseVersion = normalizeReleaseVersion(input.releaseVersion);
const size = input.content.byteLength;
const insertScript = db().prepare(
@@ -213,8 +226,8 @@ export function createScript(input: CreateScriptInput): { script: ScriptRow; ver
VALUES (?, ?, ?, ?, ?)`
);
const insertVersion = db().prepare(
`INSERT INTO script_versions (script_id, version, sha256, size, content, notes, kind)
VALUES (?, 1, ?, ?, ?, ?, ?)`
`INSERT INTO script_versions (script_id, version, sha256, size, content, notes, kind, release_version)
VALUES (?, 1, ?, ?, ?, ?, ?, ?)`
);
let scriptId!: number;
@@ -222,7 +235,7 @@ export function createScript(input: CreateScriptInput): { script: ScriptRow; ver
db().transaction(() => {
const s = insertScript.run(input.name, targetRelPath, input.scopeType ?? null, input.scopeValue ?? null, kind);
scriptId = Number(s.lastInsertRowid);
const v = insertVersion.run(scriptId, sha, size, input.content, input.notes ?? null, kind);
const v = insertVersion.run(scriptId, sha, size, input.content, input.notes ?? null, kind, releaseVersion);
versionId = Number(v.lastInsertRowid);
})();
@@ -232,7 +245,7 @@ export function createScript(input: CreateScriptInput): { script: ScriptRow; ver
};
}
export function uploadNewVersion(scriptId: number, content: Buffer, notes?: string): ScriptVersionRow {
export function uploadNewVersion(scriptId: number, content: Buffer, notes?: string, releaseVersion?: string): ScriptVersionRow {
const script = getScript(scriptId);
if (!script) throw new ScriptError(`no such script (id=${scriptId})`, 'no-such-script');
@@ -249,13 +262,14 @@ export function uploadNewVersion(scriptId: number, content: Buffer, notes?: stri
const latest = getLatestVersion(scriptId);
const nextVersion = (latest?.version ?? 0) + 1;
const sha = sha256(content);
const release = normalizeReleaseVersion(releaseVersion);
const res = db()
.prepare(
`INSERT INTO script_versions (script_id, version, sha256, size, content, notes, kind)
VALUES (?, ?, ?, ?, ?, ?, ?)`
`INSERT INTO script_versions (script_id, version, sha256, size, content, notes, kind, release_version)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
)
.run(scriptId, nextVersion, sha, content.byteLength, content, notes ?? null, script.kind);
.run(scriptId, nextVersion, sha, content.byteLength, content, notes ?? null, script.kind, release);
return getVersion(Number(res.lastInsertRowid))!;
}