@oxidezap/baileyrs 0.0.32 → 0.1.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/README.md +77 -24
- package/lib/Bridge/adapt.d.ts +1 -1
- package/lib/Bridge/history-sync-wire.d.ts +1 -1
- package/lib/Bridge/history-sync-wire.js +2 -2
- package/lib/Bridge/schema.d.ts +1 -1
- package/lib/Bridge/schema.js +10 -10
- package/lib/Bridge/types.d.ts +1 -1
- package/lib/Compatibility/group-metadata.d.ts +1 -1
- package/lib/Compatibility/legacy-store/codecs/basic.js +1 -1
- package/lib/Compatibility/legacy-store/codecs/signal.js +17 -5
- package/lib/Compatibility/legacy-store/device.js +1 -1
- package/lib/Compatibility/legacy-store/multi-file.js +1 -1
- package/lib/Compatibility/legacy-store/native-projection.d.ts +1 -1
- package/lib/Compatibility/legacy-store/types.d.ts +1 -1
- package/lib/Compatibility/media-type.d.ts +1 -1
- package/lib/Compatibility/message-relay.d.ts +1 -1
- package/lib/Compatibility/proto-runtime.js +119 -45
- package/lib/Compatibility/socket-results.d.ts +1 -1
- package/lib/Compatibility/stanza-responses.d.ts +1 -1
- package/lib/Compatibility/usync/adapter.d.ts +1 -1
- package/lib/Compatibility/websocket-client.d.ts +24 -3
- package/lib/Compatibility/websocket-client.js +47 -18
- package/lib/Socket/bridge-client-owner.d.ts +89 -0
- package/lib/Socket/bridge-client-owner.js +135 -0
- package/lib/Socket/communities.d.ts +2 -2
- package/lib/Socket/contacts.d.ts +1 -1
- package/lib/Socket/events.d.ts +32 -1
- package/lib/Socket/events.js +140 -37
- package/lib/Socket/index.d.ts +32 -6
- package/lib/Socket/index.js +433 -132
- package/lib/Socket/messages.d.ts +4 -1
- package/lib/Socket/messages.js +6 -4
- package/lib/Socket/newsletter.d.ts +3 -3
- package/lib/Socket/terminal-close-reporter.d.ts +79 -0
- package/lib/Socket/terminal-close-reporter.js +108 -0
- package/lib/Socket/terminal-close.d.ts +39 -0
- package/lib/Socket/terminal-close.js +51 -0
- package/lib/Socket/transport.d.ts +1 -1
- package/lib/Socket/types.d.ts +1 -1
- package/lib/Types/Auth.d.ts +1 -1
- package/lib/Types/Message.d.ts +1 -1
- package/lib/Types/Socket.d.ts +2 -2
- package/lib/Utils/crypto.d.ts +2 -2
- package/lib/Utils/crypto.js +1 -1
- package/lib/Utils/event-buffer.js +31 -0
- package/lib/Utils/logger.d.ts +2 -2
- package/lib/Utils/logger.js +122 -25
- package/lib/Utils/messages.d.ts +12 -1
- package/lib/Utils/messages.js +39 -15
- package/lib/Utils/process-history-message.js +6 -10
- package/lib/Utils/process-message.js +1 -1
- package/lib/WAProto/runtime.js +5 -2
- package/package.json +3 -3
|
@@ -7,8 +7,13 @@ export const isRawNodeForwardingEnabled = (client) => client.hasRawNodeListeners
|
|
|
7
7
|
export class WebSocketClient extends EventEmitter {
|
|
8
8
|
constructor(url, config, getClient) {
|
|
9
9
|
super();
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* One value rather than a pair of booleans plus a promise that could
|
|
12
|
+
* disagree with them. `closing` carries the in-flight close so a second
|
|
13
|
+
* caller joins it instead of returning while the first `disconnect()` is
|
|
14
|
+
* still running — which is how teardown reached `free()` on a busy client.
|
|
15
|
+
*/
|
|
16
|
+
this.closeState = { phase: 'open' };
|
|
12
17
|
this.listenerMutationDepth = 0;
|
|
13
18
|
this.url = url instanceof URL ? url : new URL(url);
|
|
14
19
|
this.config = config;
|
|
@@ -24,13 +29,13 @@ export class WebSocketClient extends EventEmitter {
|
|
|
24
29
|
return this.getClient()?.isConnected() ?? false;
|
|
25
30
|
}
|
|
26
31
|
get isClosed() {
|
|
27
|
-
return this.closed;
|
|
32
|
+
return this.closeState.phase === 'closed';
|
|
28
33
|
}
|
|
29
34
|
get isClosing() {
|
|
30
|
-
return this.closing;
|
|
35
|
+
return this.closeState.phase === 'closing';
|
|
31
36
|
}
|
|
32
37
|
get isConnecting() {
|
|
33
|
-
return !this.isOpen &&
|
|
38
|
+
return !this.isOpen && this.closeState.phase === 'open';
|
|
34
39
|
}
|
|
35
40
|
get hasRawNodeListeners() {
|
|
36
41
|
return this.eventNames().some(eventName => isRawNodeEventName(eventName));
|
|
@@ -84,20 +89,44 @@ export class WebSocketClient extends EventEmitter {
|
|
|
84
89
|
const client = this.getClient();
|
|
85
90
|
if (!client || client.isConnected())
|
|
86
91
|
return;
|
|
87
|
-
|
|
92
|
+
// A close in flight has already told the client to disconnect, which is
|
|
93
|
+
// exactly what makes `isConnected()` false above. Reopening here would
|
|
94
|
+
// clear the `closing` phase, and the next `close()` would start a second
|
|
95
|
+
// disconnect against the same client while the first is still running.
|
|
96
|
+
if (this.closeState.phase === 'closing')
|
|
97
|
+
return;
|
|
98
|
+
this.closeState = { phase: 'open' };
|
|
88
99
|
void client.connect().catch(error => this.emit('error', error));
|
|
89
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Idempotent, and a second caller joins the first rather than returning
|
|
103
|
+
* while it is still going.
|
|
104
|
+
*
|
|
105
|
+
* The early return used to be bare: `void ws.close(); await sock.end()` saw
|
|
106
|
+
* the flag, returned immediately, and let teardown reach `free()` with the
|
|
107
|
+
* original `disconnect()` still in flight — the wasm heap corruption
|
|
108
|
+
* `bridge-free-safety.test.ts` documents. Awaiting a *second* `disconnect()`
|
|
109
|
+
* does not join the first one.
|
|
110
|
+
*
|
|
111
|
+
* The state is stored before `disconnect()` is called, and the work is
|
|
112
|
+
* deferred by a microtask to make that ordering hold: an inline async body
|
|
113
|
+
* runs eagerly to its first `await`, so `disconnect()` would be invoked
|
|
114
|
+
* while the state still said `open`, and anything it reaches synchronously
|
|
115
|
+
* that calls back into `close()` would issue a second one.
|
|
116
|
+
*/
|
|
90
117
|
async close() {
|
|
91
|
-
if (this.
|
|
92
|
-
return;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
118
|
+
if (this.closeState.phase !== 'open')
|
|
119
|
+
return this.closeState.done;
|
|
120
|
+
const done = Promise.resolve().then(async () => {
|
|
121
|
+
try {
|
|
122
|
+
await this.getClient()?.disconnect();
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
this.closeState = { phase: 'closed', done };
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
this.closeState = { phase: 'closing', done };
|
|
129
|
+
return done;
|
|
101
130
|
}
|
|
102
131
|
send(str, cb) {
|
|
103
132
|
const client = this.getClient();
|
|
@@ -110,9 +139,9 @@ export class WebSocketClient extends EventEmitter {
|
|
|
110
139
|
get readyState() {
|
|
111
140
|
if (this.isOpen)
|
|
112
141
|
return 1;
|
|
113
|
-
if (this.closing)
|
|
142
|
+
if (this.closeState.phase === 'closing')
|
|
114
143
|
return 2;
|
|
115
|
-
if (this.closed)
|
|
144
|
+
if (this.closeState.phase === 'closed')
|
|
116
145
|
return 3;
|
|
117
146
|
return 0;
|
|
118
147
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owns the bridge client's lifetime.
|
|
3
|
+
*
|
|
4
|
+
* The socket's startup is async and its teardown can start at any point during
|
|
5
|
+
* it — a `sock.end()` right after `makeWASocket()`, an `await using` scope
|
|
6
|
+
* exiting, or a terminal disconnect the dispatcher reports while `init()` is
|
|
7
|
+
* still building the client. That window used to be managed by hand across six
|
|
8
|
+
* closure variables and a scattering of `if (ended) return` checks, which is
|
|
9
|
+
* where every teardown bug in this file came from: startup dereferencing a
|
|
10
|
+
* handle teardown had already nulled, a client built after teardown with
|
|
11
|
+
* nobody left to free it, an `end()` that resolved for its second caller while
|
|
12
|
+
* the first was still flushing, and a re-entrant close releasing the same wasm
|
|
13
|
+
* handle twice.
|
|
14
|
+
*
|
|
15
|
+
* All of those are one question — *what phase is this client in?* — so it is
|
|
16
|
+
* one discriminated union rather than a set of booleans that can disagree:
|
|
17
|
+
*
|
|
18
|
+
* ```
|
|
19
|
+
* starting ──adopt()──► running ──close()──► closing ──► closed
|
|
20
|
+
* │ │ ▲
|
|
21
|
+
* └──────close()────────┴──discard()─────────┘
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Two rules make the whole thing safe, and both are properties of the union
|
|
25
|
+
* rather than of any individual method:
|
|
26
|
+
*
|
|
27
|
+
* - **The transition is synchronous and happens first.** `close()` publishes
|
|
28
|
+
* `closing` — carrying the promise callers await — before any teardown work
|
|
29
|
+
* starts, so re-entering it finds an in-flight close instead of starting a
|
|
30
|
+
* second one. That is why the work is deferred by a microtask rather than
|
|
31
|
+
* started inline: an async body would otherwise run eagerly to its first
|
|
32
|
+
* `await`, i.e. before the state was stored.
|
|
33
|
+
* - **`closing` still carries the client.** The socket's transport close
|
|
34
|
+
* reads it back through `peek()` (`ws.close()` is `getClient()?.disconnect()`),
|
|
35
|
+
* so dropping the handle at the start of teardown silently turns that into
|
|
36
|
+
* a no-op and moves the disconnect after the auth-store flush. `isClosing()`
|
|
37
|
+
* — not `peek()` — is the "should I still be doing work" signal.
|
|
38
|
+
*/
|
|
39
|
+
import type { WasmWhatsAppClient } from '@oxidezap/whatsapp-rust-bridge';
|
|
40
|
+
import type { ILogger } from '../Utils/logger.js';
|
|
41
|
+
export interface BridgeClientOwnerOptions {
|
|
42
|
+
logger: ILogger;
|
|
43
|
+
/**
|
|
44
|
+
* The socket's own shutdown work. Receives the adopted client, if there is
|
|
45
|
+
* one, while it is still usable, and the error teardown was started with.
|
|
46
|
+
*
|
|
47
|
+
* Runs once. Throwing propagates to `close()`'s callers; the client is
|
|
48
|
+
* released either way.
|
|
49
|
+
*/
|
|
50
|
+
teardown: (client: WasmWhatsAppClient | undefined, error: Error | undefined) => Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Hand the client back to the bridge. Separate from `teardown` because
|
|
53
|
+
* ordering matters and the two have different failure semantics: this one
|
|
54
|
+
* is best-effort and never throws out.
|
|
55
|
+
*/
|
|
56
|
+
release: (client: WasmWhatsAppClient) => Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
export interface BridgeClientOwner {
|
|
59
|
+
/** The client while `running` or `closing`; undefined before and after. */
|
|
60
|
+
peek: () => WasmWhatsAppClient | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Publish a freshly built client. Returns `false` when teardown has already
|
|
63
|
+
* started — the client is released here and the caller must stop, because
|
|
64
|
+
* nothing else will ever own it.
|
|
65
|
+
*/
|
|
66
|
+
adopt: (client: WasmWhatsAppClient) => boolean;
|
|
67
|
+
/** True from the moment `close()` is called. Startup checks it between awaits. */
|
|
68
|
+
isClosing: () => boolean;
|
|
69
|
+
/** Runs teardown once; later callers await that same run. */
|
|
70
|
+
close: (error: Error | undefined) => Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Drop the client without tearing the socket down — for a startup that
|
|
73
|
+
* failed after adopting, where the client exists but its read loop never
|
|
74
|
+
* started. Joins an in-flight close rather than releasing a client that
|
|
75
|
+
* close already owns.
|
|
76
|
+
*/
|
|
77
|
+
discard: () => Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Resolves once every release this owner started has finished, including
|
|
80
|
+
* the one a refused `adopt()` kicks off. Startup awaits it on the way out
|
|
81
|
+
* so its own promise does not settle with a release still in flight.
|
|
82
|
+
*
|
|
83
|
+
* A release can outlive the set it started in, so this drains rather than
|
|
84
|
+
* awaiting one snapshot.
|
|
85
|
+
*/
|
|
86
|
+
settled: () => Promise<void>;
|
|
87
|
+
}
|
|
88
|
+
export declare const makeBridgeClientOwner: (opts: BridgeClientOwnerOptions) => BridgeClientOwner;
|
|
89
|
+
//# sourceMappingURL=bridge-client-owner.d.ts.map
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owns the bridge client's lifetime.
|
|
3
|
+
*
|
|
4
|
+
* The socket's startup is async and its teardown can start at any point during
|
|
5
|
+
* it — a `sock.end()` right after `makeWASocket()`, an `await using` scope
|
|
6
|
+
* exiting, or a terminal disconnect the dispatcher reports while `init()` is
|
|
7
|
+
* still building the client. That window used to be managed by hand across six
|
|
8
|
+
* closure variables and a scattering of `if (ended) return` checks, which is
|
|
9
|
+
* where every teardown bug in this file came from: startup dereferencing a
|
|
10
|
+
* handle teardown had already nulled, a client built after teardown with
|
|
11
|
+
* nobody left to free it, an `end()` that resolved for its second caller while
|
|
12
|
+
* the first was still flushing, and a re-entrant close releasing the same wasm
|
|
13
|
+
* handle twice.
|
|
14
|
+
*
|
|
15
|
+
* All of those are one question — *what phase is this client in?* — so it is
|
|
16
|
+
* one discriminated union rather than a set of booleans that can disagree:
|
|
17
|
+
*
|
|
18
|
+
* ```
|
|
19
|
+
* starting ──adopt()──► running ──close()──► closing ──► closed
|
|
20
|
+
* │ │ ▲
|
|
21
|
+
* └──────close()────────┴──discard()─────────┘
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Two rules make the whole thing safe, and both are properties of the union
|
|
25
|
+
* rather than of any individual method:
|
|
26
|
+
*
|
|
27
|
+
* - **The transition is synchronous and happens first.** `close()` publishes
|
|
28
|
+
* `closing` — carrying the promise callers await — before any teardown work
|
|
29
|
+
* starts, so re-entering it finds an in-flight close instead of starting a
|
|
30
|
+
* second one. That is why the work is deferred by a microtask rather than
|
|
31
|
+
* started inline: an async body would otherwise run eagerly to its first
|
|
32
|
+
* `await`, i.e. before the state was stored.
|
|
33
|
+
* - **`closing` still carries the client.** The socket's transport close
|
|
34
|
+
* reads it back through `peek()` (`ws.close()` is `getClient()?.disconnect()`),
|
|
35
|
+
* so dropping the handle at the start of teardown silently turns that into
|
|
36
|
+
* a no-op and moves the disconnect after the auth-store flush. `isClosing()`
|
|
37
|
+
* — not `peek()` — is the "should I still be doing work" signal.
|
|
38
|
+
*/
|
|
39
|
+
export const makeBridgeClientOwner = (opts) => {
|
|
40
|
+
const { logger, teardown, release } = opts;
|
|
41
|
+
let state = { phase: 'starting' };
|
|
42
|
+
/** Releases started outside `close()`, so `settled()` can join them. */
|
|
43
|
+
const pendingReleases = new Set();
|
|
44
|
+
const releaseQuietly = async (target) => {
|
|
45
|
+
try {
|
|
46
|
+
await release(target);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
logger.error({ err }, 'failed to release the bridge client');
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
/** `releaseQuietly`, but joinable through `settled()`. */
|
|
53
|
+
const trackRelease = (target) => {
|
|
54
|
+
const running = releaseQuietly(target).finally(() => pendingReleases.delete(running));
|
|
55
|
+
pendingReleases.add(running);
|
|
56
|
+
return running;
|
|
57
|
+
};
|
|
58
|
+
/** Drain releases started outside this close — see `runClose`. */
|
|
59
|
+
const drainReleases = async () => {
|
|
60
|
+
while (pendingReleases.size)
|
|
61
|
+
await Promise.all(pendingReleases);
|
|
62
|
+
};
|
|
63
|
+
const runClose = async (client, error, done) => {
|
|
64
|
+
try {
|
|
65
|
+
await teardown(client, error);
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
state = { phase: 'closed', done };
|
|
69
|
+
if (client)
|
|
70
|
+
await releaseQuietly(client);
|
|
71
|
+
// A `discard()` in flight when this close started put the client
|
|
72
|
+
// back in `starting`, so the capture above found none and teardown
|
|
73
|
+
// ran without it. Its release is still going: joining here keeps
|
|
74
|
+
// `close()` from settling while a client is being disconnected and
|
|
75
|
+
// freed, which is what the caller is told it can rely on.
|
|
76
|
+
await drainReleases();
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
peek: () => (state.phase === 'running' || state.phase === 'closing' ? state.client : undefined),
|
|
81
|
+
adopt: candidate => {
|
|
82
|
+
if (state.phase !== 'starting') {
|
|
83
|
+
// Teardown has already been through here and found nothing, so
|
|
84
|
+
// this client would have no owner: nothing would free it and its
|
|
85
|
+
// read loop would reconnect forever against a disposed socket.
|
|
86
|
+
void trackRelease(candidate);
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
state = { phase: 'running', client: candidate };
|
|
90
|
+
return true;
|
|
91
|
+
},
|
|
92
|
+
isClosing: () => state.phase === 'closing' || state.phase === 'closed',
|
|
93
|
+
close: error => {
|
|
94
|
+
if (state.phase === 'closing' || state.phase === 'closed') {
|
|
95
|
+
logger.trace({ trace: error?.stack }, 'already closing; awaiting the in-flight teardown');
|
|
96
|
+
return state.done;
|
|
97
|
+
}
|
|
98
|
+
const client = state.phase === 'running' ? state.client : undefined;
|
|
99
|
+
// Deferred by a microtask so the `closing` state below is stored
|
|
100
|
+
// before any teardown work runs. Calling `runClose` inline would
|
|
101
|
+
// execute its body eagerly up to the first `await` — teardown starts
|
|
102
|
+
// by closing the transport — and anything reached synchronously that
|
|
103
|
+
// calls back into `close()` would find no in-flight close and start
|
|
104
|
+
// a second teardown, releasing the same wasm handle twice.
|
|
105
|
+
const done = Promise.resolve().then(() => runClose(client, error, done));
|
|
106
|
+
state = { phase: 'closing', client, done };
|
|
107
|
+
return done;
|
|
108
|
+
},
|
|
109
|
+
discard: async () => {
|
|
110
|
+
// `close()` owns the client from the moment it starts, and keeps it
|
|
111
|
+
// published for the whole of teardown — releasing it here as well
|
|
112
|
+
// would be two disconnect/free sequences on one handle. Join instead.
|
|
113
|
+
//
|
|
114
|
+
// Joining without adopting the failure: `close()` rejects when
|
|
115
|
+
// teardown rethrows the first auth-store flush error, and this is
|
|
116
|
+
// best-effort cleanup called from `init()`'s catch. Propagating it
|
|
117
|
+
// would make `initPromise` reject — which the socket documents as
|
|
118
|
+
// impossible, relies on for `getClient()`'s error message, and does
|
|
119
|
+
// not always await, so it could surface as an unhandled rejection.
|
|
120
|
+
if (state.phase === 'closing' || state.phase === 'closed') {
|
|
121
|
+
await state.done.catch(() => { });
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (state.phase !== 'running')
|
|
125
|
+
return;
|
|
126
|
+
const { client } = state;
|
|
127
|
+
// Back to `starting`, not `closed`: a later `close()` must still run
|
|
128
|
+
// teardown for everything the socket owns beyond the client.
|
|
129
|
+
state = { phase: 'starting' };
|
|
130
|
+
await trackRelease(client);
|
|
131
|
+
},
|
|
132
|
+
settled: drainReleases
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
//# sourceMappingURL=bridge-client-owner.js.map
|
|
@@ -20,7 +20,7 @@ export declare const makeCommunityMethods: (ctx: SocketContext, groups?: {
|
|
|
20
20
|
groupRevokeInvite: (jid: string) => Promise<string | undefined>;
|
|
21
21
|
groupAcceptInvite: (code: string) => Promise<string | undefined>;
|
|
22
22
|
groupRevokeInviteV4: (groupJid: string, invitedJid: string) => Promise<boolean>;
|
|
23
|
-
groupAcceptInviteV4: (key: string | import("../index.js").WAMessageKey, inviteMessage: import("whatsapp-rust-bridge/proto-types").proto.Message.IGroupInviteMessage) => Promise<any>;
|
|
23
|
+
groupAcceptInviteV4: (key: string | import("../index.js").WAMessageKey, inviteMessage: import("@oxidezap/whatsapp-rust-bridge/proto-types").proto.Message.IGroupInviteMessage) => Promise<any>;
|
|
24
24
|
groupGetInviteInfo: (code: string) => Promise<GroupMetadata>;
|
|
25
25
|
groupToggleEphemeral: (jid: string, ephemeralExpiration: number) => Promise<void>;
|
|
26
26
|
groupSettingUpdate: (jid: string, setting: "announcement" | "locked" | "not_announcement" | "unlocked") => Promise<void>;
|
|
@@ -49,7 +49,7 @@ export declare const makeCommunityMethods: (ctx: SocketContext, groups?: {
|
|
|
49
49
|
communityRevokeInvite: (jid: string) => Promise<string | undefined>;
|
|
50
50
|
communityAcceptInvite: (code: string) => Promise<string | undefined>;
|
|
51
51
|
communityRevokeInviteV4: (communityJid: string, invitedJid: string) => Promise<boolean>;
|
|
52
|
-
communityAcceptInviteV4: (key: string | import("../index.js").WAMessageKey, inviteMessage: import("whatsapp-rust-bridge/proto-types").proto.Message.IGroupInviteMessage) => Promise<any>;
|
|
52
|
+
communityAcceptInviteV4: (key: string | import("../index.js").WAMessageKey, inviteMessage: import("@oxidezap/whatsapp-rust-bridge/proto-types").proto.Message.IGroupInviteMessage) => Promise<any>;
|
|
53
53
|
communityGetInviteInfo: (code: string) => Promise<GroupMetadata>;
|
|
54
54
|
communityToggleEphemeral: (jid: string, ephemeralExpiration: number) => Promise<void>;
|
|
55
55
|
communitySettingUpdate: (jid: string, setting: "announcement" | "locked" | "not_announcement" | "unlocked") => Promise<void>;
|
package/lib/Socket/contacts.d.ts
CHANGED
|
@@ -12,6 +12,6 @@ export type OnWhatsAppResult = {
|
|
|
12
12
|
export declare const makeContactMethods: (ctx: SocketContext) => {
|
|
13
13
|
onWhatsApp: (...phoneNumber: string[]) => Promise<OnWhatsAppResult[] | undefined>;
|
|
14
14
|
profilePictureUrl: (jid: string, type?: 'preview' | 'image', timeoutMs?: number) => Promise<string | undefined>;
|
|
15
|
-
fetchUserInfo: (...jids: string[]) => Promise<Record<string, import("whatsapp-rust-bridge").UserInfoResult>>;
|
|
15
|
+
fetchUserInfo: (...jids: string[]) => Promise<Record<string, import("@oxidezap/whatsapp-rust-bridge").UserInfoResult>>;
|
|
16
16
|
};
|
|
17
17
|
//# sourceMappingURL=contacts.d.ts.map
|
package/lib/Socket/events.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* mapped type so TS forces a handler per variant — a missing handler
|
|
7
7
|
* is a compile error.
|
|
8
8
|
*/
|
|
9
|
-
import type { WhatsAppEvent, WhatsAppEventCallbacks } from 'whatsapp-rust-bridge';
|
|
9
|
+
import type { WhatsAppEvent, WhatsAppEventCallbacks } from '@oxidezap/whatsapp-rust-bridge';
|
|
10
10
|
import type { CanonicalEvent } from '../Bridge/index.js';
|
|
11
11
|
import type { SocketContext } from './types.js';
|
|
12
12
|
interface EventCallbacks {
|
|
@@ -20,6 +20,37 @@ interface EventCallbacks {
|
|
|
20
20
|
onDirtyState?: (event: Extract<CanonicalEvent, {
|
|
21
21
|
type: 'dirtyState';
|
|
22
22
|
}>) => void;
|
|
23
|
+
/**
|
|
24
|
+
* The engine has stopped reconnecting: this client is dead weight only
|
|
25
|
+
* `free()` can reclaim.
|
|
26
|
+
*
|
|
27
|
+
* Owns publishing the `close` too — `publish()` must be called, and the
|
|
28
|
+
* point of handing it over is that the socket can finish tearing down
|
|
29
|
+
* first. Upstream does the same, emitting its close only after `ws.close()`
|
|
30
|
+
* and the end handlers (`Socket/socket.ts`). A consumer answering `close`
|
|
31
|
+
* with a replacement socket on the same auth folder would otherwise race
|
|
32
|
+
* the old one's store flush and `free()`.
|
|
33
|
+
*/
|
|
34
|
+
onTerminalClose?: (error: Error, publish: () => void) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Hand back a cleanup for anything the dispatcher armed that outlives a
|
|
37
|
+
* single event — today the history-sync pause timer. The socket registers
|
|
38
|
+
* it as an end handler, so a plain `sock.end()` or an `await using` scope
|
|
39
|
+
* exiting cancels it too: only the terminal-close path goes through
|
|
40
|
+
* `emitClose`, and a timer surviving disposal fires
|
|
41
|
+
* `messaging-history.status: paused` from a socket that is already gone.
|
|
42
|
+
*
|
|
43
|
+
* Called once, during `makeEventHandlers`.
|
|
44
|
+
*/
|
|
45
|
+
onCleanup?: (cleanup: () => void) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Whether `sock.setAutoReconnect(true)` is in effect. A plain drop is only
|
|
48
|
+
* transient while the engine still intends to retry: with auto-reconnect
|
|
49
|
+
* off, the run loop dispatches `Disconnected` and then breaks for good
|
|
50
|
+
* (`client/lifecycle.rs` tests the flag *after* the dispatch), so the same
|
|
51
|
+
* event becomes terminal. Absent callback means the default, enabled.
|
|
52
|
+
*/
|
|
53
|
+
isAutoReconnectEnabled?: () => boolean;
|
|
23
54
|
}
|
|
24
55
|
/**
|
|
25
56
|
* Create typed single and batch handlers for the bridge. The bridge only uses
|