@awiki/dsh-plugin 0.2.5 → 0.3.0-rc.2
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 +69 -28
- package/README.zh.md +60 -21
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/cordis.patch.yml +0 -8
- package/lib/client.js +6755 -2022
- package/lib/client.js.map +1 -1
- package/lib/index.js +1321 -72
- package/lib/model-proxy-contract.js +8 -1
- package/lib/provider.js +3 -1
- package/lib/{sdk-adapter-DKgkyApB.mjs → sdk-adapter-BIbsJmRj.mjs} +245 -4
- package/lib/typert.host.js +944 -57
- package/lib/typert.remote-client.d.ts +37 -1
- package/lib/typert.remote-client.d.ts.map +1 -1
- package/lib/typert.remote-client.js +944 -57
- package/lib/types/client/AwikiGroupAccessNotice.d.ts +12 -0
- package/lib/types/client/AwikiGroupAccessNotice.d.ts.map +1 -0
- package/lib/types/client/AwikiGroupAccessNotice.js +31 -0
- package/lib/types/client/AwikiGroupAccessNotice.js.map +1 -0
- package/lib/types/client/AwikiGroupDetails.d.ts +23 -0
- package/lib/types/client/AwikiGroupDetails.d.ts.map +1 -0
- package/lib/types/client/AwikiGroupDetails.js +144 -0
- package/lib/types/client/AwikiGroupDetails.js.map +1 -0
- package/lib/types/client/AwikiIdentityAccess.d.ts +22 -0
- package/lib/types/client/AwikiIdentityAccess.d.ts.map +1 -0
- package/lib/types/client/AwikiIdentityAccess.js +156 -0
- package/lib/types/client/AwikiIdentityAccess.js.map +1 -0
- package/lib/types/client/AwikiIdentityPage.d.ts +11 -0
- package/lib/types/client/AwikiIdentityPage.d.ts.map +1 -0
- package/lib/types/client/AwikiIdentityPage.js +8 -0
- package/lib/types/client/AwikiIdentityPage.js.map +1 -0
- package/lib/types/client/AwikiMail.d.ts +2 -1
- package/lib/types/client/AwikiMail.d.ts.map +1 -1
- package/lib/types/client/AwikiMail.js +157 -33
- package/lib/types/client/AwikiMail.js.map +1 -1
- package/lib/types/client/AwikiOnboarding.d.ts.map +1 -1
- package/lib/types/client/AwikiOnboarding.js +29 -9
- package/lib/types/client/AwikiOnboarding.js.map +1 -1
- package/lib/types/client/AwikiOverlay.d.ts +0 -5
- package/lib/types/client/AwikiOverlay.d.ts.map +1 -1
- package/lib/types/client/AwikiOverlay.js +202 -129
- package/lib/types/client/AwikiOverlay.js.map +1 -1
- package/lib/types/client/AwikiProfileCard.d.ts +9 -0
- package/lib/types/client/AwikiProfileCard.d.ts.map +1 -0
- package/lib/types/client/AwikiProfileCard.js +90 -0
- package/lib/types/client/AwikiProfileCard.js.map +1 -0
- package/lib/types/client/AwikiRecoveryForm.d.ts +27 -0
- package/lib/types/client/AwikiRecoveryForm.d.ts.map +1 -0
- package/lib/types/client/AwikiRecoveryForm.js +152 -0
- package/lib/types/client/AwikiRecoveryForm.js.map +1 -0
- package/lib/types/client/AwikiSettingsSection.d.ts +0 -2
- package/lib/types/client/AwikiSettingsSection.d.ts.map +1 -1
- package/lib/types/client/AwikiSettingsSection.js +18 -16
- package/lib/types/client/AwikiSettingsSection.js.map +1 -1
- package/lib/types/client/MentionText.d.ts +7 -0
- package/lib/types/client/MentionText.d.ts.map +1 -0
- package/lib/types/client/MentionText.js +10 -0
- package/lib/types/client/MentionText.js.map +1 -0
- package/lib/types/client/controller.d.ts +131 -3
- package/lib/types/client/controller.d.ts.map +1 -1
- package/lib/types/client/controller.js +908 -29
- 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 +24 -4
- package/lib/types/client/index.js.map +1 -1
- package/lib/types/client/mail-list-cache.d.ts +15 -0
- package/lib/types/client/mail-list-cache.d.ts.map +1 -0
- package/lib/types/client/mail-list-cache.js +212 -0
- package/lib/types/client/mail-list-cache.js.map +1 -0
- package/lib/types/client/mentions.d.ts +51 -0
- package/lib/types/client/mentions.d.ts.map +1 -0
- package/lib/types/client/mentions.js +165 -0
- package/lib/types/client/mentions.js.map +1 -0
- package/lib/types/client/model-proxy-controller.d.ts +4 -0
- package/lib/types/client/model-proxy-controller.d.ts.map +1 -1
- package/lib/types/client/model-proxy-controller.js +68 -3
- package/lib/types/client/model-proxy-controller.js.map +1 -1
- package/lib/types/client/recharge-availability.d.ts +1 -1
- package/lib/types/client/recharge-availability.d.ts.map +1 -1
- package/lib/types/client/recharge-availability.js +1 -1
- package/lib/types/client/recharge-availability.js.map +1 -1
- 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 +14 -8
- package/lib/types/client/settings-locales.js.map +1 -1
- package/lib/types/client/slots.d.ts +27 -2
- package/lib/types/client/slots.d.ts.map +1 -1
- package/lib/types/conversation-preferences.d.ts +20 -0
- package/lib/types/conversation-preferences.d.ts.map +1 -0
- package/lib/types/conversation-preferences.js +294 -0
- package/lib/types/conversation-preferences.js.map +1 -0
- package/lib/types/index.d.ts +45 -6
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +562 -23
- package/lib/types/index.js.map +1 -1
- package/lib/types/model-proxy-contract.d.ts +6 -0
- package/lib/types/model-proxy-contract.d.ts.map +1 -1
- package/lib/types/model-proxy-contract.js +6 -0
- package/lib/types/model-proxy-contract.js.map +1 -1
- package/lib/types/provider-api.d.ts +29 -1
- package/lib/types/provider-api.d.ts.map +1 -1
- package/lib/types/provider.d.ts.map +1 -1
- package/lib/types/provider.js +2 -0
- package/lib/types/provider.js.map +1 -1
- package/lib/types/sdk-adapter.d.ts +18 -1
- package/lib/types/sdk-adapter.d.ts.map +1 -1
- package/lib/types/sdk-adapter.js +277 -4
- package/lib/types/sdk-adapter.js.map +1 -1
- package/lib/types/sent-mail-store.d.ts +22 -0
- package/lib/types/sent-mail-store.d.ts.map +1 -0
- package/lib/types/sent-mail-store.js +246 -0
- package/lib/types/sent-mail-store.js.map +1 -0
- package/lib/types/types.d.ts +183 -2
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/types.js.map +1 -1
- package/package.json +15 -26
- package/lib/model-proxy.js +0 -383
- package/lib/types/client/model-account-settings-availability.d.ts +0 -4
- package/lib/types/client/model-account-settings-availability.d.ts.map +0 -1
- package/lib/types/client/model-account-settings-availability.js +0 -4
- package/lib/types/client/model-account-settings-availability.js.map +0 -1
- package/lib/types/model-proxy.d.ts +0 -14
- package/lib/types/model-proxy.d.ts.map +0 -1
- package/lib/types/model-proxy.js +0 -371
- package/lib/types/model-proxy.js.map +0 -1
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as downloadedAttachment } from "./sdk-adapter-
|
|
1
|
+
import { n as downloadedAttachment } from "./sdk-adapter-BIbsJmRj.mjs";
|
|
2
2
|
import "@deepseek-ai/cordis";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { isAbsolute, join } from "node:path";
|
|
@@ -592,15 +592,15 @@ const AWIKI_SETTINGS_RPC_ENDPOINTS = {
|
|
|
592
592
|
//#endregion
|
|
593
593
|
//#region lib/types/settings-rpc.js
|
|
594
594
|
/** Loopback-only Host transport for AWiki's durable plugin settings. */
|
|
595
|
-
function isRecord$
|
|
595
|
+
function isRecord$2(value) {
|
|
596
596
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
597
597
|
}
|
|
598
598
|
function expectedRevision(payload) {
|
|
599
|
-
if (!isRecord$
|
|
599
|
+
if (!isRecord$2(payload) || !Number.isSafeInteger(payload.expectedRevision) || payload.expectedRevision < 0) return;
|
|
600
600
|
return payload.expectedRevision;
|
|
601
601
|
}
|
|
602
602
|
function sanitizeLayer(value) {
|
|
603
|
-
if (!isRecord$
|
|
603
|
+
if (!isRecord$2(value)) return void 0;
|
|
604
604
|
if (!Object.hasOwn(value, "domain")) return {};
|
|
605
605
|
if (typeof value["domain"] !== "string") return void 0;
|
|
606
606
|
const domain = normalizeAwikiDomain(value[AWIKI_DOMAIN_FIELD]);
|
|
@@ -609,7 +609,7 @@ function sanitizeLayer(value) {
|
|
|
609
609
|
}
|
|
610
610
|
function view(provider) {
|
|
611
611
|
const descriptor = provider.describe({ redactSecrets: true }).find((candidate) => candidate.ns === AWIKI_SETTINGS_NAMESPACE);
|
|
612
|
-
if (descriptor === void 0 || !isRecord$
|
|
612
|
+
if (descriptor === void 0 || !isRecord$2(descriptor.value) || typeof descriptor.value.domain !== "string") return;
|
|
613
613
|
const domain = normalizeAwikiDomain(descriptor.value.domain);
|
|
614
614
|
if (domain !== descriptor.value.domain) return void 0;
|
|
615
615
|
const base = descriptor.base === void 0 ? void 0 : sanitizeLayer(descriptor.base);
|
|
@@ -660,7 +660,7 @@ function createAwikiSettingsRpcHandler(getProvider) {
|
|
|
660
660
|
const provider = getProvider();
|
|
661
661
|
if (provider === void 0) return unavailable();
|
|
662
662
|
if (endpoint === AWIKI_SETTINGS_RPC_ENDPOINTS.describe) {
|
|
663
|
-
if (!isRecord$
|
|
663
|
+
if (!isRecord$2(payload)) return badRequest();
|
|
664
664
|
const current = view(provider);
|
|
665
665
|
return current === void 0 ? unavailable() : {
|
|
666
666
|
ok: true,
|
|
@@ -671,7 +671,7 @@ function createAwikiSettingsRpcHandler(getProvider) {
|
|
|
671
671
|
if (revision === void 0) return badRequest();
|
|
672
672
|
let operation;
|
|
673
673
|
if (endpoint === AWIKI_SETTINGS_RPC_ENDPOINTS.setDomain) {
|
|
674
|
-
if (!isRecord$
|
|
674
|
+
if (!isRecord$2(payload) || typeof payload.domain !== "string") return badRequest();
|
|
675
675
|
let domain;
|
|
676
676
|
try {
|
|
677
677
|
domain = normalizeAwikiDomain(payload.domain);
|
|
@@ -740,7 +740,7 @@ var AwikiSessionStore = class {
|
|
|
740
740
|
if (await readFile(this.markerPath, "utf8") !== SIGNED_OUT_MARKER) throw new TypeError("awiki: local session marker is invalid");
|
|
741
741
|
return true;
|
|
742
742
|
} catch (error) {
|
|
743
|
-
if (isMissing$
|
|
743
|
+
if (isMissing$4(error)) return false;
|
|
744
744
|
throw error;
|
|
745
745
|
}
|
|
746
746
|
}
|
|
@@ -758,7 +758,7 @@ var AwikiSessionStore = class {
|
|
|
758
758
|
mode: 384
|
|
759
759
|
});
|
|
760
760
|
} catch (error) {
|
|
761
|
-
if (!isFileExists$
|
|
761
|
+
if (!isFileExists$3(error) || !await this.isSignedOut()) throw error;
|
|
762
762
|
}
|
|
763
763
|
await chmod(this.markerPath, 384);
|
|
764
764
|
}
|
|
@@ -767,7 +767,7 @@ var AwikiSessionStore = class {
|
|
|
767
767
|
try {
|
|
768
768
|
await unlink(this.markerPath);
|
|
769
769
|
} catch (error) {
|
|
770
|
-
if (!isMissing$
|
|
770
|
+
if (!isMissing$4(error)) throw error;
|
|
771
771
|
}
|
|
772
772
|
}
|
|
773
773
|
async hasPrivateHostDirectory() {
|
|
@@ -776,15 +776,15 @@ var AwikiSessionStore = class {
|
|
|
776
776
|
if (!directory.isDirectory() || directory.isSymbolicLink()) throw new TypeError("awiki: local session directory is invalid");
|
|
777
777
|
return true;
|
|
778
778
|
} catch (error) {
|
|
779
|
-
if (isMissing$
|
|
779
|
+
if (isMissing$4(error)) return false;
|
|
780
780
|
throw error;
|
|
781
781
|
}
|
|
782
782
|
}
|
|
783
783
|
};
|
|
784
|
-
function isMissing$
|
|
784
|
+
function isMissing$4(error) {
|
|
785
785
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
786
786
|
}
|
|
787
|
-
function isFileExists$
|
|
787
|
+
function isFileExists$3(error) {
|
|
788
788
|
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
789
789
|
}
|
|
790
790
|
//#endregion
|
|
@@ -877,7 +877,7 @@ var AwikiImageAttachmentCache = class {
|
|
|
877
877
|
force: true
|
|
878
878
|
});
|
|
879
879
|
} catch (error) {
|
|
880
|
-
if (!isMissing$
|
|
880
|
+
if (!isMissing$3(error)) throw error;
|
|
881
881
|
}
|
|
882
882
|
}
|
|
883
883
|
decode(input, ownerDid, request) {
|
|
@@ -903,7 +903,7 @@ var AwikiImageAttachmentCache = class {
|
|
|
903
903
|
if (!await this.hasPrivateDirectory(this.hostDirectory)) throw new TypeError("awiki: local Host directory is invalid");
|
|
904
904
|
await chmod(this.hostDirectory, 448);
|
|
905
905
|
await mkdir(this.directory, { mode: 448 }).catch((error) => {
|
|
906
|
-
if (!isFileExists(error)) throw error;
|
|
906
|
+
if (!isFileExists$2(error)) throw error;
|
|
907
907
|
});
|
|
908
908
|
if (!await this.hasPrivateDirectory(this.directory)) throw new TypeError("awiki: local image cache directory is invalid");
|
|
909
909
|
await chmod(this.directory, 448);
|
|
@@ -941,17 +941,511 @@ var AwikiImageAttachmentCache = class {
|
|
|
941
941
|
if (!metadata.isDirectory() || metadata.isSymbolicLink()) throw new TypeError("awiki: local image cache path is invalid");
|
|
942
942
|
return true;
|
|
943
943
|
} catch (error) {
|
|
944
|
-
if (isMissing$
|
|
944
|
+
if (isMissing$3(error)) return false;
|
|
945
|
+
throw error;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
function isMissing$3(error) {
|
|
950
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
951
|
+
}
|
|
952
|
+
function isFileExists$2(error) {
|
|
953
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
954
|
+
}
|
|
955
|
+
//#endregion
|
|
956
|
+
//#region lib/types/sent-mail-store.js
|
|
957
|
+
/** Private, owner-bound persistence for mail successfully sent by this installation. */
|
|
958
|
+
const STORE_VERSION$1 = 1;
|
|
959
|
+
const STORE_DIRECTORY$1 = "sent-mail-v1";
|
|
960
|
+
const MAX_RECORDS = 200;
|
|
961
|
+
const MAX_STORE_BYTES$1 = 16777216;
|
|
962
|
+
const PREVIEW_CHARACTERS = 160;
|
|
963
|
+
const LOCAL_SENT_MAIL_ID_PREFIX = "awiki-sent-v1:";
|
|
964
|
+
function invalidState$1() {
|
|
965
|
+
throw new TypeError("awiki: local sent-mail history is invalid");
|
|
966
|
+
}
|
|
967
|
+
function isMissing$2(error) {
|
|
968
|
+
return typeof error === "object" && error !== null && error.code === "ENOENT";
|
|
969
|
+
}
|
|
970
|
+
function isFileExists$1(error) {
|
|
971
|
+
return typeof error === "object" && error !== null && error.code === "EEXIST";
|
|
972
|
+
}
|
|
973
|
+
function validToken(value, maxCharacters) {
|
|
974
|
+
return typeof value === "string" && value.length > 0 && value.trim() === value && Array.from(value).length <= maxCharacters && !/[\u0000-\u001f\u007f-\u009f]/u.test(value);
|
|
975
|
+
}
|
|
976
|
+
function validAddress(value) {
|
|
977
|
+
return typeof value === "string" && Array.from(value).length >= 3 && Array.from(value).length <= 320 && value.includes("@") && !/[\s\u0000-\u001f\u007f-\u009f]/u.test(value);
|
|
978
|
+
}
|
|
979
|
+
function decodeRecord(input) {
|
|
980
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) invalidState$1();
|
|
981
|
+
const value = input;
|
|
982
|
+
if (typeof value.id !== "string" || !/^awiki-sent-v1:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u.test(value.id) || value.serviceMessageId !== void 0 && !validToken(value.serviceMessageId, 2048) || value.from !== void 0 && !validAddress(value.from) || typeof value.sentAt !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u.test(value.sentAt) || !Number.isFinite(Date.parse(value.sentAt))) invalidState$1();
|
|
983
|
+
let request;
|
|
984
|
+
try {
|
|
985
|
+
request = mailSendRequest({
|
|
986
|
+
to: value.to,
|
|
987
|
+
cc: value.cc,
|
|
988
|
+
subject: value.subject,
|
|
989
|
+
bodyText: value.bodyText
|
|
990
|
+
});
|
|
991
|
+
} catch {
|
|
992
|
+
invalidState$1();
|
|
993
|
+
}
|
|
994
|
+
return {
|
|
995
|
+
id: value.id,
|
|
996
|
+
...value.serviceMessageId === void 0 ? {} : { serviceMessageId: value.serviceMessageId },
|
|
997
|
+
...value.from === void 0 ? {} : { from: value.from },
|
|
998
|
+
to: [...request.to],
|
|
999
|
+
cc: [...request.cc ?? []],
|
|
1000
|
+
subject: request.subject,
|
|
1001
|
+
bodyText: request.bodyText,
|
|
1002
|
+
sentAt: value.sentAt
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
function message(record) {
|
|
1006
|
+
const characters = Array.from(record.bodyText);
|
|
1007
|
+
const preview = characters.slice(0, PREVIEW_CHARACTERS).join("");
|
|
1008
|
+
return {
|
|
1009
|
+
summary: {
|
|
1010
|
+
id: record.id,
|
|
1011
|
+
folder: "sent",
|
|
1012
|
+
from: record.from === void 0 ? [] : [record.from],
|
|
1013
|
+
to: [...record.to],
|
|
1014
|
+
cc: [...record.cc],
|
|
1015
|
+
subject: record.subject,
|
|
1016
|
+
subjectTruncated: false,
|
|
1017
|
+
preview,
|
|
1018
|
+
previewTruncated: characters.length > PREVIEW_CHARACTERS,
|
|
1019
|
+
sentAt: record.sentAt,
|
|
1020
|
+
unread: false,
|
|
1021
|
+
hasAttachments: false,
|
|
1022
|
+
attachmentCount: 0
|
|
1023
|
+
},
|
|
1024
|
+
bodyText: record.bodyText,
|
|
1025
|
+
bodyTruncated: false,
|
|
1026
|
+
hasHtmlBody: false,
|
|
1027
|
+
attachments: []
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
function isLocalSentMailId(messageId) {
|
|
1031
|
+
return String(messageId).startsWith(LOCAL_SENT_MAIL_ID_PREFIX);
|
|
1032
|
+
}
|
|
1033
|
+
/** Atomic, bounded history of sends accepted by the Mail Service. */
|
|
1034
|
+
var AwikiSentMailStore = class {
|
|
1035
|
+
hostDirectory;
|
|
1036
|
+
directory;
|
|
1037
|
+
mutation = Promise.resolve();
|
|
1038
|
+
constructor(stateRoot) {
|
|
1039
|
+
this.hostDirectory = join(stateRoot, ".host");
|
|
1040
|
+
this.directory = join(this.hostDirectory, STORE_DIRECTORY$1);
|
|
1041
|
+
}
|
|
1042
|
+
async list(ownerDid, request) {
|
|
1043
|
+
const records = request.unreadOnly === true ? [] : await this.load(ownerDid);
|
|
1044
|
+
const offset = request.offset ?? 0;
|
|
1045
|
+
const limit = request.limit ?? 20;
|
|
1046
|
+
const page = records.slice(offset, offset + limit);
|
|
1047
|
+
const nextOffset = offset + page.length;
|
|
1048
|
+
const hasMore = nextOffset < records.length;
|
|
1049
|
+
return {
|
|
1050
|
+
items: page.map((record) => message(record).summary),
|
|
1051
|
+
...hasMore ? { nextOffset } : {},
|
|
1052
|
+
hasMore
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
async read(ownerDid, messageId) {
|
|
1056
|
+
if (!isLocalSentMailId(messageId)) return void 0;
|
|
1057
|
+
const record = (await this.load(ownerDid)).find((candidate) => candidate.id === String(messageId));
|
|
1058
|
+
return record === void 0 ? void 0 : message(record);
|
|
1059
|
+
}
|
|
1060
|
+
append(ownerDid, request, result, account) {
|
|
1061
|
+
const normalized = mailSendRequest(request);
|
|
1062
|
+
const record = {
|
|
1063
|
+
id: `${LOCAL_SENT_MAIL_ID_PREFIX}${randomUUID()}`,
|
|
1064
|
+
...result.messageId === void 0 ? {} : { serviceMessageId: String(result.messageId) },
|
|
1065
|
+
...account?.mailboxAddress === void 0 ? {} : { from: account.mailboxAddress },
|
|
1066
|
+
to: [...normalized.to],
|
|
1067
|
+
cc: [...normalized.cc ?? []],
|
|
1068
|
+
subject: normalized.subject,
|
|
1069
|
+
bodyText: normalized.bodyText,
|
|
1070
|
+
sentAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1071
|
+
};
|
|
1072
|
+
const append = async () => {
|
|
1073
|
+
const records = await this.load(ownerDid);
|
|
1074
|
+
await this.write(ownerDid, [record, ...records].slice(0, MAX_RECORDS));
|
|
1075
|
+
};
|
|
1076
|
+
const pending = this.mutation.then(append, append);
|
|
1077
|
+
this.mutation = pending.catch(() => void 0);
|
|
1078
|
+
return pending;
|
|
1079
|
+
}
|
|
1080
|
+
async clear() {
|
|
1081
|
+
await this.mutation;
|
|
1082
|
+
try {
|
|
1083
|
+
if (!await this.hasDirectory(this.hostDirectory)) return;
|
|
1084
|
+
const metadata = await lstat(this.directory);
|
|
1085
|
+
if (metadata.isSymbolicLink() || !metadata.isDirectory()) {
|
|
1086
|
+
await unlink(this.directory);
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
await rm(this.directory, {
|
|
1090
|
+
recursive: true,
|
|
1091
|
+
force: true
|
|
1092
|
+
});
|
|
1093
|
+
} catch (error) {
|
|
1094
|
+
if (!isMissing$2(error)) throw error;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
async load(ownerDid) {
|
|
1098
|
+
if (!await this.hasDirectory(this.hostDirectory) || !await this.hasDirectory(this.directory)) return [];
|
|
1099
|
+
const path = this.path(ownerDid);
|
|
1100
|
+
let text;
|
|
1101
|
+
try {
|
|
1102
|
+
const metadata = await lstat(path);
|
|
1103
|
+
if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size > MAX_STORE_BYTES$1) invalidState$1();
|
|
1104
|
+
text = await readFile(path, "utf8");
|
|
1105
|
+
} catch (error) {
|
|
1106
|
+
if (isMissing$2(error)) return [];
|
|
1107
|
+
throw error;
|
|
1108
|
+
}
|
|
1109
|
+
let parsed;
|
|
1110
|
+
try {
|
|
1111
|
+
parsed = JSON.parse(text);
|
|
1112
|
+
} catch {
|
|
1113
|
+
invalidState$1();
|
|
1114
|
+
}
|
|
1115
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) invalidState$1();
|
|
1116
|
+
const value = parsed;
|
|
1117
|
+
if (value.version !== STORE_VERSION$1 || value.ownerDid !== String(ownerDid) || !Array.isArray(value.records) || value.records.length > MAX_RECORDS) invalidState$1();
|
|
1118
|
+
return value.records.map(decodeRecord);
|
|
1119
|
+
}
|
|
1120
|
+
async write(ownerDid, records) {
|
|
1121
|
+
await this.ensureDirectory();
|
|
1122
|
+
const path = this.path(ownerDid);
|
|
1123
|
+
const temporary = join(this.directory, `.${this.key(ownerDid)}.${randomUUID()}.tmp`);
|
|
1124
|
+
const text = JSON.stringify({
|
|
1125
|
+
version: STORE_VERSION$1,
|
|
1126
|
+
ownerDid: String(ownerDid),
|
|
1127
|
+
records
|
|
1128
|
+
});
|
|
1129
|
+
if (Buffer.byteLength(text, "utf8") > MAX_STORE_BYTES$1) invalidState$1();
|
|
1130
|
+
try {
|
|
1131
|
+
await writeFile(temporary, text, {
|
|
1132
|
+
flag: "wx",
|
|
1133
|
+
mode: 384
|
|
1134
|
+
});
|
|
1135
|
+
await rename(temporary, path);
|
|
1136
|
+
await chmod(path, 384);
|
|
1137
|
+
} finally {
|
|
1138
|
+
await unlink(temporary).catch(() => void 0);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
async ensureDirectory() {
|
|
1142
|
+
await mkdir(this.hostDirectory, {
|
|
1143
|
+
recursive: true,
|
|
1144
|
+
mode: 448
|
|
1145
|
+
});
|
|
1146
|
+
if (!await this.hasDirectory(this.hostDirectory)) invalidState$1();
|
|
1147
|
+
await chmod(this.hostDirectory, 448);
|
|
1148
|
+
await mkdir(this.directory, { mode: 448 }).catch((error) => {
|
|
1149
|
+
if (!isFileExists$1(error)) throw error;
|
|
1150
|
+
});
|
|
1151
|
+
if (!await this.hasDirectory(this.directory)) invalidState$1();
|
|
1152
|
+
await chmod(this.directory, 448);
|
|
1153
|
+
}
|
|
1154
|
+
async hasDirectory(path) {
|
|
1155
|
+
try {
|
|
1156
|
+
const metadata = await lstat(path);
|
|
1157
|
+
if (!metadata.isDirectory() || metadata.isSymbolicLink()) invalidState$1();
|
|
1158
|
+
return true;
|
|
1159
|
+
} catch (error) {
|
|
1160
|
+
if (isMissing$2(error)) return false;
|
|
945
1161
|
throw error;
|
|
946
1162
|
}
|
|
947
1163
|
}
|
|
1164
|
+
path(ownerDid) {
|
|
1165
|
+
return join(this.directory, `${this.key(ownerDid)}.json`);
|
|
1166
|
+
}
|
|
1167
|
+
key(ownerDid) {
|
|
1168
|
+
return createHash("sha256").update(String(ownerDid)).digest("hex");
|
|
1169
|
+
}
|
|
948
1170
|
};
|
|
1171
|
+
//#endregion
|
|
1172
|
+
//#region lib/types/conversation-preferences.js
|
|
1173
|
+
const STORE_VERSION = 1;
|
|
1174
|
+
const STORE_DIRECTORY = "conversation-preferences";
|
|
1175
|
+
const MAX_STORE_BYTES = 2097152;
|
|
1176
|
+
const MAX_HIDDEN_CONVERSATIONS = 500;
|
|
1177
|
+
const MAX_IDENTIFIER_CHARACTERS = 2048;
|
|
1178
|
+
const MAX_TITLE_CHARACTERS = 1024;
|
|
1179
|
+
const MAX_PREVIEW_CHARACTERS = 4096;
|
|
1180
|
+
const MAX_HANDLE_CHARACTERS = 512;
|
|
1181
|
+
const MAX_RECOVERY_SIGNATURE_CHARACTERS = 128;
|
|
1182
|
+
function invalidState() {
|
|
1183
|
+
throw new TypeError("awiki: conversation preferences are invalid");
|
|
1184
|
+
}
|
|
949
1185
|
function isMissing$1(error) {
|
|
950
1186
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
951
1187
|
}
|
|
952
1188
|
function isFileExists(error) {
|
|
953
1189
|
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
954
1190
|
}
|
|
1191
|
+
function isRecord$1(value) {
|
|
1192
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1193
|
+
}
|
|
1194
|
+
function boundedString$1(value, maximum) {
|
|
1195
|
+
if (typeof value !== "string" || value.length === 0 || value.length > maximum * 2) invalidState();
|
|
1196
|
+
if (Array.from(value).length > maximum) invalidState();
|
|
1197
|
+
return value;
|
|
1198
|
+
}
|
|
1199
|
+
function optionalString(value, maximum) {
|
|
1200
|
+
return value === void 0 ? void 0 : boundedString$1(value, maximum);
|
|
1201
|
+
}
|
|
1202
|
+
function optionalCount(value) {
|
|
1203
|
+
if (value === void 0) return void 0;
|
|
1204
|
+
if (!Number.isSafeInteger(value) || value < 0 || value > 4294967295) invalidState();
|
|
1205
|
+
return value;
|
|
1206
|
+
}
|
|
1207
|
+
function optionalTimestamp(value) {
|
|
1208
|
+
if (value === void 0) return void 0;
|
|
1209
|
+
if (!Number.isSafeInteger(value) || value < 0) invalidState();
|
|
1210
|
+
return value;
|
|
1211
|
+
}
|
|
1212
|
+
/** Rebuild a bounded display-only snapshot before it reaches private persistence. */
|
|
1213
|
+
function conversation(value) {
|
|
1214
|
+
if (!isRecord$1(value)) invalidState();
|
|
1215
|
+
const kind = value.kind;
|
|
1216
|
+
const id = boundedString$1(value.id, MAX_IDENTIFIER_CHARACTERS);
|
|
1217
|
+
const title = boundedString$1(value.title, MAX_TITLE_CHARACTERS);
|
|
1218
|
+
const unreadCount = optionalCount(value.unreadCount);
|
|
1219
|
+
const lastMessageAt = optionalTimestamp(value.lastMessageAt);
|
|
1220
|
+
const lastMessagePreview = optionalString(value.lastMessagePreview, MAX_PREVIEW_CHARACTERS);
|
|
1221
|
+
const common = {
|
|
1222
|
+
id,
|
|
1223
|
+
title,
|
|
1224
|
+
...unreadCount === void 0 ? {} : { unreadCount },
|
|
1225
|
+
...lastMessageAt === void 0 ? {} : { lastMessageAt },
|
|
1226
|
+
...lastMessagePreview === void 0 ? {} : { lastMessagePreview }
|
|
1227
|
+
};
|
|
1228
|
+
if (kind === "direct") {
|
|
1229
|
+
const peerDid = boundedString$1(value.peerDid, MAX_IDENTIFIER_CHARACTERS);
|
|
1230
|
+
if (!peerDid.startsWith("did:")) invalidState();
|
|
1231
|
+
const peerHandle = optionalString(value.peerHandle, MAX_HANDLE_CHARACTERS);
|
|
1232
|
+
const displayName = optionalString(value.displayName, MAX_TITLE_CHARACTERS);
|
|
1233
|
+
return {
|
|
1234
|
+
kind,
|
|
1235
|
+
...common,
|
|
1236
|
+
peerDid,
|
|
1237
|
+
...peerHandle === void 0 ? {} : { peerHandle },
|
|
1238
|
+
...displayName === void 0 ? {} : { displayName }
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1241
|
+
if (kind === "group") {
|
|
1242
|
+
const groupDid = boundedString$1(value.groupDid, MAX_IDENTIFIER_CHARACTERS);
|
|
1243
|
+
if (!groupDid.startsWith("did:")) invalidState();
|
|
1244
|
+
return {
|
|
1245
|
+
kind,
|
|
1246
|
+
...common,
|
|
1247
|
+
groupDid
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
invalidState();
|
|
1251
|
+
}
|
|
1252
|
+
function hiddenPreference(value) {
|
|
1253
|
+
if (!isRecord$1(value) || !Number.isSafeInteger(value.hiddenAt) || value.hiddenAt < 0) invalidState();
|
|
1254
|
+
return {
|
|
1255
|
+
conversation: conversation(value.conversation),
|
|
1256
|
+
hiddenAt: value.hiddenAt
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
function preferences(value, expectedOwnerDid) {
|
|
1260
|
+
if (!isRecord$1(value) || value.version !== STORE_VERSION || value.ownerDid !== String(expectedOwnerDid) || !Array.isArray(value.hiddenConversations) || value.hiddenConversations.length > MAX_HIDDEN_CONVERSATIONS) invalidState();
|
|
1261
|
+
const hiddenConversations = value.hiddenConversations.map(hiddenPreference);
|
|
1262
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1263
|
+
for (const hidden of hiddenConversations) {
|
|
1264
|
+
if (seen.has(hidden.conversation.id)) invalidState();
|
|
1265
|
+
seen.add(hidden.conversation.id);
|
|
1266
|
+
}
|
|
1267
|
+
const dismissedGroupRecoverySignature = optionalString(value.dismissedGroupRecoverySignature, MAX_RECOVERY_SIGNATURE_CHARACTERS);
|
|
1268
|
+
return {
|
|
1269
|
+
version: STORE_VERSION,
|
|
1270
|
+
ownerDid: String(expectedOwnerDid),
|
|
1271
|
+
hiddenConversations,
|
|
1272
|
+
...dismissedGroupRecoverySignature === void 0 ? {} : { dismissedGroupRecoverySignature }
|
|
1273
|
+
};
|
|
1274
|
+
}
|
|
1275
|
+
function publicPreferences(value) {
|
|
1276
|
+
return {
|
|
1277
|
+
hiddenConversations: value.hiddenConversations.map((hidden) => ({
|
|
1278
|
+
conversation: { ...hidden.conversation },
|
|
1279
|
+
hiddenAt: hidden.hiddenAt
|
|
1280
|
+
})),
|
|
1281
|
+
...value.dismissedGroupRecoverySignature === void 0 ? {} : { dismissedGroupRecoverySignature: value.dismissedGroupRecoverySignature }
|
|
1282
|
+
};
|
|
1283
|
+
}
|
|
1284
|
+
function emptyPreferences(ownerDid) {
|
|
1285
|
+
return {
|
|
1286
|
+
version: STORE_VERSION,
|
|
1287
|
+
ownerDid: String(ownerDid),
|
|
1288
|
+
hiddenConversations: []
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
/** Validate one browser mutation before entering private Host persistence. */
|
|
1292
|
+
function normalizeConversationPreferenceMutation(value) {
|
|
1293
|
+
try {
|
|
1294
|
+
if (!isRecord$1(value)) return void 0;
|
|
1295
|
+
if (value.action === "hide") return {
|
|
1296
|
+
action: "hide",
|
|
1297
|
+
conversation: conversation(value.conversation)
|
|
1298
|
+
};
|
|
1299
|
+
if (value.action === "restore") return {
|
|
1300
|
+
action: "restore",
|
|
1301
|
+
conversationId: boundedString$1(value.conversationId, MAX_IDENTIFIER_CHARACTERS)
|
|
1302
|
+
};
|
|
1303
|
+
if (value.action === "dismiss-group-recovery") return {
|
|
1304
|
+
action: "dismiss-group-recovery",
|
|
1305
|
+
signature: boundedString$1(value.signature, MAX_RECOVERY_SIGNATURE_CHARACTERS)
|
|
1306
|
+
};
|
|
1307
|
+
} catch {
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
/** Atomic identity-scoped product preferences, independent of Core membership and history. */
|
|
1312
|
+
var AwikiConversationPreferenceStore = class {
|
|
1313
|
+
hostDirectory;
|
|
1314
|
+
directory;
|
|
1315
|
+
mutation = Promise.resolve();
|
|
1316
|
+
constructor(stateRoot) {
|
|
1317
|
+
this.hostDirectory = join(stateRoot, ".host");
|
|
1318
|
+
this.directory = join(this.hostDirectory, STORE_DIRECTORY);
|
|
1319
|
+
}
|
|
1320
|
+
async get(ownerDid) {
|
|
1321
|
+
await this.mutation;
|
|
1322
|
+
return publicPreferences(await this.load(ownerDid));
|
|
1323
|
+
}
|
|
1324
|
+
update(ownerDid, request) {
|
|
1325
|
+
const mutate = async () => {
|
|
1326
|
+
const normalized = normalizeConversationPreferenceMutation(request);
|
|
1327
|
+
if (normalized === void 0) invalidState();
|
|
1328
|
+
const current = await this.load(ownerDid);
|
|
1329
|
+
let next;
|
|
1330
|
+
switch (normalized.action) {
|
|
1331
|
+
case "hide": {
|
|
1332
|
+
const snapshot = normalized.conversation;
|
|
1333
|
+
const hidden = current.hiddenConversations.filter((item) => item.conversation.id !== snapshot.id);
|
|
1334
|
+
hidden.unshift({
|
|
1335
|
+
conversation: snapshot,
|
|
1336
|
+
hiddenAt: Date.now()
|
|
1337
|
+
});
|
|
1338
|
+
next = {
|
|
1339
|
+
...current,
|
|
1340
|
+
hiddenConversations: hidden.slice(0, MAX_HIDDEN_CONVERSATIONS)
|
|
1341
|
+
};
|
|
1342
|
+
break;
|
|
1343
|
+
}
|
|
1344
|
+
case "restore": {
|
|
1345
|
+
const conversationId = normalized.conversationId;
|
|
1346
|
+
next = {
|
|
1347
|
+
...current,
|
|
1348
|
+
hiddenConversations: current.hiddenConversations.filter((item) => item.conversation.id !== conversationId)
|
|
1349
|
+
};
|
|
1350
|
+
break;
|
|
1351
|
+
}
|
|
1352
|
+
case "dismiss-group-recovery": {
|
|
1353
|
+
const signature = normalized.signature;
|
|
1354
|
+
next = {
|
|
1355
|
+
...current,
|
|
1356
|
+
dismissedGroupRecoverySignature: signature
|
|
1357
|
+
};
|
|
1358
|
+
break;
|
|
1359
|
+
}
|
|
1360
|
+
default: invalidState();
|
|
1361
|
+
}
|
|
1362
|
+
await this.write(ownerDid, next);
|
|
1363
|
+
return publicPreferences(next);
|
|
1364
|
+
};
|
|
1365
|
+
const pending = this.mutation.then(mutate, mutate);
|
|
1366
|
+
this.mutation = pending.then(() => void 0, () => void 0);
|
|
1367
|
+
return pending;
|
|
1368
|
+
}
|
|
1369
|
+
async clear() {
|
|
1370
|
+
await this.mutation;
|
|
1371
|
+
try {
|
|
1372
|
+
if (!await this.hasDirectory(this.hostDirectory)) return;
|
|
1373
|
+
const metadata = await lstat(this.directory);
|
|
1374
|
+
if (metadata.isSymbolicLink() || !metadata.isDirectory()) {
|
|
1375
|
+
await unlink(this.directory);
|
|
1376
|
+
return;
|
|
1377
|
+
}
|
|
1378
|
+
await rm(this.directory, {
|
|
1379
|
+
recursive: true,
|
|
1380
|
+
force: true
|
|
1381
|
+
});
|
|
1382
|
+
} catch (error) {
|
|
1383
|
+
if (!isMissing$1(error)) throw error;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
async load(ownerDid) {
|
|
1387
|
+
if (!await this.hasDirectory(this.hostDirectory) || !await this.hasDirectory(this.directory)) return emptyPreferences(ownerDid);
|
|
1388
|
+
const path = this.path(ownerDid);
|
|
1389
|
+
try {
|
|
1390
|
+
const metadata = await lstat(path);
|
|
1391
|
+
if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size > MAX_STORE_BYTES) invalidState();
|
|
1392
|
+
const text = await readFile(path, "utf8");
|
|
1393
|
+
if (Buffer.byteLength(text, "utf8") > MAX_STORE_BYTES) invalidState();
|
|
1394
|
+
return preferences(JSON.parse(text), ownerDid);
|
|
1395
|
+
} catch (error) {
|
|
1396
|
+
if (isMissing$1(error)) return emptyPreferences(ownerDid);
|
|
1397
|
+
if (error instanceof SyntaxError) invalidState();
|
|
1398
|
+
throw error;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
async write(ownerDid, value) {
|
|
1402
|
+
const snapshot = preferences(value, ownerDid);
|
|
1403
|
+
const text = `${JSON.stringify(snapshot)}\n`;
|
|
1404
|
+
if (Buffer.byteLength(text, "utf8") > MAX_STORE_BYTES) invalidState();
|
|
1405
|
+
await this.ensureDirectory();
|
|
1406
|
+
const path = this.path(ownerDid);
|
|
1407
|
+
const temporary = join(this.directory, `.${this.key(ownerDid)}.${randomUUID()}.tmp`);
|
|
1408
|
+
try {
|
|
1409
|
+
await writeFile(temporary, text, {
|
|
1410
|
+
flag: "wx",
|
|
1411
|
+
mode: 384
|
|
1412
|
+
});
|
|
1413
|
+
await rename(temporary, path);
|
|
1414
|
+
await chmod(path, 384);
|
|
1415
|
+
} finally {
|
|
1416
|
+
await unlink(temporary).catch(() => void 0);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
async ensureDirectory() {
|
|
1420
|
+
await mkdir(this.hostDirectory, {
|
|
1421
|
+
recursive: true,
|
|
1422
|
+
mode: 448
|
|
1423
|
+
});
|
|
1424
|
+
if (!await this.hasDirectory(this.hostDirectory)) invalidState();
|
|
1425
|
+
await chmod(this.hostDirectory, 448);
|
|
1426
|
+
await mkdir(this.directory, { mode: 448 }).catch((error) => {
|
|
1427
|
+
if (!isFileExists(error)) throw error;
|
|
1428
|
+
});
|
|
1429
|
+
if (!await this.hasDirectory(this.directory)) invalidState();
|
|
1430
|
+
await chmod(this.directory, 448);
|
|
1431
|
+
}
|
|
1432
|
+
async hasDirectory(path) {
|
|
1433
|
+
try {
|
|
1434
|
+
const metadata = await lstat(path);
|
|
1435
|
+
if (!metadata.isDirectory() || metadata.isSymbolicLink()) invalidState();
|
|
1436
|
+
return true;
|
|
1437
|
+
} catch (error) {
|
|
1438
|
+
if (isMissing$1(error)) return false;
|
|
1439
|
+
throw error;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
path(ownerDid) {
|
|
1443
|
+
return join(this.directory, `${this.key(ownerDid)}.json`);
|
|
1444
|
+
}
|
|
1445
|
+
key(ownerDid) {
|
|
1446
|
+
return createHash("sha256").update(String(ownerDid)).digest("hex");
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
955
1449
|
//#endregion
|
|
956
1450
|
//#region lib/types/listener-state.js
|
|
957
1451
|
const STATE_VERSION = 1;
|
|
@@ -1683,8 +2177,11 @@ const FAILURE_CODES = /* @__PURE__ */ new Set([
|
|
|
1683
2177
|
"handle-unavailable",
|
|
1684
2178
|
"not-found",
|
|
1685
2179
|
"forbidden",
|
|
2180
|
+
"identity-recovery-required",
|
|
1686
2181
|
"conflict",
|
|
1687
2182
|
"rate-limited",
|
|
2183
|
+
"group-membership-required",
|
|
2184
|
+
"group-identity-stale",
|
|
1688
2185
|
"attachment-too-large",
|
|
1689
2186
|
"summary-unavailable",
|
|
1690
2187
|
"summary-timeout",
|
|
@@ -1709,8 +2206,11 @@ const FAILURE_MESSAGES = {
|
|
|
1709
2206
|
"handle-unavailable": "The requested AWiki handle is unavailable.",
|
|
1710
2207
|
"not-found": "The requested AWiki resource was not found.",
|
|
1711
2208
|
"forbidden": "The AWiki operation is not permitted.",
|
|
2209
|
+
"identity-recovery-required": "The local AWiki identity must be recovered before it can be used again.",
|
|
1712
2210
|
"conflict": "The AWiki operation conflicts with current state.",
|
|
1713
2211
|
"rate-limited": "The AWiki service rate-limited the request.",
|
|
2212
|
+
"group-membership-required": "The active AWiki identity is not a member of this group.",
|
|
2213
|
+
"group-identity-stale": "The AWiki group identity binding is still recovering.",
|
|
1714
2214
|
"attachment-too-large": "The attachment exceeds this deployment's size limit.",
|
|
1715
2215
|
"summary-unavailable": "AI summary is unavailable. Check the current default model configuration.",
|
|
1716
2216
|
"summary-timeout": "AI summary timed out. Try again.",
|
|
@@ -1840,11 +2340,16 @@ function normalizeFailure(error) {
|
|
|
1840
2340
|
const MAX_GROUP_NAME_CHARACTERS = 100;
|
|
1841
2341
|
const MAX_GROUP_INITIAL_MEMBERS = 50;
|
|
1842
2342
|
const MAX_GROUP_MEMBER_CHARACTERS = 512;
|
|
2343
|
+
const MAX_PROFILE_DISPLAY_NAME_CHARACTERS = 50;
|
|
2344
|
+
const MAX_PROFILE_BIO_CHARACTERS = 100;
|
|
2345
|
+
const MAX_PROFILE_TAGS = 5;
|
|
2346
|
+
const MAX_PROFILE_TAG_CHARACTERS = 30;
|
|
2347
|
+
const MAX_MESSAGE_CHARACTERS = 2e4;
|
|
1843
2348
|
function normalizeCreateGroupRequest(request) {
|
|
1844
2349
|
if (typeof request?.name !== "string" || !Array.isArray(request.members)) return void 0;
|
|
1845
2350
|
const name = request.name.trim();
|
|
1846
2351
|
if (name.length === 0 || Array.from(name).length > MAX_GROUP_NAME_CHARACTERS) return void 0;
|
|
1847
|
-
if (request.members.length
|
|
2352
|
+
if (request.members.length > MAX_GROUP_INITIAL_MEMBERS) return void 0;
|
|
1848
2353
|
const members = [];
|
|
1849
2354
|
const seen = /* @__PURE__ */ new Set();
|
|
1850
2355
|
for (const raw of request.members) {
|
|
@@ -1855,44 +2360,207 @@ function normalizeCreateGroupRequest(request) {
|
|
|
1855
2360
|
seen.add(member);
|
|
1856
2361
|
members.push(member);
|
|
1857
2362
|
}
|
|
1858
|
-
return
|
|
2363
|
+
return {
|
|
1859
2364
|
name,
|
|
1860
2365
|
members
|
|
1861
2366
|
};
|
|
1862
2367
|
}
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
if (typeof error === "object" && error !== null && Reflect.get(error, "name") === "AwikiSummaryProviderError") switch (Reflect.get(error, "code")) {
|
|
1868
|
-
case "route-unavailable": return failure("summary-unavailable");
|
|
1869
|
-
case "timeout": return failure("summary-timeout");
|
|
1870
|
-
case "cancelled": return failure("summary-cancelled");
|
|
1871
|
-
case "truncated":
|
|
1872
|
-
case "tool-call":
|
|
1873
|
-
case "empty-output":
|
|
1874
|
-
case "invalid-output": return failure("summary-invalid-output");
|
|
1875
|
-
default: return failure("summary-failed");
|
|
1876
|
-
}
|
|
1877
|
-
} catch {}
|
|
1878
|
-
return failure("summary-failed");
|
|
2368
|
+
function normalizeMember(value) {
|
|
2369
|
+
if (typeof value !== "string") return void 0;
|
|
2370
|
+
const member = value.trim().replace(/^@+/u, "");
|
|
2371
|
+
return member.length > 0 && Array.from(member).length <= MAX_GROUP_MEMBER_CHARACTERS ? member : void 0;
|
|
1879
2372
|
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
return Array.from(text).slice(0, maxCharacters).join("");
|
|
2373
|
+
function normalizeGroupDid(value) {
|
|
2374
|
+
if (typeof value !== "string" || !value.startsWith("did:") || value.length > 2048) return void 0;
|
|
2375
|
+
return value;
|
|
1884
2376
|
}
|
|
1885
|
-
/**
|
|
1886
|
-
function
|
|
1887
|
-
|
|
1888
|
-
const
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
2377
|
+
/** Rebuild the browser-safe recovery DTO instead of trusting provider object shape. */
|
|
2378
|
+
function publicGroupRebindRecoverySummary(value) {
|
|
2379
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
2380
|
+
const candidate = value;
|
|
2381
|
+
if ([
|
|
2382
|
+
candidate.processed,
|
|
2383
|
+
candidate.completed,
|
|
2384
|
+
candidate.pending,
|
|
2385
|
+
candidate.blocked
|
|
2386
|
+
].some((count) => !Number.isSafeInteger(count) || count < 0 || count > 4294967295)) return;
|
|
2387
|
+
if (!Array.isArray(candidate.items) || candidate.items.length > 500) return void 0;
|
|
2388
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2389
|
+
const items = [];
|
|
2390
|
+
for (const value of candidate.items) {
|
|
2391
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
2392
|
+
const item = value;
|
|
2393
|
+
const groupDid = normalizeGroupDid(item.groupDid);
|
|
2394
|
+
if (groupDid === void 0 || seen.has(groupDid) || item.status !== "pending" && item.status !== "blocked") return;
|
|
2395
|
+
seen.add(groupDid);
|
|
2396
|
+
items.push({
|
|
2397
|
+
groupDid,
|
|
2398
|
+
status: item.status
|
|
2399
|
+
});
|
|
2400
|
+
}
|
|
2401
|
+
return {
|
|
2402
|
+
processed: candidate.processed,
|
|
2403
|
+
completed: candidate.completed,
|
|
2404
|
+
pending: candidate.pending,
|
|
2405
|
+
blocked: candidate.blocked,
|
|
2406
|
+
items
|
|
1893
2407
|
};
|
|
1894
|
-
|
|
1895
|
-
|
|
2408
|
+
}
|
|
2409
|
+
function normalizeProfileRequest(request) {
|
|
2410
|
+
if (typeof request?.displayName !== "string" || typeof request.bio !== "string" || !Array.isArray(request.tags)) return void 0;
|
|
2411
|
+
const displayName = request.displayName.trim();
|
|
2412
|
+
const bio = request.bio.trim();
|
|
2413
|
+
if (displayName.length === 0 || Array.from(displayName).length > MAX_PROFILE_DISPLAY_NAME_CHARACTERS || Array.from(bio).length > MAX_PROFILE_BIO_CHARACTERS || request.tags.length > MAX_PROFILE_TAGS) return void 0;
|
|
2414
|
+
const tags = [];
|
|
2415
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2416
|
+
for (const raw of request.tags) {
|
|
2417
|
+
if (typeof raw !== "string") return void 0;
|
|
2418
|
+
const tag = raw.trim();
|
|
2419
|
+
const key = tag.toLocaleLowerCase();
|
|
2420
|
+
if (tag.length === 0 || Array.from(tag).length > MAX_PROFILE_TAG_CHARACTERS || seen.has(key)) return void 0;
|
|
2421
|
+
seen.add(key);
|
|
2422
|
+
tags.push(tag);
|
|
2423
|
+
}
|
|
2424
|
+
return {
|
|
2425
|
+
displayName,
|
|
2426
|
+
bio,
|
|
2427
|
+
tags
|
|
2428
|
+
};
|
|
2429
|
+
}
|
|
2430
|
+
function normalizeRecoveryOperation(request) {
|
|
2431
|
+
if (typeof request?.operationId !== "string") return void 0;
|
|
2432
|
+
const operationId = request.operationId.trim();
|
|
2433
|
+
return operationId.length > 0 && operationId.length <= 512 ? { operationId } : void 0;
|
|
2434
|
+
}
|
|
2435
|
+
function normalizeRecoveryOtpRequest(request) {
|
|
2436
|
+
if (typeof request?.fullHandle !== "string" || typeof request.phone !== "string") return void 0;
|
|
2437
|
+
const fullHandle = request.fullHandle.trim().replace(/^@+/u, "");
|
|
2438
|
+
const phone = request.phone.trim();
|
|
2439
|
+
if (fullHandle.length === 0 || fullHandle.length > 512 || phone.length < 5 || phone.length > 32) return void 0;
|
|
2440
|
+
return {
|
|
2441
|
+
fullHandle,
|
|
2442
|
+
phone
|
|
2443
|
+
};
|
|
2444
|
+
}
|
|
2445
|
+
function normalizeRecoveryPrepareRequest(request) {
|
|
2446
|
+
const operation = normalizeRecoveryOperation(request);
|
|
2447
|
+
if (operation === void 0 || typeof request.phone !== "string" || typeof request.otp !== "string") return void 0;
|
|
2448
|
+
const phone = request.phone.trim();
|
|
2449
|
+
const otp = request.otp.trim();
|
|
2450
|
+
if (phone.length < 5 || phone.length > 32 || !/^\d{4,12}$/u.test(otp)) return void 0;
|
|
2451
|
+
return {
|
|
2452
|
+
...operation,
|
|
2453
|
+
phone,
|
|
2454
|
+
otp
|
|
2455
|
+
};
|
|
2456
|
+
}
|
|
2457
|
+
const IDENTITY_ACCESS_RESPONSE_MAX_BYTES = 65536;
|
|
2458
|
+
/** Read one untrusted discovery response without buffering beyond the fixed Host limit. */
|
|
2459
|
+
async function readBoundedResponseText(response, maxBytes) {
|
|
2460
|
+
const declaredLength = response.headers.get("content-length");
|
|
2461
|
+
if (declaredLength !== null && /^\d+$/u.test(declaredLength) && Number(declaredLength) > maxBytes) return void 0;
|
|
2462
|
+
if (response.body === null) return "";
|
|
2463
|
+
const reader = response.body.getReader();
|
|
2464
|
+
const chunks = [];
|
|
2465
|
+
let length = 0;
|
|
2466
|
+
try {
|
|
2467
|
+
while (true) {
|
|
2468
|
+
const result = await reader.read();
|
|
2469
|
+
if (result.done) break;
|
|
2470
|
+
length += result.value.byteLength;
|
|
2471
|
+
if (length > maxBytes) {
|
|
2472
|
+
await reader.cancel();
|
|
2473
|
+
return;
|
|
2474
|
+
}
|
|
2475
|
+
chunks.push(Uint8Array.from(result.value));
|
|
2476
|
+
}
|
|
2477
|
+
} catch {
|
|
2478
|
+
return;
|
|
2479
|
+
} finally {
|
|
2480
|
+
reader.releaseLock();
|
|
2481
|
+
}
|
|
2482
|
+
const bytes = new Uint8Array(length);
|
|
2483
|
+
let offset = 0;
|
|
2484
|
+
for (const chunk of chunks) {
|
|
2485
|
+
bytes.set(chunk, offset);
|
|
2486
|
+
offset += chunk.byteLength;
|
|
2487
|
+
}
|
|
2488
|
+
return Buffer.from(bytes).toString("utf8");
|
|
2489
|
+
}
|
|
2490
|
+
/** Resolve one configured-domain Handle without widening registration authority. */
|
|
2491
|
+
function identityAccessTarget(request, configuredDomain) {
|
|
2492
|
+
if (typeof request?.handle !== "string") return void 0;
|
|
2493
|
+
const raw = request.handle.trim();
|
|
2494
|
+
if (raw.length === 0 || raw.length > 255 || /[\u0000-\u001f\u007f]/u.test(raw)) return void 0;
|
|
2495
|
+
const lowered = raw.replace(/[A-Z]/gu, (character) => character.toLowerCase());
|
|
2496
|
+
const handle = lowered.startsWith("wba://") ? lowered.slice(6) : lowered;
|
|
2497
|
+
const dot = handle.indexOf(".");
|
|
2498
|
+
const localPart = (dot < 0 ? handle : handle.slice(0, dot)).trim();
|
|
2499
|
+
const domain = (dot < 0 ? configuredDomain : handle.slice(dot + 1)).trim().replace(/\.$/u, "");
|
|
2500
|
+
if (localPart.length === 0 || domain !== configuredDomain) return void 0;
|
|
2501
|
+
return {
|
|
2502
|
+
localPart,
|
|
2503
|
+
fullHandle: `${localPart}.${configuredDomain}`
|
|
2504
|
+
};
|
|
2505
|
+
}
|
|
2506
|
+
function normalizeSendTextRequest(request) {
|
|
2507
|
+
if (typeof request?.text !== "string" || typeof request.idempotencyKey !== "string" || typeof request.target !== "object" || request.target === null) return void 0;
|
|
2508
|
+
const text = request.text;
|
|
2509
|
+
const codePoints = Array.from(text);
|
|
2510
|
+
if (text.trim().length === 0 || codePoints.length > MAX_MESSAGE_CHARACTERS || request.idempotencyKey.length === 0 || request.idempotencyKey.length > 512) return void 0;
|
|
2511
|
+
if (request.target.kind === "direct") {
|
|
2512
|
+
if (typeof request.target.peer !== "string" || request.mentions !== void 0) return void 0;
|
|
2513
|
+
} else if (request.target.kind === "group") {
|
|
2514
|
+
if (typeof request.target.group !== "string") return void 0;
|
|
2515
|
+
} else return void 0;
|
|
2516
|
+
if (request.mentions === void 0) return request;
|
|
2517
|
+
if (!Array.isArray(request.mentions) || request.mentions.length === 0 || request.mentions.length > 100) return void 0;
|
|
2518
|
+
const ids = /* @__PURE__ */ new Set();
|
|
2519
|
+
let previousEnd = 0;
|
|
2520
|
+
const mentions = [...request.mentions].sort((left, right) => left.start - right.start || left.end - right.end);
|
|
2521
|
+
for (const mention of mentions) {
|
|
2522
|
+
if (typeof mention !== "object" || mention === null || typeof mention.id !== "string" || mention.id.trim() === "" || ids.has(mention.id) || !Number.isSafeInteger(mention.start) || !Number.isSafeInteger(mention.end) || mention.start < previousEnd || mention.start < 0 || mention.end <= mention.start || mention.end > codePoints.length || typeof mention.did !== "string" || !mention.did.startsWith("did:") || mention.displayName !== void 0 && typeof mention.displayName !== "string") return void 0;
|
|
2523
|
+
ids.add(mention.id);
|
|
2524
|
+
previousEnd = mention.end;
|
|
2525
|
+
}
|
|
2526
|
+
return {
|
|
2527
|
+
...request,
|
|
2528
|
+
mentions
|
|
2529
|
+
};
|
|
2530
|
+
}
|
|
2531
|
+
/** Normalize summary-provider failures without returning prompts, model output, routes, or causes. */
|
|
2532
|
+
function normalizeSummaryFailure(error) {
|
|
2533
|
+
if (error instanceof SummaryProviderUnavailableError) return failure("summary-unavailable");
|
|
2534
|
+
try {
|
|
2535
|
+
if (typeof error === "object" && error !== null && Reflect.get(error, "name") === "AwikiSummaryProviderError") switch (Reflect.get(error, "code")) {
|
|
2536
|
+
case "route-unavailable": return failure("summary-unavailable");
|
|
2537
|
+
case "timeout": return failure("summary-timeout");
|
|
2538
|
+
case "cancelled": return failure("summary-cancelled");
|
|
2539
|
+
case "truncated":
|
|
2540
|
+
case "tool-call":
|
|
2541
|
+
case "empty-output":
|
|
2542
|
+
case "invalid-output": return failure("summary-invalid-output");
|
|
2543
|
+
default: return failure("summary-failed");
|
|
2544
|
+
}
|
|
2545
|
+
} catch {}
|
|
2546
|
+
return failure("summary-failed");
|
|
2547
|
+
}
|
|
2548
|
+
/** Bound one untrusted display string before it can consume the shared model budget. */
|
|
2549
|
+
function boundedText(value, maxCharacters, fallback = "") {
|
|
2550
|
+
const text = value?.trim() ?? fallback;
|
|
2551
|
+
return Array.from(text).slice(0, maxCharacters).join("");
|
|
2552
|
+
}
|
|
2553
|
+
/** Remove routing identifiers, attachment ids, hashes, and all binary fields from one message. */
|
|
2554
|
+
function minimizeSummaryMessage(message) {
|
|
2555
|
+
const sender = boundedText(message.senderDisplayName ?? message.senderHandle, 50, message.outgoing ? "我" : "对方");
|
|
2556
|
+
const base = {
|
|
2557
|
+
id: message.id,
|
|
2558
|
+
sender,
|
|
2559
|
+
outgoing: message.outgoing,
|
|
2560
|
+
sentAt: new Date(message.sentAt).toISOString()
|
|
2561
|
+
};
|
|
2562
|
+
if (message.content.kind === "text") return {
|
|
2563
|
+
...base,
|
|
1896
2564
|
content: {
|
|
1897
2565
|
kind: "text",
|
|
1898
2566
|
text: boundedText(message.content.text, 4e3)
|
|
@@ -2001,11 +2669,29 @@ let AwikiService = (() => {
|
|
|
2001
2669
|
let _getSession_decorators;
|
|
2002
2670
|
let _logout_decorators;
|
|
2003
2671
|
let _login_decorators;
|
|
2672
|
+
let _inspectIdentityAccess_decorators;
|
|
2004
2673
|
let _sendRegistrationOtp_decorators;
|
|
2005
2674
|
let _registerIdentity_decorators;
|
|
2006
2675
|
let _updateDisplayName_decorators;
|
|
2676
|
+
let _getProfile_decorators;
|
|
2677
|
+
let _updateProfile_decorators;
|
|
2678
|
+
let _sendRecoveryOtp_decorators;
|
|
2679
|
+
let _prepareRecovery_decorators;
|
|
2680
|
+
let _activateRecovery_decorators;
|
|
2681
|
+
let _getRecoveryStatus_decorators;
|
|
2682
|
+
let _resumeRecovery_decorators;
|
|
2683
|
+
let _discardRecovery_decorators;
|
|
2007
2684
|
let _resolvePeer_decorators;
|
|
2008
2685
|
let _createGroup_decorators;
|
|
2686
|
+
let _getGroup_decorators;
|
|
2687
|
+
let _joinGroup_decorators;
|
|
2688
|
+
let _leaveGroup_decorators;
|
|
2689
|
+
let _listGroupMembers_decorators;
|
|
2690
|
+
let _addGroupMember_decorators;
|
|
2691
|
+
let _removeGroupMember_decorators;
|
|
2692
|
+
let _resumeGroupRebindRecovery_decorators;
|
|
2693
|
+
let _getConversationPreferences_decorators;
|
|
2694
|
+
let _updateConversationPreference_decorators;
|
|
2009
2695
|
let _listConversations_decorators;
|
|
2010
2696
|
let _getHistory_decorators;
|
|
2011
2697
|
let _getLocalHistory_decorators;
|
|
@@ -2028,11 +2714,29 @@ let AwikiService = (() => {
|
|
|
2028
2714
|
_getSession_decorators = [Remote];
|
|
2029
2715
|
_logout_decorators = [Remote];
|
|
2030
2716
|
_login_decorators = [Remote];
|
|
2717
|
+
_inspectIdentityAccess_decorators = [Remote];
|
|
2031
2718
|
_sendRegistrationOtp_decorators = [Remote];
|
|
2032
2719
|
_registerIdentity_decorators = [Remote];
|
|
2033
2720
|
_updateDisplayName_decorators = [Remote];
|
|
2721
|
+
_getProfile_decorators = [Remote];
|
|
2722
|
+
_updateProfile_decorators = [Remote];
|
|
2723
|
+
_sendRecoveryOtp_decorators = [Remote];
|
|
2724
|
+
_prepareRecovery_decorators = [Remote];
|
|
2725
|
+
_activateRecovery_decorators = [Remote];
|
|
2726
|
+
_getRecoveryStatus_decorators = [Remote];
|
|
2727
|
+
_resumeRecovery_decorators = [Remote];
|
|
2728
|
+
_discardRecovery_decorators = [Remote];
|
|
2034
2729
|
_resolvePeer_decorators = [Remote];
|
|
2035
2730
|
_createGroup_decorators = [Remote];
|
|
2731
|
+
_getGroup_decorators = [Remote];
|
|
2732
|
+
_joinGroup_decorators = [Remote];
|
|
2733
|
+
_leaveGroup_decorators = [Remote];
|
|
2734
|
+
_listGroupMembers_decorators = [Remote];
|
|
2735
|
+
_addGroupMember_decorators = [Remote];
|
|
2736
|
+
_removeGroupMember_decorators = [Remote];
|
|
2737
|
+
_resumeGroupRebindRecovery_decorators = [Remote];
|
|
2738
|
+
_getConversationPreferences_decorators = [Remote];
|
|
2739
|
+
_updateConversationPreference_decorators = [Remote];
|
|
2036
2740
|
_listConversations_decorators = [Remote];
|
|
2037
2741
|
_getHistory_decorators = [Remote];
|
|
2038
2742
|
_getLocalHistory_decorators = [Remote];
|
|
@@ -2102,6 +2806,17 @@ let AwikiService = (() => {
|
|
|
2102
2806
|
},
|
|
2103
2807
|
metadata: _metadata
|
|
2104
2808
|
}, null, _instanceExtraInitializers);
|
|
2809
|
+
__esDecorate(this, null, _inspectIdentityAccess_decorators, {
|
|
2810
|
+
kind: "method",
|
|
2811
|
+
name: "inspectIdentityAccess",
|
|
2812
|
+
static: false,
|
|
2813
|
+
private: false,
|
|
2814
|
+
access: {
|
|
2815
|
+
has: (obj) => "inspectIdentityAccess" in obj,
|
|
2816
|
+
get: (obj) => obj.inspectIdentityAccess
|
|
2817
|
+
},
|
|
2818
|
+
metadata: _metadata
|
|
2819
|
+
}, null, _instanceExtraInitializers);
|
|
2105
2820
|
__esDecorate(this, null, _sendRegistrationOtp_decorators, {
|
|
2106
2821
|
kind: "method",
|
|
2107
2822
|
name: "sendRegistrationOtp",
|
|
@@ -2135,6 +2850,94 @@ let AwikiService = (() => {
|
|
|
2135
2850
|
},
|
|
2136
2851
|
metadata: _metadata
|
|
2137
2852
|
}, null, _instanceExtraInitializers);
|
|
2853
|
+
__esDecorate(this, null, _getProfile_decorators, {
|
|
2854
|
+
kind: "method",
|
|
2855
|
+
name: "getProfile",
|
|
2856
|
+
static: false,
|
|
2857
|
+
private: false,
|
|
2858
|
+
access: {
|
|
2859
|
+
has: (obj) => "getProfile" in obj,
|
|
2860
|
+
get: (obj) => obj.getProfile
|
|
2861
|
+
},
|
|
2862
|
+
metadata: _metadata
|
|
2863
|
+
}, null, _instanceExtraInitializers);
|
|
2864
|
+
__esDecorate(this, null, _updateProfile_decorators, {
|
|
2865
|
+
kind: "method",
|
|
2866
|
+
name: "updateProfile",
|
|
2867
|
+
static: false,
|
|
2868
|
+
private: false,
|
|
2869
|
+
access: {
|
|
2870
|
+
has: (obj) => "updateProfile" in obj,
|
|
2871
|
+
get: (obj) => obj.updateProfile
|
|
2872
|
+
},
|
|
2873
|
+
metadata: _metadata
|
|
2874
|
+
}, null, _instanceExtraInitializers);
|
|
2875
|
+
__esDecorate(this, null, _sendRecoveryOtp_decorators, {
|
|
2876
|
+
kind: "method",
|
|
2877
|
+
name: "sendRecoveryOtp",
|
|
2878
|
+
static: false,
|
|
2879
|
+
private: false,
|
|
2880
|
+
access: {
|
|
2881
|
+
has: (obj) => "sendRecoveryOtp" in obj,
|
|
2882
|
+
get: (obj) => obj.sendRecoveryOtp
|
|
2883
|
+
},
|
|
2884
|
+
metadata: _metadata
|
|
2885
|
+
}, null, _instanceExtraInitializers);
|
|
2886
|
+
__esDecorate(this, null, _prepareRecovery_decorators, {
|
|
2887
|
+
kind: "method",
|
|
2888
|
+
name: "prepareRecovery",
|
|
2889
|
+
static: false,
|
|
2890
|
+
private: false,
|
|
2891
|
+
access: {
|
|
2892
|
+
has: (obj) => "prepareRecovery" in obj,
|
|
2893
|
+
get: (obj) => obj.prepareRecovery
|
|
2894
|
+
},
|
|
2895
|
+
metadata: _metadata
|
|
2896
|
+
}, null, _instanceExtraInitializers);
|
|
2897
|
+
__esDecorate(this, null, _activateRecovery_decorators, {
|
|
2898
|
+
kind: "method",
|
|
2899
|
+
name: "activateRecovery",
|
|
2900
|
+
static: false,
|
|
2901
|
+
private: false,
|
|
2902
|
+
access: {
|
|
2903
|
+
has: (obj) => "activateRecovery" in obj,
|
|
2904
|
+
get: (obj) => obj.activateRecovery
|
|
2905
|
+
},
|
|
2906
|
+
metadata: _metadata
|
|
2907
|
+
}, null, _instanceExtraInitializers);
|
|
2908
|
+
__esDecorate(this, null, _getRecoveryStatus_decorators, {
|
|
2909
|
+
kind: "method",
|
|
2910
|
+
name: "getRecoveryStatus",
|
|
2911
|
+
static: false,
|
|
2912
|
+
private: false,
|
|
2913
|
+
access: {
|
|
2914
|
+
has: (obj) => "getRecoveryStatus" in obj,
|
|
2915
|
+
get: (obj) => obj.getRecoveryStatus
|
|
2916
|
+
},
|
|
2917
|
+
metadata: _metadata
|
|
2918
|
+
}, null, _instanceExtraInitializers);
|
|
2919
|
+
__esDecorate(this, null, _resumeRecovery_decorators, {
|
|
2920
|
+
kind: "method",
|
|
2921
|
+
name: "resumeRecovery",
|
|
2922
|
+
static: false,
|
|
2923
|
+
private: false,
|
|
2924
|
+
access: {
|
|
2925
|
+
has: (obj) => "resumeRecovery" in obj,
|
|
2926
|
+
get: (obj) => obj.resumeRecovery
|
|
2927
|
+
},
|
|
2928
|
+
metadata: _metadata
|
|
2929
|
+
}, null, _instanceExtraInitializers);
|
|
2930
|
+
__esDecorate(this, null, _discardRecovery_decorators, {
|
|
2931
|
+
kind: "method",
|
|
2932
|
+
name: "discardRecovery",
|
|
2933
|
+
static: false,
|
|
2934
|
+
private: false,
|
|
2935
|
+
access: {
|
|
2936
|
+
has: (obj) => "discardRecovery" in obj,
|
|
2937
|
+
get: (obj) => obj.discardRecovery
|
|
2938
|
+
},
|
|
2939
|
+
metadata: _metadata
|
|
2940
|
+
}, null, _instanceExtraInitializers);
|
|
2138
2941
|
__esDecorate(this, null, _resolvePeer_decorators, {
|
|
2139
2942
|
kind: "method",
|
|
2140
2943
|
name: "resolvePeer",
|
|
@@ -2157,6 +2960,105 @@ let AwikiService = (() => {
|
|
|
2157
2960
|
},
|
|
2158
2961
|
metadata: _metadata
|
|
2159
2962
|
}, null, _instanceExtraInitializers);
|
|
2963
|
+
__esDecorate(this, null, _getGroup_decorators, {
|
|
2964
|
+
kind: "method",
|
|
2965
|
+
name: "getGroup",
|
|
2966
|
+
static: false,
|
|
2967
|
+
private: false,
|
|
2968
|
+
access: {
|
|
2969
|
+
has: (obj) => "getGroup" in obj,
|
|
2970
|
+
get: (obj) => obj.getGroup
|
|
2971
|
+
},
|
|
2972
|
+
metadata: _metadata
|
|
2973
|
+
}, null, _instanceExtraInitializers);
|
|
2974
|
+
__esDecorate(this, null, _joinGroup_decorators, {
|
|
2975
|
+
kind: "method",
|
|
2976
|
+
name: "joinGroup",
|
|
2977
|
+
static: false,
|
|
2978
|
+
private: false,
|
|
2979
|
+
access: {
|
|
2980
|
+
has: (obj) => "joinGroup" in obj,
|
|
2981
|
+
get: (obj) => obj.joinGroup
|
|
2982
|
+
},
|
|
2983
|
+
metadata: _metadata
|
|
2984
|
+
}, null, _instanceExtraInitializers);
|
|
2985
|
+
__esDecorate(this, null, _leaveGroup_decorators, {
|
|
2986
|
+
kind: "method",
|
|
2987
|
+
name: "leaveGroup",
|
|
2988
|
+
static: false,
|
|
2989
|
+
private: false,
|
|
2990
|
+
access: {
|
|
2991
|
+
has: (obj) => "leaveGroup" in obj,
|
|
2992
|
+
get: (obj) => obj.leaveGroup
|
|
2993
|
+
},
|
|
2994
|
+
metadata: _metadata
|
|
2995
|
+
}, null, _instanceExtraInitializers);
|
|
2996
|
+
__esDecorate(this, null, _listGroupMembers_decorators, {
|
|
2997
|
+
kind: "method",
|
|
2998
|
+
name: "listGroupMembers",
|
|
2999
|
+
static: false,
|
|
3000
|
+
private: false,
|
|
3001
|
+
access: {
|
|
3002
|
+
has: (obj) => "listGroupMembers" in obj,
|
|
3003
|
+
get: (obj) => obj.listGroupMembers
|
|
3004
|
+
},
|
|
3005
|
+
metadata: _metadata
|
|
3006
|
+
}, null, _instanceExtraInitializers);
|
|
3007
|
+
__esDecorate(this, null, _addGroupMember_decorators, {
|
|
3008
|
+
kind: "method",
|
|
3009
|
+
name: "addGroupMember",
|
|
3010
|
+
static: false,
|
|
3011
|
+
private: false,
|
|
3012
|
+
access: {
|
|
3013
|
+
has: (obj) => "addGroupMember" in obj,
|
|
3014
|
+
get: (obj) => obj.addGroupMember
|
|
3015
|
+
},
|
|
3016
|
+
metadata: _metadata
|
|
3017
|
+
}, null, _instanceExtraInitializers);
|
|
3018
|
+
__esDecorate(this, null, _removeGroupMember_decorators, {
|
|
3019
|
+
kind: "method",
|
|
3020
|
+
name: "removeGroupMember",
|
|
3021
|
+
static: false,
|
|
3022
|
+
private: false,
|
|
3023
|
+
access: {
|
|
3024
|
+
has: (obj) => "removeGroupMember" in obj,
|
|
3025
|
+
get: (obj) => obj.removeGroupMember
|
|
3026
|
+
},
|
|
3027
|
+
metadata: _metadata
|
|
3028
|
+
}, null, _instanceExtraInitializers);
|
|
3029
|
+
__esDecorate(this, null, _resumeGroupRebindRecovery_decorators, {
|
|
3030
|
+
kind: "method",
|
|
3031
|
+
name: "resumeGroupRebindRecovery",
|
|
3032
|
+
static: false,
|
|
3033
|
+
private: false,
|
|
3034
|
+
access: {
|
|
3035
|
+
has: (obj) => "resumeGroupRebindRecovery" in obj,
|
|
3036
|
+
get: (obj) => obj.resumeGroupRebindRecovery
|
|
3037
|
+
},
|
|
3038
|
+
metadata: _metadata
|
|
3039
|
+
}, null, _instanceExtraInitializers);
|
|
3040
|
+
__esDecorate(this, null, _getConversationPreferences_decorators, {
|
|
3041
|
+
kind: "method",
|
|
3042
|
+
name: "getConversationPreferences",
|
|
3043
|
+
static: false,
|
|
3044
|
+
private: false,
|
|
3045
|
+
access: {
|
|
3046
|
+
has: (obj) => "getConversationPreferences" in obj,
|
|
3047
|
+
get: (obj) => obj.getConversationPreferences
|
|
3048
|
+
},
|
|
3049
|
+
metadata: _metadata
|
|
3050
|
+
}, null, _instanceExtraInitializers);
|
|
3051
|
+
__esDecorate(this, null, _updateConversationPreference_decorators, {
|
|
3052
|
+
kind: "method",
|
|
3053
|
+
name: "updateConversationPreference",
|
|
3054
|
+
static: false,
|
|
3055
|
+
private: false,
|
|
3056
|
+
access: {
|
|
3057
|
+
has: (obj) => "updateConversationPreference" in obj,
|
|
3058
|
+
get: (obj) => obj.updateConversationPreference
|
|
3059
|
+
},
|
|
3060
|
+
metadata: _metadata
|
|
3061
|
+
}, null, _instanceExtraInitializers);
|
|
2160
3062
|
__esDecorate(this, null, _listConversations_decorators, {
|
|
2161
3063
|
kind: "method",
|
|
2162
3064
|
name: "listConversations",
|
|
@@ -2323,6 +3225,8 @@ let AwikiService = (() => {
|
|
|
2323
3225
|
resolved = __runInitializers(this, _instanceExtraInitializers);
|
|
2324
3226
|
sessionStore;
|
|
2325
3227
|
imageAttachmentCache;
|
|
3228
|
+
sentMailStore;
|
|
3229
|
+
conversationPreferenceStore;
|
|
2326
3230
|
startupUserServiceDomain;
|
|
2327
3231
|
settingsProvider;
|
|
2328
3232
|
provider;
|
|
@@ -2347,6 +3251,8 @@ let AwikiService = (() => {
|
|
|
2347
3251
|
this.externalHttpAuth = createAwikiExternalHttpAuth(() => this.acquireExternalHttpAuthSession());
|
|
2348
3252
|
this.sessionStore = new AwikiSessionStore(this.resolved.stateRoot);
|
|
2349
3253
|
this.imageAttachmentCache = new AwikiImageAttachmentCache(this.resolved.stateRoot, this.resolved.attachmentMaxBytes, this.resolved.imageAttachmentCacheMaxBytes);
|
|
3254
|
+
this.sentMailStore = new AwikiSentMailStore(this.resolved.stateRoot);
|
|
3255
|
+
this.conversationPreferenceStore = new AwikiConversationPreferenceStore(this.resolved.stateRoot);
|
|
2350
3256
|
this.startupUserServiceDomain = this.resolved.userServiceDomain;
|
|
2351
3257
|
ctx.inject(["settings"], (settingsCtx) => {
|
|
2352
3258
|
const provider = settingsCtx.settings;
|
|
@@ -2544,11 +3450,79 @@ let AwikiService = (() => {
|
|
|
2544
3450
|
}
|
|
2545
3451
|
});
|
|
2546
3452
|
}
|
|
2547
|
-
/**
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
3453
|
+
/** Classify one configured-domain Handle before selecting the registration or recovery OTP purpose. */
|
|
3454
|
+
async inspectIdentityAccess(request) {
|
|
3455
|
+
const target = identityAccessTarget(request, this.startupUserServiceDomain);
|
|
3456
|
+
if (target === void 0) return {
|
|
3457
|
+
ok: false,
|
|
3458
|
+
error: failure("invalid-request")
|
|
3459
|
+
};
|
|
3460
|
+
const endpoint = new URL(`/.well-known/handle/${encodeURIComponent(target.localPart)}`, this.resolved.userServiceUrl);
|
|
3461
|
+
const abort = new AbortController();
|
|
3462
|
+
const timeout = setTimeout(() => {
|
|
3463
|
+
abort.abort();
|
|
3464
|
+
}, 1e4);
|
|
3465
|
+
let response;
|
|
3466
|
+
try {
|
|
3467
|
+
response = await fetch(endpoint, {
|
|
3468
|
+
method: "GET",
|
|
3469
|
+
headers: {
|
|
3470
|
+
accept: "application/json",
|
|
3471
|
+
"cache-control": "no-store"
|
|
3472
|
+
},
|
|
3473
|
+
cache: "no-store",
|
|
3474
|
+
redirect: "error",
|
|
3475
|
+
signal: abort.signal
|
|
3476
|
+
});
|
|
3477
|
+
} catch {
|
|
3478
|
+
return {
|
|
3479
|
+
ok: false,
|
|
3480
|
+
error: failure("network")
|
|
3481
|
+
};
|
|
3482
|
+
} finally {
|
|
3483
|
+
clearTimeout(timeout);
|
|
3484
|
+
}
|
|
3485
|
+
if (response.status === 404) return {
|
|
3486
|
+
ok: true,
|
|
3487
|
+
value: {
|
|
3488
|
+
status: "available",
|
|
3489
|
+
fullHandle: target.fullHandle
|
|
3490
|
+
}
|
|
3491
|
+
};
|
|
3492
|
+
if (!response.ok) return {
|
|
3493
|
+
ok: false,
|
|
3494
|
+
error: failure("remote")
|
|
3495
|
+
};
|
|
3496
|
+
try {
|
|
3497
|
+
const text = await readBoundedResponseText(response, IDENTITY_ACCESS_RESPONSE_MAX_BYTES);
|
|
3498
|
+
if (text === void 0) return {
|
|
3499
|
+
ok: false,
|
|
3500
|
+
error: failure("remote")
|
|
3501
|
+
};
|
|
3502
|
+
const value = JSON.parse(text);
|
|
3503
|
+
if (typeof value !== "object" || value === null) return {
|
|
3504
|
+
ok: false,
|
|
3505
|
+
error: failure("remote")
|
|
3506
|
+
};
|
|
3507
|
+
const binding = value;
|
|
3508
|
+
if (binding.handle !== target.fullHandle || typeof binding.did !== "string" || !binding.did.startsWith("did:") || typeof binding.status !== "string" || binding.status.length === 0) return {
|
|
3509
|
+
ok: false,
|
|
3510
|
+
error: failure("remote")
|
|
3511
|
+
};
|
|
3512
|
+
return {
|
|
3513
|
+
ok: true,
|
|
3514
|
+
value: {
|
|
3515
|
+
status: "existing",
|
|
3516
|
+
fullHandle: target.fullHandle
|
|
3517
|
+
}
|
|
3518
|
+
};
|
|
3519
|
+
} catch {
|
|
3520
|
+
return {
|
|
3521
|
+
ok: false,
|
|
3522
|
+
error: failure("remote")
|
|
3523
|
+
};
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
2552
3526
|
sendRegistrationOtp(request) {
|
|
2553
3527
|
return this.run((client) => client.sendRegistrationOtp(request));
|
|
2554
3528
|
}
|
|
@@ -2559,18 +3533,7 @@ let AwikiService = (() => {
|
|
|
2559
3533
|
*/
|
|
2560
3534
|
async registerIdentity(request) {
|
|
2561
3535
|
const result = await this.run((client) => client.registerIdentity(request));
|
|
2562
|
-
if (result.ok)
|
|
2563
|
-
this.activeIdentityDid = result.value.did;
|
|
2564
|
-
this.publishSession({
|
|
2565
|
-
status: "active",
|
|
2566
|
-
identity: result.value
|
|
2567
|
-
});
|
|
2568
|
-
const provider = this.provider;
|
|
2569
|
-
if (provider !== void 0) {
|
|
2570
|
-
await provider.listenerStartup;
|
|
2571
|
-
await this.startListener(provider);
|
|
2572
|
-
}
|
|
2573
|
-
}
|
|
3536
|
+
if (result.ok) await this.activateRegisteredIdentity(result.value);
|
|
2574
3537
|
return result;
|
|
2575
3538
|
}
|
|
2576
3539
|
/**
|
|
@@ -2583,6 +3546,92 @@ let AwikiService = (() => {
|
|
|
2583
3546
|
if (result.ok) this.activeIdentityDid = result.value.did;
|
|
2584
3547
|
return result;
|
|
2585
3548
|
}
|
|
3549
|
+
/** Return the public editable profile for the active identity. */
|
|
3550
|
+
getProfile() {
|
|
3551
|
+
return this.run((client) => client.getProfile());
|
|
3552
|
+
}
|
|
3553
|
+
/** Update Display Name, bio, and tags after applying product limits in the Host. */
|
|
3554
|
+
updateProfile(request) {
|
|
3555
|
+
const normalized = normalizeProfileRequest(request);
|
|
3556
|
+
if (normalized === void 0) return Promise.resolve({
|
|
3557
|
+
ok: false,
|
|
3558
|
+
error: failure("invalid-request")
|
|
3559
|
+
});
|
|
3560
|
+
return this.run((client) => client.updateProfile(normalized));
|
|
3561
|
+
}
|
|
3562
|
+
/** Start durable phone recovery for one existing full Handle. */
|
|
3563
|
+
sendRecoveryOtp(request) {
|
|
3564
|
+
const normalized = normalizeRecoveryOtpRequest(request);
|
|
3565
|
+
if (normalized === void 0) return Promise.resolve({
|
|
3566
|
+
ok: false,
|
|
3567
|
+
error: failure("invalid-request")
|
|
3568
|
+
});
|
|
3569
|
+
return this.run((client) => client.sendRecoveryOtp(normalized), { allowSignedOut: true });
|
|
3570
|
+
}
|
|
3571
|
+
/** Verify a recovery OTP and freeze its exact intent before the remote commit. */
|
|
3572
|
+
prepareRecovery(request) {
|
|
3573
|
+
const normalized = normalizeRecoveryPrepareRequest(request);
|
|
3574
|
+
if (normalized === void 0) return Promise.resolve({
|
|
3575
|
+
ok: false,
|
|
3576
|
+
error: failure("invalid-request")
|
|
3577
|
+
});
|
|
3578
|
+
return this.run((client) => client.prepareRecovery(normalized), { allowSignedOut: true });
|
|
3579
|
+
}
|
|
3580
|
+
/** Attempt one prepared recovery commit; uncertain outcomes remain durable in Core. */
|
|
3581
|
+
async activateRecovery(request) {
|
|
3582
|
+
const normalized = normalizeRecoveryOperation(request);
|
|
3583
|
+
if (normalized === void 0) return {
|
|
3584
|
+
ok: false,
|
|
3585
|
+
error: failure("invalid-request")
|
|
3586
|
+
};
|
|
3587
|
+
const result = await this.run((client) => client.activateRecovery(normalized), { allowSignedOut: true });
|
|
3588
|
+
if (result.ok && !await this.applyRecoveredSession(result.value)) return {
|
|
3589
|
+
ok: false,
|
|
3590
|
+
error: failure("remote")
|
|
3591
|
+
};
|
|
3592
|
+
return result;
|
|
3593
|
+
}
|
|
3594
|
+
/** Read durable recovery state before deciding whether a retry is valid. */
|
|
3595
|
+
async getRecoveryStatus(request) {
|
|
3596
|
+
const normalized = normalizeRecoveryOperation(request);
|
|
3597
|
+
if (normalized === void 0) return {
|
|
3598
|
+
ok: false,
|
|
3599
|
+
error: failure("invalid-request")
|
|
3600
|
+
};
|
|
3601
|
+
const result = await this.run((client) => client.getRecoveryStatus(normalized), { allowSignedOut: true });
|
|
3602
|
+
if (result.ok && !await this.applyRecoveredSession(result.value)) return {
|
|
3603
|
+
ok: false,
|
|
3604
|
+
error: failure("remote")
|
|
3605
|
+
};
|
|
3606
|
+
return result;
|
|
3607
|
+
}
|
|
3608
|
+
/** Resume only the exact Core-owned operation selected by the browser. */
|
|
3609
|
+
async resumeRecovery(request) {
|
|
3610
|
+
const normalized = normalizeRecoveryOperation(request);
|
|
3611
|
+
if (normalized === void 0) return {
|
|
3612
|
+
ok: false,
|
|
3613
|
+
error: failure("invalid-request")
|
|
3614
|
+
};
|
|
3615
|
+
const result = await this.run((client) => client.resumeRecovery(normalized), { allowSignedOut: true });
|
|
3616
|
+
if (result.ok && !await this.applyRecoveredSession(result.value)) return {
|
|
3617
|
+
ok: false,
|
|
3618
|
+
error: failure("remote")
|
|
3619
|
+
};
|
|
3620
|
+
return result;
|
|
3621
|
+
}
|
|
3622
|
+
/** Discard only a pre-attempt operation; Core rejects post-attempt deletion. */
|
|
3623
|
+
async discardRecovery(request) {
|
|
3624
|
+
const normalized = normalizeRecoveryOperation(request);
|
|
3625
|
+
if (normalized === void 0) return {
|
|
3626
|
+
ok: false,
|
|
3627
|
+
error: failure("invalid-request")
|
|
3628
|
+
};
|
|
3629
|
+
const result = await this.run((client) => client.discardRecovery(normalized), { allowSignedOut: true });
|
|
3630
|
+
return result.ok ? {
|
|
3631
|
+
ok: true,
|
|
3632
|
+
value: { completed: true }
|
|
3633
|
+
} : result;
|
|
3634
|
+
}
|
|
2586
3635
|
/**
|
|
2587
3636
|
* Resolve one Handle or DID before the browser opens a direct chat.
|
|
2588
3637
|
* @param request - typed Handle or DID.
|
|
@@ -2623,6 +3672,96 @@ let AwikiService = (() => {
|
|
|
2623
3672
|
}
|
|
2624
3673
|
};
|
|
2625
3674
|
}
|
|
3675
|
+
/** Return one authoritative group snapshot for permission-aware UI. */
|
|
3676
|
+
getGroup(request) {
|
|
3677
|
+
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
3678
|
+
if (groupDid === void 0) return Promise.resolve({
|
|
3679
|
+
ok: false,
|
|
3680
|
+
error: failure("invalid-request")
|
|
3681
|
+
});
|
|
3682
|
+
return this.run((client) => client.getGroup(groupDid));
|
|
3683
|
+
}
|
|
3684
|
+
/** Join one open group and return its authoritative membership state. */
|
|
3685
|
+
joinGroup(request) {
|
|
3686
|
+
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
3687
|
+
if (groupDid === void 0) return Promise.resolve({
|
|
3688
|
+
ok: false,
|
|
3689
|
+
error: failure("invalid-request")
|
|
3690
|
+
});
|
|
3691
|
+
return this.run((client) => client.joinGroup(groupDid));
|
|
3692
|
+
}
|
|
3693
|
+
/** Leave one group. Core rejects owner leave and unsupported security profiles. */
|
|
3694
|
+
async leaveGroup(request) {
|
|
3695
|
+
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
3696
|
+
if (groupDid === void 0) return Promise.resolve({
|
|
3697
|
+
ok: false,
|
|
3698
|
+
error: failure("invalid-request")
|
|
3699
|
+
});
|
|
3700
|
+
const result = await this.run((client) => client.leaveGroup(groupDid));
|
|
3701
|
+
return result.ok ? {
|
|
3702
|
+
ok: true,
|
|
3703
|
+
value: { completed: true }
|
|
3704
|
+
} : result;
|
|
3705
|
+
}
|
|
3706
|
+
/** Read one authoritative versioned member page. */
|
|
3707
|
+
listGroupMembers(request) {
|
|
3708
|
+
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
3709
|
+
if (groupDid === void 0 || request.cursor !== void 0 && (typeof request.cursor !== "string" || request.cursor.length > 4096) || request.limit !== void 0 && (!Number.isSafeInteger(request.limit) || request.limit < 1 || request.limit > 100)) return Promise.resolve({
|
|
3710
|
+
ok: false,
|
|
3711
|
+
error: failure("invalid-request")
|
|
3712
|
+
});
|
|
3713
|
+
return this.run((client) => client.listGroupMembers({
|
|
3714
|
+
groupDid,
|
|
3715
|
+
...request.cursor === void 0 ? {} : { cursor: request.cursor },
|
|
3716
|
+
...request.limit === void 0 ? {} : { limit: request.limit }
|
|
3717
|
+
}));
|
|
3718
|
+
}
|
|
3719
|
+
/** Invite one ordinary member after group creation. */
|
|
3720
|
+
addGroupMember(request) {
|
|
3721
|
+
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
3722
|
+
const member = normalizeMember(request?.member);
|
|
3723
|
+
if (groupDid === void 0 || member === void 0 || request.role !== void 0 && request.role !== "member") return Promise.resolve({
|
|
3724
|
+
ok: false,
|
|
3725
|
+
error: failure("invalid-request")
|
|
3726
|
+
});
|
|
3727
|
+
return this.run((client) => client.addGroupMember(groupDid, member));
|
|
3728
|
+
}
|
|
3729
|
+
/** Remove one member. The authoritative Core role check remains decisive. */
|
|
3730
|
+
removeGroupMember(request) {
|
|
3731
|
+
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
3732
|
+
const member = normalizeMember(request?.member);
|
|
3733
|
+
if (groupDid === void 0 || member === void 0) return Promise.resolve({
|
|
3734
|
+
ok: false,
|
|
3735
|
+
error: failure("invalid-request")
|
|
3736
|
+
});
|
|
3737
|
+
return this.run((client) => client.removeGroupMember(groupDid, member));
|
|
3738
|
+
}
|
|
3739
|
+
/** Resume durable group membership convergence after account sync restores old groups. */
|
|
3740
|
+
async resumeGroupRebindRecovery() {
|
|
3741
|
+
const result = await this.run((client) => client.resumeGroupRebindRecovery());
|
|
3742
|
+
if (!result.ok) return result;
|
|
3743
|
+
const summary = publicGroupRebindRecoverySummary(result.value);
|
|
3744
|
+
return summary === void 0 ? {
|
|
3745
|
+
ok: false,
|
|
3746
|
+
error: failure("remote")
|
|
3747
|
+
} : {
|
|
3748
|
+
ok: true,
|
|
3749
|
+
value: summary
|
|
3750
|
+
};
|
|
3751
|
+
}
|
|
3752
|
+
/** Read presentation-only roster preferences for the active identity. */
|
|
3753
|
+
getConversationPreferences() {
|
|
3754
|
+
return this.run(async (client) => this.conversationPreferenceStore.get(await this.ownerDid(client)));
|
|
3755
|
+
}
|
|
3756
|
+
/** Persist one bounded local roster preference without changing Core or remote membership. */
|
|
3757
|
+
updateConversationPreference(request) {
|
|
3758
|
+
const normalized = normalizeConversationPreferenceMutation(request);
|
|
3759
|
+
if (normalized === void 0) return Promise.resolve({
|
|
3760
|
+
ok: false,
|
|
3761
|
+
error: failure("invalid-request")
|
|
3762
|
+
});
|
|
3763
|
+
return this.run(async (client) => this.conversationPreferenceStore.update(await this.ownerDid(client), normalized));
|
|
3764
|
+
}
|
|
2626
3765
|
/**
|
|
2627
3766
|
* List direct and existing group conversations.
|
|
2628
3767
|
* @param request - Optional opaque cursor and page limit.
|
|
@@ -2762,7 +3901,12 @@ let AwikiService = (() => {
|
|
|
2762
3901
|
* @returns The accepted public message or a closed failure.
|
|
2763
3902
|
*/
|
|
2764
3903
|
sendText(request) {
|
|
2765
|
-
|
|
3904
|
+
const normalized = normalizeSendTextRequest(request);
|
|
3905
|
+
if (normalized === void 0) return Promise.resolve({
|
|
3906
|
+
ok: false,
|
|
3907
|
+
error: failure("invalid-request")
|
|
3908
|
+
});
|
|
3909
|
+
return this.run((client) => client.sendText(normalized));
|
|
2766
3910
|
}
|
|
2767
3911
|
/**
|
|
2768
3912
|
* Upload and send one attachment after Host validation.
|
|
@@ -2854,20 +3998,72 @@ let AwikiService = (() => {
|
|
|
2854
3998
|
return this.run((client) => client.getMailAccount());
|
|
2855
3999
|
}
|
|
2856
4000
|
/** List one bounded mailbox page on explicit browser/tool demand. */
|
|
2857
|
-
listMailInbox(request) {
|
|
2858
|
-
|
|
4001
|
+
async listMailInbox(request) {
|
|
4002
|
+
let normalized;
|
|
4003
|
+
try {
|
|
4004
|
+
normalized = mailInboxRequest(request ?? {});
|
|
4005
|
+
} catch {
|
|
4006
|
+
return {
|
|
4007
|
+
ok: false,
|
|
4008
|
+
error: failure("invalid-request")
|
|
4009
|
+
};
|
|
4010
|
+
}
|
|
4011
|
+
return this.run(async (client) => {
|
|
4012
|
+
if (normalized.folder !== "sent") return client.listMailInbox(normalized);
|
|
4013
|
+
return this.sentMailStore.list(await this.ownerDid(client), normalized);
|
|
4014
|
+
});
|
|
2859
4015
|
}
|
|
2860
4016
|
/** Read one bounded plain-text mail message. */
|
|
2861
|
-
readMail(request) {
|
|
2862
|
-
|
|
4017
|
+
async readMail(request) {
|
|
4018
|
+
let normalized;
|
|
4019
|
+
try {
|
|
4020
|
+
normalized = mailReadRequest(request);
|
|
4021
|
+
} catch {
|
|
4022
|
+
return {
|
|
4023
|
+
ok: false,
|
|
4024
|
+
error: failure("invalid-request")
|
|
4025
|
+
};
|
|
4026
|
+
}
|
|
4027
|
+
return this.run(async (client) => {
|
|
4028
|
+
if (!isLocalSentMailId(normalized.messageId)) return client.readMail(normalized);
|
|
4029
|
+
const local = await this.sentMailStore.read(await this.ownerDid(client), normalized.messageId);
|
|
4030
|
+
if (local === void 0) throw Object.assign(/* @__PURE__ */ new Error("sent mail not found"), {
|
|
4031
|
+
name: "AwikiSdkError",
|
|
4032
|
+
code: "not-found"
|
|
4033
|
+
});
|
|
4034
|
+
return local;
|
|
4035
|
+
});
|
|
2863
4036
|
}
|
|
2864
4037
|
/** Mark explicitly selected mail messages read. Browser callers require an explicit click. */
|
|
2865
4038
|
markMailRead(request) {
|
|
2866
4039
|
return this.runValidatedMail(() => mailMarkReadRequest(request), (client, normalized) => client.markMailRead(normalized));
|
|
2867
4040
|
}
|
|
2868
4041
|
/** Send one plain-text mail once. Browser callers require an explicit confirmation. */
|
|
2869
|
-
sendMail(request) {
|
|
2870
|
-
|
|
4042
|
+
async sendMail(request) {
|
|
4043
|
+
let normalized;
|
|
4044
|
+
try {
|
|
4045
|
+
normalized = mailSendRequest(request);
|
|
4046
|
+
} catch {
|
|
4047
|
+
return {
|
|
4048
|
+
ok: false,
|
|
4049
|
+
error: failure("invalid-request")
|
|
4050
|
+
};
|
|
4051
|
+
}
|
|
4052
|
+
return this.run(async (client) => {
|
|
4053
|
+
const result = await client.sendMail(normalized);
|
|
4054
|
+
if (!result.accepted) return result;
|
|
4055
|
+
try {
|
|
4056
|
+
const ownerDid = await this.ownerDid(client);
|
|
4057
|
+
const account = await client.getMailAccount().catch(() => void 0);
|
|
4058
|
+
await this.sentMailStore.append(ownerDid, normalized, result, account);
|
|
4059
|
+
return result;
|
|
4060
|
+
} catch {
|
|
4061
|
+
return result.warnings.length >= 100 ? result : {
|
|
4062
|
+
...result,
|
|
4063
|
+
warnings: [...result.warnings, "Sent history could not be saved locally."]
|
|
4064
|
+
};
|
|
4065
|
+
}
|
|
4066
|
+
});
|
|
2871
4067
|
}
|
|
2872
4068
|
/**
|
|
2873
4069
|
* Permanently remove the exact SDK-owned local state after an explicit browser acknowledgement.
|
|
@@ -2890,6 +4086,8 @@ let AwikiService = (() => {
|
|
|
2890
4086
|
}
|
|
2891
4087
|
try {
|
|
2892
4088
|
await this.imageAttachmentCache.clear();
|
|
4089
|
+
await this.sentMailStore.clear();
|
|
4090
|
+
await this.conversationPreferenceStore.clear();
|
|
2893
4091
|
await this.sessionStore.signIn();
|
|
2894
4092
|
this.signedOut = false;
|
|
2895
4093
|
this.activeIdentityDid = void 0;
|
|
@@ -2905,6 +4103,46 @@ let AwikiService = (() => {
|
|
|
2905
4103
|
}
|
|
2906
4104
|
});
|
|
2907
4105
|
}
|
|
4106
|
+
/** Re-enter only after Core confirms that the exact recovered identity is applied locally. */
|
|
4107
|
+
async applyRecoveredSession(progress) {
|
|
4108
|
+
if (progress.phase !== "applied") return true;
|
|
4109
|
+
return this.mutateSession(async () => {
|
|
4110
|
+
const provider = this.provider;
|
|
4111
|
+
if (provider === void 0) return false;
|
|
4112
|
+
try {
|
|
4113
|
+
const identity = await provider.client.getIdentity();
|
|
4114
|
+
if (identity === null || identity.did !== progress.currentDid) return false;
|
|
4115
|
+
if (this.signedOut === false && this.activeIdentityDid === identity.did) return true;
|
|
4116
|
+
await this.sessionStore.signIn();
|
|
4117
|
+
this.signedOut = false;
|
|
4118
|
+
this.activeIdentityDid = identity.did;
|
|
4119
|
+
this.invalidateSummaries();
|
|
4120
|
+
const session = {
|
|
4121
|
+
status: "active",
|
|
4122
|
+
identity
|
|
4123
|
+
};
|
|
4124
|
+
this.publishSession(session);
|
|
4125
|
+
await provider.listenerStartup;
|
|
4126
|
+
await this.startListener(provider);
|
|
4127
|
+
return true;
|
|
4128
|
+
} catch {
|
|
4129
|
+
return false;
|
|
4130
|
+
}
|
|
4131
|
+
});
|
|
4132
|
+
}
|
|
4133
|
+
/** Publish one newly registered identity and start its listener through the existing session path. */
|
|
4134
|
+
async activateRegisteredIdentity(identity) {
|
|
4135
|
+
this.activeIdentityDid = identity.did;
|
|
4136
|
+
this.publishSession({
|
|
4137
|
+
status: "active",
|
|
4138
|
+
identity
|
|
4139
|
+
});
|
|
4140
|
+
const provider = this.provider;
|
|
4141
|
+
if (provider !== void 0) {
|
|
4142
|
+
await provider.listenerStartup;
|
|
4143
|
+
await this.startListener(provider);
|
|
4144
|
+
}
|
|
4145
|
+
}
|
|
2908
4146
|
/** Invalidate cached session work and cancel every model request still owned by the old session. */
|
|
2909
4147
|
invalidateSummaries() {
|
|
2910
4148
|
this.sessionRevision += 1;
|
|
@@ -2915,6 +4153,17 @@ let AwikiService = (() => {
|
|
|
2915
4153
|
publishSession(session) {
|
|
2916
4154
|
this.hostContext.emit("awiki/session", session);
|
|
2917
4155
|
}
|
|
4156
|
+
/** Resolve and cache the owner binding required by private Host-side projections. */
|
|
4157
|
+
async ownerDid(client) {
|
|
4158
|
+
const identity = this.activeIdentityDid === void 0 ? await client.getIdentity() : void 0;
|
|
4159
|
+
const ownerDid = this.activeIdentityDid ?? identity?.did;
|
|
4160
|
+
if (ownerDid === void 0) throw Object.assign(/* @__PURE__ */ new Error("not registered"), {
|
|
4161
|
+
name: "AwikiSdkError",
|
|
4162
|
+
code: "not-registered"
|
|
4163
|
+
});
|
|
4164
|
+
this.activeIdentityDid = ownerDid;
|
|
4165
|
+
return ownerDid;
|
|
4166
|
+
}
|
|
2918
4167
|
/** Invoke the current client and normalize every rejection to a public result. */
|
|
2919
4168
|
async run(operation, options = {}) {
|
|
2920
4169
|
try {
|