@awiki/dsh-plugin 0.2.3 → 0.2.5
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 +86 -18
- package/README.zh.md +71 -17
- package/THIRD_PARTY_NOTICES.md +8 -1
- package/cordis.patch.yml +13 -0
- package/lib/client.js +8223 -1939
- package/lib/client.js.map +1 -1
- package/lib/index.js +1487 -60
- package/lib/model-proxy-contract.js +89 -0
- package/lib/model-proxy.js +383 -0
- package/lib/provider.js +2 -1
- package/lib/sdk-adapter-DKgkyApB.mjs +669 -0
- package/lib/typert.host.js +470 -482
- package/lib/typert.remote-client.d.ts +15 -1
- package/lib/typert.remote-client.d.ts.map +1 -1
- package/lib/typert.remote-client.js +469 -103
- package/lib/types/attachment-cache.d.ts +28 -0
- package/lib/types/attachment-cache.d.ts.map +1 -0
- package/lib/types/attachment-cache.js +194 -0
- package/lib/types/attachment-cache.js.map +1 -0
- package/lib/types/client/AwikiMail.d.ts +14 -0
- package/lib/types/client/AwikiMail.d.ts.map +1 -0
- package/lib/types/client/AwikiMail.js +260 -0
- package/lib/types/client/AwikiMail.js.map +1 -0
- package/lib/types/client/AwikiOnboarding.d.ts +22 -0
- package/lib/types/client/AwikiOnboarding.d.ts.map +1 -0
- package/lib/types/client/AwikiOnboarding.js +87 -0
- package/lib/types/client/AwikiOnboarding.js.map +1 -0
- package/lib/types/client/AwikiOverlay.d.ts +15 -0
- package/lib/types/client/AwikiOverlay.d.ts.map +1 -1
- package/lib/types/client/AwikiOverlay.js +251 -20
- package/lib/types/client/AwikiOverlay.js.map +1 -1
- package/lib/types/client/AwikiSettingsSection.d.ts +20 -4
- package/lib/types/client/AwikiSettingsSection.d.ts.map +1 -1
- package/lib/types/client/AwikiSettingsSection.js +279 -23
- package/lib/types/client/AwikiSettingsSection.js.map +1 -1
- package/lib/types/client/RechargeComingSoonDialog.d.ts +11 -0
- package/lib/types/client/RechargeComingSoonDialog.d.ts.map +1 -0
- package/lib/types/client/RechargeComingSoonDialog.js +8 -0
- package/lib/types/client/RechargeComingSoonDialog.js.map +1 -0
- package/lib/types/client/controller.d.ts +82 -4
- package/lib/types/client/controller.d.ts.map +1 -1
- package/lib/types/client/controller.js +517 -74
- package/lib/types/client/controller.js.map +1 -1
- package/lib/types/client/image-cache.d.ts +20 -0
- package/lib/types/client/image-cache.d.ts.map +1 -0
- package/lib/types/client/image-cache.js +177 -0
- package/lib/types/client/image-cache.js.map +1 -0
- package/lib/types/client/index.d.ts +2 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +84 -41
- package/lib/types/client/index.js.map +1 -1
- package/lib/types/client/model-account-settings-availability.d.ts +4 -0
- package/lib/types/client/model-account-settings-availability.d.ts.map +1 -0
- package/lib/types/client/model-account-settings-availability.js +4 -0
- package/lib/types/client/model-account-settings-availability.js.map +1 -0
- package/lib/types/client/model-availability-controller.d.ts +27 -0
- package/lib/types/client/model-availability-controller.d.ts.map +1 -0
- package/lib/types/client/model-availability-controller.js +111 -0
- package/lib/types/client/model-availability-controller.js.map +1 -0
- package/lib/types/client/model-proxy-controller.d.ts +41 -0
- package/lib/types/client/model-proxy-controller.d.ts.map +1 -0
- package/lib/types/client/model-proxy-controller.js +241 -0
- package/lib/types/client/model-proxy-controller.js.map +1 -0
- package/lib/types/client/recharge-availability.d.ts +6 -0
- package/lib/types/client/recharge-availability.d.ts.map +1 -0
- package/lib/types/client/recharge-availability.js +6 -0
- package/lib/types/client/recharge-availability.js.map +1 -0
- package/lib/types/client/settings-locales.d.ts +1 -1
- package/lib/types/client/settings-locales.d.ts.map +1 -1
- package/lib/types/client/settings-locales.js +180 -2
- package/lib/types/client/settings-locales.js.map +1 -1
- package/lib/types/client/slots.d.ts +15 -2
- package/lib/types/client/slots.d.ts.map +1 -1
- package/lib/types/index.d.ts +56 -2
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +462 -31
- package/lib/types/index.js.map +1 -1
- package/lib/types/listener-state.d.ts +23 -0
- package/lib/types/listener-state.d.ts.map +1 -0
- package/lib/types/listener-state.js +124 -0
- package/lib/types/listener-state.js.map +1 -0
- package/lib/types/listener.d.ts +96 -0
- package/lib/types/listener.d.ts.map +1 -0
- package/lib/types/listener.js +575 -0
- package/lib/types/listener.js.map +1 -0
- package/lib/types/mail.d.ts +8 -0
- package/lib/types/mail.d.ts.map +1 -0
- package/lib/types/mail.js +75 -0
- package/lib/types/mail.js.map +1 -0
- package/lib/types/model-proxy-contract.d.ts +61 -0
- package/lib/types/model-proxy-contract.d.ts.map +1 -0
- package/lib/types/model-proxy-contract.js +129 -0
- package/lib/types/model-proxy-contract.js.map +1 -0
- package/lib/types/model-proxy.d.ts +14 -0
- package/lib/types/model-proxy.d.ts.map +1 -0
- package/lib/types/model-proxy.js +371 -0
- package/lib/types/model-proxy.js.map +1 -0
- package/lib/types/provider-api.d.ts +78 -2
- package/lib/types/provider-api.d.ts.map +1 -1
- package/lib/types/provider.d.ts.map +1 -1
- package/lib/types/provider.js +1 -0
- package/lib/types/provider.js.map +1 -1
- package/lib/types/sdk-adapter.d.ts +26 -2
- package/lib/types/sdk-adapter.d.ts.map +1 -1
- package/lib/types/sdk-adapter.js +380 -24
- package/lib/types/sdk-adapter.js.map +1 -1
- package/lib/types/settings-rpc.js +1 -1
- package/lib/types/settings-rpc.js.map +1 -1
- package/lib/types/tools.d.ts +10 -0
- package/lib/types/tools.d.ts.map +1 -1
- package/lib/types/tools.js +98 -0
- package/lib/types/tools.js.map +1 -1
- package/lib/types/types.d.ts +103 -1
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/types.js.map +1 -1
- package/package.json +65 -40
- package/lib/sdk-adapter-DK6RqV-c.mjs +0 -355
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
//#region lib/types/sdk-adapter.js
|
|
2
|
+
/** Rust IM Core adapter that copies native values into Host-owned public DTOs. */
|
|
3
|
+
const GROUP_LOOKUP_LIMIT = 100;
|
|
4
|
+
const MAX_GROUP_LOOKUP_PAGES = 20;
|
|
5
|
+
const RUST_FAILURE_CODES = {
|
|
6
|
+
invalid_input: "invalid-request",
|
|
7
|
+
invalid_state_root: "invalid-request",
|
|
8
|
+
invalid_cursor: "invalid-request",
|
|
9
|
+
identity_required: "not-registered",
|
|
10
|
+
identity_not_found: "not-registered",
|
|
11
|
+
identity_not_ready: "not-registered",
|
|
12
|
+
auth_required: "not-registered",
|
|
13
|
+
invalid_otp: "invalid-otp",
|
|
14
|
+
challenge_expired: "challenge-expired",
|
|
15
|
+
handle_unavailable: "handle-unavailable",
|
|
16
|
+
not_found: "not-found",
|
|
17
|
+
permission_denied: "forbidden",
|
|
18
|
+
auth_revoked: "forbidden",
|
|
19
|
+
conflict: "conflict",
|
|
20
|
+
join_required: "handle-unavailable",
|
|
21
|
+
state_in_use: "conflict",
|
|
22
|
+
rate_limited: "rate-limited",
|
|
23
|
+
timeout: "network",
|
|
24
|
+
transport_unavailable: "network",
|
|
25
|
+
sync_failed: "network",
|
|
26
|
+
session_expired: "network",
|
|
27
|
+
attachment_transfer_network: "network"
|
|
28
|
+
};
|
|
29
|
+
/** Closed provider error consumed by the Host's fixed public failure mapping. */
|
|
30
|
+
var AwikiSdkError = class extends Error {
|
|
31
|
+
code;
|
|
32
|
+
name = "AwikiSdkError";
|
|
33
|
+
constructor(code) {
|
|
34
|
+
super(`AWiki SDK operation failed: ${code}`);
|
|
35
|
+
this.code = code;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
function fail(code = "remote") {
|
|
39
|
+
throw new AwikiSdkError(code);
|
|
40
|
+
}
|
|
41
|
+
function mapError(error, ambiguousSend = false) {
|
|
42
|
+
if (error instanceof AwikiSdkError) throw error;
|
|
43
|
+
let code = "remote";
|
|
44
|
+
try {
|
|
45
|
+
if (typeof error === "object" && error !== null) {
|
|
46
|
+
const value = error;
|
|
47
|
+
if (value.name === "ImCoreNodeError" && typeof value.code === "string") code = ambiguousSend && (value.code === "timeout" || value.code === "transport_unavailable") ? "delivery-unknown" : RUST_FAILURE_CODES[value.code] ?? "remote";
|
|
48
|
+
}
|
|
49
|
+
} catch {}
|
|
50
|
+
fail(code);
|
|
51
|
+
}
|
|
52
|
+
function safeInteger(value, minimum = 0) {
|
|
53
|
+
if (!/^(?:0|[1-9]\d*)$/u.test(value)) fail();
|
|
54
|
+
const parsed = Number(value);
|
|
55
|
+
if (!Number.isSafeInteger(parsed) || parsed < minimum) fail();
|
|
56
|
+
return parsed;
|
|
57
|
+
}
|
|
58
|
+
function timestamp(value) {
|
|
59
|
+
const parsed = Date.parse(value);
|
|
60
|
+
if (!Number.isSafeInteger(parsed)) fail();
|
|
61
|
+
return parsed;
|
|
62
|
+
}
|
|
63
|
+
function required(value) {
|
|
64
|
+
if (value === void 0 || value.trim().length === 0) fail();
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
/** Recover the browser's exact optimistic message identity without widening the Remote schema. */
|
|
68
|
+
function browserMessageId(idempotencyKey) {
|
|
69
|
+
return /^msg-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/u.test(idempotencyKey) ? idempotencyKey : void 0;
|
|
70
|
+
}
|
|
71
|
+
function remoteString(value, maxBytes) {
|
|
72
|
+
if (typeof value !== "string" || value.includes("\0") || Buffer.byteLength(value, "utf8") > maxBytes) fail();
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
function remoteOptionalString(value, maxBytes) {
|
|
76
|
+
return value === void 0 ? void 0 : remoteString(value, maxBytes);
|
|
77
|
+
}
|
|
78
|
+
function mailToken(value, maxCharacters) {
|
|
79
|
+
if (typeof value !== "string" || value.length === 0 || value.trim() !== value || Array.from(value).length > maxCharacters || /[\u0000-\u001f\u007f-\u009f]/u.test(value)) fail();
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
82
|
+
function mailAddress(value) {
|
|
83
|
+
if (typeof value !== "string") fail();
|
|
84
|
+
const length = Array.from(value).length;
|
|
85
|
+
if (length < 3 || length > 320 || !value.includes("@") || /[\s\u0000-\u001f\u007f-\u009f]/u.test(value)) fail();
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
88
|
+
function mailAddresses(value) {
|
|
89
|
+
if (!Array.isArray(value) || value.length > 100) fail();
|
|
90
|
+
return value.map(mailAddress);
|
|
91
|
+
}
|
|
92
|
+
function mailTimestamp(value) {
|
|
93
|
+
if (value === void 0) return void 0;
|
|
94
|
+
const copied = remoteString(value, 64);
|
|
95
|
+
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/u.test(copied) || !Number.isFinite(Date.parse(copied))) fail();
|
|
96
|
+
return copied;
|
|
97
|
+
}
|
|
98
|
+
function uint32(value) {
|
|
99
|
+
if (!Number.isSafeInteger(value) || value < 0 || value > 4294967295) fail();
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
function boolean(value) {
|
|
103
|
+
if (typeof value !== "boolean") fail();
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
function mailSummary(value) {
|
|
107
|
+
const receivedAt = mailTimestamp(value.receivedAt);
|
|
108
|
+
const sentAt = mailTimestamp(value.sentAt);
|
|
109
|
+
const folder = value.folder === void 0 ? void 0 : mailToken(value.folder, 64);
|
|
110
|
+
const preview = remoteOptionalString(value.preview, 4096);
|
|
111
|
+
const attachmentCount = value.attachmentCount === void 0 ? void 0 : uint32(value.attachmentCount);
|
|
112
|
+
return {
|
|
113
|
+
id: mailToken(value.id, 2048),
|
|
114
|
+
...folder === void 0 ? {} : { folder },
|
|
115
|
+
from: mailAddresses(value.from),
|
|
116
|
+
to: mailAddresses(value.to),
|
|
117
|
+
cc: mailAddresses(value.cc),
|
|
118
|
+
subject: remoteString(value.subject, 1024),
|
|
119
|
+
subjectTruncated: boolean(value.subjectTruncated),
|
|
120
|
+
...preview === void 0 ? {} : { preview },
|
|
121
|
+
previewTruncated: boolean(value.previewTruncated),
|
|
122
|
+
...receivedAt === void 0 ? {} : { receivedAt },
|
|
123
|
+
...sentAt === void 0 ? {} : { sentAt },
|
|
124
|
+
unread: boolean(value.unread),
|
|
125
|
+
hasAttachments: boolean(value.hasAttachments),
|
|
126
|
+
...attachmentCount === void 0 ? {} : { attachmentCount }
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function mailAttachment(value) {
|
|
130
|
+
const fileName = remoteOptionalString(value.fileName, 512);
|
|
131
|
+
const contentType = remoteOptionalString(value.contentType, 255);
|
|
132
|
+
const sizeBytes = value.sizeBytes === void 0 ? void 0 : remoteString(value.sizeBytes, 20);
|
|
133
|
+
if (sizeBytes !== void 0 && !/^(?:0|[1-9]\d*)$/u.test(sizeBytes)) fail();
|
|
134
|
+
return {
|
|
135
|
+
index: uint32(value.index),
|
|
136
|
+
...fileName === void 0 ? {} : { fileName },
|
|
137
|
+
...contentType === void 0 ? {} : { contentType },
|
|
138
|
+
...sizeBytes === void 0 ? {} : { sizeBytes }
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function mailAccount(value) {
|
|
142
|
+
const mailboxAddress = value.mailboxAddress === void 0 ? void 0 : mailAddress(value.mailboxAddress);
|
|
143
|
+
const displayName = remoteOptionalString(value.displayName, 512);
|
|
144
|
+
const status = remoteOptionalString(value.status, 128);
|
|
145
|
+
return {
|
|
146
|
+
...mailboxAddress === void 0 ? {} : { mailboxAddress },
|
|
147
|
+
...displayName === void 0 ? {} : { displayName },
|
|
148
|
+
...status === void 0 ? {} : { status }
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function mailInbox(value) {
|
|
152
|
+
if (!Array.isArray(value.items) || value.items.length > 100) fail();
|
|
153
|
+
const hasMore = boolean(value.hasMore);
|
|
154
|
+
const nextOffset = value.nextOffset === void 0 ? void 0 : uint32(value.nextOffset);
|
|
155
|
+
if (hasMore && nextOffset === void 0 || !hasMore && nextOffset !== void 0) fail();
|
|
156
|
+
return {
|
|
157
|
+
items: value.items.map(mailSummary),
|
|
158
|
+
...nextOffset === void 0 ? {} : { nextOffset },
|
|
159
|
+
hasMore
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function mailMessage(value) {
|
|
163
|
+
if (!Array.isArray(value.attachments) || value.attachments.length > 100) fail();
|
|
164
|
+
const bodyText = remoteOptionalString(value.bodyText, 65536);
|
|
165
|
+
return {
|
|
166
|
+
summary: mailSummary(value.summary),
|
|
167
|
+
...bodyText === void 0 ? {} : { bodyText },
|
|
168
|
+
bodyTruncated: boolean(value.bodyTruncated),
|
|
169
|
+
hasHtmlBody: boolean(value.hasHtmlBody),
|
|
170
|
+
attachments: value.attachments.map(mailAttachment)
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function sha256(value) {
|
|
174
|
+
const provided = value.sha256Hex?.toLowerCase();
|
|
175
|
+
if (provided !== void 0 && /^[a-f0-9]{64}$/u.test(provided)) return provided;
|
|
176
|
+
try {
|
|
177
|
+
const bytes = Buffer.from(value.digestB64u, "base64url");
|
|
178
|
+
if (bytes.byteLength === 32 && bytes.toString("base64url") === value.digestB64u) return bytes.toString("hex");
|
|
179
|
+
} catch {}
|
|
180
|
+
fail();
|
|
181
|
+
}
|
|
182
|
+
/** Copy one native identity without retaining provider-owned objects. */
|
|
183
|
+
function identity(value) {
|
|
184
|
+
return {
|
|
185
|
+
handle: required(value.handle),
|
|
186
|
+
did: required(value.did),
|
|
187
|
+
...value.displayName === void 0 ? {} : { displayName: value.displayName },
|
|
188
|
+
registeredAt: safeInteger(value.registeredAtMs)
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/** Copy one native attachment and normalize its decimal/digest encodings. */
|
|
192
|
+
function attachment(value) {
|
|
193
|
+
return {
|
|
194
|
+
id: required(value.id),
|
|
195
|
+
fileName: required(value.fileName),
|
|
196
|
+
mimeType: required(value.mimeType),
|
|
197
|
+
size: safeInteger(value.sizeBytes),
|
|
198
|
+
sha256: sha256(value)
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function preview(value) {
|
|
202
|
+
if (value === void 0) return void 0;
|
|
203
|
+
switch (value.content.kind) {
|
|
204
|
+
case "text": return value.content.text;
|
|
205
|
+
case "attachment": {
|
|
206
|
+
const fileName = value.content.attachment?.fileName;
|
|
207
|
+
return fileName === void 0 ? void 0 : `[附件] ${fileName}`;
|
|
208
|
+
}
|
|
209
|
+
default: return;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/** Provider-only protocol events are not part of the browser's text/attachment history contract. */
|
|
213
|
+
function displayableMessage(value) {
|
|
214
|
+
return value.content.kind === "text" || value.content.kind === "attachment";
|
|
215
|
+
}
|
|
216
|
+
/** Copy one native page and brand its opaque cursor for the Host API. */
|
|
217
|
+
function page(value, copy) {
|
|
218
|
+
return {
|
|
219
|
+
items: value.items.map(copy),
|
|
220
|
+
...value.nextCursor === void 0 ? {} : { nextCursor: String(value.nextCursor) },
|
|
221
|
+
hasMore: value.hasMore
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function httpHeaders(headers) {
|
|
225
|
+
return headers.map((header) => ({
|
|
226
|
+
name: String(header.name),
|
|
227
|
+
value: String(header.value)
|
|
228
|
+
}));
|
|
229
|
+
}
|
|
230
|
+
function externalHttpAttempt(value) {
|
|
231
|
+
return {
|
|
232
|
+
targetUrl: String(value.targetUrl),
|
|
233
|
+
method: String(value.method),
|
|
234
|
+
headerPatch: httpHeaders(value.headerPatch),
|
|
235
|
+
retryCount: value.retryCount,
|
|
236
|
+
async handleResponse(response) {
|
|
237
|
+
try {
|
|
238
|
+
const retry = await value.handleResponse({
|
|
239
|
+
statusCode: response.statusCode,
|
|
240
|
+
headers: response.headers.map((header) => ({
|
|
241
|
+
name: header.name,
|
|
242
|
+
value: header.value
|
|
243
|
+
}))
|
|
244
|
+
});
|
|
245
|
+
return retry === null ? null : externalHttpAttempt(retry);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
mapError(error);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
/** Adapt the Rust Node bridge to the frozen Host provider interface. */
|
|
253
|
+
var RustSdkAdapter = class {
|
|
254
|
+
client;
|
|
255
|
+
attachmentConversations = /* @__PURE__ */ new Map();
|
|
256
|
+
disposal;
|
|
257
|
+
listener;
|
|
258
|
+
constructor(client) {
|
|
259
|
+
this.client = Promise.resolve(client);
|
|
260
|
+
this.listener = {
|
|
261
|
+
syncNow: (reason) => this.listenerSyncNow(reason),
|
|
262
|
+
startRealtime: () => this.listenerStartRealtime(),
|
|
263
|
+
listConversations: (request) => this.listenerConversations(request),
|
|
264
|
+
getHistory: (request) => this.listenerHistory(request),
|
|
265
|
+
markConversationRead: (conversationId) => this.markConversationRead(conversationId),
|
|
266
|
+
sendText: (request) => this.sendText(request)
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
async run(operation, ambiguousSend = false) {
|
|
270
|
+
try {
|
|
271
|
+
return await operation(await this.client);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
mapError(error, ambiguousSend);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
async displayableMessages(client, values) {
|
|
277
|
+
const messages = values.filter(displayableMessage);
|
|
278
|
+
const peers = [...new Set(messages.filter((message) => message.conversationKind === "group" && !message.outgoing && message.senderHandle === void 0 && message.senderDisplayName === void 0).map((message) => message.senderDid))];
|
|
279
|
+
if (peers.length === 0) return [...messages];
|
|
280
|
+
const profiles = await client.hydrateDisplayProfiles({ peers });
|
|
281
|
+
const byDid = /* @__PURE__ */ new Map();
|
|
282
|
+
for (const profile of profiles) if (profile.did !== void 0) byDid.set(profile.did, profile);
|
|
283
|
+
return messages.map((message) => {
|
|
284
|
+
const profile = byDid.get(message.senderDid);
|
|
285
|
+
if (profile === void 0) return message;
|
|
286
|
+
return {
|
|
287
|
+
...message,
|
|
288
|
+
...profile.handle === void 0 ? {} : { senderHandle: profile.handle },
|
|
289
|
+
...profile.displayName === void 0 ? {} : { senderDisplayName: profile.displayName }
|
|
290
|
+
};
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Join the persisted Core peer-profile projection onto direct roster rows.
|
|
295
|
+
* The conversation registry intentionally keeps routing identifiers separate
|
|
296
|
+
* from display metadata, so a bare roster row may otherwise regress to a Handle.
|
|
297
|
+
*/
|
|
298
|
+
async displayableConversations(client, values) {
|
|
299
|
+
const peers = [...new Set(values.filter((conversation) => conversation.kind === "direct" && conversation.peerDid !== void 0).map((conversation) => conversation.peerDid))];
|
|
300
|
+
const profiles = peers.length === 0 ? [] : await client.hydrateDisplayProfiles({ peers });
|
|
301
|
+
const byPeer = /* @__PURE__ */ new Map();
|
|
302
|
+
for (const [index, profile] of profiles.entries()) {
|
|
303
|
+
const requested = peers[index];
|
|
304
|
+
if (requested !== void 0) byPeer.set(requested, profile);
|
|
305
|
+
if (profile.did !== void 0) byPeer.set(profile.did, profile);
|
|
306
|
+
if (profile.handle !== void 0) byPeer.set(profile.handle, profile);
|
|
307
|
+
}
|
|
308
|
+
return values.map((value) => this.conversation(value, value.kind === "direct" ? byPeer.get(value.peerDid ?? "") ?? byPeer.get(value.peerHandle ?? "") : void 0));
|
|
309
|
+
}
|
|
310
|
+
message(value) {
|
|
311
|
+
const sentAt = value.sentAt === void 0 ? fail() : timestamp(value.sentAt);
|
|
312
|
+
const common = {
|
|
313
|
+
id: required(value.id),
|
|
314
|
+
conversationId: required(value.conversationId),
|
|
315
|
+
conversationKind: value.conversationKind,
|
|
316
|
+
senderDid: required(value.senderDid),
|
|
317
|
+
...value.senderHandle === void 0 ? {} : { senderHandle: value.senderHandle },
|
|
318
|
+
...value.senderDisplayName === void 0 ? {} : { senderDisplayName: value.senderDisplayName },
|
|
319
|
+
sentAt,
|
|
320
|
+
outgoing: value.outgoing
|
|
321
|
+
};
|
|
322
|
+
switch (value.content.kind) {
|
|
323
|
+
case "text": return {
|
|
324
|
+
...common,
|
|
325
|
+
content: {
|
|
326
|
+
kind: "text",
|
|
327
|
+
text: required(value.content.text)
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
case "attachment": {
|
|
331
|
+
if (value.content.attachment === void 0) fail();
|
|
332
|
+
const copied = attachment(value.content.attachment);
|
|
333
|
+
this.attachmentConversations.set(`${String(common.id)}\u0000${String(copied.id)}`, String(common.conversationId));
|
|
334
|
+
return {
|
|
335
|
+
...common,
|
|
336
|
+
content: {
|
|
337
|
+
kind: "attachment",
|
|
338
|
+
attachment: copied,
|
|
339
|
+
...value.content.caption === void 0 ? {} : { caption: value.content.caption }
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
default: fail();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
conversation(value, profile) {
|
|
347
|
+
const id = required(value.id);
|
|
348
|
+
const displayName = profile?.displayName?.trim();
|
|
349
|
+
const profileHandle = profile?.handle?.trim();
|
|
350
|
+
const title = displayName === void 0 || displayName.length === 0 ? value.title?.trim() : displayName;
|
|
351
|
+
const lastMessagePreview = preview(value.lastMessage);
|
|
352
|
+
const common = {
|
|
353
|
+
id,
|
|
354
|
+
title: title === void 0 || title.length === 0 ? required(value.kind === "direct" ? value.peerHandle ?? value.peerDid : value.groupDid) : title,
|
|
355
|
+
unreadCount: value.unreadCount,
|
|
356
|
+
...value.lastMessageAt === void 0 ? {} : { lastMessageAt: timestamp(value.lastMessageAt) },
|
|
357
|
+
...lastMessagePreview === void 0 ? {} : { lastMessagePreview }
|
|
358
|
+
};
|
|
359
|
+
if (value.lastMessage !== void 0 && displayableMessage(value.lastMessage)) this.message(value.lastMessage);
|
|
360
|
+
switch (value.kind) {
|
|
361
|
+
case "direct": return {
|
|
362
|
+
kind: "direct",
|
|
363
|
+
...common,
|
|
364
|
+
peerDid: required(profile?.did ?? value.peerDid),
|
|
365
|
+
...profileHandle === void 0 && value.peerHandle === void 0 ? {} : { peerHandle: required(profileHandle ?? value.peerHandle) },
|
|
366
|
+
...displayName === void 0 || displayName.length === 0 ? {} : { displayName }
|
|
367
|
+
};
|
|
368
|
+
case "group": return {
|
|
369
|
+
kind: "group",
|
|
370
|
+
...common,
|
|
371
|
+
groupDid: required(value.groupDid)
|
|
372
|
+
};
|
|
373
|
+
default: fail();
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
createdGroup(value) {
|
|
377
|
+
return {
|
|
378
|
+
kind: "group",
|
|
379
|
+
id: required(value.conversationId),
|
|
380
|
+
groupDid: required(value.did),
|
|
381
|
+
title: required(value.title),
|
|
382
|
+
unreadCount: 0
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
groupMember(value) {
|
|
386
|
+
return {
|
|
387
|
+
did: required(value.did),
|
|
388
|
+
...value.handle === void 0 ? {} : { handle: value.handle }
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
listenerConversation(value) {
|
|
392
|
+
const common = {
|
|
393
|
+
id: required(value.id),
|
|
394
|
+
unreadCount: value.unreadCount,
|
|
395
|
+
...value.lastMessageAt === void 0 ? {} : { lastMessageAt: timestamp(value.lastMessageAt) }
|
|
396
|
+
};
|
|
397
|
+
if (value.kind === "direct") return {
|
|
398
|
+
kind: "direct",
|
|
399
|
+
...common,
|
|
400
|
+
peerDid: required(value.peerDid),
|
|
401
|
+
...value.peerHandle === void 0 ? {} : { peerHandle: value.peerHandle }
|
|
402
|
+
};
|
|
403
|
+
return {
|
|
404
|
+
kind: "group",
|
|
405
|
+
...common
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
listenerMessage(value) {
|
|
409
|
+
const sentAt = value.sentAt === void 0 ? fail() : timestamp(value.sentAt);
|
|
410
|
+
const common = {
|
|
411
|
+
id: required(value.id),
|
|
412
|
+
conversationId: required(value.conversationId),
|
|
413
|
+
conversationKind: value.conversationKind,
|
|
414
|
+
senderDid: required(value.senderDid),
|
|
415
|
+
sentAt,
|
|
416
|
+
outgoing: value.outgoing
|
|
417
|
+
};
|
|
418
|
+
return value.content.kind === "text" && value.content.text !== void 0 ? {
|
|
419
|
+
...common,
|
|
420
|
+
content: {
|
|
421
|
+
kind: "text",
|
|
422
|
+
text: required(value.content.text)
|
|
423
|
+
}
|
|
424
|
+
} : {
|
|
425
|
+
...common,
|
|
426
|
+
content: { kind: "ignored" }
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
listenerSyncNow(reason) {
|
|
430
|
+
return this.run(async (client) => {
|
|
431
|
+
const result = await client.syncNow({ reason });
|
|
432
|
+
if (result.status === "idle" || result.status === "changed") return;
|
|
433
|
+
if (result.status === "auth_revoked") fail("forbidden");
|
|
434
|
+
fail("network");
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
listenerStartRealtime() {
|
|
438
|
+
return this.run(async (client) => {
|
|
439
|
+
const session = await client.startRealtime();
|
|
440
|
+
return {
|
|
441
|
+
nextEvent: () => this.run(() => session.nextEvent()),
|
|
442
|
+
stop: () => this.run(() => session.stop())
|
|
443
|
+
};
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
listenerConversations(request) {
|
|
447
|
+
return this.run(async (client) => page(await client.listConversations(request), (value) => this.listenerConversation(value)));
|
|
448
|
+
}
|
|
449
|
+
listenerHistory(request) {
|
|
450
|
+
return this.run(async (client) => {
|
|
451
|
+
const history = await client.getHistory({
|
|
452
|
+
conversationId: String(request.conversationId),
|
|
453
|
+
...request.cursor === void 0 ? {} : { cursor: String(request.cursor) },
|
|
454
|
+
...request.limit === void 0 ? {} : { limit: request.limit }
|
|
455
|
+
});
|
|
456
|
+
return page({
|
|
457
|
+
...history,
|
|
458
|
+
items: [...history.items].reverse()
|
|
459
|
+
}, (value) => this.listenerMessage(value));
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
async conversationId(client, target) {
|
|
463
|
+
if (target.kind === "direct") return required((await client.resolvePeer(target.peer)).conversationId);
|
|
464
|
+
let cursor;
|
|
465
|
+
for (let index = 0; index < MAX_GROUP_LOOKUP_PAGES; index += 1) {
|
|
466
|
+
const result = await client.listConversations({
|
|
467
|
+
...cursor === void 0 ? {} : { cursor },
|
|
468
|
+
limit: GROUP_LOOKUP_LIMIT
|
|
469
|
+
});
|
|
470
|
+
const match = result.items.find((item) => item.kind === "group" && (item.id === target.group || item.groupDid === target.group));
|
|
471
|
+
if (match !== void 0) return required(match.id);
|
|
472
|
+
if (!result.hasMore || result.nextCursor === void 0) fail("not-found");
|
|
473
|
+
cursor = result.nextCursor;
|
|
474
|
+
}
|
|
475
|
+
fail("not-found");
|
|
476
|
+
}
|
|
477
|
+
prepareExternalHttpRequest(request) {
|
|
478
|
+
return this.run(async (client) => externalHttpAttempt(await client.prepareExternalHttpRequest({
|
|
479
|
+
url: request.url,
|
|
480
|
+
method: request.method,
|
|
481
|
+
headers: request.headers.map((header) => ({
|
|
482
|
+
name: header.name,
|
|
483
|
+
value: header.value
|
|
484
|
+
})),
|
|
485
|
+
...request.body === void 0 ? {} : { body: Uint8Array.from(request.body) }
|
|
486
|
+
})));
|
|
487
|
+
}
|
|
488
|
+
getIdentity() {
|
|
489
|
+
return this.run(async (client) => {
|
|
490
|
+
const value = await client.getDefaultIdentity();
|
|
491
|
+
return value === null ? null : identity(value);
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
sendRegistrationOtp(request) {
|
|
495
|
+
return this.run(async (client) => {
|
|
496
|
+
const value = await client.requestRegistrationOtp(request);
|
|
497
|
+
return {
|
|
498
|
+
retryAfterSeconds: value.retryAfterSeconds,
|
|
499
|
+
retryAt: value.retryAt
|
|
500
|
+
};
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
registerIdentity(request) {
|
|
504
|
+
return this.run(async (client) => identity(await client.completeRegistration(request)));
|
|
505
|
+
}
|
|
506
|
+
updateDisplayName(request) {
|
|
507
|
+
return this.run(async (client) => identity(await client.updateDisplayName(request.displayName)));
|
|
508
|
+
}
|
|
509
|
+
resolvePeer(peer) {
|
|
510
|
+
return this.run(async (client) => {
|
|
511
|
+
const value = await client.resolvePeer(peer);
|
|
512
|
+
return {
|
|
513
|
+
did: required(value.did),
|
|
514
|
+
conversationId: required(value.conversationId),
|
|
515
|
+
...value.handle === void 0 ? {} : { handle: value.handle },
|
|
516
|
+
...value.displayName === void 0 ? {} : { displayName: value.displayName }
|
|
517
|
+
};
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
createGroup(name) {
|
|
521
|
+
return this.run(async (client) => this.createdGroup(await client.createGroup({ name })));
|
|
522
|
+
}
|
|
523
|
+
addGroupMember(groupDid, member) {
|
|
524
|
+
return this.run(async (client) => this.groupMember(await client.addGroupMember({
|
|
525
|
+
groupDid: String(groupDid),
|
|
526
|
+
member
|
|
527
|
+
})));
|
|
528
|
+
}
|
|
529
|
+
listConversations(request) {
|
|
530
|
+
return this.run(async (client) => {
|
|
531
|
+
const conversations = await client.listConversations(request);
|
|
532
|
+
return {
|
|
533
|
+
...page(conversations, (value) => value),
|
|
534
|
+
items: await this.displayableConversations(client, conversations.items)
|
|
535
|
+
};
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
getHistory(request) {
|
|
539
|
+
return this.run(async (client) => {
|
|
540
|
+
const history = await client.getHistory({
|
|
541
|
+
conversationId: String(request.conversationId),
|
|
542
|
+
...request.cursor === void 0 ? {} : { cursor: String(request.cursor) },
|
|
543
|
+
...request.limit === void 0 ? {} : { limit: request.limit }
|
|
544
|
+
});
|
|
545
|
+
return page({
|
|
546
|
+
...history,
|
|
547
|
+
items: await this.displayableMessages(client, [...history.items].reverse())
|
|
548
|
+
}, (value) => this.message(value));
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
getLocalHistory(request) {
|
|
552
|
+
return this.run(async (client) => {
|
|
553
|
+
const history = await client.getLocalConversationTimeline({
|
|
554
|
+
conversationId: String(request.conversationId),
|
|
555
|
+
...request.cursor === void 0 ? {} : { cursor: String(request.cursor) },
|
|
556
|
+
...request.limit === void 0 ? {} : { limit: request.limit }
|
|
557
|
+
});
|
|
558
|
+
return page({
|
|
559
|
+
...history,
|
|
560
|
+
items: await this.displayableMessages(client, [...history.items].reverse())
|
|
561
|
+
}, (value) => this.message(value));
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
markConversationRead(conversationId) {
|
|
565
|
+
return this.run(async (client) => (await client.markConversationRead(String(conversationId))).updatedCount);
|
|
566
|
+
}
|
|
567
|
+
sendText(request) {
|
|
568
|
+
return this.run(async (client) => {
|
|
569
|
+
const clientMessageId = browserMessageId(request.idempotencyKey);
|
|
570
|
+
return this.message(await client.sendText({
|
|
571
|
+
conversationId: await this.conversationId(client, request.target),
|
|
572
|
+
text: request.text,
|
|
573
|
+
...clientMessageId === void 0 ? {} : { clientMessageId },
|
|
574
|
+
idempotencyKey: request.idempotencyKey
|
|
575
|
+
}));
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
sendAttachment(request) {
|
|
579
|
+
return this.run(async (client) => {
|
|
580
|
+
const clientMessageId = browserMessageId(request.idempotencyKey);
|
|
581
|
+
return this.message(await client.sendAttachment({
|
|
582
|
+
conversationId: await this.conversationId(client, request.target),
|
|
583
|
+
fileName: request.attachment.fileName,
|
|
584
|
+
mimeType: request.attachment.mimeType,
|
|
585
|
+
bytes: request.attachment.bytes,
|
|
586
|
+
...request.caption === void 0 ? {} : { caption: request.caption },
|
|
587
|
+
...clientMessageId === void 0 ? {} : { clientMessageId },
|
|
588
|
+
idempotencyKey: request.idempotencyKey
|
|
589
|
+
}));
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
downloadAttachment(request) {
|
|
593
|
+
return this.run(async (client) => {
|
|
594
|
+
const conversationId = this.attachmentConversations.get(`${String(request.messageId)}\u0000${String(request.attachmentId)}`);
|
|
595
|
+
if (conversationId === void 0) fail("not-found");
|
|
596
|
+
const value = await client.downloadAttachment({
|
|
597
|
+
conversationId,
|
|
598
|
+
messageId: String(request.messageId),
|
|
599
|
+
attachmentId: String(request.attachmentId)
|
|
600
|
+
});
|
|
601
|
+
return {
|
|
602
|
+
attachment: attachment(value.attachment),
|
|
603
|
+
bytes: Uint8Array.from(value.bytes)
|
|
604
|
+
};
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
getMailAccount() {
|
|
608
|
+
return this.run(async (client) => mailAccount(await client.getMailAccount()));
|
|
609
|
+
}
|
|
610
|
+
listMailInbox(request = {}) {
|
|
611
|
+
return this.run(async (client) => mailInbox(await client.listMailInbox({
|
|
612
|
+
...request.folder === void 0 ? {} : { folder: request.folder },
|
|
613
|
+
...request.unreadOnly === void 0 ? {} : { unreadOnly: request.unreadOnly },
|
|
614
|
+
...request.limit === void 0 ? {} : { limit: request.limit },
|
|
615
|
+
...request.offset === void 0 ? {} : { offset: request.offset }
|
|
616
|
+
})));
|
|
617
|
+
}
|
|
618
|
+
readMail(request) {
|
|
619
|
+
return this.run(async (client) => mailMessage(await client.readMail(request.messageId)));
|
|
620
|
+
}
|
|
621
|
+
markMailRead(request) {
|
|
622
|
+
return this.run(async (client) => {
|
|
623
|
+
return { updated: uint32((await client.markMailRead({ messageIds: [...request.messageIds] })).updated) };
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
sendMail(request) {
|
|
627
|
+
return this.run(async (client) => {
|
|
628
|
+
const value = await client.sendMail({
|
|
629
|
+
to: [...request.to],
|
|
630
|
+
...request.cc === void 0 ? {} : { cc: [...request.cc] },
|
|
631
|
+
subject: request.subject,
|
|
632
|
+
bodyText: request.bodyText
|
|
633
|
+
});
|
|
634
|
+
if (!Array.isArray(value.warnings) || value.warnings.length > 100) fail();
|
|
635
|
+
const messageId = value.messageId === void 0 ? void 0 : mailToken(value.messageId, 2048);
|
|
636
|
+
return {
|
|
637
|
+
accepted: boolean(value.accepted),
|
|
638
|
+
...messageId === void 0 ? {} : { messageId },
|
|
639
|
+
warnings: value.warnings.map((warning) => remoteString(warning, 1024))
|
|
640
|
+
};
|
|
641
|
+
}, true);
|
|
642
|
+
}
|
|
643
|
+
clearLocalData() {
|
|
644
|
+
return this.run((client) => client.clearLocalData());
|
|
645
|
+
}
|
|
646
|
+
dispose() {
|
|
647
|
+
this.disposal ??= this.client.then(async (client) => {
|
|
648
|
+
try {
|
|
649
|
+
await client.close();
|
|
650
|
+
} catch (error) {
|
|
651
|
+
mapError(error);
|
|
652
|
+
}
|
|
653
|
+
}, () => void 0);
|
|
654
|
+
return this.disposal;
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
/**
|
|
658
|
+
* Convert a raw provider download to the Remote JSON representation.
|
|
659
|
+
* @param value - provider-verified public metadata and bytes.
|
|
660
|
+
* @returns detached metadata with canonical Base64 bytes.
|
|
661
|
+
*/
|
|
662
|
+
function downloadedAttachment(value) {
|
|
663
|
+
return {
|
|
664
|
+
attachment: { ...value.attachment },
|
|
665
|
+
bytesBase64: Buffer.from(value.bytes).toString("base64")
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
//#endregion
|
|
669
|
+
export { downloadedAttachment as n, RustSdkAdapter as t };
|