@lacrous/omnicloud 0.2.22 → 0.2.24

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/dist/index.d.cts CHANGED
@@ -909,6 +909,24 @@ interface FolderRepository {
909
909
  deletedAt?: Date | null;
910
910
  trashBatchId?: string | null;
911
911
  }): Promise<number>;
912
+ /**
913
+ * Trashes a folder subtree and the files inside it in one atomic step, so a
914
+ * failure cannot leave the folders trashed while their files stay active.
915
+ */
916
+ trashSubtree(folderIds: string[], fileIds: string[], stamp: {
917
+ deletedAt: Date;
918
+ trashBatchId: string;
919
+ }): Promise<void>;
920
+ /**
921
+ * Restores a folder subtree and its files in one atomic step. When `reparent` is
922
+ * given, the subtree root is moved under that parent in the same step.
923
+ */
924
+ restoreSubtree(folderIds: string[], fileIds: string[], options: {
925
+ rootId: string;
926
+ reparent: {
927
+ parentId: string | null;
928
+ } | null;
929
+ }): Promise<void>;
912
930
  deleteMany(ids: string[]): Promise<void>;
913
931
  countByUser(userId: string): Promise<number>;
914
932
  }
package/dist/index.d.ts CHANGED
@@ -909,6 +909,24 @@ interface FolderRepository {
909
909
  deletedAt?: Date | null;
910
910
  trashBatchId?: string | null;
911
911
  }): Promise<number>;
912
+ /**
913
+ * Trashes a folder subtree and the files inside it in one atomic step, so a
914
+ * failure cannot leave the folders trashed while their files stay active.
915
+ */
916
+ trashSubtree(folderIds: string[], fileIds: string[], stamp: {
917
+ deletedAt: Date;
918
+ trashBatchId: string;
919
+ }): Promise<void>;
920
+ /**
921
+ * Restores a folder subtree and its files in one atomic step. When `reparent` is
922
+ * given, the subtree root is moved under that parent in the same step.
923
+ */
924
+ restoreSubtree(folderIds: string[], fileIds: string[], options: {
925
+ rootId: string;
926
+ reparent: {
927
+ parentId: string | null;
928
+ } | null;
929
+ }): Promise<void>;
912
930
  deleteMany(ids: string[]): Promise<void>;
913
931
  countByUser(userId: string): Promise<number>;
914
932
  }
package/dist/index.js CHANGED
@@ -2114,11 +2114,11 @@ var FolderService = class {
2114
2114
  const fileIds = await this.collectFileIds(userId, subtree);
2115
2115
  const batchId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
2116
2116
  const stampedAt = /* @__PURE__ */ new Date();
2117
- await this.folders.updateMany(
2117
+ await this.folders.trashSubtree(
2118
2118
  subtree.map((folder) => folder.id),
2119
+ fileIds,
2119
2120
  { deletedAt: stampedAt, trashBatchId: batchId }
2120
2121
  );
2121
- await this.files.updateMany(fileIds, { deletedAt: stampedAt, trashBatchId: batchId });
2122
2122
  await this.activity.record({
2123
2123
  userId,
2124
2124
  action: "trash",
@@ -2153,14 +2153,11 @@ var FolderService = class {
2153
2153
  );
2154
2154
  const restorableFileIds = restorableFiles.map((file) => file.id);
2155
2155
  if (restorableFolders.length > 0) {
2156
- await this.folders.updateMany(
2156
+ await this.folders.restoreSubtree(
2157
2157
  restorableFolders.map((folder) => folder.id),
2158
- { deletedAt: null, trashBatchId: null }
2158
+ restorableFileIds,
2159
+ { rootId: id, reparent: { parentId } }
2159
2160
  );
2160
- await this.folders.update(id, { parentId });
2161
- }
2162
- if (restorableFileIds.length > 0) {
2163
- await this.files.updateMany(restorableFileIds, { deletedAt: null, trashBatchId: null });
2164
2161
  }
2165
2162
  await this.activity.record({
2166
2163
  userId,
@@ -2187,9 +2184,16 @@ var FolderService = class {
2187
2184
  );
2188
2185
  const engine = await this.engineFor(userId);
2189
2186
  const removedFileIds = [];
2187
+ const versionsByFile = await this.files.listVersionsForFiles(affected.map((file) => file.id));
2190
2188
  for (const file of affected) {
2191
2189
  try {
2192
- await engine.remove({ messageId: String(file.telegramMessageId) });
2190
+ const messageIds = /* @__PURE__ */ new Set([String(file.telegramMessageId)]);
2191
+ for (const version of versionsByFile.get(file.id) ?? []) {
2192
+ messageIds.add(String(version.telegramMessageId));
2193
+ }
2194
+ for (const messageId of messageIds) {
2195
+ await engine.remove({ messageId });
2196
+ }
2193
2197
  removedFileIds.push(file.id);
2194
2198
  } catch {
2195
2199
  }
@@ -2664,6 +2668,13 @@ function mapTelegramError(error, fallbackMessage) {
2664
2668
  case "CHANNEL_INVALID":
2665
2669
  case "CHAT_ID_INVALID":
2666
2670
  return new StorageNotInitializedError();
2671
+ // Permanent: the account cannot write to the channel. Retrying cannot help.
2672
+ case "CHAT_WRITE_FORBIDDEN":
2673
+ case "CHAT_ADMIN_REQUIRED":
2674
+ return new ForbiddenError("OmniCloud cannot write to the storage channel for this account");
2675
+ // Permanent: the stored channel reference is stale. Retrying with the same reference fails too.
2676
+ case "PEER_ID_INVALID":
2677
+ return new StorageNotInitializedError();
2667
2678
  case "MSG_ID_INVALID":
2668
2679
  case "MESSAGE_ID_INVALID":
2669
2680
  return new TelegramFileNotFoundError();