@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/types/index.js
CHANGED
|
@@ -50,6 +50,8 @@ import { AWIKI_SETTINGS_RPC_CHANNEL } from "./settings-rpc-contract.js";
|
|
|
50
50
|
import { createAwikiSettingsRpcHandler } from "./settings-rpc.js";
|
|
51
51
|
import { AwikiSessionStore } from "./session.js";
|
|
52
52
|
import { AwikiImageAttachmentCache, minimumImageAttachmentCacheMaxBytes } from "./attachment-cache.js";
|
|
53
|
+
import { AwikiSentMailStore, isLocalSentMailId } from "./sent-mail-store.js";
|
|
54
|
+
import { AwikiConversationPreferenceStore, normalizeConversationPreferenceMutation, } from "./conversation-preferences.js";
|
|
53
55
|
import { AwikiAgentListener, DshAwikiListenerAgentRuntime, } from "./listener.js";
|
|
54
56
|
export { AWIKI_CLEAR_LOCAL_DATA_CONFIRMATION, AWIKI_LOGOUT_CONFIRMATION } from "./types.js";
|
|
55
57
|
export { AWIKI_EXTERNAL_HTTP_MAX_BODY_BYTES, AwikiExternalHttpAuthError, } from "./external-http-auth.js";
|
|
@@ -98,8 +100,11 @@ const FAILURE_CODES = new Set([
|
|
|
98
100
|
'handle-unavailable',
|
|
99
101
|
'not-found',
|
|
100
102
|
'forbidden',
|
|
103
|
+
'identity-recovery-required',
|
|
101
104
|
'conflict',
|
|
102
105
|
'rate-limited',
|
|
106
|
+
'group-membership-required',
|
|
107
|
+
'group-identity-stale',
|
|
103
108
|
'attachment-too-large',
|
|
104
109
|
'summary-unavailable',
|
|
105
110
|
'summary-timeout',
|
|
@@ -124,8 +129,11 @@ const FAILURE_MESSAGES = {
|
|
|
124
129
|
'handle-unavailable': 'The requested AWiki handle is unavailable.',
|
|
125
130
|
'not-found': 'The requested AWiki resource was not found.',
|
|
126
131
|
'forbidden': 'The AWiki operation is not permitted.',
|
|
132
|
+
'identity-recovery-required': 'The local AWiki identity must be recovered before it can be used again.',
|
|
127
133
|
'conflict': 'The AWiki operation conflicts with current state.',
|
|
128
134
|
'rate-limited': 'The AWiki service rate-limited the request.',
|
|
135
|
+
'group-membership-required': 'The active AWiki identity is not a member of this group.',
|
|
136
|
+
'group-identity-stale': 'The AWiki group identity binding is still recovering.',
|
|
129
137
|
'attachment-too-large': 'The attachment exceeds this deployment\'s size limit.',
|
|
130
138
|
'summary-unavailable': 'AI summary is unavailable. Check the current default model configuration.',
|
|
131
139
|
'summary-timeout': 'AI summary timed out. Try again.',
|
|
@@ -294,13 +302,18 @@ function normalizeFailure(error) {
|
|
|
294
302
|
const MAX_GROUP_NAME_CHARACTERS = 100;
|
|
295
303
|
const MAX_GROUP_INITIAL_MEMBERS = 50;
|
|
296
304
|
const MAX_GROUP_MEMBER_CHARACTERS = 512;
|
|
305
|
+
const MAX_PROFILE_DISPLAY_NAME_CHARACTERS = 50;
|
|
306
|
+
const MAX_PROFILE_BIO_CHARACTERS = 100;
|
|
307
|
+
const MAX_PROFILE_TAGS = 5;
|
|
308
|
+
const MAX_PROFILE_TAG_CHARACTERS = 30;
|
|
309
|
+
const MAX_MESSAGE_CHARACTERS = 20_000;
|
|
297
310
|
function normalizeCreateGroupRequest(request) {
|
|
298
311
|
if (typeof request?.name !== 'string' || !Array.isArray(request.members))
|
|
299
312
|
return undefined;
|
|
300
313
|
const name = request.name.trim();
|
|
301
314
|
if (name.length === 0 || Array.from(name).length > MAX_GROUP_NAME_CHARACTERS)
|
|
302
315
|
return undefined;
|
|
303
|
-
if (request.members.length
|
|
316
|
+
if (request.members.length > MAX_GROUP_INITIAL_MEMBERS)
|
|
304
317
|
return undefined;
|
|
305
318
|
const members = [];
|
|
306
319
|
const seen = new Set();
|
|
@@ -315,7 +328,194 @@ function normalizeCreateGroupRequest(request) {
|
|
|
315
328
|
seen.add(member);
|
|
316
329
|
members.push(member);
|
|
317
330
|
}
|
|
318
|
-
return
|
|
331
|
+
return { name, members };
|
|
332
|
+
}
|
|
333
|
+
function normalizeMember(value) {
|
|
334
|
+
if (typeof value !== 'string')
|
|
335
|
+
return undefined;
|
|
336
|
+
const member = value.trim().replace(/^@+/u, '');
|
|
337
|
+
return member.length > 0 && Array.from(member).length <= MAX_GROUP_MEMBER_CHARACTERS
|
|
338
|
+
? member
|
|
339
|
+
: undefined;
|
|
340
|
+
}
|
|
341
|
+
function normalizeGroupDid(value) {
|
|
342
|
+
if (typeof value !== 'string' || !value.startsWith('did:') || value.length > 2_048)
|
|
343
|
+
return undefined;
|
|
344
|
+
return value;
|
|
345
|
+
}
|
|
346
|
+
/** Rebuild the browser-safe recovery DTO instead of trusting provider object shape. */
|
|
347
|
+
function publicGroupRebindRecoverySummary(value) {
|
|
348
|
+
if (typeof value !== 'object' || value === null)
|
|
349
|
+
return undefined;
|
|
350
|
+
const candidate = value;
|
|
351
|
+
const counts = [candidate.processed, candidate.completed, candidate.pending, candidate.blocked];
|
|
352
|
+
if (counts.some(count => !Number.isSafeInteger(count) || count < 0 || count > 0xffff_ffff)) {
|
|
353
|
+
return undefined;
|
|
354
|
+
}
|
|
355
|
+
if (!Array.isArray(candidate.items) || candidate.items.length > 500)
|
|
356
|
+
return undefined;
|
|
357
|
+
const seen = new Set();
|
|
358
|
+
const items = [];
|
|
359
|
+
for (const value of candidate.items) {
|
|
360
|
+
if (typeof value !== 'object' || value === null)
|
|
361
|
+
return undefined;
|
|
362
|
+
const item = value;
|
|
363
|
+
const groupDid = normalizeGroupDid(item.groupDid);
|
|
364
|
+
if (groupDid === undefined || seen.has(groupDid) || (item.status !== 'pending' && item.status !== 'blocked')) {
|
|
365
|
+
return undefined;
|
|
366
|
+
}
|
|
367
|
+
seen.add(groupDid);
|
|
368
|
+
items.push({ groupDid, status: item.status });
|
|
369
|
+
}
|
|
370
|
+
return {
|
|
371
|
+
processed: candidate.processed,
|
|
372
|
+
completed: candidate.completed,
|
|
373
|
+
pending: candidate.pending,
|
|
374
|
+
blocked: candidate.blocked,
|
|
375
|
+
items,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
function normalizeProfileRequest(request) {
|
|
379
|
+
if (typeof request?.displayName !== 'string' || typeof request.bio !== 'string' || !Array.isArray(request.tags))
|
|
380
|
+
return undefined;
|
|
381
|
+
const displayName = request.displayName.trim();
|
|
382
|
+
const bio = request.bio.trim();
|
|
383
|
+
if (displayName.length === 0
|
|
384
|
+
|| Array.from(displayName).length > MAX_PROFILE_DISPLAY_NAME_CHARACTERS
|
|
385
|
+
|| Array.from(bio).length > MAX_PROFILE_BIO_CHARACTERS
|
|
386
|
+
|| request.tags.length > MAX_PROFILE_TAGS)
|
|
387
|
+
return undefined;
|
|
388
|
+
const tags = [];
|
|
389
|
+
const seen = new Set();
|
|
390
|
+
for (const raw of request.tags) {
|
|
391
|
+
if (typeof raw !== 'string')
|
|
392
|
+
return undefined;
|
|
393
|
+
const tag = raw.trim();
|
|
394
|
+
const key = tag.toLocaleLowerCase();
|
|
395
|
+
if (tag.length === 0 || Array.from(tag).length > MAX_PROFILE_TAG_CHARACTERS || seen.has(key))
|
|
396
|
+
return undefined;
|
|
397
|
+
seen.add(key);
|
|
398
|
+
tags.push(tag);
|
|
399
|
+
}
|
|
400
|
+
return { displayName, bio, tags };
|
|
401
|
+
}
|
|
402
|
+
function normalizeRecoveryOperation(request) {
|
|
403
|
+
if (typeof request?.operationId !== 'string')
|
|
404
|
+
return undefined;
|
|
405
|
+
const operationId = request.operationId.trim();
|
|
406
|
+
return operationId.length > 0 && operationId.length <= 512 ? { operationId } : undefined;
|
|
407
|
+
}
|
|
408
|
+
function normalizeRecoveryOtpRequest(request) {
|
|
409
|
+
if (typeof request?.fullHandle !== 'string' || typeof request.phone !== 'string')
|
|
410
|
+
return undefined;
|
|
411
|
+
const fullHandle = request.fullHandle.trim().replace(/^@+/u, '');
|
|
412
|
+
const phone = request.phone.trim();
|
|
413
|
+
if (fullHandle.length === 0 || fullHandle.length > 512 || phone.length < 5 || phone.length > 32)
|
|
414
|
+
return undefined;
|
|
415
|
+
return { fullHandle, phone };
|
|
416
|
+
}
|
|
417
|
+
function normalizeRecoveryPrepareRequest(request) {
|
|
418
|
+
const operation = normalizeRecoveryOperation(request);
|
|
419
|
+
if (operation === undefined || typeof request.phone !== 'string' || typeof request.otp !== 'string')
|
|
420
|
+
return undefined;
|
|
421
|
+
const phone = request.phone.trim();
|
|
422
|
+
const otp = request.otp.trim();
|
|
423
|
+
if (phone.length < 5 || phone.length > 32 || !/^\d{4,12}$/u.test(otp))
|
|
424
|
+
return undefined;
|
|
425
|
+
return { ...operation, phone, otp };
|
|
426
|
+
}
|
|
427
|
+
const IDENTITY_ACCESS_RESPONSE_MAX_BYTES = 64 * 1024;
|
|
428
|
+
/** Read one untrusted discovery response without buffering beyond the fixed Host limit. */
|
|
429
|
+
async function readBoundedResponseText(response, maxBytes) {
|
|
430
|
+
const declaredLength = response.headers.get('content-length');
|
|
431
|
+
if (declaredLength !== null && /^\d+$/u.test(declaredLength) && Number(declaredLength) > maxBytes)
|
|
432
|
+
return undefined;
|
|
433
|
+
if (response.body === null)
|
|
434
|
+
return '';
|
|
435
|
+
const reader = response.body.getReader();
|
|
436
|
+
const chunks = [];
|
|
437
|
+
let length = 0;
|
|
438
|
+
try {
|
|
439
|
+
while (true) {
|
|
440
|
+
const result = await reader.read();
|
|
441
|
+
if (result.done)
|
|
442
|
+
break;
|
|
443
|
+
length += result.value.byteLength;
|
|
444
|
+
if (length > maxBytes) {
|
|
445
|
+
await reader.cancel();
|
|
446
|
+
return undefined;
|
|
447
|
+
}
|
|
448
|
+
chunks.push(Uint8Array.from(result.value));
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
catch {
|
|
452
|
+
return undefined;
|
|
453
|
+
}
|
|
454
|
+
finally {
|
|
455
|
+
reader.releaseLock();
|
|
456
|
+
}
|
|
457
|
+
const bytes = new Uint8Array(length);
|
|
458
|
+
let offset = 0;
|
|
459
|
+
for (const chunk of chunks) {
|
|
460
|
+
bytes.set(chunk, offset);
|
|
461
|
+
offset += chunk.byteLength;
|
|
462
|
+
}
|
|
463
|
+
return Buffer.from(bytes).toString('utf8');
|
|
464
|
+
}
|
|
465
|
+
/** Resolve one configured-domain Handle without widening registration authority. */
|
|
466
|
+
function identityAccessTarget(request, configuredDomain) {
|
|
467
|
+
if (typeof request?.handle !== 'string')
|
|
468
|
+
return undefined;
|
|
469
|
+
const raw = request.handle.trim();
|
|
470
|
+
if (raw.length === 0 || raw.length > 255 || /[\u0000-\u001f\u007f]/u.test(raw))
|
|
471
|
+
return undefined;
|
|
472
|
+
const lowered = raw.replace(/[A-Z]/gu, character => character.toLowerCase());
|
|
473
|
+
const handle = lowered.startsWith('wba://') ? lowered.slice('wba://'.length) : lowered;
|
|
474
|
+
const dot = handle.indexOf('.');
|
|
475
|
+
const localPart = (dot < 0 ? handle : handle.slice(0, dot)).trim();
|
|
476
|
+
const domain = (dot < 0 ? configuredDomain : handle.slice(dot + 1)).trim().replace(/\.$/u, '');
|
|
477
|
+
if (localPart.length === 0 || domain !== configuredDomain)
|
|
478
|
+
return undefined;
|
|
479
|
+
return { localPart, fullHandle: `${localPart}.${configuredDomain}` };
|
|
480
|
+
}
|
|
481
|
+
function normalizeSendTextRequest(request) {
|
|
482
|
+
if (typeof request?.text !== 'string' || typeof request.idempotencyKey !== 'string'
|
|
483
|
+
|| typeof request.target !== 'object' || request.target === null)
|
|
484
|
+
return undefined;
|
|
485
|
+
const text = request.text;
|
|
486
|
+
const codePoints = Array.from(text);
|
|
487
|
+
if (text.trim().length === 0 || codePoints.length > MAX_MESSAGE_CHARACTERS
|
|
488
|
+
|| request.idempotencyKey.length === 0 || request.idempotencyKey.length > 512)
|
|
489
|
+
return undefined;
|
|
490
|
+
if (request.target.kind === 'direct') {
|
|
491
|
+
if (typeof request.target.peer !== 'string' || request.mentions !== undefined)
|
|
492
|
+
return undefined;
|
|
493
|
+
}
|
|
494
|
+
else if (request.target.kind === 'group') {
|
|
495
|
+
if (typeof request.target.group !== 'string')
|
|
496
|
+
return undefined;
|
|
497
|
+
}
|
|
498
|
+
else
|
|
499
|
+
return undefined;
|
|
500
|
+
if (request.mentions === undefined)
|
|
501
|
+
return request;
|
|
502
|
+
if (!Array.isArray(request.mentions) || request.mentions.length === 0 || request.mentions.length > 100)
|
|
503
|
+
return undefined;
|
|
504
|
+
const ids = new Set();
|
|
505
|
+
let previousEnd = 0;
|
|
506
|
+
const mentions = [...request.mentions].sort((left, right) => left.start - right.start || left.end - right.end);
|
|
507
|
+
for (const mention of mentions) {
|
|
508
|
+
if (typeof mention !== 'object' || mention === null
|
|
509
|
+
|| typeof mention.id !== 'string' || mention.id.trim() === '' || ids.has(mention.id)
|
|
510
|
+
|| !Number.isSafeInteger(mention.start) || !Number.isSafeInteger(mention.end)
|
|
511
|
+
|| mention.start < previousEnd || mention.start < 0 || mention.end <= mention.start || mention.end > codePoints.length
|
|
512
|
+
|| typeof mention.did !== 'string' || !mention.did.startsWith('did:')
|
|
513
|
+
|| (mention.displayName !== undefined && typeof mention.displayName !== 'string'))
|
|
514
|
+
return undefined;
|
|
515
|
+
ids.add(mention.id);
|
|
516
|
+
previousEnd = mention.end;
|
|
517
|
+
}
|
|
518
|
+
return { ...request, mentions };
|
|
319
519
|
}
|
|
320
520
|
/** Normalize summary-provider failures without returning prompts, model output, routes, or causes. */
|
|
321
521
|
function normalizeSummaryFailure(error) {
|
|
@@ -450,11 +650,29 @@ let AwikiService = (() => {
|
|
|
450
650
|
let _getSession_decorators;
|
|
451
651
|
let _logout_decorators;
|
|
452
652
|
let _login_decorators;
|
|
653
|
+
let _inspectIdentityAccess_decorators;
|
|
453
654
|
let _sendRegistrationOtp_decorators;
|
|
454
655
|
let _registerIdentity_decorators;
|
|
455
656
|
let _updateDisplayName_decorators;
|
|
657
|
+
let _getProfile_decorators;
|
|
658
|
+
let _updateProfile_decorators;
|
|
659
|
+
let _sendRecoveryOtp_decorators;
|
|
660
|
+
let _prepareRecovery_decorators;
|
|
661
|
+
let _activateRecovery_decorators;
|
|
662
|
+
let _getRecoveryStatus_decorators;
|
|
663
|
+
let _resumeRecovery_decorators;
|
|
664
|
+
let _discardRecovery_decorators;
|
|
456
665
|
let _resolvePeer_decorators;
|
|
457
666
|
let _createGroup_decorators;
|
|
667
|
+
let _getGroup_decorators;
|
|
668
|
+
let _joinGroup_decorators;
|
|
669
|
+
let _leaveGroup_decorators;
|
|
670
|
+
let _listGroupMembers_decorators;
|
|
671
|
+
let _addGroupMember_decorators;
|
|
672
|
+
let _removeGroupMember_decorators;
|
|
673
|
+
let _resumeGroupRebindRecovery_decorators;
|
|
674
|
+
let _getConversationPreferences_decorators;
|
|
675
|
+
let _updateConversationPreference_decorators;
|
|
458
676
|
let _listConversations_decorators;
|
|
459
677
|
let _getHistory_decorators;
|
|
460
678
|
let _getLocalHistory_decorators;
|
|
@@ -477,11 +695,29 @@ let AwikiService = (() => {
|
|
|
477
695
|
_getSession_decorators = [Remote];
|
|
478
696
|
_logout_decorators = [Remote];
|
|
479
697
|
_login_decorators = [Remote];
|
|
698
|
+
_inspectIdentityAccess_decorators = [Remote];
|
|
480
699
|
_sendRegistrationOtp_decorators = [Remote];
|
|
481
700
|
_registerIdentity_decorators = [Remote];
|
|
482
701
|
_updateDisplayName_decorators = [Remote];
|
|
702
|
+
_getProfile_decorators = [Remote];
|
|
703
|
+
_updateProfile_decorators = [Remote];
|
|
704
|
+
_sendRecoveryOtp_decorators = [Remote];
|
|
705
|
+
_prepareRecovery_decorators = [Remote];
|
|
706
|
+
_activateRecovery_decorators = [Remote];
|
|
707
|
+
_getRecoveryStatus_decorators = [Remote];
|
|
708
|
+
_resumeRecovery_decorators = [Remote];
|
|
709
|
+
_discardRecovery_decorators = [Remote];
|
|
483
710
|
_resolvePeer_decorators = [Remote];
|
|
484
711
|
_createGroup_decorators = [Remote];
|
|
712
|
+
_getGroup_decorators = [Remote];
|
|
713
|
+
_joinGroup_decorators = [Remote];
|
|
714
|
+
_leaveGroup_decorators = [Remote];
|
|
715
|
+
_listGroupMembers_decorators = [Remote];
|
|
716
|
+
_addGroupMember_decorators = [Remote];
|
|
717
|
+
_removeGroupMember_decorators = [Remote];
|
|
718
|
+
_resumeGroupRebindRecovery_decorators = [Remote];
|
|
719
|
+
_getConversationPreferences_decorators = [Remote];
|
|
720
|
+
_updateConversationPreference_decorators = [Remote];
|
|
485
721
|
_listConversations_decorators = [Remote];
|
|
486
722
|
_getHistory_decorators = [Remote];
|
|
487
723
|
_getLocalHistory_decorators = [Remote];
|
|
@@ -501,11 +737,29 @@ let AwikiService = (() => {
|
|
|
501
737
|
__esDecorate(this, null, _getSession_decorators, { kind: "method", name: "getSession", static: false, private: false, access: { has: obj => "getSession" in obj, get: obj => obj.getSession }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
502
738
|
__esDecorate(this, null, _logout_decorators, { kind: "method", name: "logout", static: false, private: false, access: { has: obj => "logout" in obj, get: obj => obj.logout }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
503
739
|
__esDecorate(this, null, _login_decorators, { kind: "method", name: "login", static: false, private: false, access: { has: obj => "login" in obj, get: obj => obj.login }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
740
|
+
__esDecorate(this, null, _inspectIdentityAccess_decorators, { kind: "method", name: "inspectIdentityAccess", static: false, private: false, access: { has: obj => "inspectIdentityAccess" in obj, get: obj => obj.inspectIdentityAccess }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
504
741
|
__esDecorate(this, null, _sendRegistrationOtp_decorators, { kind: "method", name: "sendRegistrationOtp", static: false, private: false, access: { has: obj => "sendRegistrationOtp" in obj, get: obj => obj.sendRegistrationOtp }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
505
742
|
__esDecorate(this, null, _registerIdentity_decorators, { kind: "method", name: "registerIdentity", static: false, private: false, access: { has: obj => "registerIdentity" in obj, get: obj => obj.registerIdentity }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
506
743
|
__esDecorate(this, null, _updateDisplayName_decorators, { kind: "method", name: "updateDisplayName", static: false, private: false, access: { has: obj => "updateDisplayName" in obj, get: obj => obj.updateDisplayName }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
744
|
+
__esDecorate(this, null, _getProfile_decorators, { kind: "method", name: "getProfile", static: false, private: false, access: { has: obj => "getProfile" in obj, get: obj => obj.getProfile }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
745
|
+
__esDecorate(this, null, _updateProfile_decorators, { kind: "method", name: "updateProfile", static: false, private: false, access: { has: obj => "updateProfile" in obj, get: obj => obj.updateProfile }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
746
|
+
__esDecorate(this, null, _sendRecoveryOtp_decorators, { kind: "method", name: "sendRecoveryOtp", static: false, private: false, access: { has: obj => "sendRecoveryOtp" in obj, get: obj => obj.sendRecoveryOtp }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
747
|
+
__esDecorate(this, null, _prepareRecovery_decorators, { kind: "method", name: "prepareRecovery", static: false, private: false, access: { has: obj => "prepareRecovery" in obj, get: obj => obj.prepareRecovery }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
748
|
+
__esDecorate(this, null, _activateRecovery_decorators, { kind: "method", name: "activateRecovery", static: false, private: false, access: { has: obj => "activateRecovery" in obj, get: obj => obj.activateRecovery }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
749
|
+
__esDecorate(this, null, _getRecoveryStatus_decorators, { kind: "method", name: "getRecoveryStatus", static: false, private: false, access: { has: obj => "getRecoveryStatus" in obj, get: obj => obj.getRecoveryStatus }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
750
|
+
__esDecorate(this, null, _resumeRecovery_decorators, { kind: "method", name: "resumeRecovery", static: false, private: false, access: { has: obj => "resumeRecovery" in obj, get: obj => obj.resumeRecovery }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
751
|
+
__esDecorate(this, null, _discardRecovery_decorators, { kind: "method", name: "discardRecovery", static: false, private: false, access: { has: obj => "discardRecovery" in obj, get: obj => obj.discardRecovery }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
507
752
|
__esDecorate(this, null, _resolvePeer_decorators, { kind: "method", name: "resolvePeer", static: false, private: false, access: { has: obj => "resolvePeer" in obj, get: obj => obj.resolvePeer }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
508
753
|
__esDecorate(this, null, _createGroup_decorators, { kind: "method", name: "createGroup", static: false, private: false, access: { has: obj => "createGroup" in obj, get: obj => obj.createGroup }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
754
|
+
__esDecorate(this, null, _getGroup_decorators, { kind: "method", name: "getGroup", static: false, private: false, access: { has: obj => "getGroup" in obj, get: obj => obj.getGroup }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
755
|
+
__esDecorate(this, null, _joinGroup_decorators, { kind: "method", name: "joinGroup", static: false, private: false, access: { has: obj => "joinGroup" in obj, get: obj => obj.joinGroup }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
756
|
+
__esDecorate(this, null, _leaveGroup_decorators, { kind: "method", name: "leaveGroup", static: false, private: false, access: { has: obj => "leaveGroup" in obj, get: obj => obj.leaveGroup }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
757
|
+
__esDecorate(this, null, _listGroupMembers_decorators, { kind: "method", name: "listGroupMembers", static: false, private: false, access: { has: obj => "listGroupMembers" in obj, get: obj => obj.listGroupMembers }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
758
|
+
__esDecorate(this, null, _addGroupMember_decorators, { kind: "method", name: "addGroupMember", static: false, private: false, access: { has: obj => "addGroupMember" in obj, get: obj => obj.addGroupMember }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
759
|
+
__esDecorate(this, null, _removeGroupMember_decorators, { kind: "method", name: "removeGroupMember", static: false, private: false, access: { has: obj => "removeGroupMember" in obj, get: obj => obj.removeGroupMember }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
760
|
+
__esDecorate(this, null, _resumeGroupRebindRecovery_decorators, { kind: "method", name: "resumeGroupRebindRecovery", static: false, private: false, access: { has: obj => "resumeGroupRebindRecovery" in obj, get: obj => obj.resumeGroupRebindRecovery }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
761
|
+
__esDecorate(this, null, _getConversationPreferences_decorators, { kind: "method", name: "getConversationPreferences", static: false, private: false, access: { has: obj => "getConversationPreferences" in obj, get: obj => obj.getConversationPreferences }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
762
|
+
__esDecorate(this, null, _updateConversationPreference_decorators, { kind: "method", name: "updateConversationPreference", static: false, private: false, access: { has: obj => "updateConversationPreference" in obj, get: obj => obj.updateConversationPreference }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
509
763
|
__esDecorate(this, null, _listConversations_decorators, { kind: "method", name: "listConversations", static: false, private: false, access: { has: obj => "listConversations" in obj, get: obj => obj.listConversations }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
510
764
|
__esDecorate(this, null, _getHistory_decorators, { kind: "method", name: "getHistory", static: false, private: false, access: { has: obj => "getHistory" in obj, get: obj => obj.getHistory }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
511
765
|
__esDecorate(this, null, _getLocalHistory_decorators, { kind: "method", name: "getLocalHistory", static: false, private: false, access: { has: obj => "getLocalHistory" in obj, get: obj => obj.getLocalHistory }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
@@ -527,6 +781,8 @@ let AwikiService = (() => {
|
|
|
527
781
|
resolved = __runInitializers(this, _instanceExtraInitializers);
|
|
528
782
|
sessionStore;
|
|
529
783
|
imageAttachmentCache;
|
|
784
|
+
sentMailStore;
|
|
785
|
+
conversationPreferenceStore;
|
|
530
786
|
startupUserServiceDomain;
|
|
531
787
|
settingsProvider;
|
|
532
788
|
provider;
|
|
@@ -551,6 +807,8 @@ let AwikiService = (() => {
|
|
|
551
807
|
this.externalHttpAuth = createAwikiExternalHttpAuth(() => this.acquireExternalHttpAuthSession());
|
|
552
808
|
this.sessionStore = new AwikiSessionStore(this.resolved.stateRoot);
|
|
553
809
|
this.imageAttachmentCache = new AwikiImageAttachmentCache(this.resolved.stateRoot, this.resolved.attachmentMaxBytes, this.resolved.imageAttachmentCacheMaxBytes);
|
|
810
|
+
this.sentMailStore = new AwikiSentMailStore(this.resolved.stateRoot);
|
|
811
|
+
this.conversationPreferenceStore = new AwikiConversationPreferenceStore(this.resolved.stateRoot);
|
|
554
812
|
this.startupUserServiceDomain = this.resolved.userServiceDomain;
|
|
555
813
|
ctx.inject(['settings'], (settingsCtx) => {
|
|
556
814
|
const provider = settingsCtx.settings;
|
|
@@ -733,11 +991,56 @@ let AwikiService = (() => {
|
|
|
733
991
|
}
|
|
734
992
|
});
|
|
735
993
|
}
|
|
736
|
-
/**
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
994
|
+
/** Classify one configured-domain Handle before selecting the registration or recovery OTP purpose. */
|
|
995
|
+
async inspectIdentityAccess(request) {
|
|
996
|
+
const target = identityAccessTarget(request, this.startupUserServiceDomain);
|
|
997
|
+
if (target === undefined)
|
|
998
|
+
return { ok: false, error: failure('invalid-request') };
|
|
999
|
+
const endpoint = new URL(`/.well-known/handle/${encodeURIComponent(target.localPart)}`, this.resolved.userServiceUrl);
|
|
1000
|
+
const abort = new AbortController();
|
|
1001
|
+
const timeout = setTimeout(() => { abort.abort(); }, 10_000);
|
|
1002
|
+
let response;
|
|
1003
|
+
try {
|
|
1004
|
+
response = await fetch(endpoint, {
|
|
1005
|
+
method: 'GET',
|
|
1006
|
+
headers: { accept: 'application/json', 'cache-control': 'no-store' },
|
|
1007
|
+
cache: 'no-store',
|
|
1008
|
+
redirect: 'error',
|
|
1009
|
+
signal: abort.signal,
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
catch {
|
|
1013
|
+
return { ok: false, error: failure('network') };
|
|
1014
|
+
}
|
|
1015
|
+
finally {
|
|
1016
|
+
clearTimeout(timeout);
|
|
1017
|
+
}
|
|
1018
|
+
if (response.status === 404) {
|
|
1019
|
+
return { ok: true, value: { status: 'available', fullHandle: target.fullHandle } };
|
|
1020
|
+
}
|
|
1021
|
+
if (!response.ok)
|
|
1022
|
+
return { ok: false, error: failure('remote') };
|
|
1023
|
+
try {
|
|
1024
|
+
const text = await readBoundedResponseText(response, IDENTITY_ACCESS_RESPONSE_MAX_BYTES);
|
|
1025
|
+
if (text === undefined)
|
|
1026
|
+
return { ok: false, error: failure('remote') };
|
|
1027
|
+
const value = JSON.parse(text);
|
|
1028
|
+
if (typeof value !== 'object' || value === null)
|
|
1029
|
+
return { ok: false, error: failure('remote') };
|
|
1030
|
+
const binding = value;
|
|
1031
|
+
if (binding.handle !== target.fullHandle
|
|
1032
|
+
|| typeof binding.did !== 'string'
|
|
1033
|
+
|| !binding.did.startsWith('did:')
|
|
1034
|
+
|| typeof binding.status !== 'string'
|
|
1035
|
+
|| binding.status.length === 0) {
|
|
1036
|
+
return { ok: false, error: failure('remote') };
|
|
1037
|
+
}
|
|
1038
|
+
return { ok: true, value: { status: 'existing', fullHandle: target.fullHandle } };
|
|
1039
|
+
}
|
|
1040
|
+
catch {
|
|
1041
|
+
return { ok: false, error: failure('remote') };
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
741
1044
|
sendRegistrationOtp(request) {
|
|
742
1045
|
return this.run(client => client.sendRegistrationOtp(request));
|
|
743
1046
|
}
|
|
@@ -748,15 +1051,8 @@ let AwikiService = (() => {
|
|
|
748
1051
|
*/
|
|
749
1052
|
async registerIdentity(request) {
|
|
750
1053
|
const result = await this.run(client => client.registerIdentity(request));
|
|
751
|
-
if (result.ok)
|
|
752
|
-
this.
|
|
753
|
-
this.publishSession({ status: 'active', identity: result.value });
|
|
754
|
-
const provider = this.provider;
|
|
755
|
-
if (provider !== undefined) {
|
|
756
|
-
await provider.listenerStartup;
|
|
757
|
-
await this.startListener(provider);
|
|
758
|
-
}
|
|
759
|
-
}
|
|
1054
|
+
if (result.ok)
|
|
1055
|
+
await this.activateRegisteredIdentity(result.value);
|
|
760
1056
|
return result;
|
|
761
1057
|
}
|
|
762
1058
|
/**
|
|
@@ -770,6 +1066,72 @@ let AwikiService = (() => {
|
|
|
770
1066
|
this.activeIdentityDid = result.value.did;
|
|
771
1067
|
return result;
|
|
772
1068
|
}
|
|
1069
|
+
/** Return the public editable profile for the active identity. */
|
|
1070
|
+
getProfile() {
|
|
1071
|
+
return this.run(client => client.getProfile());
|
|
1072
|
+
}
|
|
1073
|
+
/** Update Display Name, bio, and tags after applying product limits in the Host. */
|
|
1074
|
+
updateProfile(request) {
|
|
1075
|
+
const normalized = normalizeProfileRequest(request);
|
|
1076
|
+
if (normalized === undefined)
|
|
1077
|
+
return Promise.resolve({ ok: false, error: failure('invalid-request') });
|
|
1078
|
+
return this.run(client => client.updateProfile(normalized));
|
|
1079
|
+
}
|
|
1080
|
+
/** Start durable phone recovery for one existing full Handle. */
|
|
1081
|
+
sendRecoveryOtp(request) {
|
|
1082
|
+
const normalized = normalizeRecoveryOtpRequest(request);
|
|
1083
|
+
if (normalized === undefined)
|
|
1084
|
+
return Promise.resolve({ ok: false, error: failure('invalid-request') });
|
|
1085
|
+
return this.run(client => client.sendRecoveryOtp(normalized), { allowSignedOut: true });
|
|
1086
|
+
}
|
|
1087
|
+
/** Verify a recovery OTP and freeze its exact intent before the remote commit. */
|
|
1088
|
+
prepareRecovery(request) {
|
|
1089
|
+
const normalized = normalizeRecoveryPrepareRequest(request);
|
|
1090
|
+
if (normalized === undefined)
|
|
1091
|
+
return Promise.resolve({ ok: false, error: failure('invalid-request') });
|
|
1092
|
+
return this.run(client => client.prepareRecovery(normalized), { allowSignedOut: true });
|
|
1093
|
+
}
|
|
1094
|
+
/** Attempt one prepared recovery commit; uncertain outcomes remain durable in Core. */
|
|
1095
|
+
async activateRecovery(request) {
|
|
1096
|
+
const normalized = normalizeRecoveryOperation(request);
|
|
1097
|
+
if (normalized === undefined)
|
|
1098
|
+
return { ok: false, error: failure('invalid-request') };
|
|
1099
|
+
const result = await this.run(client => client.activateRecovery(normalized), { allowSignedOut: true });
|
|
1100
|
+
if (result.ok && !await this.applyRecoveredSession(result.value)) {
|
|
1101
|
+
return { ok: false, error: failure('remote') };
|
|
1102
|
+
}
|
|
1103
|
+
return result;
|
|
1104
|
+
}
|
|
1105
|
+
/** Read durable recovery state before deciding whether a retry is valid. */
|
|
1106
|
+
async getRecoveryStatus(request) {
|
|
1107
|
+
const normalized = normalizeRecoveryOperation(request);
|
|
1108
|
+
if (normalized === undefined)
|
|
1109
|
+
return { ok: false, error: failure('invalid-request') };
|
|
1110
|
+
const result = await this.run(client => client.getRecoveryStatus(normalized), { allowSignedOut: true });
|
|
1111
|
+
if (result.ok && !await this.applyRecoveredSession(result.value)) {
|
|
1112
|
+
return { ok: false, error: failure('remote') };
|
|
1113
|
+
}
|
|
1114
|
+
return result;
|
|
1115
|
+
}
|
|
1116
|
+
/** Resume only the exact Core-owned operation selected by the browser. */
|
|
1117
|
+
async resumeRecovery(request) {
|
|
1118
|
+
const normalized = normalizeRecoveryOperation(request);
|
|
1119
|
+
if (normalized === undefined)
|
|
1120
|
+
return { ok: false, error: failure('invalid-request') };
|
|
1121
|
+
const result = await this.run(client => client.resumeRecovery(normalized), { allowSignedOut: true });
|
|
1122
|
+
if (result.ok && !await this.applyRecoveredSession(result.value)) {
|
|
1123
|
+
return { ok: false, error: failure('remote') };
|
|
1124
|
+
}
|
|
1125
|
+
return result;
|
|
1126
|
+
}
|
|
1127
|
+
/** Discard only a pre-attempt operation; Core rejects post-attempt deletion. */
|
|
1128
|
+
async discardRecovery(request) {
|
|
1129
|
+
const normalized = normalizeRecoveryOperation(request);
|
|
1130
|
+
if (normalized === undefined)
|
|
1131
|
+
return { ok: false, error: failure('invalid-request') };
|
|
1132
|
+
const result = await this.run(client => client.discardRecovery(normalized), { allowSignedOut: true });
|
|
1133
|
+
return result.ok ? { ok: true, value: { completed: true } } : result;
|
|
1134
|
+
}
|
|
773
1135
|
/**
|
|
774
1136
|
* Resolve one Handle or DID before the browser opens a direct chat.
|
|
775
1137
|
* @param request - typed Handle or DID.
|
|
@@ -804,6 +1166,81 @@ let AwikiService = (() => {
|
|
|
804
1166
|
value: { conversation: created.value, addedMembers, failedMembers },
|
|
805
1167
|
};
|
|
806
1168
|
}
|
|
1169
|
+
/** Return one authoritative group snapshot for permission-aware UI. */
|
|
1170
|
+
getGroup(request) {
|
|
1171
|
+
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
1172
|
+
if (groupDid === undefined)
|
|
1173
|
+
return Promise.resolve({ ok: false, error: failure('invalid-request') });
|
|
1174
|
+
return this.run(client => client.getGroup(groupDid));
|
|
1175
|
+
}
|
|
1176
|
+
/** Join one open group and return its authoritative membership state. */
|
|
1177
|
+
joinGroup(request) {
|
|
1178
|
+
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
1179
|
+
if (groupDid === undefined)
|
|
1180
|
+
return Promise.resolve({ ok: false, error: failure('invalid-request') });
|
|
1181
|
+
return this.run(client => client.joinGroup(groupDid));
|
|
1182
|
+
}
|
|
1183
|
+
/** Leave one group. Core rejects owner leave and unsupported security profiles. */
|
|
1184
|
+
async leaveGroup(request) {
|
|
1185
|
+
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
1186
|
+
if (groupDid === undefined)
|
|
1187
|
+
return Promise.resolve({ ok: false, error: failure('invalid-request') });
|
|
1188
|
+
const result = await this.run(client => client.leaveGroup(groupDid));
|
|
1189
|
+
return result.ok ? { ok: true, value: { completed: true } } : result;
|
|
1190
|
+
}
|
|
1191
|
+
/** Read one authoritative versioned member page. */
|
|
1192
|
+
listGroupMembers(request) {
|
|
1193
|
+
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
1194
|
+
if (groupDid === undefined
|
|
1195
|
+
|| (request.cursor !== undefined && (typeof request.cursor !== 'string' || request.cursor.length > 4_096))
|
|
1196
|
+
|| (request.limit !== undefined && (!Number.isSafeInteger(request.limit) || request.limit < 1 || request.limit > 100))) {
|
|
1197
|
+
return Promise.resolve({ ok: false, error: failure('invalid-request') });
|
|
1198
|
+
}
|
|
1199
|
+
return this.run(client => client.listGroupMembers({
|
|
1200
|
+
groupDid,
|
|
1201
|
+
...request.cursor === undefined ? {} : { cursor: request.cursor },
|
|
1202
|
+
...request.limit === undefined ? {} : { limit: request.limit },
|
|
1203
|
+
}));
|
|
1204
|
+
}
|
|
1205
|
+
/** Invite one ordinary member after group creation. */
|
|
1206
|
+
addGroupMember(request) {
|
|
1207
|
+
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
1208
|
+
const member = normalizeMember(request?.member);
|
|
1209
|
+
if (groupDid === undefined || member === undefined || (request.role !== undefined && request.role !== 'member')) {
|
|
1210
|
+
return Promise.resolve({ ok: false, error: failure('invalid-request') });
|
|
1211
|
+
}
|
|
1212
|
+
return this.run(client => client.addGroupMember(groupDid, member));
|
|
1213
|
+
}
|
|
1214
|
+
/** Remove one member. The authoritative Core role check remains decisive. */
|
|
1215
|
+
removeGroupMember(request) {
|
|
1216
|
+
const groupDid = normalizeGroupDid(request?.groupDid);
|
|
1217
|
+
const member = normalizeMember(request?.member);
|
|
1218
|
+
if (groupDid === undefined || member === undefined) {
|
|
1219
|
+
return Promise.resolve({ ok: false, error: failure('invalid-request') });
|
|
1220
|
+
}
|
|
1221
|
+
return this.run(client => client.removeGroupMember(groupDid, member));
|
|
1222
|
+
}
|
|
1223
|
+
/** Resume durable group membership convergence after account sync restores old groups. */
|
|
1224
|
+
async resumeGroupRebindRecovery() {
|
|
1225
|
+
const result = await this.run(client => client.resumeGroupRebindRecovery());
|
|
1226
|
+
if (!result.ok)
|
|
1227
|
+
return result;
|
|
1228
|
+
const summary = publicGroupRebindRecoverySummary(result.value);
|
|
1229
|
+
return summary === undefined
|
|
1230
|
+
? { ok: false, error: failure('remote') }
|
|
1231
|
+
: { ok: true, value: summary };
|
|
1232
|
+
}
|
|
1233
|
+
/** Read presentation-only roster preferences for the active identity. */
|
|
1234
|
+
getConversationPreferences() {
|
|
1235
|
+
return this.run(async (client) => this.conversationPreferenceStore.get(await this.ownerDid(client)));
|
|
1236
|
+
}
|
|
1237
|
+
/** Persist one bounded local roster preference without changing Core or remote membership. */
|
|
1238
|
+
updateConversationPreference(request) {
|
|
1239
|
+
const normalized = normalizeConversationPreferenceMutation(request);
|
|
1240
|
+
if (normalized === undefined)
|
|
1241
|
+
return Promise.resolve({ ok: false, error: failure('invalid-request') });
|
|
1242
|
+
return this.run(async (client) => this.conversationPreferenceStore.update(await this.ownerDid(client), normalized));
|
|
1243
|
+
}
|
|
807
1244
|
/**
|
|
808
1245
|
* List direct and existing group conversations.
|
|
809
1246
|
* @param request - Optional opaque cursor and page limit.
|
|
@@ -928,7 +1365,10 @@ let AwikiService = (() => {
|
|
|
928
1365
|
* @returns The accepted public message or a closed failure.
|
|
929
1366
|
*/
|
|
930
1367
|
sendText(request) {
|
|
931
|
-
|
|
1368
|
+
const normalized = normalizeSendTextRequest(request);
|
|
1369
|
+
if (normalized === undefined)
|
|
1370
|
+
return Promise.resolve({ ok: false, error: failure('invalid-request') });
|
|
1371
|
+
return this.run(client => client.sendText(normalized));
|
|
932
1372
|
}
|
|
933
1373
|
/**
|
|
934
1374
|
* Upload and send one attachment after Host validation.
|
|
@@ -1013,20 +1453,68 @@ let AwikiService = (() => {
|
|
|
1013
1453
|
return this.run(client => client.getMailAccount());
|
|
1014
1454
|
}
|
|
1015
1455
|
/** List one bounded mailbox page on explicit browser/tool demand. */
|
|
1016
|
-
listMailInbox(request) {
|
|
1017
|
-
|
|
1456
|
+
async listMailInbox(request) {
|
|
1457
|
+
let normalized;
|
|
1458
|
+
try {
|
|
1459
|
+
normalized = mailInboxRequest(request ?? {});
|
|
1460
|
+
}
|
|
1461
|
+
catch {
|
|
1462
|
+
return { ok: false, error: failure('invalid-request') };
|
|
1463
|
+
}
|
|
1464
|
+
return this.run(async (client) => {
|
|
1465
|
+
if (normalized.folder !== 'sent')
|
|
1466
|
+
return client.listMailInbox(normalized);
|
|
1467
|
+
return this.sentMailStore.list(await this.ownerDid(client), normalized);
|
|
1468
|
+
});
|
|
1018
1469
|
}
|
|
1019
1470
|
/** Read one bounded plain-text mail message. */
|
|
1020
|
-
readMail(request) {
|
|
1021
|
-
|
|
1471
|
+
async readMail(request) {
|
|
1472
|
+
let normalized;
|
|
1473
|
+
try {
|
|
1474
|
+
normalized = mailReadRequest(request);
|
|
1475
|
+
}
|
|
1476
|
+
catch {
|
|
1477
|
+
return { ok: false, error: failure('invalid-request') };
|
|
1478
|
+
}
|
|
1479
|
+
return this.run(async (client) => {
|
|
1480
|
+
if (!isLocalSentMailId(normalized.messageId))
|
|
1481
|
+
return client.readMail(normalized);
|
|
1482
|
+
const local = await this.sentMailStore.read(await this.ownerDid(client), normalized.messageId);
|
|
1483
|
+
if (local === undefined) {
|
|
1484
|
+
throw Object.assign(new Error('sent mail not found'), { name: 'AwikiSdkError', code: 'not-found' });
|
|
1485
|
+
}
|
|
1486
|
+
return local;
|
|
1487
|
+
});
|
|
1022
1488
|
}
|
|
1023
1489
|
/** Mark explicitly selected mail messages read. Browser callers require an explicit click. */
|
|
1024
1490
|
markMailRead(request) {
|
|
1025
1491
|
return this.runValidatedMail(() => mailMarkReadRequest(request), (client, normalized) => client.markMailRead(normalized));
|
|
1026
1492
|
}
|
|
1027
1493
|
/** Send one plain-text mail once. Browser callers require an explicit confirmation. */
|
|
1028
|
-
sendMail(request) {
|
|
1029
|
-
|
|
1494
|
+
async sendMail(request) {
|
|
1495
|
+
let normalized;
|
|
1496
|
+
try {
|
|
1497
|
+
normalized = mailSendRequest(request);
|
|
1498
|
+
}
|
|
1499
|
+
catch {
|
|
1500
|
+
return { ok: false, error: failure('invalid-request') };
|
|
1501
|
+
}
|
|
1502
|
+
return this.run(async (client) => {
|
|
1503
|
+
const result = await client.sendMail(normalized);
|
|
1504
|
+
if (!result.accepted)
|
|
1505
|
+
return result;
|
|
1506
|
+
try {
|
|
1507
|
+
const ownerDid = await this.ownerDid(client);
|
|
1508
|
+
const account = await client.getMailAccount().catch(() => undefined);
|
|
1509
|
+
await this.sentMailStore.append(ownerDid, normalized, result, account);
|
|
1510
|
+
return result;
|
|
1511
|
+
}
|
|
1512
|
+
catch {
|
|
1513
|
+
return result.warnings.length >= 100
|
|
1514
|
+
? result
|
|
1515
|
+
: { ...result, warnings: [...result.warnings, 'Sent history could not be saved locally.'] };
|
|
1516
|
+
}
|
|
1517
|
+
});
|
|
1030
1518
|
}
|
|
1031
1519
|
/**
|
|
1032
1520
|
* Permanently remove the exact SDK-owned local state after an explicit browser acknowledgement.
|
|
@@ -1050,6 +1538,8 @@ let AwikiService = (() => {
|
|
|
1050
1538
|
}
|
|
1051
1539
|
try {
|
|
1052
1540
|
await this.imageAttachmentCache.clear();
|
|
1541
|
+
await this.sentMailStore.clear();
|
|
1542
|
+
await this.conversationPreferenceStore.clear();
|
|
1053
1543
|
await this.sessionStore.signIn();
|
|
1054
1544
|
this.signedOut = false;
|
|
1055
1545
|
this.activeIdentityDid = undefined;
|
|
@@ -1064,6 +1554,45 @@ let AwikiService = (() => {
|
|
|
1064
1554
|
}
|
|
1065
1555
|
});
|
|
1066
1556
|
}
|
|
1557
|
+
/** Re-enter only after Core confirms that the exact recovered identity is applied locally. */
|
|
1558
|
+
async applyRecoveredSession(progress) {
|
|
1559
|
+
if (progress.phase !== 'applied')
|
|
1560
|
+
return true;
|
|
1561
|
+
return this.mutateSession(async () => {
|
|
1562
|
+
const provider = this.provider;
|
|
1563
|
+
if (provider === undefined)
|
|
1564
|
+
return false;
|
|
1565
|
+
try {
|
|
1566
|
+
const identity = await provider.client.getIdentity();
|
|
1567
|
+
if (identity === null || identity.did !== progress.currentDid)
|
|
1568
|
+
return false;
|
|
1569
|
+
if (this.signedOut === false && this.activeIdentityDid === identity.did)
|
|
1570
|
+
return true;
|
|
1571
|
+
await this.sessionStore.signIn();
|
|
1572
|
+
this.signedOut = false;
|
|
1573
|
+
this.activeIdentityDid = identity.did;
|
|
1574
|
+
this.invalidateSummaries();
|
|
1575
|
+
const session = { status: 'active', identity };
|
|
1576
|
+
this.publishSession(session);
|
|
1577
|
+
await provider.listenerStartup;
|
|
1578
|
+
await this.startListener(provider);
|
|
1579
|
+
return true;
|
|
1580
|
+
}
|
|
1581
|
+
catch {
|
|
1582
|
+
return false;
|
|
1583
|
+
}
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
/** Publish one newly registered identity and start its listener through the existing session path. */
|
|
1587
|
+
async activateRegisteredIdentity(identity) {
|
|
1588
|
+
this.activeIdentityDid = identity.did;
|
|
1589
|
+
this.publishSession({ status: 'active', identity });
|
|
1590
|
+
const provider = this.provider;
|
|
1591
|
+
if (provider !== undefined) {
|
|
1592
|
+
await provider.listenerStartup;
|
|
1593
|
+
await this.startListener(provider);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1067
1596
|
/** Invalidate cached session work and cancel every model request still owned by the old session. */
|
|
1068
1597
|
invalidateSummaries() {
|
|
1069
1598
|
this.sessionRevision += 1;
|
|
@@ -1075,6 +1604,16 @@ let AwikiService = (() => {
|
|
|
1075
1604
|
publishSession(session) {
|
|
1076
1605
|
this.hostContext.emit('awiki/session', session);
|
|
1077
1606
|
}
|
|
1607
|
+
/** Resolve and cache the owner binding required by private Host-side projections. */
|
|
1608
|
+
async ownerDid(client) {
|
|
1609
|
+
const identity = this.activeIdentityDid === undefined ? await client.getIdentity() : undefined;
|
|
1610
|
+
const ownerDid = this.activeIdentityDid ?? identity?.did;
|
|
1611
|
+
if (ownerDid === undefined) {
|
|
1612
|
+
throw Object.assign(new Error('not registered'), { name: 'AwikiSdkError', code: 'not-registered' });
|
|
1613
|
+
}
|
|
1614
|
+
this.activeIdentityDid = ownerDid;
|
|
1615
|
+
return ownerDid;
|
|
1616
|
+
}
|
|
1078
1617
|
/** Invoke the current client and normalize every rejection to a public result. */
|
|
1079
1618
|
async run(operation, options = {}) {
|
|
1080
1619
|
try {
|