Skip to content

Commit ca1bc8a

Browse files
committed
chore: add local release script and backfill 4.3.0 changelog
1 parent f602818 commit ca1bc8a

3 files changed

Lines changed: 97 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# zaileys
22

3+
## 4.3.0
4+
5+
### Minor Changes
6+
7+
- Add umbrella `message` event that fires for any inbound message type.
8+
- Add `staticId` (stable hash of roomId+senderId) and make `uniqueId` a 16-char uppercase hex.
9+
- Resolve `@lid` mentions to PN via the lid mapping, normalize device suffixes, and rewrite inline @numbers in text to match.
10+
- Derive message flags from content: `isEdited`, `isDeleted`, `isPinned`, `isUnPinned`, `isBot`, `isStatusMention`, `isGroupStatusMention`, `isStory`, `isHideTags`.
11+
12+
### Patch Changes
13+
14+
- Fix quoted/`replied()` context: carry media, resolve sender LID→PN, inherit the parent chat room, and parse timestamps from number/string/Long.
15+
- Fix `senderDevice` always reporting `android` (the device suffix was stripped before decoding).
16+
- Bound LID mention resolution with a 3s timeout so a hung resolver never drops the message.
17+
318
## 4.0.0
419

520
### Major Changes

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"dev": "tsx --watch examples/quickstart-connect.ts",
3737
"build": "tsup",
3838
"prepublishOnly": "tsup",
39+
"release": "node scripts/release.mjs",
3940
"typecheck": "tsgo --noEmit",
4041
"typecheck:legacy": "tsc --noEmit",
4142
"typecheck:audit": "tsx scripts/audit-tsgo-compat.ts",

scripts/release.mjs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/usr/bin/env node
2+
// Local, GH-Actions-free release: derive the bump + changelog from conventional
3+
// commits since the last `zaileys@*` tag, then version -> build -> publish -> tag -> push.
4+
// Usage: node scripts/release.mjs [--dry-run] [--patch|--minor|--major] [--no-publish] [--no-push]
5+
import { execSync } from 'node:child_process'
6+
import { readFileSync, writeFileSync } from 'node:fs'
7+
import { fileURLToPath } from 'node:url'
8+
import { dirname, join } from 'node:path'
9+
10+
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
11+
const args = new Set(process.argv.slice(2))
12+
const dryRun = args.has('--dry-run')
13+
const noPublish = args.has('--no-publish')
14+
const noPush = args.has('--no-push')
15+
const forced = args.has('--major') ? 'major' : args.has('--minor') ? 'minor' : args.has('--patch') ? 'patch' : null
16+
17+
const sh = (cmd, opts = {}) => execSync(cmd, { cwd: ROOT, encoding: 'utf8', stdio: opts.capture ? 'pipe' : 'inherit', ...opts })
18+
const out = (cmd) => sh(cmd, { capture: true }).trim()
19+
const die = (msg) => { console.error(`\n✖ ${msg}`); process.exit(1) }
20+
21+
const lastTag = (() => {
22+
try { return out('git describe --tags --abbrev=0 --match "zaileys@*"') } catch { return null }
23+
})()
24+
25+
const range = lastTag ? `${lastTag}..HEAD` : 'HEAD'
26+
const subjects = out(`git log ${range} --pretty=format:%s%x00%b%x1e`)
27+
.split('\x1e').map((s) => s.trim()).filter(Boolean)
28+
.map((block) => { const [subject, body = ''] = block.split('\x00'); return { subject, body } })
29+
30+
if (subjects.length === 0) die(`No commits since ${lastTag ?? 'repo start'} — nothing to release.`)
31+
32+
const RE = /^(\w+)(?:\(([^)]+)\))?(!)?:\s*(.+)$/
33+
const major = [], minor = [], patch = []
34+
for (const { subject, body } of subjects) {
35+
const m = RE.exec(subject)
36+
if (!m) continue
37+
const [, type, , bang, desc] = m
38+
const breaking = bang === '!' || /BREAKING CHANGE/.test(body)
39+
const line = desc.trim()
40+
if (breaking) major.push(line)
41+
else if (type === 'feat') minor.push(line)
42+
else if (type === 'fix' || type === 'perf') patch.push(line)
43+
}
44+
45+
const bump = forced ?? (major.length ? 'major' : minor.length ? 'minor' : patch.length ? 'patch' : null)
46+
if (!bump) die('No feat/fix/perf/breaking commits since last release — nothing to publish (chore/docs only).')
47+
48+
const pkgPath = join(ROOT, 'package.json')
49+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
50+
const [maj, min, pat] = pkg.version.split('.').map(Number)
51+
const next = bump === 'major' ? `${maj + 1}.0.0` : bump === 'minor' ? `${maj}.${min + 1}.0` : `${maj}.${min}.${pat + 1}`
52+
53+
const section = (title, items) => (items.length ? `### ${title}\n\n${items.map((i) => `- ${i}`).join('\n')}\n\n` : '')
54+
const entry = `## ${next}\n\n` +
55+
section('Major Changes', major) + section('Minor Changes', minor) + section('Patch Changes', patch)
56+
57+
console.log(`\nRelease: ${pkg.version} -> ${next} (${bump}) from ${subjects.length} commits since ${lastTag ?? 'start'}\n`)
58+
console.log(entry)
59+
60+
if (dryRun) { console.log('--dry-run: no changes written.'); process.exit(0) }
61+
62+
pkg.version = next
63+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
64+
65+
const clog = readFileSync(join(ROOT, 'CHANGELOG.md'), 'utf8')
66+
const header = '# zaileys\n\n'
67+
const rest = clog.startsWith(header) ? clog.slice(header.length) : clog
68+
writeFileSync(join(ROOT, 'CHANGELOG.md'), header + entry + rest)
69+
70+
sh('pnpm build')
71+
if (!noPublish) sh('npm publish')
72+
73+
sh('git add package.json CHANGELOG.md')
74+
sh(`git commit -m "chore: release v${next}" --no-verify`)
75+
sh(`git tag zaileys@${next}`)
76+
if (!noPush) {
77+
const branch = out('git rev-parse --abbrev-ref HEAD')
78+
sh(`git push origin ${branch} --follow-tags`)
79+
sh(`git push origin ${branch}:main`)
80+
}
81+
console.log(`\n✔ Released zaileys@${next}`)

0 commit comments

Comments
 (0)