@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.
Files changed (124) hide show
  1. package/README.md +69 -28
  2. package/README.zh.md +60 -21
  3. package/THIRD_PARTY_NOTICES.md +1 -1
  4. package/cordis.patch.yml +0 -8
  5. package/lib/client.js +6755 -2022
  6. package/lib/client.js.map +1 -1
  7. package/lib/index.js +1321 -72
  8. package/lib/model-proxy-contract.js +8 -1
  9. package/lib/provider.js +3 -1
  10. package/lib/{sdk-adapter-DKgkyApB.mjs → sdk-adapter-BIbsJmRj.mjs} +245 -4
  11. package/lib/typert.host.js +944 -57
  12. package/lib/typert.remote-client.d.ts +37 -1
  13. package/lib/typert.remote-client.d.ts.map +1 -1
  14. package/lib/typert.remote-client.js +944 -57
  15. package/lib/types/client/AwikiGroupAccessNotice.d.ts +12 -0
  16. package/lib/types/client/AwikiGroupAccessNotice.d.ts.map +1 -0
  17. package/lib/types/client/AwikiGroupAccessNotice.js +31 -0
  18. package/lib/types/client/AwikiGroupAccessNotice.js.map +1 -0
  19. package/lib/types/client/AwikiGroupDetails.d.ts +23 -0
  20. package/lib/types/client/AwikiGroupDetails.d.ts.map +1 -0
  21. package/lib/types/client/AwikiGroupDetails.js +144 -0
  22. package/lib/types/client/AwikiGroupDetails.js.map +1 -0
  23. package/lib/types/client/AwikiIdentityAccess.d.ts +22 -0
  24. package/lib/types/client/AwikiIdentityAccess.d.ts.map +1 -0
  25. package/lib/types/client/AwikiIdentityAccess.js +156 -0
  26. package/lib/types/client/AwikiIdentityAccess.js.map +1 -0
  27. package/lib/types/client/AwikiIdentityPage.d.ts +11 -0
  28. package/lib/types/client/AwikiIdentityPage.d.ts.map +1 -0
  29. package/lib/types/client/AwikiIdentityPage.js +8 -0
  30. package/lib/types/client/AwikiIdentityPage.js.map +1 -0
  31. package/lib/types/client/AwikiMail.d.ts +2 -1
  32. package/lib/types/client/AwikiMail.d.ts.map +1 -1
  33. package/lib/types/client/AwikiMail.js +157 -33
  34. package/lib/types/client/AwikiMail.js.map +1 -1
  35. package/lib/types/client/AwikiOnboarding.d.ts.map +1 -1
  36. package/lib/types/client/AwikiOnboarding.js +29 -9
  37. package/lib/types/client/AwikiOnboarding.js.map +1 -1
  38. package/lib/types/client/AwikiOverlay.d.ts +0 -5
  39. package/lib/types/client/AwikiOverlay.d.ts.map +1 -1
  40. package/lib/types/client/AwikiOverlay.js +202 -129
  41. package/lib/types/client/AwikiOverlay.js.map +1 -1
  42. package/lib/types/client/AwikiProfileCard.d.ts +9 -0
  43. package/lib/types/client/AwikiProfileCard.d.ts.map +1 -0
  44. package/lib/types/client/AwikiProfileCard.js +90 -0
  45. package/lib/types/client/AwikiProfileCard.js.map +1 -0
  46. package/lib/types/client/AwikiRecoveryForm.d.ts +27 -0
  47. package/lib/types/client/AwikiRecoveryForm.d.ts.map +1 -0
  48. package/lib/types/client/AwikiRecoveryForm.js +152 -0
  49. package/lib/types/client/AwikiRecoveryForm.js.map +1 -0
  50. package/lib/types/client/AwikiSettingsSection.d.ts +0 -2
  51. package/lib/types/client/AwikiSettingsSection.d.ts.map +1 -1
  52. package/lib/types/client/AwikiSettingsSection.js +18 -16
  53. package/lib/types/client/AwikiSettingsSection.js.map +1 -1
  54. package/lib/types/client/MentionText.d.ts +7 -0
  55. package/lib/types/client/MentionText.d.ts.map +1 -0
  56. package/lib/types/client/MentionText.js +10 -0
  57. package/lib/types/client/MentionText.js.map +1 -0
  58. package/lib/types/client/controller.d.ts +131 -3
  59. package/lib/types/client/controller.d.ts.map +1 -1
  60. package/lib/types/client/controller.js +908 -29
  61. package/lib/types/client/controller.js.map +1 -1
  62. package/lib/types/client/index.d.ts.map +1 -1
  63. package/lib/types/client/index.js +24 -4
  64. package/lib/types/client/index.js.map +1 -1
  65. package/lib/types/client/mail-list-cache.d.ts +15 -0
  66. package/lib/types/client/mail-list-cache.d.ts.map +1 -0
  67. package/lib/types/client/mail-list-cache.js +212 -0
  68. package/lib/types/client/mail-list-cache.js.map +1 -0
  69. package/lib/types/client/mentions.d.ts +51 -0
  70. package/lib/types/client/mentions.d.ts.map +1 -0
  71. package/lib/types/client/mentions.js +165 -0
  72. package/lib/types/client/mentions.js.map +1 -0
  73. package/lib/types/client/model-proxy-controller.d.ts +4 -0
  74. package/lib/types/client/model-proxy-controller.d.ts.map +1 -1
  75. package/lib/types/client/model-proxy-controller.js +68 -3
  76. package/lib/types/client/model-proxy-controller.js.map +1 -1
  77. package/lib/types/client/recharge-availability.d.ts +1 -1
  78. package/lib/types/client/recharge-availability.d.ts.map +1 -1
  79. package/lib/types/client/recharge-availability.js +1 -1
  80. package/lib/types/client/recharge-availability.js.map +1 -1
  81. package/lib/types/client/settings-locales.d.ts +1 -1
  82. package/lib/types/client/settings-locales.d.ts.map +1 -1
  83. package/lib/types/client/settings-locales.js +14 -8
  84. package/lib/types/client/settings-locales.js.map +1 -1
  85. package/lib/types/client/slots.d.ts +27 -2
  86. package/lib/types/client/slots.d.ts.map +1 -1
  87. package/lib/types/conversation-preferences.d.ts +20 -0
  88. package/lib/types/conversation-preferences.d.ts.map +1 -0
  89. package/lib/types/conversation-preferences.js +294 -0
  90. package/lib/types/conversation-preferences.js.map +1 -0
  91. package/lib/types/index.d.ts +45 -6
  92. package/lib/types/index.d.ts.map +1 -1
  93. package/lib/types/index.js +562 -23
  94. package/lib/types/index.js.map +1 -1
  95. package/lib/types/model-proxy-contract.d.ts +6 -0
  96. package/lib/types/model-proxy-contract.d.ts.map +1 -1
  97. package/lib/types/model-proxy-contract.js +6 -0
  98. package/lib/types/model-proxy-contract.js.map +1 -1
  99. package/lib/types/provider-api.d.ts +29 -1
  100. package/lib/types/provider-api.d.ts.map +1 -1
  101. package/lib/types/provider.d.ts.map +1 -1
  102. package/lib/types/provider.js +2 -0
  103. package/lib/types/provider.js.map +1 -1
  104. package/lib/types/sdk-adapter.d.ts +18 -1
  105. package/lib/types/sdk-adapter.d.ts.map +1 -1
  106. package/lib/types/sdk-adapter.js +277 -4
  107. package/lib/types/sdk-adapter.js.map +1 -1
  108. package/lib/types/sent-mail-store.d.ts +22 -0
  109. package/lib/types/sent-mail-store.d.ts.map +1 -0
  110. package/lib/types/sent-mail-store.js +246 -0
  111. package/lib/types/sent-mail-store.js.map +1 -0
  112. package/lib/types/types.d.ts +183 -2
  113. package/lib/types/types.d.ts.map +1 -1
  114. package/lib/types/types.js.map +1 -1
  115. package/package.json +15 -26
  116. package/lib/model-proxy.js +0 -383
  117. package/lib/types/client/model-account-settings-availability.d.ts +0 -4
  118. package/lib/types/client/model-account-settings-availability.d.ts.map +0 -1
  119. package/lib/types/client/model-account-settings-availability.js +0 -4
  120. package/lib/types/client/model-account-settings-availability.js.map +0 -1
  121. package/lib/types/model-proxy.d.ts +0 -14
  122. package/lib/types/model-proxy.d.ts.map +0 -1
  123. package/lib/types/model-proxy.js +0 -371
  124. package/lib/types/model-proxy.js.map +0 -1
@@ -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 === 0 || request.members.length > MAX_GROUP_INITIAL_MEMBERS)
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 members.length === 0 ? undefined : { name, members };
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
- * Send one Legacy registration verification code.
738
- * @param request - Handle and phone used for the registration challenge.
739
- * @returns Public retry timing or a closed failure.
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.activeIdentityDid = result.value.did;
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
- return this.run(client => client.sendText(request));
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
- return this.runValidatedMail(() => mailInboxRequest(request ?? {}), (client, normalized) => client.listMailInbox(normalized));
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
- return this.runValidatedMail(() => mailReadRequest(request), (client, normalized) => client.readMail(normalized));
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
- return this.runValidatedMail(() => mailSendRequest(request), (client, normalized) => client.sendMail(normalized));
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 {