@awiki/dsh-plugin 0.3.16 → 0.3.18
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 +4 -0
- package/THIRD_PARTY_NOTICES.md +6 -0
- package/lib/client.js +3543 -746
- package/lib/client.js.map +1 -1
- package/lib/index.js +218 -41
- package/lib/{sdk-adapter-DGcTiEZz.mjs → package-version.generated-D0MSDRZn.mjs} +83 -10
- package/lib/provider.js +5 -3
- package/lib/typert.host.js +481 -127
- package/lib/typert.remote-client.d.ts +9 -3
- package/lib/typert.remote-client.d.ts.map +1 -1
- package/lib/typert.remote-client.js +481 -127
- package/lib/types/client/AwikiAvatar.d.ts +40 -0
- package/lib/types/client/AwikiAvatar.d.ts.map +1 -0
- package/lib/types/client/AwikiAvatar.js +201 -0
- package/lib/types/client/AwikiAvatar.js.map +1 -0
- package/lib/types/client/AwikiAvatarEditor.d.ts +11 -0
- package/lib/types/client/AwikiAvatarEditor.d.ts.map +1 -0
- package/lib/types/client/AwikiAvatarEditor.js +113 -0
- package/lib/types/client/AwikiAvatarEditor.js.map +1 -0
- package/lib/types/client/AwikiAvatarPreview.d.ts +8 -0
- package/lib/types/client/AwikiAvatarPreview.d.ts.map +1 -0
- package/lib/types/client/AwikiAvatarPreview.js +68 -0
- package/lib/types/client/AwikiAvatarPreview.js.map +1 -0
- package/lib/types/client/AwikiGroupDetails.js +2 -2
- package/lib/types/client/AwikiGroupDetails.js.map +1 -1
- package/lib/types/client/AwikiIdentityAccess.d.ts +1 -0
- package/lib/types/client/AwikiIdentityAccess.d.ts.map +1 -1
- package/lib/types/client/AwikiIdentityAccess.js +10 -2
- package/lib/types/client/AwikiIdentityAccess.js.map +1 -1
- package/lib/types/client/AwikiOverlay.d.ts.map +1 -1
- package/lib/types/client/AwikiOverlay.js +92 -27
- package/lib/types/client/AwikiOverlay.js.map +1 -1
- package/lib/types/client/AwikiProfileCard.d.ts +1 -1
- package/lib/types/client/AwikiProfileCard.d.ts.map +1 -1
- package/lib/types/client/AwikiProfileCard.js +6 -2
- package/lib/types/client/AwikiProfileCard.js.map +1 -1
- package/lib/types/client/avatar-cache.d.ts +24 -0
- package/lib/types/client/avatar-cache.d.ts.map +1 -0
- package/lib/types/client/avatar-cache.js +336 -0
- package/lib/types/client/avatar-cache.js.map +1 -0
- package/lib/types/client/avatar-dialog.d.ts +3 -0
- package/lib/types/client/avatar-dialog.d.ts.map +1 -0
- package/lib/types/client/avatar-dialog.js +18 -0
- package/lib/types/client/avatar-dialog.js.map +1 -0
- package/lib/types/client/avatar-image.d.ts +26 -0
- package/lib/types/client/avatar-image.d.ts.map +1 -0
- package/lib/types/client/avatar-image.js +193 -0
- package/lib/types/client/avatar-image.js.map +1 -0
- package/lib/types/client/controller.d.ts +30 -4
- package/lib/types/client/controller.d.ts.map +1 -1
- package/lib/types/client/controller.js +267 -56
- package/lib/types/client/controller.js.map +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +10 -2
- package/lib/types/client/index.js.map +1 -1
- package/lib/types/client/slots.d.ts +12 -3
- package/lib/types/client/slots.d.ts.map +1 -1
- package/lib/types/conversation-preferences.d.ts.map +1 -1
- package/lib/types/conversation-preferences.js +27 -0
- package/lib/types/conversation-preferences.js.map +1 -1
- package/lib/types/index.d.ts +8 -2
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +76 -11
- package/lib/types/index.js.map +1 -1
- package/lib/types/listener.d.ts.map +1 -1
- package/lib/types/listener.js +9 -8
- package/lib/types/listener.js.map +1 -1
- package/lib/types/package-version.generated.d.ts +2 -2
- package/lib/types/package-version.generated.js +2 -2
- package/lib/types/provider-api.d.ts +9 -3
- package/lib/types/provider-api.d.ts.map +1 -1
- package/lib/types/provider.d.ts.map +1 -1
- package/lib/types/provider.js +5 -2
- package/lib/types/provider.js.map +1 -1
- package/lib/types/sdk-adapter.d.ts +6 -3
- package/lib/types/sdk-adapter.d.ts.map +1 -1
- package/lib/types/sdk-adapter.js +58 -7
- package/lib/types/sdk-adapter.js.map +1 -1
- package/lib/types/tenant-registry.d.ts +2 -0
- package/lib/types/tenant-registry.d.ts.map +1 -1
- package/lib/types/tenant-registry.js +83 -16
- package/lib/types/tenant-registry.js.map +1 -1
- package/lib/types/types.d.ts +63 -7
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/types.js.map +1 -1
- package/lib/types/update-policy.d.ts +2 -2
- package/package.json +33 -34
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as downloadedAttachment, c as successfulMailRecoveryObservability, l as isMessageTarget, n as DSH_AWIKI_PACKAGE_VERSION, o as failedMailRecoveryObservability, r as AwikiSdkError, s as fencedMailRecoveryObservability, t as DSH_AWIKI_MODEL_PROXY_PACKAGE_VERSION } from "./package-version.generated-D0MSDRZn.mjs";
|
|
2
2
|
import "@deepseek-ai/cordis";
|
|
3
3
|
import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
|
|
4
4
|
import { homedir } from "node:os";
|
|
@@ -2141,17 +2141,27 @@ function preferences(value, expectedOwnerDid) {
|
|
|
2141
2141
|
if (seen.has(hidden.conversation.id)) invalidState();
|
|
2142
2142
|
seen.add(hidden.conversation.id);
|
|
2143
2143
|
}
|
|
2144
|
+
const encryptedConversationIds = value.encryptedConversationIds === void 0 ? [] : value.encryptedConversationIds;
|
|
2145
|
+
if (!Array.isArray(encryptedConversationIds) || encryptedConversationIds.length > MAX_HIDDEN_CONVERSATIONS) invalidState();
|
|
2144
2146
|
return {
|
|
2147
|
+
encryptedConversationIds: encryptedConversationIds.map((id) => {
|
|
2148
|
+
const canonical = boundedString$1(id, MAX_IDENTIFIER_CHARACTERS);
|
|
2149
|
+
if (!canonical.startsWith("dm:")) invalidState();
|
|
2150
|
+
return canonical;
|
|
2151
|
+
}),
|
|
2145
2152
|
version: STORE_VERSION,
|
|
2146
2153
|
ownerDid: String(expectedOwnerDid),
|
|
2147
2154
|
hiddenConversations
|
|
2148
2155
|
};
|
|
2149
2156
|
}
|
|
2150
2157
|
function publicPreferences(value) {
|
|
2151
|
-
return {
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2158
|
+
return {
|
|
2159
|
+
encryptedConversationIds: [...value.encryptedConversationIds ?? []],
|
|
2160
|
+
hiddenConversations: value.hiddenConversations.map((hidden) => ({
|
|
2161
|
+
conversation: { ...hidden.conversation },
|
|
2162
|
+
hiddenAt: hidden.hiddenAt
|
|
2163
|
+
}))
|
|
2164
|
+
};
|
|
2155
2165
|
}
|
|
2156
2166
|
function emptyPreferences(ownerDid) {
|
|
2157
2167
|
return {
|
|
@@ -2164,6 +2174,15 @@ function emptyPreferences(ownerDid) {
|
|
|
2164
2174
|
function normalizeConversationPreferenceMutation(value) {
|
|
2165
2175
|
try {
|
|
2166
2176
|
if (!isRecord$3(value)) return void 0;
|
|
2177
|
+
if (value.action === "security" && typeof value.encrypted === "boolean") {
|
|
2178
|
+
const conversationId = boundedString$1(value.conversationId, MAX_IDENTIFIER_CHARACTERS);
|
|
2179
|
+
if (!conversationId.startsWith("dm:")) return void 0;
|
|
2180
|
+
return {
|
|
2181
|
+
action: "security",
|
|
2182
|
+
conversationId,
|
|
2183
|
+
encrypted: value.encrypted
|
|
2184
|
+
};
|
|
2185
|
+
}
|
|
2167
2186
|
if (value.action === "hide") return {
|
|
2168
2187
|
action: "hide",
|
|
2169
2188
|
conversation: conversation(value.conversation)
|
|
@@ -2196,6 +2215,17 @@ var AwikiConversationPreferenceStore = class {
|
|
|
2196
2215
|
const current = await this.load(ownerDid);
|
|
2197
2216
|
let next;
|
|
2198
2217
|
switch (normalized.action) {
|
|
2218
|
+
case "security": {
|
|
2219
|
+
const ids = new Set(current.encryptedConversationIds ?? []);
|
|
2220
|
+
if (normalized.encrypted) ids.add(normalized.conversationId);
|
|
2221
|
+
else ids.delete(normalized.conversationId);
|
|
2222
|
+
if (ids.size > MAX_HIDDEN_CONVERSATIONS) invalidState();
|
|
2223
|
+
next = {
|
|
2224
|
+
...current,
|
|
2225
|
+
encryptedConversationIds: [...ids]
|
|
2226
|
+
};
|
|
2227
|
+
break;
|
|
2228
|
+
}
|
|
2199
2229
|
case "hide": {
|
|
2200
2230
|
const snapshot = normalized.conversation;
|
|
2201
2231
|
const hidden = current.hiddenConversations.filter((item) => item.conversation.id !== snapshot.id);
|
|
@@ -2765,29 +2795,29 @@ var AwikiAgentListener = class {
|
|
|
2765
2795
|
await this.stateMutation;
|
|
2766
2796
|
const route = this.state.conversations[conversation.id];
|
|
2767
2797
|
if (route?.lastProcessedMessageId === message.id) return;
|
|
2768
|
-
if (message.content.kind !== "text") {
|
|
2798
|
+
if (message.content.kind !== "text" || message.encrypted === true && message.decryptionState !== "decrypted") {
|
|
2769
2799
|
await this.commit(conversation, message.id, route?.sessionId);
|
|
2770
2800
|
return;
|
|
2771
2801
|
}
|
|
2772
2802
|
const parsed = command(message.content.text);
|
|
2773
2803
|
if (parsed?.name === "/help") {
|
|
2774
|
-
await this.reply(conversation, message
|
|
2804
|
+
await this.reply(conversation, message, HELP_TEXT);
|
|
2775
2805
|
await this.commit(conversation, message.id, route?.sessionId);
|
|
2776
2806
|
return;
|
|
2777
2807
|
}
|
|
2778
2808
|
if (parsed?.name === "/status") {
|
|
2779
|
-
await this.reply(conversation, message
|
|
2809
|
+
await this.reply(conversation, message, route?.sessionId === void 0 ? NO_SESSION_TEXT : `当前 DSH 会话:${route.sessionId}`);
|
|
2780
2810
|
await this.commit(conversation, message.id, route?.sessionId);
|
|
2781
2811
|
return;
|
|
2782
2812
|
}
|
|
2783
2813
|
if (parsed?.name === "/new" && parsed.argument.length === 0) {
|
|
2784
2814
|
await this.agents.reset(route?.sessionId);
|
|
2785
|
-
await this.reply(conversation, message
|
|
2815
|
+
await this.reply(conversation, message, RESET_TEXT);
|
|
2786
2816
|
await this.commit(conversation, message.id, void 0);
|
|
2787
2817
|
return;
|
|
2788
2818
|
}
|
|
2789
2819
|
if (parsed !== void 0 && parsed.name !== "/new") {
|
|
2790
|
-
await this.reply(conversation, message
|
|
2820
|
+
await this.reply(conversation, message, UNKNOWN_COMMAND_TEXT);
|
|
2791
2821
|
await this.commit(conversation, message.id, route?.sessionId);
|
|
2792
2822
|
return;
|
|
2793
2823
|
}
|
|
@@ -2803,10 +2833,10 @@ var AwikiAgentListener = class {
|
|
|
2803
2833
|
} catch {
|
|
2804
2834
|
output = AGENT_FAILURE_TEXT;
|
|
2805
2835
|
}
|
|
2806
|
-
await this.reply(conversation, message
|
|
2836
|
+
await this.reply(conversation, message, output);
|
|
2807
2837
|
await this.commit(conversation, message.id, sessionId);
|
|
2808
2838
|
}
|
|
2809
|
-
async reply(conversation,
|
|
2839
|
+
async reply(conversation, message, text) {
|
|
2810
2840
|
const parts = chunks(text);
|
|
2811
2841
|
for (const [index, part] of parts.entries()) await this.awiki.sendText({
|
|
2812
2842
|
target: {
|
|
@@ -2814,7 +2844,8 @@ var AwikiAgentListener = class {
|
|
|
2814
2844
|
conversationId: conversation.id
|
|
2815
2845
|
},
|
|
2816
2846
|
text: part,
|
|
2817
|
-
|
|
2847
|
+
security: message.encrypted === true ? "e2ee-required" : "plain",
|
|
2848
|
+
idempotencyKey: replyKey(message.id, index)
|
|
2818
2849
|
});
|
|
2819
2850
|
}
|
|
2820
2851
|
async commit(conversation, messageId, sessionId) {
|
|
@@ -3137,7 +3168,7 @@ function endpointsForOrigin(origin, domain) {
|
|
|
3137
3168
|
function officialProfile(entry) {
|
|
3138
3169
|
return {
|
|
3139
3170
|
tenantId: entry.tenantId,
|
|
3140
|
-
storageScopeId:
|
|
3171
|
+
storageScopeId: randomUUID(),
|
|
3141
3172
|
kind: "built_in",
|
|
3142
3173
|
displayName: entry.displayName,
|
|
3143
3174
|
backendBaseUrl: entry.backendOrigin,
|
|
@@ -3177,10 +3208,13 @@ function decodeTenant(value) {
|
|
|
3177
3208
|
const backendBaseUrl = safeString(value.backendBaseUrl);
|
|
3178
3209
|
const didHost = safeString(value.didHost);
|
|
3179
3210
|
const endpoints = decodeEndpoints(value.endpoints);
|
|
3211
|
+
const preferenceTenantIds = value.preferenceTenantIds;
|
|
3212
|
+
if (preferenceTenantIds !== void 0 && (!Array.isArray(preferenceTenantIds) || preferenceTenantIds.some((id) => typeof id !== "string" || id.trim() === "") || new Set(preferenceTenantIds).size !== preferenceTenantIds.length)) return void 0;
|
|
3180
3213
|
if (tenantId === void 0 || storageScopeId === void 0 || displayName === void 0 || backendBaseUrl === void 0 || didHost === void 0 || endpoints === void 0 || value.kind !== "built_in" && value.kind !== "custom" || value.lifecycle !== "active" && value.lifecycle !== "inactive" && value.lifecycle !== "archived" || value.storageLayout !== "scope-v1" && value.storageLayout !== "legacy-base" && value.storageLayout !== "domain-v1") return;
|
|
3181
3214
|
return {
|
|
3182
3215
|
tenantId,
|
|
3183
3216
|
storageScopeId,
|
|
3217
|
+
...preferenceTenantIds === void 0 ? {} : { preferenceTenantIds },
|
|
3184
3218
|
kind: value.kind,
|
|
3185
3219
|
displayName,
|
|
3186
3220
|
backendBaseUrl,
|
|
@@ -3190,12 +3224,12 @@ function decodeTenant(value) {
|
|
|
3190
3224
|
endpoints
|
|
3191
3225
|
};
|
|
3192
3226
|
}
|
|
3193
|
-
function decodeDocument(value) {
|
|
3227
|
+
function decodeDocument(value, allowDuplicateScopes = false) {
|
|
3194
3228
|
if (!isRecord$1(value) || value.schemaVersion !== 1 || !Number.isSafeInteger(value.officialCatalogVersion) || value.officialCatalogVersion < 1 || value.officialCatalogVersion > 2 || !Number.isSafeInteger(value.generation) || value.generation < 0 || typeof value.activeTenantId !== "string" || !Array.isArray(value.tenants)) return void 0;
|
|
3195
3229
|
const tenants = value.tenants.map(decodeTenant);
|
|
3196
3230
|
if (tenants.some((tenant) => tenant === void 0)) return void 0;
|
|
3197
3231
|
const complete = tenants;
|
|
3198
|
-
if (new Set(complete.map((tenant) => tenant.tenantId)).size !== complete.length || new Set(complete.map((tenant) => tenant.storageScopeId)).size !== complete.length || !complete.some((tenant) => tenant.tenantId === value.activeTenantId && tenant.lifecycle === "active") || complete.filter((tenant) => tenant.lifecycle === "active").length !== 1) return void 0;
|
|
3232
|
+
if (new Set(complete.map((tenant) => tenant.tenantId)).size !== complete.length || !allowDuplicateScopes && new Set(complete.map((tenant) => tenant.storageScopeId)).size !== complete.length || complete.some((tenant) => !/^[a-zA-Z0-9_-]+$/u.test(tenant.storageScopeId)) || !complete.some((tenant) => tenant.tenantId === value.activeTenantId && tenant.lifecycle === "active") || complete.filter((tenant) => tenant.lifecycle === "active").length !== 1) return void 0;
|
|
3199
3233
|
return {
|
|
3200
3234
|
schemaVersion: 1,
|
|
3201
3235
|
officialCatalogVersion: 2,
|
|
@@ -3213,7 +3247,7 @@ function directoryHasData(path) {
|
|
|
3213
3247
|
}
|
|
3214
3248
|
function sameOfficialEndpoint(tenant, entry) {
|
|
3215
3249
|
const origin = entry.backendOrigin;
|
|
3216
|
-
return tenant.didHost === entry.didHost
|
|
3250
|
+
return tenant.didHost === entry.didHost && tenant.backendBaseUrl.replace(/\/$/u, "") === origin && tenant.endpoints.userServiceUrl.replace(/\/$/u, "") === origin;
|
|
3217
3251
|
}
|
|
3218
3252
|
function preservedTenantId(tenants, tenant) {
|
|
3219
3253
|
const base = `custom-${tenant.storageScopeId}`;
|
|
@@ -3244,6 +3278,7 @@ function reconcileOfficials(document) {
|
|
|
3244
3278
|
tenants[exactIndex] = {
|
|
3245
3279
|
...officialProfile(entry),
|
|
3246
3280
|
storageScopeId: current.storageScopeId,
|
|
3281
|
+
...current.preferenceTenantIds === void 0 ? {} : { preferenceTenantIds: current.preferenceTenantIds },
|
|
3247
3282
|
storageLayout: current.storageLayout,
|
|
3248
3283
|
lifecycle: current.lifecycle
|
|
3249
3284
|
};
|
|
@@ -3253,7 +3288,8 @@ function reconcileOfficials(document) {
|
|
|
3253
3288
|
tenants[exactIndex] = {
|
|
3254
3289
|
...current,
|
|
3255
3290
|
tenantId: preservedId,
|
|
3256
|
-
kind: "custom"
|
|
3291
|
+
kind: "custom",
|
|
3292
|
+
preferenceTenantIds: [.../* @__PURE__ */ new Set([current.tenantId, ...current.preferenceTenantIds ?? []])]
|
|
3257
3293
|
};
|
|
3258
3294
|
if (activeTenantId === current.tenantId) activeTenantId = preservedId;
|
|
3259
3295
|
exactIndex = -1;
|
|
@@ -3265,6 +3301,7 @@ function reconcileOfficials(document) {
|
|
|
3265
3301
|
tenants[legacyIndex] = {
|
|
3266
3302
|
...officialProfile(entry),
|
|
3267
3303
|
storageScopeId: current.storageScopeId,
|
|
3304
|
+
preferenceTenantIds: [.../* @__PURE__ */ new Set([current.tenantId, ...current.preferenceTenantIds ?? []])],
|
|
3268
3305
|
storageLayout: current.storageLayout,
|
|
3269
3306
|
lifecycle: current.lifecycle
|
|
3270
3307
|
};
|
|
@@ -3282,6 +3319,7 @@ function reconcileOfficials(document) {
|
|
|
3282
3319
|
tenants[endpointIndex] = {
|
|
3283
3320
|
...officialProfile(entry),
|
|
3284
3321
|
storageScopeId: current.storageScopeId,
|
|
3322
|
+
preferenceTenantIds: [.../* @__PURE__ */ new Set([current.tenantId, ...current.preferenceTenantIds ?? []])],
|
|
3285
3323
|
storageLayout: current.storageLayout,
|
|
3286
3324
|
lifecycle: current.lifecycle
|
|
3287
3325
|
};
|
|
@@ -3298,6 +3336,50 @@ function reconcileOfficials(document) {
|
|
|
3298
3336
|
function cloneDocument(document) {
|
|
3299
3337
|
return structuredClone(document);
|
|
3300
3338
|
}
|
|
3339
|
+
function tenantStateRoot(base, tenant) {
|
|
3340
|
+
if (tenant.storageLayout === "legacy-base") return resolve(base);
|
|
3341
|
+
if (tenant.storageLayout === "domain-v1") return resolve(dirname(base), "tenants", normalizeAwikiDomain(tenant.didHost), basename(base));
|
|
3342
|
+
return resolve(dirname(base), "tenant-scopes", tenant.storageScopeId, basename(base));
|
|
3343
|
+
}
|
|
3344
|
+
function validateDocument(base, document) {
|
|
3345
|
+
if (decodeDocument(document) === void 0 || new Set(document.tenants.map((tenant) => tenantStateRoot(base, tenant))).size !== document.tenants.length) throw new Error("registry schema or storage ownership invariants are invalid");
|
|
3346
|
+
}
|
|
3347
|
+
/** Repair only the known catalog-slot collision with a unique pre-migration owner. */
|
|
3348
|
+
function repairCatalogCollision(base, parsed, backupPath) {
|
|
3349
|
+
const document = decodeDocument(parsed, true);
|
|
3350
|
+
if (document === void 0 || !existsSync(backupPath)) return void 0;
|
|
3351
|
+
const backup = decodeDocument(JSON.parse(readFileSync(backupPath, "utf8")));
|
|
3352
|
+
if (backup === void 0) return void 0;
|
|
3353
|
+
let repaired = false;
|
|
3354
|
+
const tenants = [...document.tenants];
|
|
3355
|
+
for (const entry of OFFICIALS) {
|
|
3356
|
+
const group = tenants.filter((tenant) => tenant.storageScopeId === entry.storageScopeId);
|
|
3357
|
+
if (group.length !== 2) continue;
|
|
3358
|
+
const current = group.find((tenant) => tenant.tenantId === entry.tenantId && sameOfficialEndpoint(tenant, entry));
|
|
3359
|
+
const preserved = group.find((tenant) => tenant.kind === "custom" && tenant.tenantId === `custom-${entry.storageScopeId}`);
|
|
3360
|
+
if (current === void 0 || preserved === void 0 || current.storageLayout !== "scope-v1" || preserved.storageLayout !== "scope-v1") continue;
|
|
3361
|
+
const owners = backup.tenants.filter((tenant) => tenant.storageScopeId === entry.storageScopeId);
|
|
3362
|
+
const owner = owners[0];
|
|
3363
|
+
if (owners.length !== 1 || owner === void 0 || owner.storageLayout !== preserved.storageLayout || owner.didHost !== preserved.didHost || owner.backendBaseUrl !== preserved.backendBaseUrl || JSON.stringify(owner.endpoints) !== JSON.stringify(preserved.endpoints)) continue;
|
|
3364
|
+
const identityPath = join(tenantStateRoot(base, preserved), "identities", "registry.json");
|
|
3365
|
+
if (existsSync(identityPath)) {
|
|
3366
|
+
const identities = JSON.parse(readFileSync(identityPath, "utf8"));
|
|
3367
|
+
if (!isRecord$1(identities) || !isRecord$1(identities.credentials) || Object.values(identities.credentials).some((value) => !isRecord$1(value) || typeof value.did !== "string" || !value.did.startsWith(`did:wba:${preserved.didHost}:`))) continue;
|
|
3368
|
+
}
|
|
3369
|
+
tenants[tenants.indexOf(current)] = {
|
|
3370
|
+
...current,
|
|
3371
|
+
storageScopeId: randomUUID()
|
|
3372
|
+
};
|
|
3373
|
+
repaired = true;
|
|
3374
|
+
}
|
|
3375
|
+
if (!repaired) return void 0;
|
|
3376
|
+
const result = {
|
|
3377
|
+
...document,
|
|
3378
|
+
tenants
|
|
3379
|
+
};
|
|
3380
|
+
validateDocument(base, result);
|
|
3381
|
+
return result;
|
|
3382
|
+
}
|
|
3301
3383
|
/** Durable registry. All mutations are synchronous, backup-aware, and atomic. */
|
|
3302
3384
|
var AwikiTenantRegistry = class AwikiTenantRegistry {
|
|
3303
3385
|
baseStateRoot;
|
|
@@ -3317,10 +3399,16 @@ var AwikiTenantRegistry = class AwikiTenantRegistry {
|
|
|
3317
3399
|
static open(baseStateRoot, seed) {
|
|
3318
3400
|
const filePath = registryFilePath(baseStateRoot);
|
|
3319
3401
|
if (existsSync(filePath)) try {
|
|
3320
|
-
const
|
|
3402
|
+
const parsed = JSON.parse(readFileSync(filePath, "utf8"));
|
|
3403
|
+
const decoded = decodeDocument(parsed) ?? repairCatalogCollision(baseStateRoot, parsed, `${filePath}.pre-v1.bak`);
|
|
3321
3404
|
if (decoded === void 0) throw new Error("registry schema or invariants are invalid");
|
|
3322
3405
|
const registry = new AwikiTenantRegistry(baseStateRoot, reconcileOfficials(decoded), true);
|
|
3323
|
-
|
|
3406
|
+
validateDocument(baseStateRoot, registry.document);
|
|
3407
|
+
if (JSON.stringify(parsed) !== JSON.stringify(registry.document)) {
|
|
3408
|
+
const repairBackup = `${filePath}.pre-scope-repair.bak`;
|
|
3409
|
+
if (!existsSync(repairBackup)) copyFileSync(filePath, repairBackup);
|
|
3410
|
+
registry.persist(true);
|
|
3411
|
+
}
|
|
3324
3412
|
return registry;
|
|
3325
3413
|
} catch (error) {
|
|
3326
3414
|
const diagnostic = `AWiki tenant registry was not migrated: ${error instanceof Error ? error.message : "unknown error"}\n`;
|
|
@@ -3329,7 +3417,7 @@ var AwikiTenantRegistry = class AwikiTenantRegistry {
|
|
|
3329
3417
|
encoding: "utf8",
|
|
3330
3418
|
mode: 384
|
|
3331
3419
|
});
|
|
3332
|
-
|
|
3420
|
+
throw new Error("awiki: tenant registry needs repair; no environment was opened", { cause: error });
|
|
3333
3421
|
}
|
|
3334
3422
|
const hasLegacyData = directoryHasData(baseStateRoot);
|
|
3335
3423
|
const document = seed.configured || hasLegacyData ? legacyDocument(seed, hasLegacyData && !seed.configured) : freshDocument();
|
|
@@ -3354,9 +3442,7 @@ var AwikiTenantRegistry = class AwikiTenantRegistry {
|
|
|
3354
3442
|
return tenant === void 0 ? void 0 : structuredClone(tenant);
|
|
3355
3443
|
}
|
|
3356
3444
|
stateRoot(tenant) {
|
|
3357
|
-
|
|
3358
|
-
if (tenant.storageLayout === "domain-v1") return join(dirname(this.baseStateRoot), "tenants", tenant.didHost, basename(this.baseStateRoot));
|
|
3359
|
-
return join(dirname(this.baseStateRoot), "tenant-scopes", tenant.storageScopeId, basename(this.baseStateRoot));
|
|
3445
|
+
return tenantStateRoot(this.baseStateRoot, tenant);
|
|
3360
3446
|
}
|
|
3361
3447
|
createCustom(displayName, rawDomain) {
|
|
3362
3448
|
const domain = normalizeAwikiDomain(rawDomain);
|
|
@@ -3426,6 +3512,7 @@ var AwikiTenantRegistry = class AwikiTenantRegistry {
|
|
|
3426
3512
|
return cloneDocument(this.document);
|
|
3427
3513
|
}
|
|
3428
3514
|
persist(backup) {
|
|
3515
|
+
validateDocument(this.baseStateRoot, this.document);
|
|
3429
3516
|
if (!this.persistent) throw new Error("awiki: tenant registry is read-only until its migration diagnostic is resolved");
|
|
3430
3517
|
mkdirSync(dirname(this.filePath), { recursive: true });
|
|
3431
3518
|
if (backup && existsSync(this.filePath) && !existsSync(this.backupPath)) copyFileSync(this.filePath, this.backupPath);
|
|
@@ -3569,11 +3656,6 @@ function checkInstallation(requirements, installed) {
|
|
|
3569
3656
|
return {};
|
|
3570
3657
|
}
|
|
3571
3658
|
//#endregion
|
|
3572
|
-
//#region lib/types/package-version.generated.js
|
|
3573
|
-
/** Generated from package.json by scripts/sync-package-versions.mjs. */
|
|
3574
|
-
const DSH_AWIKI_PACKAGE_VERSION = "0.3.16";
|
|
3575
|
-
const DSH_AWIKI_MODEL_PROXY_PACKAGE_VERSION = "0.1.11";
|
|
3576
|
-
//#endregion
|
|
3577
3659
|
//#region lib/types/update-policy.js
|
|
3578
3660
|
/** Tenant-scoped DSH AWiki plugin update policy and verified cache. */
|
|
3579
3661
|
const DSH_AWIKI_VERSION = DSH_AWIKI_PACKAGE_VERSION;
|
|
@@ -4011,6 +4093,7 @@ const FAILURE_CODES = /* @__PURE__ */ new Set([
|
|
|
4011
4093
|
"state-in-use",
|
|
4012
4094
|
"rate-limited",
|
|
4013
4095
|
"group-membership-required",
|
|
4096
|
+
"group-member-encryption-not-ready",
|
|
4014
4097
|
"group-identity-stale",
|
|
4015
4098
|
"attachment-too-large",
|
|
4016
4099
|
"summary-unavailable",
|
|
@@ -4049,6 +4132,7 @@ const FAILURE_MESSAGES = {
|
|
|
4049
4132
|
"conflict": "The AWiki operation conflicts with current state.",
|
|
4050
4133
|
"state-in-use": "AWiki data is already open in another client.",
|
|
4051
4134
|
"rate-limited": "The AWiki service rate-limited the request.",
|
|
4135
|
+
"group-member-encryption-not-ready": "The member has not prepared encrypted messaging.",
|
|
4052
4136
|
"group-membership-required": "The active AWiki identity is not a member of this group.",
|
|
4053
4137
|
"group-identity-stale": "The AWiki group identity binding is still recovering.",
|
|
4054
4138
|
"attachment-too-large": "The attachment exceeds this deployment's size limit.",
|
|
@@ -4258,6 +4342,8 @@ const MAX_PROFILE_TAGS = 5;
|
|
|
4258
4342
|
const MAX_PROFILE_TAG_CHARACTERS = 30;
|
|
4259
4343
|
const MAX_MESSAGE_CHARACTERS = 2e4;
|
|
4260
4344
|
function normalizeCreateGroupRequest(request) {
|
|
4345
|
+
if (request?.operationId !== void 0 && (typeof request.operationId !== "string" || !/^[a-zA-Z0-9_-]{1,100}$/.test(request.operationId))) return void 0;
|
|
4346
|
+
if (request?.encrypted !== void 0 && typeof request.encrypted !== "boolean") return void 0;
|
|
4261
4347
|
if (typeof request?.name !== "string" || !Array.isArray(request.members)) return void 0;
|
|
4262
4348
|
const name = request.name.trim();
|
|
4263
4349
|
if (name.length === 0 || Array.from(name).length > MAX_GROUP_NAME_CHARACTERS) return void 0;
|
|
@@ -4274,7 +4360,9 @@ function normalizeCreateGroupRequest(request) {
|
|
|
4274
4360
|
}
|
|
4275
4361
|
return {
|
|
4276
4362
|
name,
|
|
4277
|
-
members
|
|
4363
|
+
members,
|
|
4364
|
+
...request.operationId === void 0 ? {} : { operationId: request.operationId },
|
|
4365
|
+
...request.encrypted === void 0 ? {} : { encrypted: request.encrypted }
|
|
4278
4366
|
};
|
|
4279
4367
|
}
|
|
4280
4368
|
function normalizeMember(value) {
|
|
@@ -4286,6 +4374,22 @@ function normalizeGroupDid(value) {
|
|
|
4286
4374
|
if (typeof value !== "string" || !value.startsWith("did:") || value.length > 2048) return void 0;
|
|
4287
4375
|
return value;
|
|
4288
4376
|
}
|
|
4377
|
+
function validAvatarRequest(request, image) {
|
|
4378
|
+
if (request === null || typeof request !== "object" || Array.isArray(request)) return false;
|
|
4379
|
+
const value = request;
|
|
4380
|
+
const keys = image ? [
|
|
4381
|
+
"requestId",
|
|
4382
|
+
"expectedProfileVersion",
|
|
4383
|
+
"imageBase64"
|
|
4384
|
+
] : ["requestId", "expectedProfileVersion"];
|
|
4385
|
+
if (Object.keys(value).length !== keys.length || Object.keys(value).some((key) => !keys.includes(key))) return false;
|
|
4386
|
+
if (typeof value.requestId !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/u.test(value.requestId)) return false;
|
|
4387
|
+
if (typeof value.expectedProfileVersion !== "string" || !/^(0|[1-9][0-9]{0,18})$/u.test(value.expectedProfileVersion) || BigInt(value.expectedProfileVersion) > 9223372036854775807n) return false;
|
|
4388
|
+
if (!image) return true;
|
|
4389
|
+
if (typeof value.imageBase64 !== "string" || value.imageBase64.length === 0 || value.imageBase64.length > 699052) return false;
|
|
4390
|
+
const bytes = Buffer.from(value.imageBase64, "base64");
|
|
4391
|
+
return bytes.length <= 524288 && bytes.length >= 4 && bytes[0] === 255 && bytes[1] === 216 && bytes[bytes.length - 2] === 255 && bytes[bytes.length - 1] === 217 && bytes.toString("base64") === value.imageBase64;
|
|
4392
|
+
}
|
|
4289
4393
|
function normalizeProfileRequest(request) {
|
|
4290
4394
|
if (typeof request?.displayName !== "string" || typeof request.bio !== "string" || !Array.isArray(request.tags)) return void 0;
|
|
4291
4395
|
const displayName = request.displayName.trim();
|
|
@@ -4385,6 +4489,7 @@ function identityAccessTarget(request, configuredDomain) {
|
|
|
4385
4489
|
};
|
|
4386
4490
|
}
|
|
4387
4491
|
function normalizeSendTextRequest(request) {
|
|
4492
|
+
if (request?.security !== void 0 && request.security !== "plain" && request.security !== "e2ee-required") return void 0;
|
|
4388
4493
|
if (typeof request?.text !== "string" || typeof request.idempotencyKey !== "string" || !isMessageTarget(request.target)) return void 0;
|
|
4389
4494
|
const text = request.text;
|
|
4390
4495
|
const codePoints = Array.from(text);
|
|
@@ -4574,6 +4679,8 @@ let AwikiService = (() => {
|
|
|
4574
4679
|
let _prepareRootTransfer_decorators;
|
|
4575
4680
|
let _confirmRootTransfer_decorators;
|
|
4576
4681
|
let _updateDisplayName_decorators;
|
|
4682
|
+
let _setAvatar_decorators;
|
|
4683
|
+
let _clearAvatar_decorators;
|
|
4577
4684
|
let _getProfile_decorators;
|
|
4578
4685
|
let _updateProfile_decorators;
|
|
4579
4686
|
let _sendRecoveryOtp_decorators;
|
|
@@ -4586,6 +4693,7 @@ let AwikiService = (() => {
|
|
|
4586
4693
|
let _resolvePeer_decorators;
|
|
4587
4694
|
let _createGroup_decorators;
|
|
4588
4695
|
let _getGroup_decorators;
|
|
4696
|
+
let _repairGroupSecurity_decorators;
|
|
4589
4697
|
let _joinGroup_decorators;
|
|
4590
4698
|
let _leaveGroup_decorators;
|
|
4591
4699
|
let _getDisplayProfiles_decorators;
|
|
@@ -4643,6 +4751,8 @@ let AwikiService = (() => {
|
|
|
4643
4751
|
_prepareRootTransfer_decorators = [Remote];
|
|
4644
4752
|
_confirmRootTransfer_decorators = [Remote];
|
|
4645
4753
|
_updateDisplayName_decorators = [Remote];
|
|
4754
|
+
_setAvatar_decorators = [Remote];
|
|
4755
|
+
_clearAvatar_decorators = [Remote];
|
|
4646
4756
|
_getProfile_decorators = [Remote];
|
|
4647
4757
|
_updateProfile_decorators = [Remote];
|
|
4648
4758
|
_sendRecoveryOtp_decorators = [Remote];
|
|
@@ -4655,6 +4765,7 @@ let AwikiService = (() => {
|
|
|
4655
4765
|
_resolvePeer_decorators = [Remote];
|
|
4656
4766
|
_createGroup_decorators = [Remote];
|
|
4657
4767
|
_getGroup_decorators = [Remote];
|
|
4768
|
+
_repairGroupSecurity_decorators = [Remote];
|
|
4658
4769
|
_joinGroup_decorators = [Remote];
|
|
4659
4770
|
_leaveGroup_decorators = [Remote];
|
|
4660
4771
|
_getDisplayProfiles_decorators = [Remote];
|
|
@@ -5019,6 +5130,28 @@ let AwikiService = (() => {
|
|
|
5019
5130
|
},
|
|
5020
5131
|
metadata: _metadata
|
|
5021
5132
|
}, null, _instanceExtraInitializers);
|
|
5133
|
+
__esDecorate(this, null, _setAvatar_decorators, {
|
|
5134
|
+
kind: "method",
|
|
5135
|
+
name: "setAvatar",
|
|
5136
|
+
static: false,
|
|
5137
|
+
private: false,
|
|
5138
|
+
access: {
|
|
5139
|
+
has: (obj) => "setAvatar" in obj,
|
|
5140
|
+
get: (obj) => obj.setAvatar
|
|
5141
|
+
},
|
|
5142
|
+
metadata: _metadata
|
|
5143
|
+
}, null, _instanceExtraInitializers);
|
|
5144
|
+
__esDecorate(this, null, _clearAvatar_decorators, {
|
|
5145
|
+
kind: "method",
|
|
5146
|
+
name: "clearAvatar",
|
|
5147
|
+
static: false,
|
|
5148
|
+
private: false,
|
|
5149
|
+
access: {
|
|
5150
|
+
has: (obj) => "clearAvatar" in obj,
|
|
5151
|
+
get: (obj) => obj.clearAvatar
|
|
5152
|
+
},
|
|
5153
|
+
metadata: _metadata
|
|
5154
|
+
}, null, _instanceExtraInitializers);
|
|
5022
5155
|
__esDecorate(this, null, _getProfile_decorators, {
|
|
5023
5156
|
kind: "method",
|
|
5024
5157
|
name: "getProfile",
|
|
@@ -5151,6 +5284,17 @@ let AwikiService = (() => {
|
|
|
5151
5284
|
},
|
|
5152
5285
|
metadata: _metadata
|
|
5153
5286
|
}, null, _instanceExtraInitializers);
|
|
5287
|
+
__esDecorate(this, null, _repairGroupSecurity_decorators, {
|
|
5288
|
+
kind: "method",
|
|
5289
|
+
name: "repairGroupSecurity",
|
|
5290
|
+
static: false,
|
|
5291
|
+
private: false,
|
|
5292
|
+
access: {
|
|
5293
|
+
has: (obj) => "repairGroupSecurity" in obj,
|
|
5294
|
+
get: (obj) => obj.repairGroupSecurity
|
|
5295
|
+
},
|
|
5296
|
+
metadata: _metadata
|
|
5297
|
+
}, null, _instanceExtraInitializers);
|
|
5154
5298
|
__esDecorate(this, null, _joinGroup_decorators, {
|
|
5155
5299
|
kind: "method",
|
|
5156
5300
|
name: "joinGroup",
|
|
@@ -5773,6 +5917,11 @@ let AwikiService = (() => {
|
|
|
5773
5917
|
let committed = false;
|
|
5774
5918
|
try {
|
|
5775
5919
|
await this.sessionMutation;
|
|
5920
|
+
await this.sessionStore.signOut();
|
|
5921
|
+
this.signedOut = true;
|
|
5922
|
+
this.sessionRevision += 1;
|
|
5923
|
+
this.activeIdentityDid = void 0;
|
|
5924
|
+
await new AwikiSessionStore(registry.stateRoot(target)).signOut();
|
|
5776
5925
|
this.invalidateSummaries();
|
|
5777
5926
|
for (const participant of this.tenantParticipants) {
|
|
5778
5927
|
await participant.prepareSwitch(context);
|
|
@@ -5781,7 +5930,10 @@ let AwikiService = (() => {
|
|
|
5781
5930
|
await this.disposeProvider(previousProvider);
|
|
5782
5931
|
const targetProvider = this.openTenantProvider(target, factory, false);
|
|
5783
5932
|
targetOpened = true;
|
|
5784
|
-
await targetProvider.client.getIdentity()
|
|
5933
|
+
if (await targetProvider.client.getIdentity() === null) {
|
|
5934
|
+
await this.sessionStore.signIn();
|
|
5935
|
+
this.signedOut = false;
|
|
5936
|
+
}
|
|
5785
5937
|
await Promise.all([this.discoverTenantCapabilities(3e3), this.refreshUpdatePolicy()]);
|
|
5786
5938
|
registry.commitActive(target.tenantId);
|
|
5787
5939
|
committed = true;
|
|
@@ -5877,6 +6029,7 @@ let AwikiService = (() => {
|
|
|
5877
6029
|
handleRecoveryPhoneEnabled: capabilities.handleRecoveryPhoneEnabled,
|
|
5878
6030
|
...capabilities.guestGatewayBaseUrl === void 0 ? {} : { integrationGuideUrl: new URL("/guest/guide/integration", capabilities.guestGatewayBaseUrl).toString() },
|
|
5879
6031
|
tenantId: capabilities.tenantId,
|
|
6032
|
+
tenantStorageScopeId: this.activeTenant?.storageScopeId,
|
|
5880
6033
|
tenantGeneration: capabilities.generation,
|
|
5881
6034
|
tenantOnline: capabilities.online,
|
|
5882
6035
|
services: {
|
|
@@ -6031,12 +6184,6 @@ let AwikiService = (() => {
|
|
|
6031
6184
|
ok: true,
|
|
6032
6185
|
value: { status: "signed-out" }
|
|
6033
6186
|
};
|
|
6034
|
-
const identity = await this.run((client) => client.getIdentity(), { allowSignedOut: true });
|
|
6035
|
-
if (!identity.ok) return identity;
|
|
6036
|
-
if (identity.value === null) return {
|
|
6037
|
-
ok: false,
|
|
6038
|
-
error: failure("not-registered")
|
|
6039
|
-
};
|
|
6040
6187
|
try {
|
|
6041
6188
|
await this.sessionStore.signOut();
|
|
6042
6189
|
this.signedOut = true;
|
|
@@ -6598,6 +6745,22 @@ let AwikiService = (() => {
|
|
|
6598
6745
|
if (result.ok) this.activeIdentityDid = result.value.did;
|
|
6599
6746
|
return result;
|
|
6600
6747
|
}
|
|
6748
|
+
/** Replace only the current authenticated human account's avatar. */
|
|
6749
|
+
setAvatar(request) {
|
|
6750
|
+
if (!validAvatarRequest(request, true)) return Promise.resolve({
|
|
6751
|
+
ok: false,
|
|
6752
|
+
error: failure("invalid-request")
|
|
6753
|
+
});
|
|
6754
|
+
return this.run((client) => client.setAvatar(request));
|
|
6755
|
+
}
|
|
6756
|
+
/** Restore the current account's default character avatar. */
|
|
6757
|
+
clearAvatar(request) {
|
|
6758
|
+
if (!validAvatarRequest(request, false)) return Promise.resolve({
|
|
6759
|
+
ok: false,
|
|
6760
|
+
error: failure("invalid-request")
|
|
6761
|
+
});
|
|
6762
|
+
return this.run((client) => client.clearAvatar(request));
|
|
6763
|
+
}
|
|
6601
6764
|
/** Return the public editable profile for the active identity. */
|
|
6602
6765
|
getProfile() {
|
|
6603
6766
|
return this.run((client) => client.getProfile());
|
|
@@ -6711,7 +6874,7 @@ let AwikiService = (() => {
|
|
|
6711
6874
|
ok: false,
|
|
6712
6875
|
error: failure("invalid-request")
|
|
6713
6876
|
};
|
|
6714
|
-
const created = await this.run((client) => client.createGroup(normalized.name));
|
|
6877
|
+
const created = await this.run((client) => client.createGroup(normalized.name, normalized.encrypted, normalized.operationId));
|
|
6715
6878
|
if (!created.ok) return created;
|
|
6716
6879
|
const addedMembers = [];
|
|
6717
6880
|
const failedMembers = [];
|
|
@@ -6741,6 +6904,15 @@ let AwikiService = (() => {
|
|
|
6741
6904
|
});
|
|
6742
6905
|
return this.run((client) => client.getGroup(groupDid));
|
|
6743
6906
|
}
|
|
6907
|
+
/** Resume owner-held group encryption maintenance through Core. */
|
|
6908
|
+
repairGroupSecurity(request) {
|
|
6909
|
+
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
6910
|
+
if (groupDid === void 0) return Promise.resolve({
|
|
6911
|
+
ok: false,
|
|
6912
|
+
error: failure("invalid-request")
|
|
6913
|
+
});
|
|
6914
|
+
return this.run((client) => client.repairGroupSecurity(groupDid));
|
|
6915
|
+
}
|
|
6744
6916
|
/** Join one open group and return its authoritative membership state. */
|
|
6745
6917
|
joinGroup(request) {
|
|
6746
6918
|
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
@@ -6764,12 +6936,12 @@ let AwikiService = (() => {
|
|
|
6764
6936
|
} : result;
|
|
6765
6937
|
}
|
|
6766
6938
|
/** Read one authoritative versioned member page. */
|
|
6767
|
-
getDisplayProfiles(peers) {
|
|
6768
|
-
if (!Array.isArray(peers) || peers.length > 100 || peers.some((peer) => typeof peer !== "string" || !peer.startsWith("did:"))) return Promise.resolve({
|
|
6939
|
+
getDisplayProfiles(peers, refresh) {
|
|
6940
|
+
if (refresh !== void 0 && typeof refresh !== "boolean" || !Array.isArray(peers) || peers.length > 100 || peers.some((peer) => typeof peer !== "string" || !peer.startsWith("did:"))) return Promise.resolve({
|
|
6769
6941
|
ok: false,
|
|
6770
6942
|
error: failure("invalid-request")
|
|
6771
6943
|
});
|
|
6772
|
-
return this.run((client) => client.getDisplayProfiles(peers));
|
|
6944
|
+
return this.run((client) => client.getDisplayProfiles(peers, refresh));
|
|
6773
6945
|
}
|
|
6774
6946
|
listGroupMembers(request) {
|
|
6775
6947
|
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
@@ -6968,6 +7140,10 @@ let AwikiService = (() => {
|
|
|
6968
7140
|
* @returns The accepted attachment message or a closed failure.
|
|
6969
7141
|
*/
|
|
6970
7142
|
async sendAttachment(request) {
|
|
7143
|
+
if (request?.security !== void 0 && request.security !== "plain" && request.security !== "e2ee-required") return {
|
|
7144
|
+
ok: false,
|
|
7145
|
+
error: failure("invalid-request")
|
|
7146
|
+
};
|
|
6971
7147
|
if (!isMessageTarget(request?.target)) return {
|
|
6972
7148
|
ok: false,
|
|
6973
7149
|
error: failure("invalid-request")
|
|
@@ -6976,6 +7152,7 @@ let AwikiService = (() => {
|
|
|
6976
7152
|
if (!decoded.ok) return decoded;
|
|
6977
7153
|
return this.run(async (client) => {
|
|
6978
7154
|
const message = await client.sendAttachment({
|
|
7155
|
+
...request.security === void 0 ? {} : { security: request.security },
|
|
6979
7156
|
target: request.target,
|
|
6980
7157
|
attachment: {
|
|
6981
7158
|
fileName: request.fileName,
|