@awiki/dsh-plugin 0.3.7-dsh-test.20260831.2 → 0.3.7

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 (99) hide show
  1. package/README.md +60 -58
  2. package/README.zh.md +51 -45
  3. package/THIRD_PARTY_NOTICES.md +1 -1
  4. package/cordis.patch.yml +8 -7
  5. package/lib/client.js +1119 -1340
  6. package/lib/client.js.map +1 -1
  7. package/lib/index.js +809 -1085
  8. package/lib/provider.js +17 -70
  9. package/lib/{sdk-adapter-FGaOi8It.mjs → sdk-adapter--trNlr-T.mjs} +84 -168
  10. package/lib/typert.host.js +178 -406
  11. package/lib/typert.remote-client.d.ts +7 -19
  12. package/lib/typert.remote-client.d.ts.map +1 -1
  13. package/lib/typert.remote-client.js +178 -406
  14. package/lib/types/base64.d.ts +4 -0
  15. package/lib/types/base64.d.ts.map +1 -0
  16. package/lib/types/base64.js +28 -0
  17. package/lib/types/base64.js.map +1 -0
  18. package/lib/types/client/AwikiIdentityAccess.d.ts +5 -6
  19. package/lib/types/client/AwikiIdentityAccess.d.ts.map +1 -1
  20. package/lib/types/client/AwikiIdentityAccess.js +27 -88
  21. package/lib/types/client/AwikiIdentityAccess.js.map +1 -1
  22. package/lib/types/client/AwikiMail.d.ts +1 -1
  23. package/lib/types/client/AwikiMail.d.ts.map +1 -1
  24. package/lib/types/client/AwikiMail.js +130 -6
  25. package/lib/types/client/AwikiMail.js.map +1 -1
  26. package/lib/types/client/AwikiOverlay.d.ts.map +1 -1
  27. package/lib/types/client/AwikiOverlay.js +12 -5
  28. package/lib/types/client/AwikiOverlay.js.map +1 -1
  29. package/lib/types/client/AwikiRecoveryForm.d.ts.map +1 -1
  30. package/lib/types/client/AwikiRecoveryForm.js +1 -1
  31. package/lib/types/client/AwikiRecoveryForm.js.map +1 -1
  32. package/lib/types/client/controller.d.ts +34 -20
  33. package/lib/types/client/controller.d.ts.map +1 -1
  34. package/lib/types/client/controller.js +203 -56
  35. package/lib/types/client/controller.js.map +1 -1
  36. package/lib/types/client/index.d.ts.map +1 -1
  37. package/lib/types/client/index.js +4 -8
  38. package/lib/types/client/index.js.map +1 -1
  39. package/lib/types/client/mail-attachment.d.ts +40 -0
  40. package/lib/types/client/mail-attachment.d.ts.map +1 -0
  41. package/lib/types/client/mail-attachment.js +187 -0
  42. package/lib/types/client/mail-attachment.js.map +1 -0
  43. package/lib/types/client/settings-locales.js +8 -8
  44. package/lib/types/client/settings-locales.js.map +1 -1
  45. package/lib/types/client/slots.d.ts +10 -10
  46. package/lib/types/client/slots.d.ts.map +1 -1
  47. package/lib/types/conversation-preferences.d.ts.map +1 -1
  48. package/lib/types/conversation-preferences.js +17 -0
  49. package/lib/types/conversation-preferences.js.map +1 -1
  50. package/lib/types/index.d.ts +30 -59
  51. package/lib/types/index.d.ts.map +1 -1
  52. package/lib/types/index.js +464 -805
  53. package/lib/types/index.js.map +1 -1
  54. package/lib/types/listener-state.d.ts +3 -5
  55. package/lib/types/listener-state.d.ts.map +1 -1
  56. package/lib/types/listener-state.js +13 -28
  57. package/lib/types/listener-state.js.map +1 -1
  58. package/lib/types/listener.d.ts +32 -9
  59. package/lib/types/listener.d.ts.map +1 -1
  60. package/lib/types/listener.js +127 -11
  61. package/lib/types/listener.js.map +1 -1
  62. package/lib/types/mail.d.ts +28 -2
  63. package/lib/types/mail.d.ts.map +1 -1
  64. package/lib/types/mail.js +79 -2
  65. package/lib/types/mail.js.map +1 -1
  66. package/lib/types/profile-state.d.ts +17 -0
  67. package/lib/types/profile-state.d.ts.map +1 -0
  68. package/lib/types/profile-state.js +58 -0
  69. package/lib/types/profile-state.js.map +1 -0
  70. package/lib/types/provider-api.d.ts +38 -102
  71. package/lib/types/provider-api.d.ts.map +1 -1
  72. package/lib/types/provider.d.ts +2 -8
  73. package/lib/types/provider.d.ts.map +1 -1
  74. package/lib/types/provider.js +16 -73
  75. package/lib/types/provider.js.map +1 -1
  76. package/lib/types/sdk-adapter.d.ts +7 -32
  77. package/lib/types/sdk-adapter.d.ts.map +1 -1
  78. package/lib/types/sdk-adapter.js +104 -163
  79. package/lib/types/sdk-adapter.js.map +1 -1
  80. package/lib/types/sent-mail-store.d.ts +7 -2
  81. package/lib/types/sent-mail-store.d.ts.map +1 -1
  82. package/lib/types/sent-mail-store.js +125 -23
  83. package/lib/types/sent-mail-store.js.map +1 -1
  84. package/lib/types/tools.d.ts +1 -1
  85. package/lib/types/tools.d.ts.map +1 -1
  86. package/lib/types/tools.js +20 -4
  87. package/lib/types/tools.js.map +1 -1
  88. package/lib/types/types.d.ts +66 -77
  89. package/lib/types/types.d.ts.map +1 -1
  90. package/lib/types/types.js.map +1 -1
  91. package/package.json +15 -20
  92. package/lib/types/client/AwikiDevices.d.ts +0 -28
  93. package/lib/types/client/AwikiDevices.d.ts.map +0 -1
  94. package/lib/types/client/AwikiDevices.js +0 -85
  95. package/lib/types/client/AwikiDevices.js.map +0 -1
  96. package/lib/types/realtime-supervisor.d.ts +0 -54
  97. package/lib/types/realtime-supervisor.d.ts.map +0 -1
  98. package/lib/types/realtime-supervisor.js +0 -242
  99. package/lib/types/realtime-supervisor.js.map +0 -1
package/lib/provider.js CHANGED
@@ -1,79 +1,26 @@
1
- import { t as RustSdkAdapter } from "./sdk-adapter-FGaOi8It.mjs";
2
- import { setTimeout } from "node:timers/promises";
1
+ import { t as RustSdkAdapter } from "./sdk-adapter--trNlr-T.mjs";
3
2
  import { openImCoreNodeClient } from "@awiki/im-core-node";
4
3
  //#region lib/types/provider.js
5
4
  /** Production AWiki provider backed by the versioned Rust IM Core Node bridge. */
6
5
  /** Cordis plugin name used by Loader diagnostics. */
7
6
  const name = "awiki-rust-sdk-provider";
8
- /** AWiki orchestration and the independent identity service must load first. */
9
- const inject = ["awiki", "anpIdentity"];
10
- const IDENTITY_PROVIDER_CAPABILITIES = [
11
- "IDENTITY_READ",
12
- "IDENTITY_CREATE",
13
- "IDENTITY_IMPORT",
14
- "IDENTITY_SIGN",
15
- "IDENTITY_ECDH_SEALED",
16
- "IDENTITY_DOCUMENT_UPDATE",
17
- "IDENTITY_KEY_LIFECYCLE",
18
- "IDENTITY_DELETE",
19
- "IDENTITY_HTTP_SIGNATURE",
20
- "AWIKI_LEGACY_ROOT_TRANSFER_V1"
21
- ];
22
- const IDENTITY_PROVIDER_READY_TIMEOUT_MS = 1e4;
23
- const IDENTITY_PROVIDER_READY_POLL_MS = 50;
7
+ /** The AWiki service must own its provider registry before this plugin loads. */
8
+ const inject = ["awiki"];
24
9
  /** Register one SDK client whose disposal follows this provider's fiber. */
25
- async function apply(ctx) {
26
- await waitForIdentityProvider(ctx.anpIdentity);
27
- ctx.effect(() => {
28
- const lease = ctx.anpIdentity.acquireProvider({
29
- consumer: "@awiki/dsh-plugin",
30
- capabilities: [...IDENTITY_PROVIDER_CAPABILITIES],
31
- ttlSeconds: 3600
32
- });
33
- try {
34
- const unregister = ctx.awiki.registerClientFactory((options) => {
35
- const openOptions = {
36
- stateRoot: options.stateRoot,
37
- serviceBaseUrl: options.userServiceUrl,
38
- didDomain: options.userServiceDomain,
39
- userServiceEndpoint: options.userServiceUrl,
40
- messageServiceEndpoint: options.messageServiceUrl,
41
- mailServiceEndpoint: options.mailServiceUrl,
42
- anpServiceEndpoint: options.messageServiceUrl,
43
- anpServiceDid: options.messageServiceDid,
44
- clientVersionInfo: {
45
- product: "awiki-daemon",
46
- release: "0815",
47
- version: "0.1.91"
48
- },
49
- multiDeviceHandleRecoveryEnabled: true,
50
- multiDeviceDeviceRevokeEnabled: true,
51
- multiDeviceAudience: "awiki-user-service",
52
- externalHttpAllowInsecureLoopbackForTesting: options.allowInsecureLoopbackForTesting,
53
- identityProvider: lease
54
- };
55
- return new RustSdkAdapter(openImCoreNodeClient(openOptions));
56
- });
57
- return async () => {
58
- try {
59
- await unregister();
60
- } finally {
61
- lease.dispose();
62
- }
63
- };
64
- } catch (error) {
65
- lease.dispose();
66
- throw error;
67
- }
68
- }, "awiki Rust SDK client");
69
- }
70
- async function waitForIdentityProvider(identity) {
71
- const deadline = Date.now() + IDENTITY_PROVIDER_READY_TIMEOUT_MS;
72
- while ((await identity.health()).status === "unavailable") {
73
- const remaining = deadline - Date.now();
74
- if (remaining <= 0) throw new Error(`awiki: ANP Identity provider did not become ready within ${IDENTITY_PROVIDER_READY_TIMEOUT_MS}ms`);
75
- await setTimeout(Math.min(IDENTITY_PROVIDER_READY_POLL_MS, remaining));
76
- }
10
+ function apply(ctx) {
11
+ ctx.effect(() => ctx.awiki.registerClientFactory((options) => new RustSdkAdapter(openImCoreNodeClient({
12
+ stateRoot: options.stateRoot,
13
+ serviceBaseUrl: options.userServiceUrl,
14
+ didDomain: options.userServiceDomain,
15
+ userServiceEndpoint: options.userServiceUrl,
16
+ messageServiceEndpoint: options.messageServiceUrl,
17
+ mailServiceEndpoint: options.mailServiceUrl,
18
+ anpServiceEndpoint: options.messageServiceUrl,
19
+ anpServiceDid: options.messageServiceDid,
20
+ multiDeviceHandleRecoveryEnabled: true,
21
+ multiDeviceAudience: "awiki-user-service",
22
+ externalHttpAllowInsecureLoopbackForTesting: options.allowInsecureLoopbackForTesting
23
+ }))), "awiki Rust SDK client");
77
24
  }
78
25
  //#endregion
79
26
  export { apply, inject, name };
@@ -20,12 +20,11 @@ const RUST_FAILURE_CODES = {
20
20
  auth_revoked: "identity-recovery-required",
21
21
  conflict: "conflict",
22
22
  join_required: "handle-unavailable",
23
- state_in_use: "conflict",
23
+ state_in_use: "state-in-use",
24
24
  rate_limited: "rate-limited",
25
25
  timeout: "network",
26
26
  transport_unavailable: "network",
27
27
  sync_failed: "network",
28
- sync_blocked: "conflict",
29
28
  session_expired: "network",
30
29
  attachment_transfer_network: "network",
31
30
  recovery_reconciliation_unavailable: "network",
@@ -34,36 +33,15 @@ const RUST_FAILURE_CODES = {
34
33
  /** Closed provider error consumed by the Host's fixed public failure mapping. */
35
34
  var AwikiSdkError = class extends Error {
36
35
  code;
37
- realtimeFailureCode;
38
36
  name = "AwikiSdkError";
39
- constructor(code, realtimeFailureCode) {
37
+ constructor(code) {
40
38
  super(`AWiki SDK operation failed: ${code}`);
41
39
  this.code = code;
42
- this.realtimeFailureCode = realtimeFailureCode;
43
40
  }
44
41
  };
45
42
  function fail(code = "remote") {
46
43
  throw new AwikiSdkError(code);
47
44
  }
48
- const REALTIME_RETRY_WARNING_PRIORITY = [
49
- "sync.retry.local_state.actor_closed",
50
- "sync.retry.local_state.database_busy",
51
- "sync.retry.local_state.constraint_failed",
52
- "sync.retry.local_state.schema_unavailable",
53
- "sync.retry.local_state.storage_unavailable",
54
- "sync.retry.local_state.codec_unavailable",
55
- "sync.retry.local_state.other",
56
- "sync.retry.transport_unavailable",
57
- "sync.retry.service_unavailable",
58
- "sync.retry.local_state_unavailable"
59
- ];
60
- function realtimeSyncFailureCode(status, warnings) {
61
- if (status === "retryable_failure") return REALTIME_RETRY_WARNING_PRIORITY.find((code) => warnings.includes(code)) ?? "sync.retryable_failure";
62
- if (status === "recovery_required") return "sync.recovery_required";
63
- if (status === "auth_revoked") return "sync.auth_revoked";
64
- if (status === "blocked") return "sync.blocked";
65
- return "sync.unexpected_status";
66
- }
67
45
  function mapError(error, ambiguousSend = false) {
68
46
  if (error instanceof AwikiSdkError) throw error;
69
47
  let code = "remote";
@@ -111,6 +89,14 @@ function mailAddress(value) {
111
89
  if (length < 3 || length > 320 || !value.includes("@") || /[\s\u0000-\u001f\u007f-\u009f]/u.test(value)) fail();
112
90
  return value;
113
91
  }
92
+ function mailFileName(value) {
93
+ if (typeof value !== "string" || value.length === 0 || value.trim() !== value || value.replace(/[. ]+$/u, "") !== value || value === "." || value === ".." || Buffer.byteLength(value, "utf8") > 255 || /[\\/\p{C}]/u.test(value)) fail();
94
+ return value;
95
+ }
96
+ function mailContentType(value) {
97
+ if (typeof value !== "string" || !/^[A-Za-z0-9!#$&^_.+-]+\/[A-Za-z0-9!#$&^_.+-]+$/u.test(value)) fail();
98
+ return value;
99
+ }
114
100
  function mailAddresses(value) {
115
101
  if (!Array.isArray(value) || value.length > 100) fail();
116
102
  return value.map(mailAddress);
@@ -125,6 +111,11 @@ function uint32(value) {
125
111
  if (!Number.isSafeInteger(value) || value < 0 || value > 4294967295) fail();
126
112
  return value;
127
113
  }
114
+ function recoveryE2eeGroupCount(impact) {
115
+ if (typeof impact !== "object" || impact === null) fail();
116
+ const value = impact;
117
+ return uint32(value.unsupportedE2eeGroupCount !== void 0 ? value.unsupportedE2eeGroupCount : value.unsupportedE2EeGroupCount);
118
+ }
128
119
  function boolean(value) {
129
120
  if (typeof value !== "boolean") fail();
130
121
  return value;
@@ -214,26 +205,6 @@ function identity(value) {
214
205
  registeredAt: safeInteger(value.registeredAtMs)
215
206
  };
216
207
  }
217
- function joinProgress(value) {
218
- return {
219
- joinSessionId: required(value.joinSessionId),
220
- localPhase: value.localPhase,
221
- remoteState: value.remoteState,
222
- expiresAt: required(value.expiresAt),
223
- ...value.sas === void 0 ? {} : { sas: required(value.sas) },
224
- completed: boolean(value.completed),
225
- ...value.identity === void 0 ? {} : { identity: identity(value.identity) }
226
- };
227
- }
228
- function adminJoinProgress(value) {
229
- return {
230
- joinSessionId: required(value.joinSessionId),
231
- localPhase: value.localPhase,
232
- remoteState: value.remoteState,
233
- expiresAt: required(value.expiresAt),
234
- ...value.sas === void 0 ? {} : { sas: required(value.sas) }
235
- };
236
- }
237
208
  function profile(value) {
238
209
  return {
239
210
  did: required(value.did),
@@ -344,25 +315,17 @@ var RustSdkAdapter = class {
344
315
  client;
345
316
  attachmentConversations = /* @__PURE__ */ new Map();
346
317
  disposal;
347
- realtime;
348
- agentInbox;
349
318
  listener;
350
319
  constructor(client) {
351
320
  this.client = Promise.resolve(client);
352
- this.realtime = {
321
+ this.listener = {
353
322
  syncNow: (reason) => this.listenerSyncNow(reason),
354
- startRealtime: () => this.listenerStartRealtime()
355
- };
356
- this.agentInbox = {
323
+ startRealtime: () => this.listenerStartRealtime(),
357
324
  listConversations: (request) => this.listenerConversations(request),
358
325
  getHistory: (request) => this.listenerHistory(request),
359
326
  markConversationRead: (conversationId) => this.markConversationRead(conversationId),
360
327
  sendText: (request) => this.sendText(request)
361
328
  };
362
- this.listener = {
363
- ...this.realtime,
364
- ...this.agentInbox
365
- };
366
329
  }
367
330
  async run(operation, ambiguousSend = false) {
368
331
  try {
@@ -565,7 +528,8 @@ var RustSdkAdapter = class {
565
528
  return this.run(async (client) => {
566
529
  const result = await client.syncNow({ reason });
567
530
  if (result.status === "idle" || result.status === "changed") return;
568
- throw new AwikiSdkError(result.status === "auth_revoked" ? "identity-recovery-required" : "network", realtimeSyncFailureCode(result.status, result.warnings));
531
+ if (result.status === "auth_revoked") fail("identity-recovery-required");
532
+ fail("network");
569
533
  });
570
534
  }
571
535
  listenerStartRealtime() {
@@ -573,9 +537,6 @@ var RustSdkAdapter = class {
573
537
  const session = await client.startRealtime();
574
538
  return {
575
539
  nextEvent: () => this.run(() => session.nextEvent()),
576
- getStatus: () => this.run(async () => {
577
- return { connected: (await session.getStatus()).connected };
578
- }),
579
540
  stop: () => this.run(() => session.stop())
580
541
  };
581
542
  });
@@ -638,114 +599,7 @@ var RustSdkAdapter = class {
638
599
  });
639
600
  }
640
601
  registerIdentity(request) {
641
- return this.run(async (client) => {
642
- const value = await client.completeRegistrationWithOutcome(request);
643
- if (value.status === "registered") return {
644
- status: "registered",
645
- identity: identity(value.identity)
646
- };
647
- return {
648
- status: "join-required",
649
- continuationId: required(value.existingHandle.continuationId),
650
- fullHandle: required(value.existingHandle.fullHandle),
651
- mode: value.existingHandle.mode === "handle_recovery_rebind" ? "handle-recovery-rebind" : "ordinary",
652
- requiresUserPresence: boolean(value.existingHandle.requiresUserPresence)
653
- };
654
- });
655
- }
656
- beginDeviceJoin(request) {
657
- return this.run(async (client) => joinProgress(await client.beginPreparedRegistrationJoin(request)));
658
- }
659
- getDeviceJoinStatus(joinSessionId) {
660
- return this.run(async (client) => joinProgress(await client.resumePreparedRegistrationJoin({ joinSessionId })));
661
- }
662
- listLocalDeviceJoinSessions() {
663
- return this.run(async (client) => (await client.listLocalDeviceJoinSessions()).map((value) => ({
664
- joinSessionId: required(value.joinSessionId),
665
- side: value.side,
666
- localPhase: value.localPhase,
667
- expiresAt: required(value.expiresAt)
668
- })));
669
- }
670
- cancelDeviceJoin(joinSessionId) {
671
- return this.run(async (client) => {
672
- const value = await client.cancelPreparedRegistrationJoin({ joinSessionId });
673
- return {
674
- joinSessionId: required(value.joinSessionId),
675
- side: value.side,
676
- localPhase: value.localPhase,
677
- expiresAt: required(value.expiresAt)
678
- };
679
- });
680
- }
681
- getCurrentDeviceSummary() {
682
- return this.run(async (client) => {
683
- const value = await client.getCurrentDeviceSummary();
684
- return {
685
- ...value.role === void 0 ? {} : { role: value.role },
686
- readiness: value.readiness,
687
- canManage: boolean(value.canManage)
688
- };
689
- });
690
- }
691
- syncDeviceManagement() {
692
- return this.run(async (client) => {
693
- await client.syncNow({ reason: "foreground_reconcile" });
694
- });
695
- }
696
- getDeviceRegistry() {
697
- return this.run(async (client) => (await client.getDeviceRegistry()).devices.map((value) => ({
698
- deviceId: required(value.protocolDeviceId),
699
- status: value.status,
700
- role: value.role,
701
- managementReady: boolean(value.managementReady),
702
- isCurrent: boolean(value.isCurrent)
703
- })));
704
- }
705
- listLocalDeviceJoinRequests() {
706
- return this.run(async (client) => (await client.listLocalDeviceJoinRequests()).map((value) => ({
707
- joinSessionId: required(value.joinSessionId),
708
- candidateKeyFingerprint: required(value.candidateKeyFingerprint),
709
- issuedAt: required(value.issuedAt),
710
- expiresAt: required(value.expiresAt),
711
- state: value.state,
712
- claimedByCurrentDevice: boolean(value.claimedByCurrentDevice),
713
- canStartVerification: boolean(value.canStartVerification)
714
- })));
715
- }
716
- startDeviceJoinVerification(request) {
717
- return this.run(async (client) => adminJoinProgress(await client.startDeviceJoinVerification(request)));
718
- }
719
- getLocalDeviceJoinVerificationProgress(joinSessionId) {
720
- return this.run(async (client) => adminJoinProgress(await client.getLocalDeviceJoinVerificationProgress({ joinSessionId })));
721
- }
722
- prepareDeviceJoinApproval(joinSessionId) {
723
- return this.run(async (client) => {
724
- return { approvalHandle: required((await client.prepareDeviceJoinApproval({
725
- joinSessionId,
726
- sasConfirmed: true
727
- })).approvalHandle) };
728
- });
729
- }
730
- confirmDeviceJoinApproval(approvalHandle) {
731
- return this.run(async (client) => adminJoinProgress(await client.confirmDeviceJoinApproval({
732
- approvalHandle,
733
- userPresenceConfirmed: true
734
- })));
735
- }
736
- rejectDeviceJoin(joinSessionId, reason) {
737
- return this.run(async (client) => adminJoinProgress(await client.rejectDeviceJoin({
738
- joinSessionId,
739
- reason
740
- })));
741
- }
742
- revokeDevice(deviceId) {
743
- return this.run(async (client) => {
744
- await client.revokeDevice({
745
- targetDeviceId: deviceId,
746
- userPresenceConfirmed: true
747
- });
748
- });
602
+ return this.run(async (client) => identity(await client.completeRegistration(request)));
749
603
  }
750
604
  updateDisplayName(request) {
751
605
  return this.run(async (client) => identity(await client.updateDisplayName(request.displayName)));
@@ -770,7 +624,9 @@ var RustSdkAdapter = class {
770
624
  ...value.failureCode === void 0 ? {} : { failureCode: value.failureCode },
771
625
  retryable: boolean(value.retryable),
772
626
  localOrdinaryDataWillMigrate: boolean(value.impact.localOrdinaryDataWillMigrate),
773
- otherDevicesMustRejoin: boolean(value.impact.otherDevicesMustRejoin)
627
+ otherDevicesMustRejoin: boolean(value.impact.otherDevicesMustRejoin),
628
+ unsupportedE2eeGroupCount: recoveryE2eeGroupCount(value.impact),
629
+ unsupportedDidOnlyGroupCount: uint32(value.impact.unsupportedDidOnlyGroupCount)
774
630
  };
775
631
  }
776
632
  sendRecoveryOtp(request) {
@@ -872,6 +728,41 @@ var RustSdkAdapter = class {
872
728
  member
873
729
  })));
874
730
  }
731
+ resumeGroupRebindRecovery() {
732
+ return this.run(async (client) => {
733
+ const value = await client.resumeGroupRebindRecovery(100);
734
+ const journal = value;
735
+ const statuses = /* @__PURE__ */ new Map();
736
+ for (const item of journal.items ?? []) {
737
+ const { groupDid: rawGroupDid, layer: rawLayer, phase: rawPhase } = item;
738
+ if (typeof rawGroupDid !== "string" || typeof rawLayer !== "string" || typeof rawPhase !== "string" || typeof item.blocked !== "boolean") throw new TypeError("invalid group recovery item");
739
+ const groupDid = required(rawGroupDid);
740
+ const layer = required(rawLayer);
741
+ const phase = required(rawPhase);
742
+ if (layer !== "p4" && layer !== "p6") throw new TypeError("invalid group recovery item");
743
+ if (phase === "complete") continue;
744
+ const status = item.blocked || phase === "blocked" ? "blocked" : "pending";
745
+ if (statuses.get(groupDid) !== "blocked") statuses.set(groupDid, status);
746
+ }
747
+ for (const group of journal.sendPausedGroups ?? []) {
748
+ if (typeof group !== "string") throw new TypeError("invalid paused recovery group");
749
+ const groupDid = required(group);
750
+ if (!statuses.has(groupDid)) statuses.set(groupDid, "pending");
751
+ }
752
+ const items = [...statuses].map(([groupDid, status]) => ({
753
+ groupDid,
754
+ status
755
+ }));
756
+ const hasJournal = journal.items !== void 0 || journal.sendPausedGroups !== void 0;
757
+ return {
758
+ processed: uint32(value.processed),
759
+ completed: uint32(value.completed),
760
+ pending: hasJournal ? items.filter((item) => item.status === "pending").length : uint32(value.pending),
761
+ blocked: hasJournal ? items.filter((item) => item.status === "blocked").length : uint32(value.blocked),
762
+ items
763
+ };
764
+ });
765
+ }
875
766
  listConversations(request) {
876
767
  return this.run(async (client) => {
877
768
  const conversations = await client.listConversations(request);
@@ -993,12 +884,21 @@ var RustSdkAdapter = class {
993
884
  });
994
885
  }
995
886
  sendMail(request) {
887
+ const attachments = request.attachments?.map((attachment) => ({
888
+ fileName: attachment.fileName,
889
+ contentType: attachment.contentType,
890
+ bytes: Uint8Array.from(attachment.bytes)
891
+ }));
996
892
  return this.run(async (client) => {
997
- const value = await client.sendMail({
893
+ const input = {
998
894
  to: [...request.to],
999
895
  ...request.cc === void 0 ? {} : { cc: [...request.cc] },
1000
896
  subject: request.subject,
1001
897
  bodyText: request.bodyText
898
+ };
899
+ const value = await client.sendMail({
900
+ ...input,
901
+ ...attachments === void 0 || attachments.length === 0 ? {} : { attachments }
1002
902
  });
1003
903
  if (!Array.isArray(value.warnings) || value.warnings.length > 100) fail();
1004
904
  const messageId = value.messageId === void 0 ? void 0 : mailToken(value.messageId, 2048);
@@ -1009,6 +909,22 @@ var RustSdkAdapter = class {
1009
909
  };
1010
910
  }, true);
1011
911
  }
912
+ downloadMailAttachment(request) {
913
+ return this.run(async (client) => {
914
+ const value = await client.downloadMailAttachment({
915
+ messageId: mailToken(request.messageId, 2048),
916
+ attachmentIndex: uint32(request.attachmentIndex)
917
+ });
918
+ const sizeBytes = safeInteger(remoteString(value.sizeBytes, 20));
919
+ if (!(value.bytes instanceof Uint8Array) || value.bytes.byteLength !== sizeBytes) fail();
920
+ return {
921
+ fileName: mailFileName(value.fileName),
922
+ contentType: mailContentType(value.contentType),
923
+ sizeBytes,
924
+ bytes: Uint8Array.from(value.bytes)
925
+ };
926
+ });
927
+ }
1012
928
  clearLocalData() {
1013
929
  return this.run((client) => client.clearLocalData());
1014
930
  }