@vanzxy/baileys 1.6.7 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @vanzxy/baileys might be problematic. Click here for more details.
- package/NOTICE.md +111 -0
- package/README.md +138 -9
- package/lib/Framework/Bot.js +209 -0
- package/lib/Framework/Context.js +90 -0
- package/lib/Framework/MediaManager.js +152 -0
- package/lib/Framework/SessionManager.js +34 -0
- package/lib/Framework/StatsManager.js +120 -0
- package/lib/Framework/Store/SQLiteStore.js +74 -0
- package/lib/Framework/index.js +11 -0
- package/lib/Socket/index.js +4 -2
- package/lib/Socket/username.js +153 -0
- package/lib/Utils/MessageBuilder.js +84 -3
- package/lib/Utils/MessageBuilder_d.ts +133 -1
- package/lib/Utils/anti-delete.js +9 -1
- package/lib/Utils/generics.js +19 -1
- package/lib/Utils/media-set.js +5 -1
- package/lib/VoIP/worker-bootstrap.js +8 -8
- package/lib/WABinary/generic-utils.js +3 -1
- package/lib/index.js +3 -0
- package/package.json +39 -35
|
@@ -763,6 +763,46 @@ class Button extends BaseBuilder {
|
|
|
763
763
|
// - a node can carry a builder-only `ref: 'name'` tag; another prop can then point back
|
|
764
764
|
// at it with `{ $ref: 'name' }`, resolved to that node's real id after the whole tree
|
|
765
765
|
// is walked (order-independent). `ref` itself is stripped and never reaches the wire.
|
|
766
|
+
//
|
|
767
|
+
// Vanz@Add 01-09-26 --- JSDoc typedefs for the "basic" A2UI catalog below (component set +
|
|
768
|
+
// props confirmed from captured traffic — see /areas/vanzxy-baileys.md). This is NOT the
|
|
769
|
+
// official A2UI spec (there isn't a public one we have access to), just what's been observed
|
|
770
|
+
// on the wire, so BloksNode ends with a permissive `AnyBloksNode` fallback: known components
|
|
771
|
+
// get full editor autocomplete + prop hints, anything else still type-checks and still works
|
|
772
|
+
// at runtime (setBloksWidget()'s own validation only ever requires a "component" string).
|
|
773
|
+
/**
|
|
774
|
+
* @typedef {{ $ref: string }} BloksRef
|
|
775
|
+
* Points back at a sibling node tagged `ref: 'name'` elsewhere in the same tree (currently
|
|
776
|
+
* only needed for `Modal.trigger`/`Modal.content` — everything else nests directly).
|
|
777
|
+
*/
|
|
778
|
+
/**
|
|
779
|
+
* @typedef {Object} BloksNodeBase
|
|
780
|
+
* @property {string} [ref] Builder-only tag so another node can reference this one via `{ $ref: ref }`. Stripped before send.
|
|
781
|
+
*/
|
|
782
|
+
/**
|
|
783
|
+
* @typedef {BloksNodeBase & { component: 'Column'|'Row', weight?: number, justify?: string, children?: BloksNode[] }} ColumnRowNode
|
|
784
|
+
* @typedef {BloksNodeBase & { component: 'Text', text: string, variant?: string }} TextNode
|
|
785
|
+
* @typedef {BloksNodeBase & { component: 'Icon', name: string }} IconNode
|
|
786
|
+
* @typedef {BloksNodeBase & { component: 'Divider' }} DividerNode
|
|
787
|
+
* @typedef {BloksNodeBase & { component: 'Image', url: string, variant?: string, fit?: string }} ImageNode
|
|
788
|
+
* @typedef {BloksNodeBase & { component: 'Video', url: string }} VideoNode
|
|
789
|
+
* @typedef {BloksNodeBase & { component: 'List', children?: BloksNode[] }} ListNode
|
|
790
|
+
* @typedef {BloksNodeBase & { component: 'TextField', label?: string, value?: string, variant?: string }} TextFieldNode
|
|
791
|
+
* @typedef {BloksNodeBase & { component: 'DateTimeInput', label?: string, value?: string, enableDate?: boolean, enableTime?: boolean }} DateTimeInputNode
|
|
792
|
+
* @typedef {BloksNodeBase & { component: 'Slider', label?: string, min?: number, max?: number, value?: number }} SliderNode
|
|
793
|
+
* @typedef {BloksNodeBase & { component: 'CheckBox', label?: string, value?: boolean }} CheckBoxNode
|
|
794
|
+
* @typedef {BloksNodeBase & { component: 'ChoicePicker', label?: string, variant?: string, displayStyle?: string, options?: Array<{label: string, value: string}>, value?: string }} ChoicePickerNode
|
|
795
|
+
* @typedef {BloksNodeBase & { component: 'Button', child?: BloksNode, variant?: string, action?: { call: string, args?: Record<string, any> } }} BloksButtonNode
|
|
796
|
+
* Note: unlike the CTA/native-flow `Button` class elsewhere in this file, an A2UI Button node
|
|
797
|
+
* has no `label`/`type`+`name` — its label comes from a nested `child` (usually a `Text` node),
|
|
798
|
+
* and tapping it fires `action.call` (with `action.args`), not a native-flow button name.
|
|
799
|
+
* @typedef {BloksNodeBase & { component: 'Modal', trigger: string|BloksRef, content: BloksNode|string|BloksRef }} ModalNode
|
|
800
|
+
* @typedef {BloksNodeBase & { component: 'Tabs', tabs: Array<{title: string, child: BloksNode}> }} TabsNode
|
|
801
|
+
* @typedef {BloksNodeBase & { component: 'Card', child?: BloksNode }} CardNode
|
|
802
|
+
* @typedef {BloksNodeBase & { component: 'AudioPlayer', url: string, description?: string }} AudioPlayerNode
|
|
803
|
+
* @typedef {BloksNodeBase & { component: string, [key: string]: any }} AnyBloksNode Fallback for components not yet confirmed on the wire — still works, just no prop-level autocomplete.
|
|
804
|
+
* @typedef {ColumnRowNode|TextNode|IconNode|DividerNode|ImageNode|VideoNode|ListNode|TextFieldNode|DateTimeInputNode|SliderNode|CheckBoxNode|ChoicePickerNode|BloksButtonNode|ModalNode|TabsNode|CardNode|AudioPlayerNode|AnyBloksNode} BloksNode
|
|
805
|
+
*/
|
|
766
806
|
#flattenBloks(tree, out, ctx = { n: 0, refs: new Map(), pending: [] }, id = 'root') {
|
|
767
807
|
if (!tree || typeof tree !== 'object') throw new TypeError('setBloksWidget: every node needs a "component" type');
|
|
768
808
|
const { component, children, child, ref, ...rest } = tree;
|
|
@@ -804,7 +844,7 @@ class Button extends BaseBuilder {
|
|
|
804
844
|
* `Modal.trigger` — tag the source node with `ref: 'someName'` and point at it with
|
|
805
845
|
* `{ $ref: 'someName' }`. Everything else (including `Modal.content`) can just be nested
|
|
806
846
|
* directly, no special key needed.
|
|
807
|
-
* @param {
|
|
847
|
+
* @param {BloksNode} tree Root node, e.g. `{ component: 'Column', children: [...] }`.
|
|
808
848
|
* @param {{uuid?: string, catalogId?: string, surfaceId?: string, version?: string}} [options]
|
|
809
849
|
*/
|
|
810
850
|
setBloksWidget(tree, { uuid = crypto.randomUUID(), catalogId = 'https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json', surfaceId, version = 'v0.9' } = {}) {
|
|
@@ -2102,6 +2142,19 @@ class AIRich extends BaseBuilder {
|
|
|
2102
2142
|
// last item that belongs to the block named by insertAt. Blocks are tracked by *object
|
|
2103
2143
|
// reference*, not saved numeric index, so earlier insertions shifting the array around never
|
|
2104
2144
|
// invalidates a later insertAt lookup (indexOf on the reference always finds the live position).
|
|
2145
|
+
//
|
|
2146
|
+
// Vanz@Note (bug 71, behavior — not fixed, documented) --- insertAt always inserts right after
|
|
2147
|
+
// the ANCHOR's block, not after "whatever was most recently inserted there". Chaining (each new
|
|
2148
|
+
// item gets its own id, and the next call's insertAt points at THAT id — exactly what the
|
|
2149
|
+
// addText/addSuggest streaming-reveal example does) produces the expected order. But calling
|
|
2150
|
+
// insertAt at the SAME static anchor id repeatedly, without giving each new item its own id to
|
|
2151
|
+
// chain onto, inserts every one of them right after the original anchor — so the order comes out
|
|
2152
|
+
// reversed relative to call order (confirmed by test: id:'x' then 3x insertAt:'x' with no id of
|
|
2153
|
+
// their own on the new items produces [x, third, second, first], not [x, first, second, third]).
|
|
2154
|
+
// Left as-is rather than "fixed": making insertAt self-advance (re-pointing the anchor's block at
|
|
2155
|
+
// whatever was just inserted) would silently change what an id resolves to for any OTHER caller
|
|
2156
|
+
// still holding that id for a later replace()/delete()/insertAt() — a subtler, harder-to-diagnose
|
|
2157
|
+
// bug than the surprising-but-deterministic order this produces. Chain with fresh ids instead.
|
|
2105
2158
|
this._blocks = new Map(); // id -> { subItems: object[], secItems: object[] }
|
|
2106
2159
|
return new Proxy(this, {
|
|
2107
2160
|
get(target, prop, receiver) {
|
|
@@ -2129,6 +2182,19 @@ class AIRich extends BaseBuilder {
|
|
|
2129
2182
|
const insertAt = opts?.insertAt;
|
|
2130
2183
|
const replace = opts?.replace;
|
|
2131
2184
|
|
|
2185
|
+
// Vanz@Fix (bug 70) --- `id` reuse across two different add*/set* calls was silently
|
|
2186
|
+
// accepted: target._blocks.set(id, ...) below just clobbers the previous registration,
|
|
2187
|
+
// so the FIRST block with that id becomes an untracked ghost — still in _sections/
|
|
2188
|
+
// _submessages (still renders), but no longer reachable via hasId/peek/delete/replace/
|
|
2189
|
+
// insertAt (the id now only resolves to the second block). Confirmed by direct test:
|
|
2190
|
+
// addText('first',{id:'dup'}); addText('second',{id:'dup'}) left both in the message
|
|
2191
|
+
// but getIds() only ever had one 'dup', pointing at 'second'. Fail fast instead — same
|
|
2192
|
+
// as re-registering the same id you're actively `replace`-ing (that's a legitimate
|
|
2193
|
+
// "update this block, keep its id" call, not a collision).
|
|
2194
|
+
if (id && target._blocks.has(id) && replace !== id) {
|
|
2195
|
+
throw new Error(`add*/set*: id "${id}" is already registered — each id must be unique (pass { replace: "${id}" } to update that block instead, or use a different id)`);
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2132
2198
|
const subBefore = target._submessages.length;
|
|
2133
2199
|
const secBefore = target._sections.length;
|
|
2134
2200
|
|
|
@@ -2977,6 +3043,14 @@ class AIRich extends BaseBuilder {
|
|
|
2977
3043
|
addWidget(data = {}, { layout } = {}) {
|
|
2978
3044
|
const items = Array.isArray(data) ? data : [data];
|
|
2979
3045
|
|
|
3046
|
+
// Vanz@Fix (bug 44) --- layout: 'Single' forces `widgets[0]` below (a "Single" layout's
|
|
3047
|
+
// view_model can only ever hold one `primitive`, never a `primitives` array — see
|
|
3048
|
+
// newLayout()). Previously an explicit { layout: 'Single' } combined with a multi-item
|
|
3049
|
+
// array silently dropped every item past the first with no error. Fail loud instead.
|
|
3050
|
+
if (layout === 'Single' && items.length > 1) {
|
|
3051
|
+
throw new TypeError(`addWidget(): layout "Single" can only hold one widget (got ${items.length}) — use "HScroll"/"ActionRow" (or omit layout) for multiple`);
|
|
3052
|
+
}
|
|
3053
|
+
|
|
2980
3054
|
items.forEach((item, i) => {
|
|
2981
3055
|
// header.title or top-level title required
|
|
2982
3056
|
const hasTitle = item?.title || item?.header?.title;
|
|
@@ -2994,6 +3068,13 @@ class AIRich extends BaseBuilder {
|
|
|
2994
3068
|
messageText: items.map((item) => item.header?.title ?? item.title).join(', '),
|
|
2995
3069
|
});
|
|
2996
3070
|
|
|
3071
|
+
// Vanz@Fix (bug 45) --- auto tool_call_id used to be `idx` scoped per-item (ctas.map's own
|
|
3072
|
+
// index), resetting to 0 for every widget item. Two items (or two separate addWidget()
|
|
3073
|
+
// calls) that both omit tool_call_id/id ended up minting the identical auto id ("00"),
|
|
3074
|
+
// so a CTA tap could route to the wrong widget's tool call. Track the counter on the
|
|
3075
|
+
// instance instead so every auto-generated id is unique for this AIRich's lifetime.
|
|
3076
|
+
this._widgetCtaCounter ??= 0;
|
|
3077
|
+
|
|
2997
3078
|
const widgets = items.map((item) => {
|
|
2998
3079
|
const ctas = item.ctas ?? item.actions;
|
|
2999
3080
|
// header accepts either a string title (legacy) or an object { title, subtitle }
|
|
@@ -3007,11 +3088,11 @@ class AIRich extends BaseBuilder {
|
|
|
3007
3088
|
},
|
|
3008
3089
|
body: {
|
|
3009
3090
|
sections: item.sections ?? [],
|
|
3010
|
-
ctas: ctas.map((cta
|
|
3091
|
+
ctas: ctas.map((cta) => ({
|
|
3011
3092
|
label: cta.label ?? '',
|
|
3012
3093
|
state: cta.state ?? 'PENDING',
|
|
3013
3094
|
kind: cta.kind ?? 'OTHER',
|
|
3014
|
-
tool_call_id: cta.tool_call_id ?? cta.id ?? String(
|
|
3095
|
+
tool_call_id: cta.tool_call_id ?? cta.id ?? String(this._widgetCtaCounter++).padStart(2, '0'),
|
|
3015
3096
|
...(cta.toast !== false && {
|
|
3016
3097
|
toast: { label: typeof cta.toast === 'string' ? cta.toast : headerTitle, __typename: 'GenAI3PExtWidgetToast' },
|
|
3017
3098
|
}),
|
|
@@ -37,6 +37,138 @@ export interface TapTargetConfigurationParams {
|
|
|
37
37
|
buttonIndex?: number;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* A2UI/Bloks "basic" catalog node types — confirmed from captured traffic (see
|
|
42
|
+
* /areas/vanzxy-baileys.md), not a public spec, so treat this as best-effort autocomplete
|
|
43
|
+
* rather than an exhaustive guarantee. `ref` is a builder-only tag (stripped before send) so
|
|
44
|
+
* another node can reference this one via `BloksRef`.
|
|
45
|
+
*/
|
|
46
|
+
export interface BloksRef {
|
|
47
|
+
$ref: string;
|
|
48
|
+
}
|
|
49
|
+
export interface BloksNodeBase {
|
|
50
|
+
/** Builder-only tag so another node can reference this one via `{ $ref: ref }`. Stripped before send. */
|
|
51
|
+
ref?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface ColumnRowNode extends BloksNodeBase {
|
|
54
|
+
component: 'Column' | 'Row';
|
|
55
|
+
weight?: number;
|
|
56
|
+
justify?: string;
|
|
57
|
+
children?: BloksNode[];
|
|
58
|
+
}
|
|
59
|
+
export interface TextNode extends BloksNodeBase {
|
|
60
|
+
component: 'Text';
|
|
61
|
+
text: string;
|
|
62
|
+
variant?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface IconNode extends BloksNodeBase {
|
|
65
|
+
component: 'Icon';
|
|
66
|
+
name: string;
|
|
67
|
+
}
|
|
68
|
+
export interface DividerNode extends BloksNodeBase {
|
|
69
|
+
component: 'Divider';
|
|
70
|
+
}
|
|
71
|
+
export interface ImageNode extends BloksNodeBase {
|
|
72
|
+
component: 'Image';
|
|
73
|
+
url: string;
|
|
74
|
+
variant?: string;
|
|
75
|
+
fit?: string;
|
|
76
|
+
}
|
|
77
|
+
export interface VideoNode extends BloksNodeBase {
|
|
78
|
+
component: 'Video';
|
|
79
|
+
url: string;
|
|
80
|
+
}
|
|
81
|
+
export interface ListNode extends BloksNodeBase {
|
|
82
|
+
component: 'List';
|
|
83
|
+
children?: BloksNode[];
|
|
84
|
+
}
|
|
85
|
+
export interface TextFieldNode extends BloksNodeBase {
|
|
86
|
+
component: 'TextField';
|
|
87
|
+
label?: string;
|
|
88
|
+
value?: string;
|
|
89
|
+
variant?: string;
|
|
90
|
+
}
|
|
91
|
+
export interface DateTimeInputNode extends BloksNodeBase {
|
|
92
|
+
component: 'DateTimeInput';
|
|
93
|
+
label?: string;
|
|
94
|
+
value?: string;
|
|
95
|
+
enableDate?: boolean;
|
|
96
|
+
enableTime?: boolean;
|
|
97
|
+
}
|
|
98
|
+
export interface SliderNode extends BloksNodeBase {
|
|
99
|
+
component: 'Slider';
|
|
100
|
+
label?: string;
|
|
101
|
+
min?: number;
|
|
102
|
+
max?: number;
|
|
103
|
+
value?: number;
|
|
104
|
+
}
|
|
105
|
+
export interface CheckBoxNode extends BloksNodeBase {
|
|
106
|
+
component: 'CheckBox';
|
|
107
|
+
label?: string;
|
|
108
|
+
value?: boolean;
|
|
109
|
+
}
|
|
110
|
+
export interface ChoicePickerNode extends BloksNodeBase {
|
|
111
|
+
component: 'ChoicePicker';
|
|
112
|
+
label?: string;
|
|
113
|
+
variant?: string;
|
|
114
|
+
displayStyle?: string;
|
|
115
|
+
options?: Array<{ label: string; value: string }>;
|
|
116
|
+
value?: string;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Unlike the CTA/native-flow `Button` class elsewhere in this file, an A2UI Button node has no
|
|
120
|
+
* `label`/`type`+`name` — its label comes from a nested `child` (usually a `Text` node), and
|
|
121
|
+
* tapping it fires `action.call` (with `action.args`), not a native-flow button name.
|
|
122
|
+
*/
|
|
123
|
+
export interface BloksButtonNode extends BloksNodeBase {
|
|
124
|
+
component: 'Button';
|
|
125
|
+
child?: BloksNode;
|
|
126
|
+
variant?: string;
|
|
127
|
+
action?: { call: string; args?: Record<string, any> };
|
|
128
|
+
}
|
|
129
|
+
export interface ModalNode extends BloksNodeBase {
|
|
130
|
+
component: 'Modal';
|
|
131
|
+
trigger: string | BloksRef;
|
|
132
|
+
content: BloksNode | string | BloksRef;
|
|
133
|
+
}
|
|
134
|
+
export interface TabsNode extends BloksNodeBase {
|
|
135
|
+
component: 'Tabs';
|
|
136
|
+
tabs: Array<{ title: string; child: BloksNode }>;
|
|
137
|
+
}
|
|
138
|
+
export interface CardNode extends BloksNodeBase {
|
|
139
|
+
component: 'Card';
|
|
140
|
+
child?: BloksNode;
|
|
141
|
+
}
|
|
142
|
+
export interface AudioPlayerNode extends BloksNodeBase {
|
|
143
|
+
component: 'AudioPlayer';
|
|
144
|
+
url: string;
|
|
145
|
+
description?: string;
|
|
146
|
+
}
|
|
147
|
+
/** Fallback for components not yet confirmed on the wire — still works at runtime, just no prop-level autocomplete. */
|
|
148
|
+
export interface AnyBloksNode extends BloksNodeBase {
|
|
149
|
+
component: string;
|
|
150
|
+
[key: string]: any;
|
|
151
|
+
}
|
|
152
|
+
export type BloksNode =
|
|
153
|
+
| ColumnRowNode
|
|
154
|
+
| TextNode
|
|
155
|
+
| IconNode
|
|
156
|
+
| DividerNode
|
|
157
|
+
| ImageNode
|
|
158
|
+
| VideoNode
|
|
159
|
+
| ListNode
|
|
160
|
+
| TextFieldNode
|
|
161
|
+
| DateTimeInputNode
|
|
162
|
+
| SliderNode
|
|
163
|
+
| CheckBoxNode
|
|
164
|
+
| ChoicePickerNode
|
|
165
|
+
| BloksButtonNode
|
|
166
|
+
| ModalNode
|
|
167
|
+
| TabsNode
|
|
168
|
+
| CardNode
|
|
169
|
+
| AudioPlayerNode
|
|
170
|
+
| AnyBloksNode;
|
|
171
|
+
|
|
40
172
|
export class Button extends BaseBuilder {
|
|
41
173
|
constructor(client: any);
|
|
42
174
|
setVideo(path: string | Buffer, options?: Record<string, any>): this;
|
|
@@ -45,7 +177,7 @@ export class Button extends BaseBuilder {
|
|
|
45
177
|
setMedia(obj: Record<string, any>): this;
|
|
46
178
|
clearButtons(): this;
|
|
47
179
|
setParams(obj: Record<string, any>): this;
|
|
48
|
-
setBloksWidget(tree:
|
|
180
|
+
setBloksWidget(tree: BloksNode, options?: { uuid?: string; catalogId?: string; surfaceId?: string; version?: string }): this;
|
|
49
181
|
addButton(name: string, params: string | Record<string, any>): this;
|
|
50
182
|
makeRow(header?: string, title?: string, description?: string, id?: string): this;
|
|
51
183
|
makeSection(title?: string, highlight_label?: string): this;
|
package/lib/Utils/anti-delete.js
CHANGED
|
@@ -80,12 +80,20 @@ export class MessageStore {
|
|
|
80
80
|
stored.isDeleted = true;
|
|
81
81
|
stored.deletedAt = now;
|
|
82
82
|
stored.deletedBy = deletedBy;
|
|
83
|
+
// Vanz@Fix (bug 66): the old check (`deletedBy === stored.message.key.participant`)
|
|
84
|
+
// only works in groups, where `participant` identifies who sent/revoked a message.
|
|
85
|
+
// In a private chat `key.participant` is always undefined (it's a group-only field),
|
|
86
|
+
// while `deletedBy` there falls back to `remoteJid` — so the comparison could never
|
|
87
|
+
// match and isRevokedBySender was always false for every DM, even though
|
|
88
|
+
// delete-for-everyone in a DM can only be done by the original sender. Treat a
|
|
89
|
+
// missing `participant` (i.e. not a group message) as "revoked by sender" by definition.
|
|
90
|
+
const isGroupMessage = !!stored.message.key.participant;
|
|
83
91
|
const info = {
|
|
84
92
|
originalMessage: stored.message,
|
|
85
93
|
key,
|
|
86
94
|
deletedAt: now,
|
|
87
95
|
deletedBy,
|
|
88
|
-
isRevokedBySender: !deletedBy || deletedBy === stored.message.key.participant
|
|
96
|
+
isRevokedBySender: !deletedBy || !isGroupMessage || deletedBy === stored.message.key.participant
|
|
89
97
|
};
|
|
90
98
|
this.deletedMessages.set(this.getKey(key), info);
|
|
91
99
|
return info;
|
package/lib/Utils/generics.js
CHANGED
|
@@ -71,7 +71,25 @@ export const encodeBigEndian = (e, t = 4) => {
|
|
|
71
71
|
};
|
|
72
72
|
export const toNumber = (t) => typeof t === 'object' && t ? ('toNumber' in t ? t.toNumber() : t.low) : t || 0;
|
|
73
73
|
/** unix timestamp of a date in seconds */
|
|
74
|
-
|
|
74
|
+
// Vanz@Fix (bug 69): unixTimestampSeconds(date) assumed `date` is always a real Date
|
|
75
|
+
// instance and called date.getTime() unconditionally. Any caller that passed a raw
|
|
76
|
+
// number (Date.now(), or an already-converted unix timestamp) or an ISO string instead
|
|
77
|
+
// of a Date crashed here with "date.getTime is not a function" — this is a coercion
|
|
78
|
+
// bug in THIS function, not a proto/BloksWidget/InteractiveMessage issue (traced and
|
|
79
|
+
// confirmed: normalizeMessageContent/getContentType never touch nested message content,
|
|
80
|
+
// and this function is called before any encode/serialize step even starts). Coerce the
|
|
81
|
+
// common input shapes instead of assuming Date, but keep throwing on genuinely invalid
|
|
82
|
+
// input (NaN) so silent bad-timestamp bugs don't get hidden.
|
|
83
|
+
export const unixTimestampSeconds = (date) => {
|
|
84
|
+
if (date == null) date = new Date(); // null AND undefined both mean "now" (default params only catch undefined)
|
|
85
|
+
const d = date instanceof Date
|
|
86
|
+
? date
|
|
87
|
+
: new Date(typeof date === 'number' && date < 1e12 ? date * 1000 : date); // treat sub-1e12 numbers as already-seconds
|
|
88
|
+
if (Number.isNaN(d.getTime())) {
|
|
89
|
+
throw new TypeError(`unixTimestampSeconds: invalid timestamp input (${typeof date}): ${date}`);
|
|
90
|
+
}
|
|
91
|
+
return d.getTime() / 1000 | 0;
|
|
92
|
+
};
|
|
75
93
|
export const debouncedTimeout = (intervalMs = 1000, task) => {
|
|
76
94
|
let timeout;
|
|
77
95
|
return {
|
package/lib/Utils/media-set.js
CHANGED
|
@@ -145,7 +145,11 @@ export const groupLabel = async (jid, text, sock) => {
|
|
|
145
145
|
type: 30,
|
|
146
146
|
memberLabel: {
|
|
147
147
|
label: text.slice(0, 30),
|
|
148
|
-
|
|
148
|
+
// Vanz@Fix (bug 67): this used Date.now() (milliseconds) while the
|
|
149
|
+
// sibling groupSetMemberLabel() correctly uses unixTimestampSeconds()
|
|
150
|
+
// for the same proto field — WA's *Timestamp fields are unix-seconds,
|
|
151
|
+
// so this was sending a timestamp ~1000x too large.
|
|
152
|
+
labelTimestamp: unixTimestampSeconds() || Date.now()
|
|
149
153
|
}
|
|
150
154
|
}
|
|
151
155
|
}, {
|
|
@@ -346,7 +346,7 @@ global.importScripts = function (...urls) {
|
|
|
346
346
|
const code = fs.readFileSync(url, "utf8");
|
|
347
347
|
eval(code);
|
|
348
348
|
}
|
|
349
|
-
catch (e) { }
|
|
349
|
+
catch (e) { console.error(`[VoIP worker-bootstrap] importScripts failed for "${url}":`, e); }
|
|
350
350
|
}
|
|
351
351
|
};
|
|
352
352
|
if (typeof global.location === "undefined") {
|
|
@@ -550,7 +550,7 @@ const resolveLoaderModule = () => {
|
|
|
550
550
|
return resolved;
|
|
551
551
|
}
|
|
552
552
|
}
|
|
553
|
-
catch (e) { }
|
|
553
|
+
catch (e) { console.error(`[VoIP worker-bootstrap] resolveLoaderModule failed for "${moduleName}":`, e); }
|
|
554
554
|
}
|
|
555
555
|
return null;
|
|
556
556
|
};
|
|
@@ -621,7 +621,7 @@ global.self.WhatsAppVoipWasmWorkerCompatibleCallbacks = {
|
|
|
621
621
|
try {
|
|
622
622
|
e.postMessage(Object.assign({ type: "waWasmWorkerCompatibleCallback", __name: "loggingCallback" }, n));
|
|
623
623
|
}
|
|
624
|
-
catch (err) { }
|
|
624
|
+
catch (err) { console.error("[VoIP worker-bootstrap] loggingCallback postMessage failed:", err); }
|
|
625
625
|
},
|
|
626
626
|
initCaptureDriverJS: function (n) {
|
|
627
627
|
e.postMessage(Object.assign({ type: "waWasmWorkerCompatibleCallback", __name: "initCaptureDriverJS" }, n));
|
|
@@ -762,9 +762,9 @@ if (typedWorkerData && (typedWorkerData.loaderCode || typedWorkerData.workerModu
|
|
|
762
762
|
WAWebVoipJsWorkerMessageHandler = jsWorkerModule.default ?? jsWorkerModule;
|
|
763
763
|
}
|
|
764
764
|
}
|
|
765
|
-
catch (e) { }
|
|
765
|
+
catch (e) { console.error("[VoIP worker-bootstrap] WAWebVoipJsWorkerMessageHandler resolution failed:", e); }
|
|
766
766
|
}
|
|
767
|
-
catch (e) { }
|
|
767
|
+
catch (e) { console.error("[VoIP worker-bootstrap] loaderCode block failed:", e); }
|
|
768
768
|
}
|
|
769
769
|
if (!wasmLoader) {
|
|
770
770
|
const resourcesPath = typedWorkerData?.resourcesPath || path.join(__dirname, "wasm-resources");
|
|
@@ -780,7 +780,7 @@ if (!wasmLoader) {
|
|
|
780
780
|
}
|
|
781
781
|
wasmLoader = resolveLoaderModule();
|
|
782
782
|
}
|
|
783
|
-
catch (e) { }
|
|
783
|
+
catch (e) { console.error(`[VoIP worker-bootstrap] failed to run loader.js from "${rsrcPath}":`, e); }
|
|
784
784
|
}
|
|
785
785
|
}
|
|
786
786
|
let s = {};
|
|
@@ -936,7 +936,7 @@ function f(t) {
|
|
|
936
936
|
try {
|
|
937
937
|
yield WAWebVoipPersistentFS.initPersistentFS(_);
|
|
938
938
|
}
|
|
939
|
-
catch (err) { }
|
|
939
|
+
catch (err) { console.error("[VoIP worker-bootstrap] initPersistentFS failed:", err); }
|
|
940
940
|
}));
|
|
941
941
|
}
|
|
942
942
|
else {
|
|
@@ -1035,7 +1035,7 @@ e.addMessageListener("waWasmWorkerCompatibleCallback", function (msg) {
|
|
|
1035
1035
|
global.self.WhatsAppVoipWasmWorkerCompatibleCallbacks[callbackName](args);
|
|
1036
1036
|
}
|
|
1037
1037
|
}
|
|
1038
|
-
catch (err) { }
|
|
1038
|
+
catch (err) { console.error("[VoIP worker-bootstrap] message handler failed:", err); }
|
|
1039
1039
|
});
|
|
1040
1040
|
if (parentPort) {
|
|
1041
1041
|
parentPort.postMessage({ type: "worker_ready" });
|
|
@@ -160,7 +160,9 @@ const FLOWS_MAP = {
|
|
|
160
160
|
// routed anything real; kept as a harmless alias in case any external caller
|
|
161
161
|
// is still constructing a raw button object with the old (wrong) name.
|
|
162
162
|
flow: true,
|
|
163
|
-
flow_action: true
|
|
163
|
+
// Vanz@Fix (bug 68): removed duplicate `flow_action: true` key — already declared
|
|
164
|
+
// above (Vanzxy extended button types block); this was a leftover copy-paste dupe,
|
|
165
|
+
// harmless (same value) but confusing on re-read.
|
|
164
166
|
// Vanz@Fix (single_select never renders alone) --- single_select must NEVER get
|
|
165
167
|
// its own dedicated native_flow node here. WhatsApp only renders a single_select
|
|
166
168
|
// button through the generic <native_flow v='9' name='mixed'> node — the same one
|
package/lib/index.js
CHANGED
|
@@ -8,6 +8,9 @@ export * from './WABinary/index.js';
|
|
|
8
8
|
export * from './WAM/index.js';
|
|
9
9
|
export * from './WAUSync/index.js';
|
|
10
10
|
export { Dugong } from './Socket/dugong.js';
|
|
11
|
+
// Vanz@Port --- Enterprise Bot Framework (Bot/Context/SessionManager/
|
|
12
|
+
// StatsManager/MediaManager/SQLiteStore). See lib/Framework/index.js.
|
|
13
|
+
export { Bot, Context, MediaManager, SessionManager, StatsManager, SQLiteStore } from './Framework/index.js';
|
|
11
14
|
// Vanz@Add --- ported from ourin-baileys 9.0.11. Audio-only WhatsApp voice-call
|
|
12
15
|
// handling (WASM call stack + WebRTC relay via optional `@roamhq/wrtc`). See
|
|
13
16
|
// lib/VoIP/index.js for usage — instantiate VoipClient(sock) after connection.open.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vanzxy/baileys",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Enhanced Baileys fork by Vanzxy \u2014 based on @itsliaaa/baileys + @whiskeysockets/baileys with fixes for audio group status and clean media without newsletter button.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -34,39 +34,39 @@
|
|
|
34
34
|
"NOTICE.md"
|
|
35
35
|
],
|
|
36
36
|
"keywords": [
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
37
|
+
"vanzxy",
|
|
38
|
+
"vanzxybaileys",
|
|
39
|
+
"vanzxy-baileys",
|
|
40
|
+
"vanzxy-whatsapp",
|
|
41
|
+
"vanzxy-baileys-md",
|
|
42
|
+
"baileys-fork-vanzxy",
|
|
43
|
+
"baileys",
|
|
44
|
+
"baileys-md",
|
|
45
|
+
"baileys-multi-device",
|
|
46
|
+
"baileys-multidevice",
|
|
47
|
+
"baileys-whatsapp",
|
|
48
|
+
"baileys-whatsapp-api",
|
|
49
|
+
"baileys-whatsapp-bot",
|
|
50
|
+
"baileys-bot",
|
|
51
|
+
"baileys-api",
|
|
52
|
+
"baileys-library",
|
|
53
|
+
"baileys-node",
|
|
54
|
+
"baileys-nodejs",
|
|
55
|
+
"baileys-javascript",
|
|
56
|
+
"baileys-js",
|
|
57
|
+
"baileys-esm",
|
|
58
|
+
"baileys-fork",
|
|
59
|
+
"whatsapp-baileys",
|
|
60
|
+
"whatsapp-bot-baileys",
|
|
61
|
+
"whatsapp-api-baileys",
|
|
62
|
+
"whatsapp-web-baileys",
|
|
63
|
+
"whatsapp-multi-device",
|
|
64
|
+
"whatsapp-automation",
|
|
65
|
+
"whatsapp-bot",
|
|
66
|
+
"whatsapp-api",
|
|
67
|
+
"whatsapp-web",
|
|
68
|
+
"multi-device",
|
|
69
|
+
"interactive-messages"
|
|
70
70
|
],
|
|
71
71
|
"homepage": "https://github.com/vanzxysenpai/vanzxybaileys#readme",
|
|
72
72
|
"author": "Vanzxy",
|
|
@@ -98,7 +98,8 @@
|
|
|
98
98
|
"mongodb": "^6.10.0",
|
|
99
99
|
"mysql2": "^3.11.0",
|
|
100
100
|
"pg": "^8.13.0",
|
|
101
|
-
"sharp": "*"
|
|
101
|
+
"sharp": "*",
|
|
102
|
+
"node-webpmux": "^3.2.0"
|
|
102
103
|
},
|
|
103
104
|
"peerDependenciesMeta": {
|
|
104
105
|
"@napi-rs/image": {
|
|
@@ -133,6 +134,9 @@
|
|
|
133
134
|
},
|
|
134
135
|
"pg": {
|
|
135
136
|
"optional": true
|
|
137
|
+
},
|
|
138
|
+
"node-webpmux": {
|
|
139
|
+
"optional": true
|
|
136
140
|
}
|
|
137
141
|
},
|
|
138
142
|
"resolutions": {
|