@telecrypt-io/storage 0.6.0 → 0.7.0

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.
@@ -100,9 +100,7 @@ function isRateLimited(error) {
100
100
  function requiresMutationReconciliation(error) {
101
101
  return (error instanceof MutationOutcomeUnknownError ||
102
102
  error instanceof RoomCreationAmbiguousError ||
103
- error instanceof RoomCleanupIncompleteError ||
104
- (error instanceof Error &&
105
- error.cleanupIncomplete === true));
103
+ error instanceof RoomCleanupIncompleteError);
106
104
  }
107
105
  async function withRateLimitRetry(operation, signal) {
108
106
  for (;;) {
@@ -175,13 +173,9 @@ async function resolveTree(storage, treeId, signal) {
175
173
  }
176
174
  }
177
175
  function isMarkedTreeDeleted(storage, treeId) {
178
- if (typeof storage.getClient !== "function")
179
- return false;
180
176
  return isTreeDeleted(storage.getClient(), treeId);
181
177
  }
182
178
  function isMarkedFileDeleted(storage, treeId, fileId) {
183
- if (typeof storage.getClient !== "function")
184
- return false;
185
179
  return isFileDeleted(storage.getClient(), treeId, fileId);
186
180
  }
187
181
  /** As `resolveTree`, but for a specific file within an already-resolved
@@ -417,10 +411,10 @@ async function unlinkExternalParents(storage, rootId, externalParents, signal) {
417
411
  // is not used here because it can be delayed or rejected independently of
418
412
  // the relation update.
419
413
  mutationAttempted = true;
420
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => client.sendStateEvent(parentId, EventType.SpaceChild, {}, rootId), signal), signal);
414
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => client.sendStateEvent(parentId, EventType.SpaceChild, {}, rootId), signal), signal);
421
415
  if (signal?.aborted)
422
416
  throw new StorageError("operation cancelled");
423
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => client.sendStateEvent(rootId, EventType.SpaceParent, {}, parentId), signal), signal);
417
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => client.sendStateEvent(rootId, EventType.SpaceParent, {}, parentId), signal), signal);
424
418
  await storage.refreshRoomState(parentId, { signal });
425
419
  await storage.refreshRoomState(rootId, { signal });
426
420
  const childLink = readRelationEvents(client, parentId, EventType.SpaceChild, rootId);
@@ -461,8 +455,8 @@ async function relinkExternalParents(storage, rootId, externalParents, signal) {
461
455
  for (const parentId of externalParents) {
462
456
  if (signal?.aborted)
463
457
  throw new StorageError("operation cancelled");
464
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => client.sendStateEvent(parentId, EventType.SpaceChild, { via: [via] }, rootId), signal), signal);
465
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => client.sendStateEvent(rootId, EventType.SpaceParent, { via: [via] }, parentId), signal), signal);
458
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => client.sendStateEvent(parentId, EventType.SpaceChild, { via: [via] }, rootId), signal), signal);
459
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => client.sendStateEvent(rootId, EventType.SpaceParent, { via: [via] }, parentId), signal), signal);
466
460
  await storage.refreshRoomState(parentId, { signal });
467
461
  await storage.refreshRoomState(rootId, { signal });
468
462
  const childLink = readRelationEvents(client, parentId, EventType.SpaceChild, rootId);
@@ -503,7 +497,7 @@ async function deleteRoomDeterministically(storage, roomId, signal) {
503
497
  continue;
504
498
  }
505
499
  try {
506
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => client.kick(roomId, member.userId, "Room deleted"), signal), signal);
500
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => client.kick(roomId, member.userId, "Room deleted"), signal), signal);
507
501
  markRoomMutationComplete();
508
502
  }
509
503
  catch (error) {
@@ -523,7 +517,7 @@ async function deleteRoomDeterministically(storage, roomId, signal) {
523
517
  const ownMembership = await storage.getRoomMembership(roomId, undefined, { signal });
524
518
  if (ownMembership === "join" || ownMembership === "invite" || ownMembership === "knock") {
525
519
  try {
526
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => client.leave(roomId), signal), signal);
520
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => client.leave(roomId), signal), signal);
527
521
  markRoomMutationComplete();
528
522
  }
529
523
  catch (error) {
@@ -532,7 +526,7 @@ async function deleteRoomDeterministically(storage, roomId, signal) {
532
526
  }
533
527
  }
534
528
  try {
535
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => client.forget(roomId), signal), signal);
529
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => client.forget(roomId), signal), signal);
536
530
  markRoomMutationComplete();
537
531
  }
538
532
  catch (error) {
@@ -632,7 +626,7 @@ export async function joinVault(storage, vaultId, options) {
632
626
  if (membership === "join")
633
627
  return { vaultId, joined: true };
634
628
  try {
635
- await withRateLimitRetry(() => withMatrixMutationAbort(storage.getClient(), () => storage.getClient().joinRoom(vaultId), signal), signal);
629
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => storage.getClient().joinRoom(vaultId), signal), signal);
636
630
  }
637
631
  catch (err) {
638
632
  if (err instanceof MutationOutcomeUnknownError)
@@ -765,7 +759,7 @@ export async function declineInvite(storage, vaultId, options) {
765
759
  return { vaultId, declined: false };
766
760
  }
767
761
  try {
768
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => client.leave(vaultId), signal), signal);
762
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => client.leave(vaultId), signal), signal);
769
763
  }
770
764
  catch (error) {
771
765
  let suppress = isGoneError(error);
@@ -777,7 +771,7 @@ export async function declineInvite(storage, vaultId, options) {
777
771
  throw error;
778
772
  }
779
773
  try {
780
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => client.forget(vaultId), signal), signal);
774
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => client.forget(vaultId), signal), signal);
781
775
  }
782
776
  catch (error) {
783
777
  let suppress = isGoneError(error);
@@ -815,7 +809,6 @@ export async function shareVault(storage, vaultId, userId, role, options) {
815
809
  ensureOperationActive(operation.signal);
816
810
  const tree = await resolveTree(storage, vaultId, operation.signal);
817
811
  const pending = withTreeMutation(storage.getClient(), async () => {
818
- const client = storage.getClient();
819
812
  try {
820
813
  ensureOperationActive(operation.signal);
821
814
  await storage.refreshRoomState(tree.id, { signal: operation.signal });
@@ -839,7 +832,7 @@ export async function shareVault(storage, vaultId, userId, role, options) {
839
832
  if (isActiveMembership(currentMembership ?? ""))
840
833
  continue;
841
834
  try {
842
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => space.invite(userId), operation.signal), operation.signal);
835
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => space.invite(userId), operation.signal), operation.signal);
843
836
  completedRoomIds.add(space.id);
844
837
  }
845
838
  catch (error) {
@@ -863,7 +856,7 @@ export async function shareVault(storage, vaultId, userId, role, options) {
863
856
  if (members.some((member) => member.userId === userId && member.role === "owner")) {
864
857
  throw new StorageError("share will not demote an existing owner");
865
858
  }
866
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => space.setPermissions(userId, role), operation.signal), operation.signal);
859
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => space.setPermissions(userId, role), operation.signal), operation.signal);
867
860
  completedRoomIds.add(space.id);
868
861
  }
869
862
  }
@@ -925,7 +918,7 @@ export async function unshareVault(storage, vaultId, userId, options) {
925
918
  if (!isRevocableMembership(membership))
926
919
  continue;
927
920
  try {
928
- await withRateLimitRetry(() => withMatrixMutationAbort(storage.getClient(), () => storage.getClient().kick(space.id, userId, "unshared"), operation.signal), operation.signal);
921
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => storage.getClient().kick(space.id, userId, "unshared"), operation.signal), operation.signal);
929
922
  completedRoomIds.add(space.id);
930
923
  }
931
924
  catch (error) {
@@ -1031,8 +1024,7 @@ async function renameTree(storage, treeId, name, options) {
1031
1024
  return withOperationDeadline(options, async (signal) => {
1032
1025
  const tree = await resolveTree(storage, treeId, signal);
1033
1026
  try {
1034
- const client = typeof storage.getClient === "function" ? storage.getClient() : undefined;
1035
- await withRateLimitRetry(() => client ? withMatrixMutationAbort(client, () => tree.setName(name), signal) : tree.setName(name), signal);
1027
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => tree.setName(name), signal), signal);
1036
1028
  await waitForCondition(async () => {
1037
1029
  ensureOperationActive(signal);
1038
1030
  const current = storage.getTree(treeId);
@@ -1149,8 +1141,7 @@ export async function renameFile(storage, treeId, fileId, name, options) {
1149
1141
  const tree = await resolveTree(storage, treeId, signal);
1150
1142
  const branch = await resolveFile(storage, tree, fileId, signal);
1151
1143
  try {
1152
- const client = typeof storage.getClient === "function" ? storage.getClient() : undefined;
1153
- await withRateLimitRetry(() => client ? withMatrixMutationAbort(client, () => branch.setName(name), signal) : branch.setName(name), signal);
1144
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => branch.setName(name), signal), signal);
1154
1145
  // `setName` resolves when the homeserver accepts the state event, but a
1155
1146
  // fresh CLI/UI process can still read the previous local room state for a
1156
1147
  // short time. Do not report success until this client has observed the new
@@ -1181,7 +1172,7 @@ async function deleteFileMedia(storage, mediaIds, signal) {
1181
1172
  const client = storage.getClient();
1182
1173
  const http = requireFileDeletionTransport(client);
1183
1174
  try {
1184
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => http.authedRequest(Method.Post, "/io.telecrypt.storage/delete_media", undefined, { media_ids: [...mediaIds] }, { prefix: ClientPrefix.Unstable, rawResponseBody: true, abortSignal: signal }), signal, "delete file media"), signal);
1175
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => http.authedRequest(Method.Post, "/io.telecrypt.storage/delete_media", undefined, { media_ids: [...mediaIds] }, { prefix: ClientPrefix.Unstable, rawResponseBody: true, abortSignal: signal }), signal, "delete file media"), signal);
1185
1176
  }
1186
1177
  catch (error) {
1187
1178
  if (error instanceof MutationOutcomeUnknownError)
@@ -1209,11 +1200,9 @@ export async function deleteFile(storage, treeId, fileId, options) {
1209
1200
  await deleteFileMedia(storage, [mediaId], signal);
1210
1201
  const completedIds = [];
1211
1202
  try {
1212
- const client = typeof storage.getClient === "function" ? storage.getClient() : undefined;
1213
- if (!client)
1214
- throw new StorageError("Matrix client unavailable");
1215
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => client.sendStateEvent(tree.id, UNSTABLE_MSC3089_BRANCH.name, {}, branch.id), signal, "delete file state"), signal);
1216
- await withRateLimitRetry(() => withMatrixMutationAbort(client, () => client.redactEvent(tree.id, branch.id), signal, "delete file event"), signal);
1203
+ const client = storage.getClient();
1204
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => client.sendStateEvent(tree.id, UNSTABLE_MSC3089_BRANCH.name, {}, branch.id), signal, "delete file state"), signal);
1205
+ await withRateLimitRetry(() => withMatrixMutationAbort(() => client.redactEvent(tree.id, branch.id), signal, "delete file event"), signal);
1217
1206
  completedIds.push(branch.id);
1218
1207
  }
1219
1208
  catch (error) {
@@ -1229,7 +1218,10 @@ export async function deleteFile(storage, treeId, fileId, options) {
1229
1218
  await storage.refreshRoomState(tree.id, { signal });
1230
1219
  ensureOperationActive(signal);
1231
1220
  const current = tree.getFile(fileId);
1232
- return !current ? true : null;
1221
+ // Matrix SDK keeps a redacted branch event in room state as an
1222
+ // inactive branch. Treat both an absent branch and that redacted
1223
+ // inactive branch as confirmed deletion.
1224
+ return !current || current.isActive === false ? true : null;
1233
1225
  }, { timeoutMs: 15000, signal });
1234
1226
  }
1235
1227
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telecrypt-io/storage",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "license": "BUSL-1.1",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.19.0",
@@ -25,12 +25,10 @@
25
25
  "node": "24.20.0"
26
26
  },
27
27
  "publishConfig": {
28
- "access": "public",
29
- "provenance": true
28
+ "access": "public"
30
29
  },
31
30
  "scripts": {
32
31
  "build": "tsc",
33
- "typecheck:tests": "tsc -p tsconfig.test.json",
34
32
  "lint": "eslint src test --ext .ts",
35
33
  "test": "vitest run",
36
34
  "test:unit": "vitest run --config vitest.unit.config.ts",