nodejs-insta-private-api-mqtt 1.0.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 +1650 -0
- package/dist/constants/constants.js +280 -0
- package/dist/constants/index.js +41 -0
- package/dist/core/client.js +243 -0
- package/dist/core/repository.js +7 -0
- package/dist/core/request.js +212 -0
- package/dist/core/state.js +1456 -0
- package/dist/core/utils.js +786 -0
- package/dist/downloadMedia.js +381 -0
- package/dist/errors/index.d.ts +16 -0
- package/dist/errors/index.js +30 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/fbns/fbns.client.d.ts +32 -0
- package/dist/fbns/fbns.client.events.d.ts +41 -0
- package/dist/fbns/fbns.client.events.js +3 -0
- package/dist/fbns/fbns.client.events.js.map +1 -0
- package/dist/fbns/fbns.client.js +179 -0
- package/dist/fbns/fbns.client.js.map +1 -0
- package/dist/fbns/fbns.device-auth.d.ts +17 -0
- package/dist/fbns/fbns.device-auth.js +54 -0
- package/dist/fbns/fbns.device-auth.js.map +1 -0
- package/dist/fbns/fbns.types.d.ts +83 -0
- package/dist/fbns/fbns.types.js +3 -0
- package/dist/fbns/fbns.types.js.map +1 -0
- package/dist/fbns/fbns.utilities.d.ts +2 -0
- package/dist/fbns/fbns.utilities.js +79 -0
- package/dist/fbns/fbns.utilities.js.map +1 -0
- package/dist/fbns/index.d.ts +4 -0
- package/dist/fbns/index.js +21 -0
- package/dist/fbns/index.js.map +1 -0
- package/dist/index.js +39 -0
- package/dist/mqttot/index.d.ts +4 -0
- package/dist/mqttot/index.js +21 -0
- package/dist/mqttot/index.js.map +1 -0
- package/dist/mqttot/mqttot.client.d.ts +39 -0
- package/dist/mqttot/mqttot.client.js +120 -0
- package/dist/mqttot/mqttot.client.js.map +1 -0
- package/dist/mqttot/mqttot.connect.request.packet.d.ts +7 -0
- package/dist/mqttot/mqttot.connect.request.packet.js +9 -0
- package/dist/mqttot/mqttot.connect.request.packet.js.map +1 -0
- package/dist/mqttot/mqttot.connect.response.packet.d.ts +7 -0
- package/dist/mqttot/mqttot.connect.response.packet.js +24 -0
- package/dist/mqttot/mqttot.connect.response.packet.js.map +1 -0
- package/dist/mqttot/mqttot.connection.d.ts +57 -0
- package/dist/mqttot/mqttot.connection.js +56 -0
- package/dist/mqttot/mqttot.connection.js.map +1 -0
- package/dist/package.json +59 -0
- package/dist/realtime/commands/commands.d.ts +15 -0
- package/dist/realtime/commands/commands.js +21 -0
- package/dist/realtime/commands/commands.js.map +1 -0
- package/dist/realtime/commands/direct.commands.d.ts +75 -0
- package/dist/realtime/commands/direct.commands.js +186 -0
- package/dist/realtime/commands/direct.commands.js.map +1 -0
- package/dist/realtime/commands/enhanced.direct.commands.js +987 -0
- package/dist/realtime/commands/index.d.ts +2 -0
- package/dist/realtime/commands/index.js +19 -0
- package/dist/realtime/commands/index.js.map +1 -0
- package/dist/realtime/delta-sync.manager.js +293 -0
- package/dist/realtime/features/dm-sender.js +88 -0
- package/dist/realtime/features/error-handler.js +73 -0
- package/dist/realtime/features/gap-handler.js +61 -0
- package/dist/realtime/features/presence.manager.js +66 -0
- package/dist/realtime/index.js +30 -0
- package/dist/realtime/messages/app-presence.event.d.ts +9 -0
- package/dist/realtime/messages/app-presence.event.js +3 -0
- package/dist/realtime/messages/app-presence.event.js.map +1 -0
- package/dist/realtime/messages/index.d.ts +3 -0
- package/dist/realtime/messages/index.js +20 -0
- package/dist/realtime/messages/index.js.map +1 -0
- package/dist/realtime/messages/message-sync.message.d.ts +222 -0
- package/dist/realtime/messages/message-sync.message.js +43 -0
- package/dist/realtime/messages/message-sync.message.js.map +1 -0
- package/dist/realtime/messages/realtime-sub.direct.data.d.ts +11 -0
- package/dist/realtime/messages/realtime-sub.direct.data.js +3 -0
- package/dist/realtime/messages/realtime-sub.direct.data.js.map +1 -0
- package/dist/realtime/messages/thread-update.message.d.ts +68 -0
- package/dist/realtime/messages/thread-update.message.js +3 -0
- package/dist/realtime/messages/thread-update.message.js.map +1 -0
- package/dist/realtime/mixins/index.d.ts +3 -0
- package/dist/realtime/mixins/index.js +20 -0
- package/dist/realtime/mixins/index.js.map +1 -0
- package/dist/realtime/mixins/message-sync.mixin.d.ts +8 -0
- package/dist/realtime/mixins/message-sync.mixin.js +381 -0
- package/dist/realtime/mixins/message-sync.mixin.js.map +1 -0
- package/dist/realtime/mixins/mixin.d.ts +19 -0
- package/dist/realtime/mixins/mixin.js +41 -0
- package/dist/realtime/mixins/mixin.js.map +1 -0
- package/dist/realtime/mixins/presence-typing.mixin.js +33 -0
- package/dist/realtime/mixins/realtime-sub.mixin.d.ts +8 -0
- package/dist/realtime/mixins/realtime-sub.mixin.js +55 -0
- package/dist/realtime/mixins/realtime-sub.mixin.js.map +1 -0
- package/dist/realtime/parsers/graphql-parser.js +43 -0
- package/dist/realtime/parsers/graphql.parser.d.ts +15 -0
- package/dist/realtime/parsers/graphql.parser.js +22 -0
- package/dist/realtime/parsers/graphql.parser.js.map +1 -0
- package/dist/realtime/parsers/index.d.ts +6 -0
- package/dist/realtime/parsers/index.js +23 -0
- package/dist/realtime/parsers/index.js.map +1 -0
- package/dist/realtime/parsers/iris-parser.js +43 -0
- package/dist/realtime/parsers/iris.parser.d.ts +17 -0
- package/dist/realtime/parsers/iris.parser.js +10 -0
- package/dist/realtime/parsers/iris.parser.js.map +1 -0
- package/dist/realtime/parsers/json-parser.js +43 -0
- package/dist/realtime/parsers/json.parser.d.ts +6 -0
- package/dist/realtime/parsers/json.parser.js +10 -0
- package/dist/realtime/parsers/json.parser.js.map +1 -0
- package/dist/realtime/parsers/parser.d.ts +9 -0
- package/dist/realtime/parsers/parser.js +3 -0
- package/dist/realtime/parsers/parser.js.map +1 -0
- package/dist/realtime/parsers/region-hint-parser.js +43 -0
- package/dist/realtime/parsers/region-hint.parser.d.ts +12 -0
- package/dist/realtime/parsers/region-hint.parser.js +15 -0
- package/dist/realtime/parsers/region-hint.parser.js.map +1 -0
- package/dist/realtime/parsers/skywalker-parser.js +43 -0
- package/dist/realtime/parsers/skywalker.parser.d.ts +12 -0
- package/dist/realtime/parsers/skywalker.parser.js +15 -0
- package/dist/realtime/parsers/skywalker.parser.js.map +1 -0
- package/dist/realtime/parsers-advanced.js +158 -0
- package/dist/realtime/proto/common.proto +38 -0
- package/dist/realtime/proto/direct.proto +65 -0
- package/dist/realtime/proto/ig-messages.proto +83 -0
- package/dist/realtime/proto/iris.proto +188 -0
- package/dist/realtime/proto-parser.js +195 -0
- package/dist/realtime/protocols/iris.handshake.js +74 -0
- package/dist/realtime/protocols/proto-definitions.js +80 -0
- package/dist/realtime/protocols/skywalker.protocol.js +91 -0
- package/dist/realtime/realtime.client.events.js +3 -0
- package/dist/realtime/realtime.client.js +449 -0
- package/dist/realtime/realtime.service.js +462 -0
- package/dist/realtime/reconnect.manager.js +94 -0
- package/dist/realtime/session.manager.js +121 -0
- package/dist/realtime/subscriptions/graphql.subscription.d.ts +47 -0
- package/dist/realtime/subscriptions/graphql.subscription.js +99 -0
- package/dist/realtime/subscriptions/graphql.subscription.js.map +1 -0
- package/dist/realtime/subscriptions/index.d.ts +2 -0
- package/dist/realtime/subscriptions/index.js +19 -0
- package/dist/realtime/subscriptions/index.js.map +1 -0
- package/dist/realtime/subscriptions/skywalker.subscription.d.ts +4 -0
- package/dist/realtime/subscriptions/skywalker.subscription.js +13 -0
- package/dist/realtime/subscriptions/skywalker.subscription.js.map +1 -0
- package/dist/realtime/topic-map.js +71 -0
- package/dist/realtime/topic.js +80 -0
- package/dist/repositories/account.repository.js +261 -0
- package/dist/repositories/direct-thread.repository.js +247 -0
- package/dist/repositories/direct.repository.js +153 -0
- package/dist/repositories/feed.repository.js +233 -0
- package/dist/repositories/friendship.repository.js +190 -0
- package/dist/repositories/hashtag.repository.js +101 -0
- package/dist/repositories/highlights.repository.js +127 -0
- package/dist/repositories/location.repository.js +84 -0
- package/dist/repositories/media.repository.js +165 -0
- package/dist/repositories/story.repository.js +156 -0
- package/dist/repositories/upload.repository.js +167 -0
- package/dist/repositories/user.repository.js +94 -0
- package/dist/sendmedia/index.js +11 -0
- package/dist/sendmedia/sendFile.js +154 -0
- package/dist/sendmedia/sendPhoto.js +145 -0
- package/dist/sendmedia/uploadPhoto.js +175 -0
- package/dist/sendmedia/uploadfFile.js +264 -0
- package/dist/services/live.service.js +147 -0
- package/dist/services/search.service.js +116 -0
- package/dist/shared/index.js +35 -0
- package/dist/shared/shared.js +86 -0
- package/dist/thrift/index.d.ts +3 -0
- package/dist/thrift/index.js +20 -0
- package/dist/thrift/index.js.map +1 -0
- package/dist/thrift/thrift.d.ts +59 -0
- package/dist/thrift/thrift.js +101 -0
- package/dist/thrift/thrift.js.map +1 -0
- package/dist/thrift/thrift.reading.d.ts +41 -0
- package/dist/thrift/thrift.reading.js +327 -0
- package/dist/thrift/thrift.reading.js.map +1 -0
- package/dist/thrift/thrift.writing.d.ts +44 -0
- package/dist/thrift/thrift.writing.js +342 -0
- package/dist/thrift/thrift.writing.js.map +1 -0
- package/dist/types/index.js +285 -0
- package/dist/useMultiFileAuthState.js +437 -0
- package/dist/utils/helper-1.js +1 -0
- package/dist/utils/helper-10.js +1 -0
- package/dist/utils/helper-11.js +1 -0
- package/dist/utils/helper-12.js +1 -0
- package/dist/utils/helper-13.js +1 -0
- package/dist/utils/helper-14.js +1 -0
- package/dist/utils/helper-15.js +1 -0
- package/dist/utils/helper-16.js +1 -0
- package/dist/utils/helper-17.js +1 -0
- package/dist/utils/helper-18.js +1 -0
- package/dist/utils/helper-19.js +1 -0
- package/dist/utils/helper-2.js +1 -0
- package/dist/utils/helper-20.js +1 -0
- package/dist/utils/helper-21.js +1 -0
- package/dist/utils/helper-22.js +1 -0
- package/dist/utils/helper-23.js +1 -0
- package/dist/utils/helper-24.js +1 -0
- package/dist/utils/helper-25.js +1 -0
- package/dist/utils/helper-26.js +1 -0
- package/dist/utils/helper-27.js +1 -0
- package/dist/utils/helper-28.js +1 -0
- package/dist/utils/helper-29.js +1 -0
- package/dist/utils/helper-3.js +1 -0
- package/dist/utils/helper-30.js +1 -0
- package/dist/utils/helper-4.js +1 -0
- package/dist/utils/helper-5.js +1 -0
- package/dist/utils/helper-6.js +1 -0
- package/dist/utils/helper-7.js +1 -0
- package/dist/utils/helper-8.js +1 -0
- package/dist/utils/helper-9.js +1 -0
- package/dist/utils/index.js +280 -0
- package/examples/listen-to-messages.js +86 -0
- package/package.json +79 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./commands"), exports);
|
|
18
|
+
__exportStar(require("./direct.commands"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/realtime/commands/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAC3B,oDAAkC"}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
const debug = require('debug')('ig:delta');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Delta Sync Manager - Apply real Instagram delta updates to local state
|
|
5
|
+
* Based on MessageSync format from reverse-engineered instagram_mqtt
|
|
6
|
+
*/
|
|
7
|
+
class DeltaSyncManager {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.state = {
|
|
10
|
+
threads: {}, // thread_id → ThreadUpdate
|
|
11
|
+
messages: {}, // item_id → MessageSyncMessage
|
|
12
|
+
typing: {}, // thread_id → TypingIndicator
|
|
13
|
+
presence: {} // user_id → PresenceIndicator
|
|
14
|
+
};
|
|
15
|
+
this.listeners = [];
|
|
16
|
+
this.operations = { add: 0, update: 0, delete: 0 };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Apply delta operations (add/update/delete) to local state
|
|
21
|
+
*/
|
|
22
|
+
applyDelta(delta) {
|
|
23
|
+
if (!delta || !delta.items || delta.items.length === 0) {
|
|
24
|
+
return { applied: 0, errors: [], stats: this.operations };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let applied = 0;
|
|
28
|
+
const errors = [];
|
|
29
|
+
|
|
30
|
+
delta.items.forEach(item => {
|
|
31
|
+
try {
|
|
32
|
+
const result = this.applyItem(item);
|
|
33
|
+
if (result) applied++;
|
|
34
|
+
} catch (e) {
|
|
35
|
+
errors.push({
|
|
36
|
+
itemId: item.id || item.item_id,
|
|
37
|
+
error: e.message,
|
|
38
|
+
operation: item.op || item.type
|
|
39
|
+
});
|
|
40
|
+
debug(`❌ Error applying item:`, e.message);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Notify listeners
|
|
45
|
+
if (applied > 0) {
|
|
46
|
+
this.notifyListeners(delta);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
applied,
|
|
51
|
+
errors,
|
|
52
|
+
total: delta.items.length,
|
|
53
|
+
stats: this.operations
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Apply single item (message, thread, typing, presence)
|
|
59
|
+
*/
|
|
60
|
+
applyItem(item) {
|
|
61
|
+
if (!item) return false;
|
|
62
|
+
|
|
63
|
+
// Get operation type from IrisItem
|
|
64
|
+
const operation = item.op || item.type || 'add'; // add, replace, delete
|
|
65
|
+
|
|
66
|
+
// Extract data from 'data' oneof field
|
|
67
|
+
if (item.data?.message) {
|
|
68
|
+
return this.applyMessage(operation, item.data.message);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (item.data?.thread) {
|
|
72
|
+
return this.applyThread(operation, item.data.thread);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (item.data?.typing) {
|
|
76
|
+
return this.applyTyping(operation, item.data.typing);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (item.data?.presence) {
|
|
80
|
+
return this.applyPresence(operation, item.data.presence);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Fallback for direct objects
|
|
84
|
+
if (item.message) {
|
|
85
|
+
return this.applyMessage(operation, item.message);
|
|
86
|
+
}
|
|
87
|
+
if (item.thread) {
|
|
88
|
+
return this.applyThread(operation, item.thread);
|
|
89
|
+
}
|
|
90
|
+
if (item.typing) {
|
|
91
|
+
return this.applyTyping(operation, item.typing);
|
|
92
|
+
}
|
|
93
|
+
if (item.presence) {
|
|
94
|
+
return this.applyPresence(operation, item.presence);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Apply message delta (real Instagram MessageSyncMessage format)
|
|
102
|
+
*/
|
|
103
|
+
applyMessage(operation, message) {
|
|
104
|
+
const msgId = message.item_id;
|
|
105
|
+
|
|
106
|
+
if (operation === 'delete' || operation === 'deletion') {
|
|
107
|
+
delete this.state.messages[msgId];
|
|
108
|
+
this.operations.delete++;
|
|
109
|
+
debug(`🗑️ Deleted message ${msgId}`);
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (operation === 'replace' || operation === 'update') {
|
|
114
|
+
if (!this.state.messages[msgId]) {
|
|
115
|
+
debug(`⚠️ Message ${msgId} not found for update`);
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
Object.assign(this.state.messages[msgId], message);
|
|
119
|
+
this.operations.update++;
|
|
120
|
+
debug(`✏️ Updated message ${msgId}: "${message.text?.substring(0, 30)}"`);
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// add/default
|
|
125
|
+
this.state.messages[msgId] = message;
|
|
126
|
+
this.operations.add++;
|
|
127
|
+
debug(`➕ Added message ${msgId}: "${message.text?.substring(0, 30) || 'media'}"`);
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Apply thread delta (real Instagram ThreadUpdate format)
|
|
133
|
+
*/
|
|
134
|
+
applyThread(operation, thread) {
|
|
135
|
+
const threadId = thread.thread_id || thread.thread_v2_id;
|
|
136
|
+
|
|
137
|
+
if (operation === 'delete') {
|
|
138
|
+
delete this.state.threads[threadId];
|
|
139
|
+
this.operations.delete++;
|
|
140
|
+
debug(`🗑️ Deleted thread ${threadId}`);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (operation === 'replace' || operation === 'update') {
|
|
145
|
+
if (!this.state.threads[threadId]) {
|
|
146
|
+
// Create new thread on update if doesn't exist
|
|
147
|
+
this.state.threads[threadId] = thread;
|
|
148
|
+
this.operations.add++;
|
|
149
|
+
debug(`➕ Created thread from update: ${thread.thread_title}`);
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
Object.assign(this.state.threads[threadId], thread);
|
|
153
|
+
this.operations.update++;
|
|
154
|
+
debug(`✏️ Updated thread ${threadId}: "${thread.thread_title}"`);
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// add/default
|
|
159
|
+
this.state.threads[threadId] = thread;
|
|
160
|
+
this.operations.add++;
|
|
161
|
+
debug(`➕ Added thread: "${thread.thread_title}" (${thread.user_ids?.length || 1} members)`);
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Apply typing indicator delta
|
|
167
|
+
*/
|
|
168
|
+
applyTyping(operation, typing) {
|
|
169
|
+
const threadId = typing.thread_id;
|
|
170
|
+
|
|
171
|
+
if (operation === 'delete' || typing.state === 'stopped') {
|
|
172
|
+
delete this.state.typing[threadId];
|
|
173
|
+
this.operations.delete++;
|
|
174
|
+
debug(`⌨️ User ${typing.from_user_id} stopped typing in ${threadId}`);
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this.state.typing[threadId] = typing;
|
|
179
|
+
this.operations.add++;
|
|
180
|
+
debug(`⌨️ User ${typing.from_user_id} typing in ${threadId}`);
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Apply presence indicator delta
|
|
186
|
+
*/
|
|
187
|
+
applyPresence(operation, presence) {
|
|
188
|
+
const userId = presence.user_id;
|
|
189
|
+
|
|
190
|
+
if (operation === 'delete' || presence.status === 'inactive') {
|
|
191
|
+
delete this.state.presence[userId];
|
|
192
|
+
this.operations.delete++;
|
|
193
|
+
debug(`🔴 User ${userId} offline`);
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
this.state.presence[userId] = presence;
|
|
198
|
+
this.operations.add++;
|
|
199
|
+
debug(`🟢 User ${userId} ${presence.status}`);
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Subscribe to state changes
|
|
205
|
+
*/
|
|
206
|
+
subscribe(callback) {
|
|
207
|
+
this.listeners.push(callback);
|
|
208
|
+
return () => {
|
|
209
|
+
this.listeners = this.listeners.filter(l => l !== callback);
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Notify listeners of changes
|
|
215
|
+
*/
|
|
216
|
+
notifyListeners(delta) {
|
|
217
|
+
this.listeners.forEach(callback => {
|
|
218
|
+
try {
|
|
219
|
+
callback(delta, this.getState());
|
|
220
|
+
} catch (e) {
|
|
221
|
+
debug('Listener error:', e.message);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Get current synchronized state
|
|
228
|
+
*/
|
|
229
|
+
getState() {
|
|
230
|
+
return {
|
|
231
|
+
threads: JSON.parse(JSON.stringify(this.state.threads)),
|
|
232
|
+
messages: JSON.parse(JSON.stringify(this.state.messages)),
|
|
233
|
+
typing: JSON.parse(JSON.stringify(this.state.typing)),
|
|
234
|
+
presence: JSON.parse(JSON.stringify(this.state.presence))
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Query methods
|
|
240
|
+
*/
|
|
241
|
+
getThread(threadId) {
|
|
242
|
+
return this.state.threads[threadId] || null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
getThreadMessages(threadId) {
|
|
246
|
+
return Object.values(this.state.messages).filter(m => m.thread_id === threadId || m.thread_v2_id === threadId);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
getThreads() {
|
|
250
|
+
return Object.values(this.state.threads);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
getAllMessages() {
|
|
254
|
+
return Object.values(this.state.messages);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
getTypingInThread(threadId) {
|
|
258
|
+
return this.state.typing[threadId] || null;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
getUserPresence(userId) {
|
|
262
|
+
return this.state.presence[userId] || null;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Stats
|
|
267
|
+
*/
|
|
268
|
+
getStats() {
|
|
269
|
+
return {
|
|
270
|
+
threads: Object.keys(this.state.threads).length,
|
|
271
|
+
messages: Object.keys(this.state.messages).length,
|
|
272
|
+
typing: Object.keys(this.state.typing).length,
|
|
273
|
+
presence: Object.keys(this.state.presence).length,
|
|
274
|
+
operations: this.operations
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Clear all state
|
|
280
|
+
*/
|
|
281
|
+
clear() {
|
|
282
|
+
this.state = {
|
|
283
|
+
threads: {},
|
|
284
|
+
messages: {},
|
|
285
|
+
typing: {},
|
|
286
|
+
presence: {}
|
|
287
|
+
};
|
|
288
|
+
this.operations = { add: 0, update: 0, delete: 0 };
|
|
289
|
+
debug('✓ State cleared');
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
module.exports = DeltaSyncManager;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DMSender = void 0;
|
|
4
|
+
const shared_1 = require("../../shared");
|
|
5
|
+
const uuid_1 = require("uuid");
|
|
6
|
+
/**
|
|
7
|
+
* Direct Message Sender via MQTT
|
|
8
|
+
*/
|
|
9
|
+
class DMSender {
|
|
10
|
+
constructor(client) {
|
|
11
|
+
this.dmDebug = (0, shared_1.debugChannel)('realtime', 'dm-sender');
|
|
12
|
+
this.client = client;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Send text message via MQTT
|
|
16
|
+
*/
|
|
17
|
+
async sendTextMessage(threadId, text, clientContext = null) {
|
|
18
|
+
this.dmDebug(`Sending text message to thread ${threadId}: "${text.substring(0, 50)}..."`);
|
|
19
|
+
const command = {
|
|
20
|
+
action: 'send_item',
|
|
21
|
+
thread_id: threadId,
|
|
22
|
+
item_type: 'text',
|
|
23
|
+
text,
|
|
24
|
+
timestamp: Date.now(),
|
|
25
|
+
client_context: clientContext || (0, uuid_1.v4)(),
|
|
26
|
+
};
|
|
27
|
+
try {
|
|
28
|
+
return await this.client.directCommands?.sendCommand({
|
|
29
|
+
action: 'send_item',
|
|
30
|
+
data: command,
|
|
31
|
+
threadId,
|
|
32
|
+
});
|
|
33
|
+
} catch (err) {
|
|
34
|
+
this.dmDebug(`Failed to send message: ${err.message}`);
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Send media message via MQTT (photo/video)
|
|
40
|
+
*/
|
|
41
|
+
async sendMediaMessage(threadId, mediaId, mediaType = 'photo', clientContext = null) {
|
|
42
|
+
this.dmDebug(`Sending ${mediaType} to thread ${threadId}`);
|
|
43
|
+
const command = {
|
|
44
|
+
action: 'send_item',
|
|
45
|
+
thread_id: threadId,
|
|
46
|
+
item_type: mediaType,
|
|
47
|
+
media_id: mediaId,
|
|
48
|
+
timestamp: Date.now(),
|
|
49
|
+
client_context: clientContext || (0, uuid_1.v4)(),
|
|
50
|
+
};
|
|
51
|
+
try {
|
|
52
|
+
return await this.client.directCommands?.sendCommand({
|
|
53
|
+
action: 'send_item',
|
|
54
|
+
data: command,
|
|
55
|
+
threadId,
|
|
56
|
+
});
|
|
57
|
+
} catch (err) {
|
|
58
|
+
this.dmDebug(`Failed to send media: ${err.message}`);
|
|
59
|
+
throw err;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Send link message
|
|
64
|
+
*/
|
|
65
|
+
async sendLinkMessage(threadId, url, title = null, clientContext = null) {
|
|
66
|
+
this.dmDebug(`Sending link to thread ${threadId}: ${url}`);
|
|
67
|
+
const command = {
|
|
68
|
+
action: 'send_item',
|
|
69
|
+
thread_id: threadId,
|
|
70
|
+
item_type: 'link',
|
|
71
|
+
url,
|
|
72
|
+
title: title || url,
|
|
73
|
+
timestamp: Date.now(),
|
|
74
|
+
client_context: clientContext || (0, uuid_1.v4)(),
|
|
75
|
+
};
|
|
76
|
+
try {
|
|
77
|
+
return await this.client.directCommands?.sendCommand({
|
|
78
|
+
action: 'send_item',
|
|
79
|
+
data: command,
|
|
80
|
+
threadId,
|
|
81
|
+
});
|
|
82
|
+
} catch (err) {
|
|
83
|
+
this.dmDebug(`Failed to send link: ${err.message}`);
|
|
84
|
+
throw err;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.DMSender = DMSender;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ErrorHandler = void 0;
|
|
4
|
+
const shared_1 = require("../../shared");
|
|
5
|
+
/**
|
|
6
|
+
* MQTT Error Handler with recovery strategies
|
|
7
|
+
*/
|
|
8
|
+
class ErrorHandler {
|
|
9
|
+
constructor(client) {
|
|
10
|
+
this.errorDebug = (0, shared_1.debugChannel)('realtime', 'errors');
|
|
11
|
+
this.errorCount = 0;
|
|
12
|
+
this.maxRetries = 5;
|
|
13
|
+
this.client = client;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Handle MQTT connection error
|
|
17
|
+
*/
|
|
18
|
+
handleConnectionError(error) {
|
|
19
|
+
this.errorCount++;
|
|
20
|
+
this.errorDebug(`Connection Error (${this.errorCount}/${this.maxRetries}): ${error.message}`);
|
|
21
|
+
|
|
22
|
+
if (this.errorCount >= this.maxRetries) {
|
|
23
|
+
this.client.emit('error', new Error('Max connection retries exceeded'));
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Exponential backoff
|
|
28
|
+
const delay = Math.min(1000 * Math.pow(2, this.errorCount - 1), 30000);
|
|
29
|
+
this.errorDebug(`Retrying in ${delay}ms...`);
|
|
30
|
+
|
|
31
|
+
setTimeout(() => {
|
|
32
|
+
this.client.reconnect();
|
|
33
|
+
}, delay);
|
|
34
|
+
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Handle payload validation error
|
|
39
|
+
*/
|
|
40
|
+
handlePayloadError(error, topic) {
|
|
41
|
+
this.errorDebug(`Payload Error on topic ${topic}: ${error.message}`);
|
|
42
|
+
this.client.emit('warning', {
|
|
43
|
+
type: 'payload_error',
|
|
44
|
+
topic,
|
|
45
|
+
error: error.message,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Handle protocol error
|
|
50
|
+
*/
|
|
51
|
+
handleProtocolError(error) {
|
|
52
|
+
this.errorDebug(`Protocol Error: ${error.message}`);
|
|
53
|
+
this.client.emit('error', new Error(`MQTT Protocol Error: ${error.message}`));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Reset error counter on successful connection
|
|
57
|
+
*/
|
|
58
|
+
resetErrorCounter() {
|
|
59
|
+
this.errorCount = 0;
|
|
60
|
+
this.errorDebug('Error counter reset');
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get error stats
|
|
64
|
+
*/
|
|
65
|
+
getErrorStats() {
|
|
66
|
+
return {
|
|
67
|
+
errorCount: this.errorCount,
|
|
68
|
+
maxRetries: this.maxRetries,
|
|
69
|
+
canRetry: this.errorCount < this.maxRetries,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.ErrorHandler = ErrorHandler;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GapHandler = void 0;
|
|
4
|
+
const shared_1 = require("../../shared");
|
|
5
|
+
/**
|
|
6
|
+
* Gap Handler - Handle message gaps and synchronization
|
|
7
|
+
*/
|
|
8
|
+
class GapHandler {
|
|
9
|
+
constructor(client) {
|
|
10
|
+
this.gapDebug = (0, shared_1.debugChannel)('realtime', 'gap');
|
|
11
|
+
this.threadGaps = new Map();
|
|
12
|
+
this.client = client;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Detect message gap in thread
|
|
16
|
+
*/
|
|
17
|
+
detectGap(threadId, lastMessageId, newMessageId) {
|
|
18
|
+
const lastId = parseInt(lastMessageId, 10);
|
|
19
|
+
const newId = parseInt(newMessageId, 10);
|
|
20
|
+
const gap = Math.abs(newId - lastId) > 1;
|
|
21
|
+
|
|
22
|
+
if (gap) {
|
|
23
|
+
this.gapDebug(`Gap detected in thread ${threadId}: ${lastMessageId} -> ${newMessageId}`);
|
|
24
|
+
this.threadGaps.set(threadId, { from: lastMessageId, to: newMessageId });
|
|
25
|
+
this.client.emit('gap', {
|
|
26
|
+
thread_id: threadId,
|
|
27
|
+
gap_from: lastMessageId,
|
|
28
|
+
gap_to: newMessageId,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return gap;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Handle gap by requesting missing messages
|
|
35
|
+
*/
|
|
36
|
+
async handleGap(threadId, gapFrom, gapTo) {
|
|
37
|
+
this.gapDebug(`Handling gap in ${threadId}: fetching messages ${gapFrom}-${gapTo}`);
|
|
38
|
+
try {
|
|
39
|
+
// Request missing messages from REST API
|
|
40
|
+
const thread = await this.client.ig.direct.getThread(threadId);
|
|
41
|
+
const messages = await thread.getMessages({ limit: 50 });
|
|
42
|
+
|
|
43
|
+
this.client.emit('gap_filled', {
|
|
44
|
+
thread_id: threadId,
|
|
45
|
+
messages_count: messages.length,
|
|
46
|
+
});
|
|
47
|
+
return messages;
|
|
48
|
+
} catch (err) {
|
|
49
|
+
this.gapDebug(`Failed to handle gap: ${err.message}`);
|
|
50
|
+
this.client.emit('error', new Error(`Gap handling failed for thread ${threadId}`));
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Clear gap tracking for thread
|
|
56
|
+
*/
|
|
57
|
+
clearGap(threadId) {
|
|
58
|
+
this.threadGaps.delete(threadId);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.GapHandler = GapHandler;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PresenceManager = void 0;
|
|
4
|
+
const shared_1 = require("../../shared");
|
|
5
|
+
const uuid_1 = require("uuid");
|
|
6
|
+
/**
|
|
7
|
+
* Presence Manager - Handle online/offline status
|
|
8
|
+
*/
|
|
9
|
+
class PresenceManager {
|
|
10
|
+
constructor(client) {
|
|
11
|
+
this.presenceDebug = (0, shared_1.debugChannel)('realtime', 'presence');
|
|
12
|
+
this.userPresence = new Map();
|
|
13
|
+
this.client = client;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Update user presence
|
|
17
|
+
*/
|
|
18
|
+
updatePresence(userId, status, lastActivity = Date.now()) {
|
|
19
|
+
this.presenceDebug(`User ${userId} is ${status}`);
|
|
20
|
+
this.userPresence.set(userId, { status, lastActivity });
|
|
21
|
+
this.client.emit('presence', {
|
|
22
|
+
user_id: userId,
|
|
23
|
+
status,
|
|
24
|
+
last_activity: lastActivity,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get user presence
|
|
29
|
+
*/
|
|
30
|
+
getPresence(userId) {
|
|
31
|
+
return this.userPresence.get(userId) || { status: 'offline', lastActivity: null };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Broadcast user's own presence
|
|
35
|
+
*/
|
|
36
|
+
async broadcastPresence(status = 'online') {
|
|
37
|
+
this.presenceDebug(`Broadcasting presence: ${status}`);
|
|
38
|
+
const payload = {
|
|
39
|
+
action: 'presence_status',
|
|
40
|
+
status,
|
|
41
|
+
timestamp: Date.now(),
|
|
42
|
+
client_context: (0, uuid_1.v4)(),
|
|
43
|
+
};
|
|
44
|
+
return this.client.directCommands?.sendCommand({
|
|
45
|
+
action: 'send_presence',
|
|
46
|
+
data: payload,
|
|
47
|
+
threadId: '',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Handle presence update
|
|
52
|
+
*/
|
|
53
|
+
handlePresenceUpdate(data) {
|
|
54
|
+
try {
|
|
55
|
+
const update = typeof data === 'string' ? JSON.parse(data) : data;
|
|
56
|
+
if (update.user_id && update.status) {
|
|
57
|
+
this.updatePresence(update.user_id, update.status, update.last_activity);
|
|
58
|
+
}
|
|
59
|
+
return update;
|
|
60
|
+
} catch (err) {
|
|
61
|
+
this.presenceDebug(`Failed to parse presence update: ${err.message}`);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.PresenceManager = PresenceManager;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PresenceTypingMixin = exports.EnhancedDirectCommands = exports.GapHandler = exports.ErrorHandler = exports.DMSender = exports.PresenceManager = exports.SkywalkerProtocol = exports.IrisHandshake = exports.RealtimeClient = void 0;
|
|
4
|
+
|
|
5
|
+
const realtime_client_1 = require("./realtime.client");
|
|
6
|
+
Object.defineProperty(exports, "RealtimeClient", { enumerable: true, get: function () { return realtime_client_1.RealtimeClient; } });
|
|
7
|
+
|
|
8
|
+
const iris_handshake_1 = require("./protocols/iris.handshake");
|
|
9
|
+
Object.defineProperty(exports, "IrisHandshake", { enumerable: true, get: function () { return iris_handshake_1.IrisHandshake; } });
|
|
10
|
+
|
|
11
|
+
const skywalker_protocol_1 = require("./protocols/skywalker.protocol");
|
|
12
|
+
Object.defineProperty(exports, "SkywalkerProtocol", { enumerable: true, get: function () { return skywalker_protocol_1.SkywalkerProtocol; } });
|
|
13
|
+
|
|
14
|
+
const presence_manager_1 = require("./features/presence.manager");
|
|
15
|
+
Object.defineProperty(exports, "PresenceManager", { enumerable: true, get: function () { return presence_manager_1.PresenceManager; } });
|
|
16
|
+
|
|
17
|
+
const dm_sender_1 = require("./features/dm-sender");
|
|
18
|
+
Object.defineProperty(exports, "DMSender", { enumerable: true, get: function () { return dm_sender_1.DMSender; } });
|
|
19
|
+
|
|
20
|
+
const error_handler_1 = require("./features/error-handler");
|
|
21
|
+
Object.defineProperty(exports, "ErrorHandler", { enumerable: true, get: function () { return error_handler_1.ErrorHandler; } });
|
|
22
|
+
|
|
23
|
+
const gap_handler_1 = require("./features/gap-handler");
|
|
24
|
+
Object.defineProperty(exports, "GapHandler", { enumerable: true, get: function () { return gap_handler_1.GapHandler; } });
|
|
25
|
+
|
|
26
|
+
const presence_typing_mixin_1 = require("./mixins/presence-typing.mixin");
|
|
27
|
+
Object.defineProperty(exports, "PresenceTypingMixin", { enumerable: true, get: function () { return presence_typing_mixin_1.PresenceTypingMixin; } });
|
|
28
|
+
|
|
29
|
+
const enhanced_direct_commands_1 = require("./commands/enhanced.direct.commands");
|
|
30
|
+
Object.defineProperty(exports, "EnhancedDirectCommands", { enumerable: true, get: function () { return enhanced_direct_commands_1.EnhancedDirectCommands; } });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-presence.event.js","sourceRoot":"","sources":["../../../src/realtime/messages/app-presence.event.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./message-sync.message"), exports);
|
|
18
|
+
__exportStar(require("./realtime-sub.direct.data"), exports);
|
|
19
|
+
__exportStar(require("./app-presence.event"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/realtime/messages/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAuC;AACvC,6DAA2C;AAC3C,uDAAqC"}
|