@lucid-agents/taskmarket 0.6.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/daemon.js +258 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/xmtp.js +321 -0
- package/dist/commands/xmtp.js.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/api.js +5 -2
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/keystore.js.map +1 -1
- package/dist/lib/signer.js +7 -6
- package/dist/lib/signer.js.map +1 -1
- package/dist/lib/xmtp-client.js +620 -0
- package/dist/lib/xmtp-client.js.map +1 -0
- package/dist/lib/xmtp-envelope.js +26 -0
- package/dist/lib/xmtp-envelope.js.map +1 -0
- package/dist/lib/xmtp-query.js +36 -0
- package/dist/lib/xmtp-query.js.map +1 -0
- package/dist/lib/xmtp-stream.js +71 -0
- package/dist/lib/xmtp-stream.js.map +1 -0
- package/package.json +6 -3
package/dist/lib/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,sCAAsC,CAAC;AAEhG,MAAM,CAAC,KAAK,UAAU,MAAM,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,sCAAsC,CAAC;AAEhG,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,IAAY,EACZ,OAA8C;IAE9C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,GAAG,IAAI,EAAE,EAAE;QAC3C,MAAM,EAAE,KAAK;QACb,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,GAAG,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;SAC5B;KACF,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,OAAO,IAAI,YAAY,GAAG,CAAC,MAAM,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAY,EAAE,IAA6B;IACvE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,GAAG,IAAI,EAAE,EAAE;QAC3C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAChC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,YAAY,GAAG,CAAC,MAAM,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/lib/keystore.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keystore.js","sourceRoot":"","sources":["../../src/lib/keystore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACvE,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"keystore.js","sourceRoot":"","sources":["../../src/lib/keystore.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/signer.js
CHANGED
|
@@ -16,19 +16,20 @@ export async function fetchDeviceKey(deviceId, apiToken) {
|
|
|
16
16
|
return data.deviceEncryptionKey;
|
|
17
17
|
}
|
|
18
18
|
export async function signTypedData(typedData, keystore) {
|
|
19
|
-
const
|
|
20
|
-
const privateKey = decryptPrivateKey(dek, keystore.encryptedKey);
|
|
21
|
-
const account = privateKeyToAccount(privateKey);
|
|
19
|
+
const account = await createWalletAccountFromKeystore(keystore);
|
|
22
20
|
const sig = await account.signTypedData(typedData);
|
|
23
21
|
return sig;
|
|
24
22
|
}
|
|
25
23
|
export async function signMessage(message, keystore) {
|
|
26
|
-
const
|
|
27
|
-
const privateKey = decryptPrivateKey(dek, keystore.encryptedKey);
|
|
28
|
-
const account = privateKeyToAccount(privateKey);
|
|
24
|
+
const account = await createWalletAccountFromKeystore(keystore);
|
|
29
25
|
const sig = await account.signMessage({ message });
|
|
30
26
|
return sig;
|
|
31
27
|
}
|
|
28
|
+
export async function createWalletAccountFromKeystore(keystore) {
|
|
29
|
+
const dek = await fetchDeviceKey(keystore.deviceId, keystore.apiToken);
|
|
30
|
+
const privateKey = decryptPrivateKey(dek, keystore.encryptedKey);
|
|
31
|
+
return privateKeyToAccount(privateKey);
|
|
32
|
+
}
|
|
32
33
|
export function createSignFn(keystore) {
|
|
33
34
|
return (typedData) => signTypedData(typedData, keystore);
|
|
34
35
|
}
|
package/dist/lib/signer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signer.js","sourceRoot":"","sources":["../../src/lib/signer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAiB,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AASnC,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,QAAgB;IACrE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,gBAAgB,QAAQ,MAAM,EAAE;QAChE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;KAC7C,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,CAAC,MAAM,MAAM,IAAI,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAoC,CAAC;IACnE,OAAO,IAAI,CAAC,mBAAmB,CAAC;AAClC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAAoB,EAAE,QAAkB;IAC1E,MAAM,
|
|
1
|
+
{"version":3,"file":"signer.js","sourceRoot":"","sources":["../../src/lib/signer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
import os from 'os';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { randomUUID, hkdfSync } from 'crypto';
|
|
4
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
5
|
+
import { decryptPrivateKey } from './keystore.js';
|
|
6
|
+
import { fetchDeviceKey } from './signer.js';
|
|
7
|
+
import { decodeEnvelope, encodeEnvelope } from './xmtp-envelope.js';
|
|
8
|
+
import { XmtpQueryManager } from './xmtp-query.js';
|
|
9
|
+
import { createInMemoryDedupeCache, runStreamWithReconnect, shouldHandleEnvelope, } from './xmtp-stream.js';
|
|
10
|
+
// Module-level singleton bus for the dev/test fallback client.
|
|
11
|
+
// All createDevClient instances in the same process share this bus — intentional
|
|
12
|
+
// for local two-agent testing, but tests must not rely on bus state being clean
|
|
13
|
+
// unless they consume or reset messages from previous operations.
|
|
14
|
+
const devMessageBus = new Map();
|
|
15
|
+
const DEFAULT_SEND_RETRY_ATTEMPTS = 3;
|
|
16
|
+
const DEFAULT_SEND_RETRY_BASE_DELAY_MS = 250;
|
|
17
|
+
const DEFAULT_SEND_RETRY_MAX_DELAY_MS = 30_000;
|
|
18
|
+
export class XmtpTransportError extends Error {
|
|
19
|
+
category;
|
|
20
|
+
retryable;
|
|
21
|
+
originalError;
|
|
22
|
+
constructor(message, category, originalError) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = 'XmtpTransportError';
|
|
25
|
+
this.category = category;
|
|
26
|
+
this.retryable = category === 'retryable';
|
|
27
|
+
this.originalError = originalError;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function defaultXmtpDbDir() {
|
|
31
|
+
return process.env.TASKMARKET_XMTP_DB_DIR ?? path.join(os.homedir(), '.taskmarket', 'xmtp');
|
|
32
|
+
}
|
|
33
|
+
function defaultDbPath(walletAddress) {
|
|
34
|
+
const normalized = walletAddress.toLowerCase();
|
|
35
|
+
return path.join(defaultXmtpDbDir(), `${normalized}.sqlite`);
|
|
36
|
+
}
|
|
37
|
+
async function createDevClient(input) {
|
|
38
|
+
const inboxId = input.existingInboxId ?? `dev-inbox-${input.walletAddress.slice(2, 10).toLowerCase()}`;
|
|
39
|
+
const installationId = input.existingInstallationId ?? randomUUID();
|
|
40
|
+
const dbPath = input.existingDbPath ?? defaultDbPath(input.walletAddress);
|
|
41
|
+
return {
|
|
42
|
+
inboxId,
|
|
43
|
+
installationId,
|
|
44
|
+
dbPath,
|
|
45
|
+
async sendMessage(toInboxId, body) {
|
|
46
|
+
const messages = devMessageBus.get(toInboxId) ?? [];
|
|
47
|
+
messages.push({ toInboxId, body });
|
|
48
|
+
devMessageBus.set(toInboxId, messages);
|
|
49
|
+
},
|
|
50
|
+
async *streamMessages(options) {
|
|
51
|
+
while (!options?.signal?.aborted) {
|
|
52
|
+
const messages = devMessageBus.get(inboxId) ?? [];
|
|
53
|
+
if (messages.length > 0) {
|
|
54
|
+
const next = messages.shift();
|
|
55
|
+
devMessageBus.set(inboxId, messages);
|
|
56
|
+
if (next) {
|
|
57
|
+
yield next.body;
|
|
58
|
+
}
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
async setConsentState(_inboxId, _state) {
|
|
65
|
+
// no-op in dev mode
|
|
66
|
+
},
|
|
67
|
+
async getConsentState(_inboxId) {
|
|
68
|
+
return 'unknown';
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function asObject(value) {
|
|
73
|
+
if (!value || (typeof value !== 'object' && typeof value !== 'function')) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
function extractString(value, keys) {
|
|
79
|
+
const objectValue = asObject(value);
|
|
80
|
+
if (!objectValue) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
for (const key of keys) {
|
|
84
|
+
const candidate = objectValue[key];
|
|
85
|
+
if (typeof candidate === 'string' && candidate.length > 0) {
|
|
86
|
+
return candidate;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
function readNumber(value, keys) {
|
|
92
|
+
const objectValue = asObject(value);
|
|
93
|
+
if (!objectValue) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
for (const key of keys) {
|
|
97
|
+
const candidate = objectValue[key];
|
|
98
|
+
if (typeof candidate === 'number' && Number.isFinite(candidate)) {
|
|
99
|
+
return candidate;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
function readMessageText(message) {
|
|
105
|
+
if (typeof message === 'string') {
|
|
106
|
+
return message;
|
|
107
|
+
}
|
|
108
|
+
const objectValue = asObject(message);
|
|
109
|
+
if (!objectValue) {
|
|
110
|
+
throw new XmtpTransportError('XMTP message payload is not a string and cannot be decoded', 'non-retryable', message);
|
|
111
|
+
}
|
|
112
|
+
for (const key of ['body', 'content', 'message']) {
|
|
113
|
+
const candidate = objectValue[key];
|
|
114
|
+
if (typeof candidate === 'string') {
|
|
115
|
+
return candidate;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
for (const key of ['body', 'content']) {
|
|
119
|
+
const candidate = objectValue[key];
|
|
120
|
+
if (candidate instanceof Uint8Array) {
|
|
121
|
+
return Buffer.from(candidate).toString('utf8');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
throw new XmtpTransportError('XMTP message payload does not expose a readable body/content field', 'non-retryable', message);
|
|
125
|
+
}
|
|
126
|
+
function classifyTransportError(error) {
|
|
127
|
+
const objectValue = asObject(error);
|
|
128
|
+
const status = readNumber(error, ['status', 'statusCode']) ??
|
|
129
|
+
(typeof objectValue?.responseStatus === 'number' ? objectValue.responseStatus : undefined);
|
|
130
|
+
const code = extractString(error, ['code', 'errorCode'])?.toLowerCase();
|
|
131
|
+
const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
|
|
132
|
+
if (message.includes('timed out') && message.includes('query')) {
|
|
133
|
+
return 'timeout';
|
|
134
|
+
}
|
|
135
|
+
if (status === 429 ||
|
|
136
|
+
(typeof status === 'number' && status >= 500) ||
|
|
137
|
+
code === 'etimedout' ||
|
|
138
|
+
code === 'econnreset' ||
|
|
139
|
+
code === 'eai_again' ||
|
|
140
|
+
code === 'rate_limit_exceeded' ||
|
|
141
|
+
code === 'rate_limited' ||
|
|
142
|
+
message.includes('rate limit') ||
|
|
143
|
+
message.includes('temporarily unavailable') ||
|
|
144
|
+
message.includes('connection reset') ||
|
|
145
|
+
message.includes('network error') ||
|
|
146
|
+
message.includes('transient')) {
|
|
147
|
+
return 'retryable';
|
|
148
|
+
}
|
|
149
|
+
return 'non-retryable';
|
|
150
|
+
}
|
|
151
|
+
function toTransportError(error, fallbackMessage) {
|
|
152
|
+
if (error instanceof XmtpTransportError) {
|
|
153
|
+
return error;
|
|
154
|
+
}
|
|
155
|
+
const category = classifyTransportError(error);
|
|
156
|
+
const message = error instanceof Error && error.message.length > 0
|
|
157
|
+
? error.message
|
|
158
|
+
: `${fallbackMessage} (${String(error)})`;
|
|
159
|
+
return new XmtpTransportError(message, category, error);
|
|
160
|
+
}
|
|
161
|
+
function sleep(ms) {
|
|
162
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
163
|
+
}
|
|
164
|
+
function parseRetryAttempts() {
|
|
165
|
+
const raw = process.env.TASKMARKET_XMTP_SEND_MAX_ATTEMPTS;
|
|
166
|
+
if (!raw) {
|
|
167
|
+
return DEFAULT_SEND_RETRY_ATTEMPTS;
|
|
168
|
+
}
|
|
169
|
+
const parsed = Number(raw);
|
|
170
|
+
if (!Number.isFinite(parsed) || parsed < 1) {
|
|
171
|
+
return DEFAULT_SEND_RETRY_ATTEMPTS;
|
|
172
|
+
}
|
|
173
|
+
return Math.floor(parsed);
|
|
174
|
+
}
|
|
175
|
+
function sendBackoffMs(attempt) {
|
|
176
|
+
const base = DEFAULT_SEND_RETRY_BASE_DELAY_MS * 2 ** Math.max(attempt - 1, 0);
|
|
177
|
+
const jitter = Math.floor(Math.random() * DEFAULT_SEND_RETRY_BASE_DELAY_MS);
|
|
178
|
+
return Math.min(DEFAULT_SEND_RETRY_MAX_DELAY_MS, base + jitter);
|
|
179
|
+
}
|
|
180
|
+
async function withRetry(operation, maxAttempts) {
|
|
181
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
182
|
+
try {
|
|
183
|
+
return await operation();
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
const mapped = toTransportError(error, 'XMTP transport operation failed');
|
|
187
|
+
if (!mapped.retryable || attempt >= maxAttempts) {
|
|
188
|
+
throw mapped;
|
|
189
|
+
}
|
|
190
|
+
await sleep(sendBackoffMs(attempt));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
throw new XmtpTransportError('XMTP retry attempts exhausted', 'non-retryable');
|
|
194
|
+
}
|
|
195
|
+
function resolveClientFactory(moduleValue) {
|
|
196
|
+
const moduleObject = asObject(moduleValue);
|
|
197
|
+
if (!moduleObject) {
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
const clientExport = Object.prototype.hasOwnProperty.call(moduleObject, 'Client')
|
|
201
|
+
? moduleObject.Client
|
|
202
|
+
: undefined;
|
|
203
|
+
const clientObject = asObject(clientExport);
|
|
204
|
+
const fromClient = clientObject?.create;
|
|
205
|
+
if (typeof fromClient === 'function') {
|
|
206
|
+
return fromClient;
|
|
207
|
+
}
|
|
208
|
+
const createClient = Object.prototype.hasOwnProperty.call(moduleObject, 'createClient')
|
|
209
|
+
? moduleObject.createClient
|
|
210
|
+
: undefined;
|
|
211
|
+
if (typeof createClient === 'function') {
|
|
212
|
+
return createClient;
|
|
213
|
+
}
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
async function createSdkClient(factory, signer, options) {
|
|
217
|
+
try {
|
|
218
|
+
return await factory(signer, options);
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
throw toTransportError(error, 'Failed to initialize XMTP SDK client');
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function deriveXmtpDbKey(dekHex) {
|
|
225
|
+
const ikm = Buffer.from(dekHex, 'hex');
|
|
226
|
+
const derived = hkdfSync('sha256', ikm, '', 'taskmarket-xmtp-db', 32);
|
|
227
|
+
return new Uint8Array(derived);
|
|
228
|
+
}
|
|
229
|
+
async function sendViaConversation(client, toInboxId, body) {
|
|
230
|
+
const conversations = asObject(client.conversations);
|
|
231
|
+
if (!conversations) {
|
|
232
|
+
throw new XmtpTransportError('XMTP SDK client does not expose conversation APIs for outbound messaging', 'non-retryable');
|
|
233
|
+
}
|
|
234
|
+
const conversationFactoryNames = [
|
|
235
|
+
'newConversation',
|
|
236
|
+
'newDm',
|
|
237
|
+
'getConversationByInboxId',
|
|
238
|
+
'getDmByInboxId',
|
|
239
|
+
'findOrCreateConversation',
|
|
240
|
+
'findOrCreateDm',
|
|
241
|
+
];
|
|
242
|
+
let conversation;
|
|
243
|
+
for (const key of conversationFactoryNames) {
|
|
244
|
+
const candidate = conversations[key];
|
|
245
|
+
if (typeof candidate !== 'function') {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
conversation = await candidate.call(conversations, toInboxId);
|
|
249
|
+
if (conversation) {
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
const conversationObject = asObject(conversation);
|
|
254
|
+
if (!conversationObject) {
|
|
255
|
+
throw new XmtpTransportError(`XMTP conversation for inbox ${toInboxId} could not be created`, 'non-retryable');
|
|
256
|
+
}
|
|
257
|
+
for (const key of ['send', 'publishMessage']) {
|
|
258
|
+
const send = conversationObject[key];
|
|
259
|
+
if (typeof send === 'function') {
|
|
260
|
+
await send.call(conversationObject, body);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
throw new XmtpTransportError('XMTP conversation object does not expose a send method', 'non-retryable');
|
|
265
|
+
}
|
|
266
|
+
async function sendWithSdkClient(client, toInboxId, body) {
|
|
267
|
+
const clientObject = asObject(client);
|
|
268
|
+
if (!clientObject) {
|
|
269
|
+
throw new XmtpTransportError('XMTP SDK client handle is invalid', 'non-retryable', client);
|
|
270
|
+
}
|
|
271
|
+
const directSendNames = ['sendMessage', 'publishMessage'];
|
|
272
|
+
for (const key of directSendNames) {
|
|
273
|
+
const send = clientObject[key];
|
|
274
|
+
if (typeof send === 'function') {
|
|
275
|
+
await send.call(clientObject, toInboxId, body);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
await sendViaConversation(clientObject, toInboxId, body);
|
|
280
|
+
}
|
|
281
|
+
async function* iterateCatchUpMessages(client) {
|
|
282
|
+
const clientObject = asObject(client);
|
|
283
|
+
if (!clientObject) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
// XMTP SDK v2: sync via conversations API
|
|
287
|
+
const conversations = asObject(clientObject.conversations);
|
|
288
|
+
if (conversations) {
|
|
289
|
+
// Sync all conversations and their messages from the network
|
|
290
|
+
for (const syncKey of ['syncAll', 'sync']) {
|
|
291
|
+
const syncMethod = conversations[syncKey];
|
|
292
|
+
if (typeof syncMethod === 'function') {
|
|
293
|
+
await syncMethod.call(conversations).catch(() => undefined);
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
// List all conversations
|
|
298
|
+
let conversationList = null;
|
|
299
|
+
for (const listKey of ['list', 'listDms', 'getAll']) {
|
|
300
|
+
const listMethod = conversations[listKey];
|
|
301
|
+
if (typeof listMethod !== 'function')
|
|
302
|
+
continue;
|
|
303
|
+
const result = await listMethod.call(conversations).catch(() => null);
|
|
304
|
+
if (Array.isArray(result)) {
|
|
305
|
+
conversationList = result;
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (conversationList && conversationList.length > 0) {
|
|
310
|
+
for (const convo of conversationList) {
|
|
311
|
+
const convoObject = asObject(convo);
|
|
312
|
+
if (!convoObject)
|
|
313
|
+
continue;
|
|
314
|
+
// Sync this conversation to fetch its messages
|
|
315
|
+
const convoSync = convoObject['sync'];
|
|
316
|
+
if (typeof convoSync === 'function') {
|
|
317
|
+
await convoSync.call(convoObject).catch(() => undefined);
|
|
318
|
+
}
|
|
319
|
+
// Get historical messages
|
|
320
|
+
for (const msgKey of ['messages', 'getMessages', 'listMessages']) {
|
|
321
|
+
const msgMethod = convoObject[msgKey];
|
|
322
|
+
if (typeof msgMethod !== 'function')
|
|
323
|
+
continue;
|
|
324
|
+
const msgs = await msgMethod.call(convoObject).catch(() => null);
|
|
325
|
+
if (!msgs)
|
|
326
|
+
break;
|
|
327
|
+
if (typeof msgs[Symbol.asyncIterator] === 'function') {
|
|
328
|
+
for await (const msg of msgs) {
|
|
329
|
+
try {
|
|
330
|
+
yield readMessageText(msg);
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
// Skip non-text messages (system messages, reactions, etc.)
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
else if (typeof msgs[Symbol.iterator] === 'function') {
|
|
338
|
+
for (const msg of msgs) {
|
|
339
|
+
try {
|
|
340
|
+
yield readMessageText(msg);
|
|
341
|
+
}
|
|
342
|
+
catch {
|
|
343
|
+
// Skip non-text messages
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// Legacy fallback: direct client methods
|
|
354
|
+
const legacyMethodNames = ['syncAllMessages', 'listMessages'];
|
|
355
|
+
for (const key of legacyMethodNames) {
|
|
356
|
+
const method = clientObject[key];
|
|
357
|
+
if (typeof method !== 'function') {
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
const result = await method.call(clientObject);
|
|
361
|
+
if (!result) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
if (typeof result[Symbol.asyncIterator] === 'function') {
|
|
365
|
+
for await (const message of result) {
|
|
366
|
+
yield readMessageText(message);
|
|
367
|
+
}
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
if (typeof result[Symbol.iterator] === 'function') {
|
|
371
|
+
for (const message of result) {
|
|
372
|
+
yield readMessageText(message);
|
|
373
|
+
}
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
yield readMessageText(result);
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
async function* iterateRealtimeMessages(client, options) {
|
|
381
|
+
const clientObject = asObject(client);
|
|
382
|
+
if (!clientObject) {
|
|
383
|
+
throw new XmtpTransportError('XMTP SDK client handle is invalid', 'non-retryable', client);
|
|
384
|
+
}
|
|
385
|
+
const streamMethodNames = ['streamAllMessages', 'streamMessages'];
|
|
386
|
+
for (const key of streamMethodNames) {
|
|
387
|
+
const method = clientObject[key];
|
|
388
|
+
if (typeof method !== 'function') {
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
const stream = await method.call(clientObject, options);
|
|
392
|
+
if (typeof stream?.[Symbol.asyncIterator] === 'function') {
|
|
393
|
+
for await (const message of stream) {
|
|
394
|
+
if (options?.signal?.aborted) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
yield readMessageText(message);
|
|
398
|
+
}
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
const conversations = asObject(clientObject.conversations);
|
|
403
|
+
if (conversations) {
|
|
404
|
+
const method = conversations.streamAllMessages;
|
|
405
|
+
if (typeof method === 'function') {
|
|
406
|
+
const stream = await method.call(conversations, options);
|
|
407
|
+
if (typeof stream?.[Symbol.asyncIterator] === 'function') {
|
|
408
|
+
for await (const message of stream) {
|
|
409
|
+
if (options?.signal?.aborted) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
yield readMessageText(message);
|
|
413
|
+
}
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
throw new XmtpTransportError('XMTP SDK client does not expose a compatible message stream API', 'non-retryable');
|
|
419
|
+
}
|
|
420
|
+
async function createProductionClient(input) {
|
|
421
|
+
let sdkModule;
|
|
422
|
+
try {
|
|
423
|
+
sdkModule = await import('@xmtp/node-sdk');
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
throw new XmtpTransportError('XMTP production mode requires @xmtp/node-sdk dependency to be installed', 'non-retryable', error);
|
|
427
|
+
}
|
|
428
|
+
const clientFactory = resolveClientFactory(sdkModule);
|
|
429
|
+
if (!clientFactory) {
|
|
430
|
+
throw new XmtpTransportError('XMTP production mode SDK does not expose a compatible client factory', 'non-retryable');
|
|
431
|
+
}
|
|
432
|
+
let signer;
|
|
433
|
+
let dbEncryptionKey;
|
|
434
|
+
if (input.runtimeSigner) {
|
|
435
|
+
const account = input.runtimeSigner;
|
|
436
|
+
signer = {
|
|
437
|
+
type: 'EOA',
|
|
438
|
+
getIdentifier: () => ({ identifier: account.address.toLowerCase(), identifierKind: 0 }),
|
|
439
|
+
signMessage: async (message) => {
|
|
440
|
+
const sig = typeof message === 'string'
|
|
441
|
+
? await account.signMessage({ message })
|
|
442
|
+
: await account.signMessage({ message: { raw: message } });
|
|
443
|
+
return Buffer.from(sig.slice(2), 'hex');
|
|
444
|
+
},
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
else if (input.keystore) {
|
|
448
|
+
const dek = await fetchDeviceKey(input.keystore.deviceId, input.keystore.apiToken);
|
|
449
|
+
const privateKey = decryptPrivateKey(dek, input.keystore.encryptedKey);
|
|
450
|
+
const account = privateKeyToAccount(privateKey);
|
|
451
|
+
signer = {
|
|
452
|
+
type: 'EOA',
|
|
453
|
+
getIdentifier: () => ({ identifier: account.address.toLowerCase(), identifierKind: 0 }),
|
|
454
|
+
signMessage: async (message) => {
|
|
455
|
+
const sig = typeof message === 'string'
|
|
456
|
+
? await account.signMessage({ message })
|
|
457
|
+
: await account.signMessage({ message: { raw: message } });
|
|
458
|
+
return Buffer.from(sig.slice(2), 'hex');
|
|
459
|
+
},
|
|
460
|
+
};
|
|
461
|
+
dbEncryptionKey = deriveXmtpDbKey(dek);
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
throw new XmtpTransportError('XMTP production mode requires keystore-backed signer material', 'non-retryable');
|
|
465
|
+
}
|
|
466
|
+
const dbPath = input.existingDbPath ?? defaultDbPath(input.walletAddress);
|
|
467
|
+
const client = await createSdkClient(clientFactory, signer, {
|
|
468
|
+
env: 'production',
|
|
469
|
+
dbPath,
|
|
470
|
+
dbEncryptionKey,
|
|
471
|
+
inboxId: input.existingInboxId,
|
|
472
|
+
installationId: input.existingInstallationId,
|
|
473
|
+
});
|
|
474
|
+
const inboxId = extractString(client, ['inboxId', 'inboxID']) ??
|
|
475
|
+
extractString(asObject(client)?.inboxState, ['inboxId']) ??
|
|
476
|
+
input.existingInboxId;
|
|
477
|
+
if (!inboxId) {
|
|
478
|
+
throw new XmtpTransportError('XMTP SDK client did not return an inboxId in production mode', 'non-retryable');
|
|
479
|
+
}
|
|
480
|
+
const installationId = extractString(client, ['installationId', 'installationID']) ??
|
|
481
|
+
extractString(asObject(client)?.installation, ['id', 'installationId']) ??
|
|
482
|
+
input.existingInstallationId ??
|
|
483
|
+
randomUUID();
|
|
484
|
+
return {
|
|
485
|
+
inboxId,
|
|
486
|
+
installationId,
|
|
487
|
+
dbPath,
|
|
488
|
+
async sendMessage(toInboxId, body) {
|
|
489
|
+
await withRetry(() => sendWithSdkClient(client, toInboxId, body), parseRetryAttempts());
|
|
490
|
+
},
|
|
491
|
+
async *streamMessages(options) {
|
|
492
|
+
for await (const message of iterateCatchUpMessages(client)) {
|
|
493
|
+
if (options?.signal?.aborted) {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
yield message;
|
|
497
|
+
}
|
|
498
|
+
for await (const message of iterateRealtimeMessages(client, options)) {
|
|
499
|
+
if (options?.signal?.aborted) {
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
yield message;
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
async setConsentState(targetInboxId, state) {
|
|
506
|
+
const clientObject = asObject(client);
|
|
507
|
+
if (!clientObject)
|
|
508
|
+
return;
|
|
509
|
+
const sdkModule = asObject(await import('@xmtp/node-sdk').catch(() => null));
|
|
510
|
+
const ConsentEntityType = asObject(sdkModule?.['ConsentEntityType']);
|
|
511
|
+
const ConsentState = asObject(sdkModule?.['ConsentState']);
|
|
512
|
+
const entityType = ConsentEntityType?.['InboxId'] ?? 1;
|
|
513
|
+
const consentStateValue = state === 'allowed' ? (ConsentState?.['Allowed'] ?? 1) : (ConsentState?.['Denied'] ?? 2);
|
|
514
|
+
// Both setConsentStates and getConsentState live on client.preferences
|
|
515
|
+
const preferences = asObject(clientObject['preferences']);
|
|
516
|
+
if (preferences && typeof preferences['setConsentStates'] === 'function') {
|
|
517
|
+
await preferences['setConsentStates'].call(preferences, [
|
|
518
|
+
{ entityType, entity: targetInboxId, state: consentStateValue },
|
|
519
|
+
]).catch(() => undefined);
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
async getConsentState(targetInboxId) {
|
|
523
|
+
const clientObject = asObject(client);
|
|
524
|
+
if (!clientObject)
|
|
525
|
+
return 'unknown';
|
|
526
|
+
const sdkModule = asObject(await import('@xmtp/node-sdk').catch(() => null));
|
|
527
|
+
const ConsentEntityType = asObject(sdkModule?.['ConsentEntityType']);
|
|
528
|
+
const ConsentState = asObject(sdkModule?.['ConsentState']);
|
|
529
|
+
const entityType = ConsentEntityType?.['InboxId'] ?? 1;
|
|
530
|
+
const preferences = asObject(clientObject['preferences']);
|
|
531
|
+
if (preferences && typeof preferences['getConsentState'] === 'function') {
|
|
532
|
+
const raw = await preferences['getConsentState'].call(preferences, entityType, targetInboxId).catch(() => null);
|
|
533
|
+
const numericState = typeof raw === 'number' ? raw : readNumber(asObject(raw) ?? {}, ['value', 'state']);
|
|
534
|
+
if (numericState === (ConsentState?.['Allowed'] ?? 1))
|
|
535
|
+
return 'allowed';
|
|
536
|
+
if (numericState === (ConsentState?.['Denied'] ?? 2))
|
|
537
|
+
return 'denied';
|
|
538
|
+
}
|
|
539
|
+
return 'unknown';
|
|
540
|
+
},
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
export async function createXmtpClient(input) {
|
|
544
|
+
if (process.env.TASKMARKET_XMTP_ENV === 'production') {
|
|
545
|
+
return createProductionClient(input);
|
|
546
|
+
}
|
|
547
|
+
return createDevClient(input);
|
|
548
|
+
}
|
|
549
|
+
export async function sendMessageEnvelope(client, toInboxId, envelope) {
|
|
550
|
+
try {
|
|
551
|
+
await client.sendMessage(toInboxId, encodeEnvelope(envelope));
|
|
552
|
+
}
|
|
553
|
+
catch (error) {
|
|
554
|
+
throw toTransportError(error, 'XMTP send failed');
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
export async function runQueryWithClient(options) {
|
|
558
|
+
const abortController = new AbortController();
|
|
559
|
+
const manager = new XmtpQueryManager();
|
|
560
|
+
const pending = manager.waitForResponse(options.envelope.requestId, options.timeoutMs);
|
|
561
|
+
let streamError;
|
|
562
|
+
await sendMessageEnvelope(options.client, options.toInboxId, options.envelope);
|
|
563
|
+
const consumeResponses = (async () => {
|
|
564
|
+
try {
|
|
565
|
+
for await (const raw of options.client.streamMessages({ signal: abortController.signal })) {
|
|
566
|
+
let envelope;
|
|
567
|
+
try {
|
|
568
|
+
envelope = decodeEnvelope(raw);
|
|
569
|
+
}
|
|
570
|
+
catch {
|
|
571
|
+
// Malformed message — skip and continue consuming
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
if (manager.resolveResponse(envelope)) {
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
catch (error) {
|
|
580
|
+
streamError = error;
|
|
581
|
+
manager.clear();
|
|
582
|
+
}
|
|
583
|
+
})();
|
|
584
|
+
try {
|
|
585
|
+
return await pending;
|
|
586
|
+
}
|
|
587
|
+
catch (error) {
|
|
588
|
+
if (streamError) {
|
|
589
|
+
throw toTransportError(streamError, 'XMTP query stream failed before response');
|
|
590
|
+
}
|
|
591
|
+
throw new XmtpTransportError(`XMTP query timed out after ${options.timeoutMs}ms`, 'timeout', error);
|
|
592
|
+
}
|
|
593
|
+
finally {
|
|
594
|
+
manager.clear();
|
|
595
|
+
abortController.abort();
|
|
596
|
+
await consumeResponses.catch(() => {
|
|
597
|
+
// Query completion is controlled by pending promise.
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
export async function listenForEnvelopes(options) {
|
|
602
|
+
const dedupeCache = createInMemoryDedupeCache();
|
|
603
|
+
await runStreamWithReconnect({
|
|
604
|
+
streamFactory: async function* () {
|
|
605
|
+
for await (const raw of options.client.streamMessages({ signal: options.signal })) {
|
|
606
|
+
yield decodeEnvelope(raw);
|
|
607
|
+
}
|
|
608
|
+
},
|
|
609
|
+
shouldStop: options.shouldStop,
|
|
610
|
+
onEnvelope: async (envelope) => {
|
|
611
|
+
if (shouldHandleEnvelope(envelope, {
|
|
612
|
+
cache: dedupeCache,
|
|
613
|
+
allowedTypes: options.allowedTypes,
|
|
614
|
+
})) {
|
|
615
|
+
await options.onEnvelope(envelope);
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
//# sourceMappingURL=xmtp-client.js.map
|