@oxidezap/baileyrs 0.2.12 → 0.3.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.
- package/lib/Compatibility/encode-proto.d.ts +7 -3
- package/lib/Compatibility/encode-proto.js +10 -5
- package/lib/Compatibility/proto-runtime.js +54 -7
- package/lib/Compatibility/signal-repository.d.ts +1 -1
- package/lib/Compatibility/signal-repository.js +61 -57
- package/lib/Compatibility/stanza-responses.d.ts +3 -3
- package/lib/Compatibility/stanza-responses.js +16 -13
- package/lib/Socket/blocking.js +11 -9
- package/lib/Socket/bridge-error-boundary.d.ts +2 -2
- package/lib/Socket/bridge-error-boundary.js +2 -2
- package/lib/Socket/business.js +63 -61
- package/lib/Socket/chat-actions.js +102 -98
- package/lib/Socket/client-operations.d.ts +6 -0
- package/lib/Socket/client-operations.js +2 -0
- package/lib/Socket/communities.js +8 -8
- package/lib/Socket/contacts.js +29 -26
- package/lib/Socket/events.js +2 -37
- package/lib/Socket/groups.js +22 -21
- package/lib/Socket/index.d.ts +2 -2
- package/lib/Socket/index.js +163 -107
- package/lib/Socket/internals.js +1 -1
- package/lib/Socket/messages.js +224 -218
- package/lib/Socket/newsletter.js +137 -133
- package/lib/Socket/prekeys.d.ts +1 -1
- package/lib/Socket/prekeys.js +20 -18
- package/lib/Socket/presence.js +15 -13
- package/lib/Socket/privacy.js +10 -10
- package/lib/Socket/profile.js +20 -18
- package/lib/Socket/server-queries.js +4 -4
- package/lib/Socket/terminal-close.d.ts +2 -36
- package/lib/Socket/terminal-close.js +29 -5
- package/lib/Socket/types.d.ts +2 -6
- package/package.json +4 -4
package/lib/Socket/newsletter.js
CHANGED
|
@@ -4,140 +4,144 @@ import { assertArgumentDomain } from '../Utils/argument-domain.js';
|
|
|
4
4
|
import { Boom } from '../Utils/boom.js';
|
|
5
5
|
import { generateProfilePicture } from '../Utils/messages-media.js';
|
|
6
6
|
export const NEWSLETTER_KEY_TYPES = ['invite', 'jid'];
|
|
7
|
-
export const makeNewsletterMethods = (ctx) =>
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* `picture` is base64 of an already-generated image, and the empty string
|
|
24
|
-
* means remove, as upstream builds it. The core splits those into two
|
|
25
|
-
* methods, so the field is dispatched rather than forwarded.
|
|
26
|
-
*/
|
|
27
|
-
newsletterUpdate: async (jid, updates) => {
|
|
28
|
-
const client = await ctx.getClient();
|
|
29
|
-
let result;
|
|
30
|
-
if (updates.name !== undefined || updates.description !== undefined) {
|
|
31
|
-
result = await client.newsletterUpdate(jid, updates.name ?? null, updates.description ?? null);
|
|
32
|
-
}
|
|
33
|
-
if (updates.picture === '') {
|
|
34
|
-
result = await client.newsletterRemovePicture(jid);
|
|
35
|
-
}
|
|
36
|
-
else if (updates.picture !== undefined) {
|
|
37
|
-
result = await client.newsletterSetPicture(jid, new Uint8Array(Buffer.from(updates.picture, 'base64')));
|
|
38
|
-
}
|
|
39
|
-
// Only when the delta asked for nothing: every write above already
|
|
40
|
-
// answers with the refreshed metadata, so reading it would be a round
|
|
41
|
-
// trip whose result is thrown away.
|
|
42
|
-
return bridgeNewsletterMetadataToBaileys(result ?? (await client.newsletterMetadata(jid)));
|
|
43
|
-
},
|
|
44
|
-
newsletterUpdateName: async (jid, name) => {
|
|
45
|
-
return bridgeNewsletterMetadataToBaileys(await (await ctx.getClient()).newsletterUpdate(jid, name, null));
|
|
46
|
-
},
|
|
47
|
-
newsletterUpdateDescription: async (jid, description) => {
|
|
48
|
-
return bridgeNewsletterMetadataToBaileys(await (await ctx.getClient()).newsletterUpdate(jid, null, description));
|
|
49
|
-
},
|
|
50
|
-
newsletterUpdatePicture: async (jid, content) => {
|
|
51
|
-
const { img } = await generateProfilePicture(content);
|
|
52
|
-
return bridgeNewsletterMetadataToBaileys(await (await ctx.getClient()).newsletterSetPicture(jid, img));
|
|
53
|
-
},
|
|
54
|
-
newsletterRemovePicture: async (jid) => {
|
|
55
|
-
return bridgeNewsletterMetadataToBaileys(await (await ctx.getClient()).newsletterRemovePicture(jid));
|
|
56
|
-
},
|
|
57
|
-
newsletterFollow: async (jid) => {
|
|
58
|
-
return bridgeNewsletterMetadataToBaileys(await (await ctx.getClient()).newsletterSubscribe(jid));
|
|
59
|
-
},
|
|
60
|
-
newsletterUnfollow: async (jid) => {
|
|
61
|
-
await (await ctx.getClient()).newsletterUnsubscribe(jid);
|
|
62
|
-
},
|
|
63
|
-
/**
|
|
64
|
-
* The names this package used before it grew upstream's. Kept so existing
|
|
65
|
-
* callers do not break on a rename that buys them nothing, and returning
|
|
66
|
-
* the bridge result unmapped for the same reason: a caller reading `jid`
|
|
67
|
-
* or `subscriberCount` off it would find them renamed otherwise.
|
|
68
|
-
* `newsletterFollow` is the one that speaks upstream's shape.
|
|
69
|
-
*/
|
|
70
|
-
newsletterSubscribe: async (jid) => {
|
|
71
|
-
return await (await ctx.getClient()).newsletterSubscribe(jid);
|
|
72
|
-
},
|
|
73
|
-
newsletterUnsubscribe: async (jid) => {
|
|
74
|
-
await (await ctx.getClient()).newsletterUnsubscribe(jid);
|
|
75
|
-
},
|
|
76
|
-
/**
|
|
77
|
-
* The follower-activity mute, which is the one a subscriber toggles. The
|
|
78
|
-
* core's other newsletter mute is for admin activity and is a different
|
|
79
|
-
* control, so the ambiguous alias is avoided here.
|
|
80
|
-
*/
|
|
81
|
-
newsletterMute: async (jid) => {
|
|
82
|
-
await (await ctx.getClient()).newsletterFollowerMute(jid, true);
|
|
83
|
-
},
|
|
84
|
-
newsletterUnmute: async (jid) => {
|
|
85
|
-
await (await ctx.getClient()).newsletterFollowerMute(jid, false);
|
|
86
|
-
},
|
|
87
|
-
newsletterSubscribers: async (jid) => {
|
|
88
|
-
const metadata = await (await ctx.getClient()).newsletterMetadata(jid);
|
|
89
|
-
return { subscribers: metadata.subscriberCount };
|
|
90
|
-
},
|
|
91
|
-
newsletterReactMessage: async (jid, serverId, reaction) => {
|
|
92
|
-
await (await ctx.getClient()).newsletterReactMessage(jid, serverId, reaction ?? null);
|
|
93
|
-
},
|
|
94
|
-
/**
|
|
95
|
-
* `since` and `after` have no equivalent: the core's query pages backward
|
|
96
|
-
* from a `before` cursor and carries no time filter. Mapping `after` onto
|
|
97
|
-
* `before` would page the opposite direction and return a plausible wrong
|
|
98
|
-
* answer, so a caller asking for either is told instead.
|
|
99
|
-
*
|
|
100
|
-
* Zero is not asking. `since: 0` is the epoch and `after: 0` is no cursor,
|
|
101
|
-
* which is what the unfiltered query already does, so the common
|
|
102
|
-
* `(jid, count, 0, 0)` call runs rather than being refused for nothing.
|
|
103
|
-
*/
|
|
104
|
-
newsletterFetchMessages: async (jid, count, since, after) => {
|
|
105
|
-
if (since) {
|
|
106
|
-
throw new Boom('newsletterFetchMessages: `since` is not supported, the message query carries no time filter', {
|
|
107
|
-
statusCode: 400
|
|
7
|
+
export const makeNewsletterMethods = (ctx) => {
|
|
8
|
+
return {
|
|
9
|
+
newsletterCreate: async (name, description) => {
|
|
10
|
+
return bridgeNewsletterMetadataToBaileys(await ctx.withClient(client => client.newsletterCreate(name, description ?? null)));
|
|
11
|
+
},
|
|
12
|
+
/**
|
|
13
|
+
* `type` selects which lookup runs: the bridge has a method per key kind
|
|
14
|
+
* rather than one that inspects the key. Resolves to null when the
|
|
15
|
+
* newsletter does not exist, matching upstream.
|
|
16
|
+
*/
|
|
17
|
+
newsletterMetadata: async (type, key) => {
|
|
18
|
+
assertArgumentDomain('newsletterMetadata', 'type', type, NEWSLETTER_KEY_TYPES);
|
|
19
|
+
return ctx.withClient(async (client) => {
|
|
20
|
+
const result = type === 'invite' ? await client.newsletterMetadataByInvite(key) : await client.newsletterMetadata(key);
|
|
21
|
+
return result ? bridgeNewsletterMetadataToBaileys(result) : null;
|
|
108
22
|
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
23
|
+
},
|
|
24
|
+
/**
|
|
25
|
+
* `picture` is base64 of an already-generated image, and the empty string
|
|
26
|
+
* means remove, as upstream builds it. The core splits those into two
|
|
27
|
+
* methods, so the field is dispatched rather than forwarded.
|
|
28
|
+
*/
|
|
29
|
+
newsletterUpdate: async (jid, updates) => {
|
|
30
|
+
return ctx.withClient(async (client) => {
|
|
31
|
+
let result;
|
|
32
|
+
if (updates.name !== undefined || updates.description !== undefined) {
|
|
33
|
+
result = await client.newsletterUpdate(jid, updates.name ?? null, updates.description ?? null);
|
|
34
|
+
}
|
|
35
|
+
if (updates.picture === '') {
|
|
36
|
+
result = await client.newsletterRemovePicture(jid);
|
|
37
|
+
}
|
|
38
|
+
else if (updates.picture !== undefined) {
|
|
39
|
+
result = await client.newsletterSetPicture(jid, new Uint8Array(Buffer.from(updates.picture, 'base64')));
|
|
40
|
+
}
|
|
41
|
+
// Only when the delta asked for nothing: every write above already
|
|
42
|
+
// answers with the refreshed metadata, so reading it would be a round
|
|
43
|
+
// trip whose result is thrown away.
|
|
44
|
+
return bridgeNewsletterMetadataToBaileys(result ?? (await client.newsletterMetadata(jid)));
|
|
129
45
|
});
|
|
46
|
+
},
|
|
47
|
+
newsletterUpdateName: async (jid, name) => {
|
|
48
|
+
return bridgeNewsletterMetadataToBaileys(await ctx.withClient(client => client.newsletterUpdate(jid, name, null)));
|
|
49
|
+
},
|
|
50
|
+
newsletterUpdateDescription: async (jid, description) => {
|
|
51
|
+
return bridgeNewsletterMetadataToBaileys(await ctx.withClient(client => client.newsletterUpdate(jid, null, description)));
|
|
52
|
+
},
|
|
53
|
+
newsletterUpdatePicture: async (jid, content) => {
|
|
54
|
+
const { img } = await generateProfilePicture(content);
|
|
55
|
+
return bridgeNewsletterMetadataToBaileys(await ctx.withClient(client => client.newsletterSetPicture(jid, img)));
|
|
56
|
+
},
|
|
57
|
+
newsletterRemovePicture: async (jid) => {
|
|
58
|
+
return bridgeNewsletterMetadataToBaileys(await ctx.withClient(client => client.newsletterRemovePicture(jid)));
|
|
59
|
+
},
|
|
60
|
+
newsletterFollow: async (jid) => {
|
|
61
|
+
return bridgeNewsletterMetadataToBaileys(await ctx.withClient(client => client.newsletterSubscribe(jid)));
|
|
62
|
+
},
|
|
63
|
+
newsletterUnfollow: async (jid) => {
|
|
64
|
+
await ctx.withClient(client => client.newsletterUnsubscribe(jid));
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* The names this package used before it grew upstream's. Kept so existing
|
|
68
|
+
* callers do not break on a rename that buys them nothing, and returning
|
|
69
|
+
* the bridge result unmapped for the same reason: a caller reading `jid`
|
|
70
|
+
* or `subscriberCount` off it would find them renamed otherwise.
|
|
71
|
+
* `newsletterFollow` is the one that speaks upstream's shape.
|
|
72
|
+
*/
|
|
73
|
+
newsletterSubscribe: async (jid) => {
|
|
74
|
+
return await ctx.withClient(client => client.newsletterSubscribe(jid));
|
|
75
|
+
},
|
|
76
|
+
newsletterUnsubscribe: async (jid) => {
|
|
77
|
+
await ctx.withClient(client => client.newsletterUnsubscribe(jid));
|
|
78
|
+
},
|
|
79
|
+
/**
|
|
80
|
+
* The follower-activity mute, which is the one a subscriber toggles. The
|
|
81
|
+
* core's other newsletter mute is for admin activity and is a different
|
|
82
|
+
* control, so the ambiguous alias is avoided here.
|
|
83
|
+
*/
|
|
84
|
+
newsletterMute: async (jid) => {
|
|
85
|
+
await ctx.withClient(client => client.newsletterFollowerMute(jid, true));
|
|
86
|
+
},
|
|
87
|
+
newsletterUnmute: async (jid) => {
|
|
88
|
+
await ctx.withClient(client => client.newsletterFollowerMute(jid, false));
|
|
89
|
+
},
|
|
90
|
+
newsletterSubscribers: async (jid) => {
|
|
91
|
+
const metadata = await ctx.withClient(client => client.newsletterMetadata(jid));
|
|
92
|
+
return { subscribers: metadata.subscriberCount };
|
|
93
|
+
},
|
|
94
|
+
newsletterReactMessage: async (jid, serverId, reaction) => {
|
|
95
|
+
await ctx.withClient(client => client.newsletterReactMessage(jid, serverId, reaction ?? null));
|
|
96
|
+
},
|
|
97
|
+
/**
|
|
98
|
+
* `since` and `after` have no equivalent: the core's query pages backward
|
|
99
|
+
* from a `before` cursor and carries no time filter. Mapping `after` onto
|
|
100
|
+
* `before` would page the opposite direction and return a plausible wrong
|
|
101
|
+
* answer, so a caller asking for either is told instead.
|
|
102
|
+
*
|
|
103
|
+
* Zero is not asking. `since: 0` is the epoch and `after: 0` is no cursor,
|
|
104
|
+
* which is what the unfiltered query already does, so the common
|
|
105
|
+
* `(jid, count, 0, 0)` call runs rather than being refused for nothing.
|
|
106
|
+
*/
|
|
107
|
+
newsletterFetchMessages: async (jid, count, since, after) => {
|
|
108
|
+
if (since) {
|
|
109
|
+
throw new Boom('newsletterFetchMessages: `since` is not supported, the message query carries no time filter', {
|
|
110
|
+
statusCode: 400
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (after) {
|
|
114
|
+
throw new Boom('newsletterFetchMessages: `after` is not supported, the message query pages backward from a `before` cursor', { statusCode: 400 });
|
|
115
|
+
}
|
|
116
|
+
return await ctx.withClient(client => client.newsletterMessages(jid, count, null));
|
|
117
|
+
},
|
|
118
|
+
subscribeNewsletterUpdates: async (jid) => {
|
|
119
|
+
const duration = await ctx.withClient(client => client.newsletterSubscribeLiveUpdates(jid));
|
|
120
|
+
return { duration: String(duration) };
|
|
121
|
+
},
|
|
122
|
+
/**
|
|
123
|
+
* The count rides on the admin-info result and the server omits it for an
|
|
124
|
+
* account that may not see it. Absent is reported as absent: `0` here would
|
|
125
|
+
* read as "no admins", which no newsletter can be.
|
|
126
|
+
*/
|
|
127
|
+
newsletterAdminCount: async (jid) => {
|
|
128
|
+
const info = await ctx.withClient(client => client.newsletterAdminInfo(jid));
|
|
129
|
+
if (info.adminCount === undefined) {
|
|
130
|
+
throw new Boom('newsletterAdminCount: the server did not return an admin count for this newsletter', {
|
|
131
|
+
statusCode: 404
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return info.adminCount;
|
|
135
|
+
},
|
|
136
|
+
newsletterChangeOwner: async (jid, newOwnerJid) => {
|
|
137
|
+
await ctx.withClient(client => client.newsletterChangeOwner(jid, newOwnerJid));
|
|
138
|
+
},
|
|
139
|
+
newsletterDemote: async (jid, userJid) => {
|
|
140
|
+
await ctx.withClient(client => client.newsletterDemoteAdmin(jid, userJid));
|
|
141
|
+
},
|
|
142
|
+
newsletterDelete: async (jid) => {
|
|
143
|
+
await ctx.withClient(client => client.newsletterDelete(jid));
|
|
130
144
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
newsletterChangeOwner: async (jid, newOwnerJid) => {
|
|
134
|
-
await (await ctx.getClient()).newsletterChangeOwner(jid, newOwnerJid);
|
|
135
|
-
},
|
|
136
|
-
newsletterDemote: async (jid, userJid) => {
|
|
137
|
-
await (await ctx.getClient()).newsletterDemoteAdmin(jid, userJid);
|
|
138
|
-
},
|
|
139
|
-
newsletterDelete: async (jid) => {
|
|
140
|
-
await (await ctx.getClient()).newsletterDelete(jid);
|
|
141
|
-
}
|
|
142
|
-
});
|
|
145
|
+
};
|
|
146
|
+
};
|
|
143
147
|
//# sourceMappingURL=newsletter.js.map
|
package/lib/Socket/prekeys.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SocketContext } from './types.js';
|
|
2
|
-
type PreKeyContext = Pick<SocketContext, '
|
|
2
|
+
type PreKeyContext = Pick<SocketContext, 'logger' | 'withClient'>;
|
|
3
3
|
export declare const makePreKeyMethods: (ctx: PreKeyContext) => {
|
|
4
4
|
uploadPreKeys: (count?: number) => Promise<void>;
|
|
5
5
|
uploadPreKeysToServerIfRequired: () => Promise<void>;
|
package/lib/Socket/prekeys.js
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import { MIN_PREKEY_COUNT } from '../Defaults/index.js';
|
|
2
|
-
export const makePreKeyMethods = (ctx) =>
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
export const makePreKeyMethods = (ctx) => {
|
|
3
|
+
return {
|
|
4
|
+
uploadPreKeys: async (count = MIN_PREKEY_COUNT) => {
|
|
5
|
+
await ctx.withClient(client => client.refreshPreKeys(count));
|
|
6
|
+
},
|
|
7
|
+
uploadPreKeysToServerIfRequired: async () => {
|
|
8
|
+
try {
|
|
9
|
+
await ctx.withClient(client => client.ensurePreKeys());
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
ctx.logger.error({ error }, 'Failed to check/upload pre-keys during initialization');
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
digestKeyBundle: async () => {
|
|
16
|
+
await ctx.withClient(client => client.validateKeyBundle());
|
|
17
|
+
},
|
|
18
|
+
rotateSignedPreKey: async () => {
|
|
19
|
+
await ctx.withClient(client => client.rotateSignedKey());
|
|
9
20
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
digestKeyBundle: async () => {
|
|
15
|
-
await (await ctx.getClient()).validateKeyBundle();
|
|
16
|
-
},
|
|
17
|
-
rotateSignedPreKey: async () => {
|
|
18
|
-
await (await ctx.getClient()).rotateSignedKey();
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
+
};
|
|
22
|
+
};
|
|
21
23
|
//# sourceMappingURL=prekeys.js.map
|
package/lib/Socket/presence.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { WA_CHAT_STATES, WA_PRESENCE_STATUSES } from '../Types/index.js';
|
|
2
2
|
import { assertArgumentDomain } from '../Utils/argument-domain.js';
|
|
3
|
-
export const makePresenceMethods = (ctx) =>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
3
|
+
export const makePresenceMethods = (ctx) => {
|
|
4
|
+
return {
|
|
5
|
+
sendPresence: async (status) => {
|
|
6
|
+
assertArgumentDomain('sendPresence', 'status', status, WA_PRESENCE_STATUSES);
|
|
7
|
+
await ctx.withClient(client => client.sendPresence(status));
|
|
8
|
+
},
|
|
9
|
+
presenceSubscribe: async (toJid) => {
|
|
10
|
+
await ctx.withClient(client => client.presenceSubscribe(toJid));
|
|
11
|
+
},
|
|
12
|
+
sendChatState: async (jid, state) => {
|
|
13
|
+
assertArgumentDomain('sendChatState', 'state', state, WA_CHAT_STATES);
|
|
14
|
+
await ctx.withClient(client => client.sendChatState(jid, state));
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
};
|
|
16
18
|
//# sourceMappingURL=presence.js.map
|
package/lib/Socket/privacy.js
CHANGED
|
@@ -6,7 +6,7 @@ export const makePrivacyMethods = (ctx) => {
|
|
|
6
6
|
return {
|
|
7
7
|
fetchPrivacySettings: async (force) => {
|
|
8
8
|
void force;
|
|
9
|
-
return
|
|
9
|
+
return ctx.withClient(client => client.fetchPrivacySettings());
|
|
10
10
|
},
|
|
11
11
|
/**
|
|
12
12
|
* The untyped escape hatch, left open on purpose: the bridge takes both
|
|
@@ -15,39 +15,39 @@ export const makePrivacyMethods = (ctx) => {
|
|
|
15
15
|
* name yet. The wrappers are the checked path.
|
|
16
16
|
*/
|
|
17
17
|
updatePrivacySetting: async (category, value) => {
|
|
18
|
-
await
|
|
18
|
+
await ctx.withClient(client => client.updatePrivacySetting(category, value));
|
|
19
19
|
},
|
|
20
20
|
updateLastSeenPrivacy: async (value) => {
|
|
21
21
|
assertArgumentDomain('updateLastSeenPrivacy', 'value', value, WA_PRIVACY_VALUES);
|
|
22
|
-
await
|
|
22
|
+
await ctx.withClient(client => client.updatePrivacySetting('last', value));
|
|
23
23
|
},
|
|
24
24
|
updateOnlinePrivacy: async (value) => {
|
|
25
25
|
assertArgumentDomain('updateOnlinePrivacy', 'value', value, WA_PRIVACY_ONLINE_VALUES);
|
|
26
|
-
await
|
|
26
|
+
await ctx.withClient(client => client.updatePrivacySetting('online', value));
|
|
27
27
|
},
|
|
28
28
|
updateProfilePicturePrivacy: async (value) => {
|
|
29
29
|
assertArgumentDomain('updateProfilePicturePrivacy', 'value', value, WA_PRIVACY_VALUES);
|
|
30
|
-
await
|
|
30
|
+
await ctx.withClient(client => client.updatePrivacySetting('profile', value));
|
|
31
31
|
},
|
|
32
32
|
updateStatusPrivacy: async (value) => {
|
|
33
33
|
assertArgumentDomain('updateStatusPrivacy', 'value', value, WA_PRIVACY_VALUES);
|
|
34
|
-
await
|
|
34
|
+
await ctx.withClient(client => client.updatePrivacySetting('status', value));
|
|
35
35
|
},
|
|
36
36
|
updateReadReceiptsPrivacy: async (value) => {
|
|
37
37
|
assertArgumentDomain('updateReadReceiptsPrivacy', 'value', value, WA_READ_RECEIPTS_VALUES);
|
|
38
|
-
await
|
|
38
|
+
await ctx.withClient(client => client.updatePrivacySetting('readreceipts', value));
|
|
39
39
|
},
|
|
40
40
|
updateGroupsAddPrivacy: async (value) => {
|
|
41
41
|
assertArgumentDomain('updateGroupsAddPrivacy', 'value', value, WA_PRIVACY_GROUP_ADD_VALUES);
|
|
42
|
-
await
|
|
42
|
+
await ctx.withClient(client => client.updatePrivacySetting('groupadd', value));
|
|
43
43
|
},
|
|
44
44
|
updateCallPrivacy: async (value) => {
|
|
45
45
|
assertArgumentDomain('updateCallPrivacy', 'value', value, WA_PRIVACY_CALL_VALUES);
|
|
46
|
-
await
|
|
46
|
+
await ctx.withClient(client => client.updatePrivacySetting('calladd', value));
|
|
47
47
|
},
|
|
48
48
|
updateMessagesPrivacy: async (value) => {
|
|
49
49
|
assertArgumentDomain('updateMessagesPrivacy', 'value', value, WA_PRIVACY_MESSAGES_VALUES);
|
|
50
|
-
await
|
|
50
|
+
await ctx.withClient(client => client.updatePrivacySetting('messages', value));
|
|
51
51
|
},
|
|
52
52
|
/**
|
|
53
53
|
* Resolves without issuing anything. The engine already issues these
|
package/lib/Socket/profile.js
CHANGED
|
@@ -3,49 +3,51 @@ import { generateProfilePicture } from '../Utils/messages-media.js';
|
|
|
3
3
|
import { isJidGroup } from '../WABinary/index.js';
|
|
4
4
|
export const makeProfileMethods = (ctx) => {
|
|
5
5
|
const setPushName = async (name) => {
|
|
6
|
-
await
|
|
6
|
+
await ctx.withClient(client => client.setPushName(name));
|
|
7
7
|
};
|
|
8
8
|
return {
|
|
9
9
|
requestPairingCode: async (phoneNumber, customPairingCode) => {
|
|
10
|
-
return await
|
|
10
|
+
return await ctx.withClient(client => client.requestPairingCode(phoneNumber, customPairingCode));
|
|
11
11
|
},
|
|
12
12
|
setPushName,
|
|
13
13
|
/** Alias for setPushName (upstream Baileys compat) */
|
|
14
14
|
updateProfileName: setPushName,
|
|
15
15
|
getPushName: async () => {
|
|
16
|
-
return await
|
|
16
|
+
return await ctx.withClient(client => client.getPushName());
|
|
17
17
|
},
|
|
18
18
|
getJid: async () => {
|
|
19
|
-
return await
|
|
19
|
+
return await ctx.withClient(client => client.getJid());
|
|
20
20
|
},
|
|
21
21
|
getLid: async () => {
|
|
22
|
-
return await
|
|
22
|
+
return await ctx.withClient(client => client.getLid());
|
|
23
23
|
},
|
|
24
24
|
updateProfilePicture: async (jid, content, dimensions) => {
|
|
25
25
|
if (!jid) {
|
|
26
26
|
throw new Boom('Illegal no-jid profile update. Please specify either your ID or the ID of the chat you wish to update');
|
|
27
27
|
}
|
|
28
28
|
const { img } = await generateProfilePicture(content, dimensions);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
return ctx.withClient(async (client) => {
|
|
30
|
+
if (isJidGroup(jid)) {
|
|
31
|
+
await client.setGroupProfilePicture(jid, img);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
await client.updateProfilePicture(img);
|
|
35
|
+
});
|
|
35
36
|
},
|
|
36
37
|
removeProfilePicture: async (jid) => {
|
|
37
38
|
if (!jid) {
|
|
38
39
|
throw new Boom('Illegal no-jid profile update. Please specify either your ID or the ID of the chat you wish to update');
|
|
39
40
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
return ctx.withClient(async (client) => {
|
|
42
|
+
if (isJidGroup(jid)) {
|
|
43
|
+
await client.removeGroupProfilePicture(jid);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
await client.removeProfilePicture();
|
|
47
|
+
});
|
|
46
48
|
},
|
|
47
49
|
updateProfileStatus: async (status) => {
|
|
48
|
-
await
|
|
50
|
+
await ctx.withClient(client => client.updateProfileStatus(status));
|
|
49
51
|
}
|
|
50
52
|
};
|
|
51
53
|
};
|
|
@@ -70,7 +70,7 @@ export const makeServerQueryMethods = (ctx) => {
|
|
|
70
70
|
// already hold a connection acquired by an upload, and stamping that
|
|
71
71
|
// one as fetched now would report it fresher than it is.
|
|
72
72
|
const held = fetched;
|
|
73
|
-
const conn = await
|
|
73
|
+
const conn = await ctx.withClient(client => client.getMediaConn(forceGet || !held));
|
|
74
74
|
mediaHost = conn.hosts[0]?.hostname ?? mediaHost;
|
|
75
75
|
const isFetch = forceGet || !held || held.auth !== conn.auth || !isLive(held);
|
|
76
76
|
fetched = isFetch ? { auth: conn.auth, ttl: conn.ttl, at: new Date() } : held;
|
|
@@ -81,10 +81,10 @@ export const makeServerQueryMethods = (ctx) => {
|
|
|
81
81
|
/** Synchronous, as upstream has it, so it reads what the last refresh saw. */
|
|
82
82
|
getMediaHost: () => mediaHost,
|
|
83
83
|
getBotListV2: async () => {
|
|
84
|
-
return flattenBotList(await
|
|
84
|
+
return flattenBotList(await ctx.withClient(client => client.getBotList()));
|
|
85
85
|
},
|
|
86
86
|
fetchNewChatMessageCap: async () => {
|
|
87
|
-
return toCapInfo(await
|
|
87
|
+
return toCapInfo(await ctx.withClient(client => client.fetchNewChatMessageCappingInfo()));
|
|
88
88
|
},
|
|
89
89
|
cleanDirtyBits: async (type, fromTimestamp) => {
|
|
90
90
|
assertArgumentDomain('cleanDirtyBits', 'type', type, DIRTY_BIT_TYPES);
|
|
@@ -99,7 +99,7 @@ export const makeServerQueryMethods = (ctx) => {
|
|
|
99
99
|
throw new Boom(`cleanDirtyBits: fromTimestamp '${fromTimestamp}' is not a number`, { statusCode: 400 });
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
|
-
await
|
|
102
|
+
await ctx.withClient(client => client.cleanDirtyBits(type, timestamp));
|
|
103
103
|
},
|
|
104
104
|
/**
|
|
105
105
|
* Refused rather than wired up. The core already fires a peer data
|
|
@@ -1,39 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Which bridge disconnects end the socket for good.
|
|
3
|
-
*
|
|
4
|
-
* This mirrors one decision that lives in the Rust engine, so keep it honest:
|
|
5
|
-
* `whatsapp-rust` clears `enable_auto_reconnect` and breaks out of its run loop
|
|
6
|
-
* on exactly these, and retries everything else on the WA Web Fibonacci backoff
|
|
7
|
-
* (`client/lifecycle.rs`).
|
|
8
|
-
*
|
|
9
|
-
* The socket layer needs the answer because `WasmWhatsAppClient.run()` returns
|
|
10
|
-
* `void` — it spawns the loop as a background task, so the loop's exit is not
|
|
11
|
-
* observable from JS (`whatsapp_rust_bridge.d.ts`, `run(): void`). Until the
|
|
12
|
-
* bridge exposes loop completion, this table is how the socket knows a client
|
|
13
|
-
* has become dead weight that only `free()` can reclaim.
|
|
14
|
-
*
|
|
15
|
-
* The upstream Baileys contract this buys us: `connection.update { close }`
|
|
16
|
-
* means "this socket is finished, build a new one" — which is what every
|
|
17
|
-
* consumer written against upstream already assumes, because upstream has no
|
|
18
|
-
* auto-reconnect at all. Transient drops therefore never surface as `close`;
|
|
19
|
-
* they surface as `connecting`.
|
|
20
|
-
*
|
|
21
|
-
* Events deliberately absent from the terminal set, and why:
|
|
22
|
-
* - `disconnected` — the engine only dispatches `Event::Disconnected` for an
|
|
23
|
-
* *unexpected* loop exit, and every terminal path sets `expected_disconnect`
|
|
24
|
-
* first, which suppresses it (`client/lifecycle.rs`). So this one is the
|
|
25
|
-
* "engine is retrying" signal — with one exception the dispatcher handles:
|
|
26
|
-
* under `setAutoReconnect(false)` the run loop dispatches `Disconnected`
|
|
27
|
-
* and only *then* tests the flag and breaks out, which makes the very same
|
|
28
|
-
* event terminal. Absence from this list means "not terminal on its own",
|
|
29
|
-
* not "never terminal".
|
|
30
|
-
* - `streamError` — reaches JS only from the engine's catch-all `<stream:error>`
|
|
31
|
-
* branch (unknown code, `<ack/>`, `<xml-not-well-formed>`); the coded ones
|
|
32
|
-
* (401/409/515/516/429/503) dispatch their own events instead. Every case
|
|
33
|
-
* that gets here keeps the connection or recycles it deliberately.
|
|
34
|
-
* - `pairError` — pairing failed, but the engine keeps its loop and re-emits a
|
|
35
|
-
* QR; nothing about the client is dead.
|
|
36
|
-
*/
|
|
37
1
|
/** True when the engine will keep retrying after this `<failure>`. */
|
|
38
2
|
export declare const isReconnectableConnectFailure: (reason: number | undefined) => boolean;
|
|
3
|
+
/** Map a typed bridge connect-failure code to Baileys' close status. */
|
|
4
|
+
export declare const mapConnectFailureToDisconnect: (reason: number | undefined) => number;
|
|
39
5
|
//# sourceMappingURL=terminal-close.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DisconnectReason } from '../Types/index.js';
|
|
1
2
|
/**
|
|
2
3
|
* Which bridge disconnects end the socket for good.
|
|
3
4
|
*
|
|
@@ -6,11 +7,10 @@
|
|
|
6
7
|
* on exactly these, and retries everything else on the WA Web Fibonacci backoff
|
|
7
8
|
* (`client/lifecycle.rs`).
|
|
8
9
|
*
|
|
9
|
-
* The socket layer needs the answer
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* has become dead weight that only `free()` can reclaim.
|
|
10
|
+
* The socket layer needs the answer for bridge events that classify a terminal
|
|
11
|
+
* close before the supervised run completion is observed. Bridge 0.21.0 also
|
|
12
|
+
* exposes `waitForRunCompletion()` for exits with no terminal event; that
|
|
13
|
+
* observer uses the same terminal-close reporter and owner as this table.
|
|
14
14
|
*
|
|
15
15
|
* The upstream Baileys contract this buys us: `connection.update { close }`
|
|
16
16
|
* means "this socket is finished, build a new one" — which is what every
|
|
@@ -48,4 +48,28 @@ const RECONNECTABLE_CONNECT_FAILURE_REASONS = new Set([
|
|
|
48
48
|
]);
|
|
49
49
|
/** True when the engine will keep retrying after this `<failure>`. */
|
|
50
50
|
export const isReconnectableConnectFailure = (reason) => reason !== undefined && RECONNECTABLE_CONNECT_FAILURE_REASONS.has(reason);
|
|
51
|
+
/** Map a typed bridge connect-failure code to Baileys' close status. */
|
|
52
|
+
export const mapConnectFailureToDisconnect = (reason) => {
|
|
53
|
+
switch (reason) {
|
|
54
|
+
case 401:
|
|
55
|
+
case 403:
|
|
56
|
+
case 406:
|
|
57
|
+
return DisconnectReason.loggedOut;
|
|
58
|
+
case 402:
|
|
59
|
+
return DisconnectReason.forbidden;
|
|
60
|
+
case 405:
|
|
61
|
+
return 405;
|
|
62
|
+
case 411:
|
|
63
|
+
return DisconnectReason.multideviceMismatch;
|
|
64
|
+
case 503:
|
|
65
|
+
case 501:
|
|
66
|
+
return DisconnectReason.unavailableService;
|
|
67
|
+
case 408:
|
|
68
|
+
return DisconnectReason.timedOut;
|
|
69
|
+
case 515:
|
|
70
|
+
return DisconnectReason.restartRequired;
|
|
71
|
+
default:
|
|
72
|
+
return DisconnectReason.connectionClosed;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
51
75
|
//# sourceMappingURL=terminal-close.js.map
|
package/lib/Socket/types.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { EventEmitter } from 'events';
|
|
2
|
-
import type { WasmWhatsAppClient } from '@oxidezap/whatsapp-rust-bridge';
|
|
3
2
|
import type { Contact, SocketConfig } from '../Types/index.js';
|
|
4
3
|
import type { makeEventBuffer } from '../Utils/event-buffer.js';
|
|
5
4
|
import type { ILogger } from '../Utils/logger.js';
|
|
5
|
+
import type { ClientOperations } from './client-operations.js';
|
|
6
6
|
/** Shared context passed to all Socket method factories */
|
|
7
|
-
export interface SocketContext {
|
|
7
|
+
export interface SocketContext extends ClientOperations {
|
|
8
8
|
ev: ReturnType<typeof makeEventBuffer>;
|
|
9
9
|
logger: ILogger;
|
|
10
10
|
fullConfig: SocketConfig;
|
|
@@ -17,10 +17,6 @@ export interface SocketContext {
|
|
|
17
17
|
id?: string;
|
|
18
18
|
lid?: string;
|
|
19
19
|
}) => void;
|
|
20
|
-
/** Returns the bridge client, awaiting initialization if needed */
|
|
21
|
-
getClient: () => Promise<WasmWhatsAppClient>;
|
|
22
|
-
/** Returns the bridge client synchronously, throws if not yet initialized */
|
|
23
|
-
getClientSync: () => WasmWhatsAppClient;
|
|
24
20
|
/** Raw stanza EventEmitter for CB: pattern compat */
|
|
25
21
|
ws: EventEmitter;
|
|
26
22
|
/**
|