Merge origin/master into sh/namespace

The names (simplex_name / RSLV) feature and master's badge feature both
extended the contact/group profile row layer. Resolution keeps both, with
simplex_name ordered last (chronological - it is the newer column):
- Profile/LocalProfile gain badge + simplex_name; simplex_name last in the
  data types, record builds, schema, and SQL row types/SELECTs/INSERTs
- SQL row types, SELECTs and INSERT/UPDATE lists carry both badge_* and
  simplex_name columns (simplex_name after badge)
- migration lists ordered by date (master 0601/0602 before names 0603+)
- SQLite chat_schema.sql regenerated; Postgres chat_schema.sql hand-merged

Verified: lib + test suite build; SchemaDump, Operators, Protocol and
direct/group profile round-trip tests pass.
This commit is contained in:
shum
2026-06-23 12:28:56 +00:00
191 changed files with 11177 additions and 1653 deletions
@@ -1,6 +1,6 @@
{
"name": "@simplex-chat/types",
"version": "0.8.0",
"version": "0.10.0",
"description": "TypeScript types for SimpleX Chat bot libraries",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -193,6 +193,33 @@ export interface AutoAccept {
acceptIncognito: boolean
}
export interface BadgeInfo {
badgeType: BadgeType
badgeExpiry?: string // ISO-8601 timestamp
badgeExtra: string
}
export interface BadgeProof {
badgeKeyIdx: number // int
presHeader: string
proof: string
badgeInfo: BadgeInfo
}
export enum BadgeStatus {
Active = "active",
Expired = "expired",
ExpiredOld = "expiredOld",
Failed = "failed",
UnknownKey = "unknownKey",
}
export enum BadgeType {
Supporter = "supporter",
Legend = "legend",
Investor = "investor",
}
export interface BlockingInfo {
reason: BlockingReason
notice?: ClientNotice
@@ -2083,6 +2110,7 @@ export interface ContactShortLinkData {
profile: Profile
message?: MsgContent
business: boolean
localBadge?: LocalBadge
}
export enum ContactStatus {
@@ -2393,6 +2421,11 @@ export interface FileTransferMeta {
cancelled: boolean
}
export enum FileType {
Normal = "normal",
Roster = "roster",
}
export type Format =
| Format.Bold
| Format.Italic
@@ -2623,6 +2656,7 @@ export interface GroupInfo {
uiThemes?: UIThemeEntityOverrides
customData?: object
groupSummary: GroupSummary
rosterVersion?: number // int64
membersRequireAttention: number // int
viaGroupLinkUri?: string
groupKeys?: GroupKeys
@@ -2989,6 +3023,11 @@ export interface LinkPreview {
content?: LinkContent
}
export interface LocalBadge {
badge: BadgeInfo
status: BadgeStatus
}
export interface LocalProfile {
profileId: number // int64
displayName: string
@@ -2999,6 +3038,7 @@ export interface LocalProfile {
simplexName?: SimplexNameInfo
preferences?: Preferences
peerType?: ChatPeerType
localBadge?: LocalBadge
localAlias: string
}
@@ -3382,6 +3422,7 @@ export interface Profile {
simplexName?: SimplexNameInfo
preferences?: Preferences
peerType?: ChatPeerType
badge?: BadgeProof
}
export type ProxyClientError =
@@ -3688,6 +3729,7 @@ export interface RcvFileTransfer {
xftpRcvFile?: XFTPRcvFile
fileInvitation: FileInvitation
fileStatus: RcvFileStatus
fileType: FileType
rcvFileInline?: InlineFileMode
senderDisplayName: string
chunkSize: number // int64
@@ -3859,6 +3901,7 @@ export enum RelayStatus {
New = "new",
Invited = "invited",
Accepted = "accepted",
AcknowledgedRoster = "acknowledgedRoster",
Active = "active",
Inactive = "inactive",
Rejected = "rejected",
@@ -4966,7 +5009,7 @@ export interface UserContactRequest {
cReqChatVRange: VersionRange
localDisplayName: string
profileId: number // int64
profile: Profile
profile: LocalProfile
createdAt: string // ISO-8601 timestamp
updatedAt: string // ISO-8601 timestamp
xContactId?: string
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "simplex-chat",
"version": "6.5.4",
"version": "7.0.0-beta.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
@@ -24,7 +24,7 @@
"docs": "typedoc"
},
"dependencies": {
"@simplex-chat/types": "^0.8.0",
"@simplex-chat/types": "^0.10.0",
"extract-zip": "^2.0.1",
"fast-deep-equal": "^3.1.3",
"node-addon-api": "^8.5.0"
@@ -4,7 +4,7 @@ const path = require('path');
const extract = require('extract-zip');
const GITHUB_REPO = 'simplex-chat/simplex-chat-libs';
const RELEASE_TAG = 'v6.5.4';
const RELEASE_TAG = 'v7.0.0-beta.0';
const BACKEND = (process.env.SIMPLEX_BACKEND || process.env.npm_config_simplex_backend || 'sqlite').toLowerCase();
if (BACKEND !== 'sqlite' && BACKEND !== 'postgres') {
@@ -5,5 +5,5 @@ Bump both together for normal releases. For wrapper-only fixes use a PEP 440
post-release: __version__ = "6.5.2.post1", LIBS_VERSION unchanged.
"""
__version__ = "6.5.4" # PEP 440 — read by hatchling for wheel metadata
LIBS_VERSION = "6.5.4" # simplex-chat-libs release tag (no 'v' prefix)
__version__ = "7.0.0b0" # PEP 440 — read by hatchling for wheel metadata
LIBS_VERSION = "7.0.0-beta.0" # simplex-chat-libs release tag (no 'v' prefix)
@@ -143,6 +143,21 @@ AgentErrorType_Tag = Literal["CMD", "CONN", "NO_USER", "SMP", "NTF", "XFTP", "FI
class AutoAccept(TypedDict):
acceptIncognito: bool
class BadgeInfo(TypedDict):
badgeType: "BadgeType"
badgeExpiry: NotRequired[str] # ISO-8601 timestamp
badgeExtra: str
class BadgeProof(TypedDict):
badgeKeyIdx: int # int
presHeader: str
proof: str
badgeInfo: "BadgeInfo"
BadgeStatus = Literal["active", "expired", "expiredOld", "failed", "unknownKey"]
BadgeType = Literal["supporter", "legend", "investor"]
class BlockingInfo(TypedDict):
reason: "BlockingReason"
notice: NotRequired["ClientNotice"]
@@ -1469,6 +1484,7 @@ class ContactShortLinkData(TypedDict):
profile: "Profile"
message: NotRequired["MsgContent"]
business: bool
localBadge: NotRequired["LocalBadge"]
ContactStatus = Literal["active", "deleted", "deletedByUser"]
@@ -1683,6 +1699,8 @@ class FileTransferMeta(TypedDict):
chunkSize: int # int64
cancelled: bool
FileType = Literal["normal", "roster"]
class Format_bold(TypedDict):
type: Literal["bold"]
@@ -1843,6 +1861,7 @@ class GroupInfo(TypedDict):
uiThemes: NotRequired["UIThemeEntityOverrides"]
customData: NotRequired[dict[str, object]]
groupSummary: "GroupSummary"
rosterVersion: NotRequired[int] # int64
membersRequireAttention: int # int
viaGroupLinkUri: NotRequired[str]
groupKeys: NotRequired["GroupKeys"]
@@ -2095,6 +2114,10 @@ class LinkPreview(TypedDict):
image: str
content: NotRequired["LinkContent"]
class LocalBadge(TypedDict):
badge: "BadgeInfo"
status: "BadgeStatus"
class LocalProfile(TypedDict):
profileId: int # int64
displayName: str
@@ -2105,6 +2128,7 @@ class LocalProfile(TypedDict):
simplexName: NotRequired["SimplexNameInfo"]
preferences: NotRequired["Preferences"]
peerType: NotRequired["ChatPeerType"]
localBadge: NotRequired["LocalBadge"]
localAlias: str
MemberCriteria = Literal["all"]
@@ -2379,6 +2403,7 @@ class Profile(TypedDict):
simplexName: NotRequired["SimplexNameInfo"]
preferences: NotRequired["Preferences"]
peerType: NotRequired["ChatPeerType"]
badge: NotRequired["BadgeProof"]
class ProxyClientError_protocolError(TypedDict):
type: Literal["protocolError"]
@@ -2592,6 +2617,7 @@ class RcvFileTransfer(TypedDict):
xftpRcvFile: NotRequired["XFTPRcvFile"]
fileInvitation: "FileInvitation"
fileStatus: "RcvFileStatus"
fileType: "FileType"
rcvFileInline: NotRequired["InlineFileMode"]
senderDisplayName: str
chunkSize: int # int64
@@ -2709,7 +2735,7 @@ class RelayProfile(TypedDict):
shortDescr: NotRequired[str]
image: NotRequired[str]
RelayStatus = Literal["new", "invited", "accepted", "active", "inactive", "rejected"]
RelayStatus = Literal["new", "invited", "accepted", "acknowledgedRoster", "active", "inactive", "rejected"]
ReportReason = Literal["spam", "content", "community", "profile", "other"]
@@ -3493,7 +3519,7 @@ class UserContactRequest(TypedDict):
cReqChatVRange: "VersionRange"
localDisplayName: str
profileId: int # int64
profile: "Profile"
profile: "LocalProfile"
createdAt: str # ISO-8601 timestamp
updatedAt: str # ISO-8601 timestamp
xContactId: NotRequired[str]
+12 -1
View File
@@ -583,6 +583,8 @@ const processCommand = (function () {
case "capabilities":
console.log("starting outgoing call - capabilities")
if (activeCall) endCall()
// Stop a preview stream from an earlier pre-connect outgoing call being replaced (activeCall may be null here)
stopNotConnectedCall()
let localStream: MediaStream | null = null
try {
@@ -623,7 +625,8 @@ const processCommand = (function () {
if (activeCall) endCall()
// It can be already defined on Android when switching calls (if the previous call was outgoing)
notConnectedCall = undefined
// Stop its preview tracks before clearing, otherwise camera/mic stay live
stopNotConnectedCall()
inactiveCallMediaSources.mic = true
inactiveCallMediaSources.camera = command.media == CallMediaType.Video
inactiveCallMediaSourcesChanged(inactiveCallMediaSources)
@@ -1444,6 +1447,14 @@ const processCommand = (function () {
}
}
// Call on any path that abandons notConnectedCall, otherwise its preview camera/mic tracks stay live.
function stopNotConnectedCall() {
if (notConnectedCall) {
notConnectedCall.localStream.getTracks().forEach((track) => track.stop())
notConnectedCall = undefined
}
}
function resetVideoElements() {
const videos = getVideoElements()
if (!videos) return
@@ -2,8 +2,8 @@
useWorker = typeof window.Worker !== "undefined"
isDesktop = true
// Create WebSocket connection.
const socket = new WebSocket(`ws://${location.host}`)
// Create WebSocket connection. location.search carries the per-call ?token=... capability required by the server.
const socket = new WebSocket(`ws://${location.host}${location.search}`)
socket.addEventListener("open", (_event) => {
console.log("Opened socket")