@lacrous/omnicloud 0.2.8 → 0.2.10
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/cli.js +8 -1
- package/dist/index.cjs +44 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/server/index.js +76 -1
package/dist/index.d.cts
CHANGED
|
@@ -1001,6 +1001,8 @@ interface FileRepository {
|
|
|
1001
1001
|
findVersionById(versionId: string): Promise<FileVersionRecord | null>;
|
|
1002
1002
|
countVersions(fileId: string): Promise<number>;
|
|
1003
1003
|
deleteVersionsByFileIds(fileIds: string[]): Promise<void>;
|
|
1004
|
+
/** Removes one version row. Callers must delete its Telegram object first. */
|
|
1005
|
+
deleteVersion(versionId: string): Promise<void>;
|
|
1004
1006
|
}
|
|
1005
1007
|
interface ActivityRepository {
|
|
1006
1008
|
record(input: {
|
|
@@ -1165,6 +1167,21 @@ declare class StorageEngine {
|
|
|
1165
1167
|
private withRetry;
|
|
1166
1168
|
}
|
|
1167
1169
|
|
|
1170
|
+
/**
|
|
1171
|
+
* Which historical versions to keep. The current version is never a candidate,
|
|
1172
|
+
* whatever the policy says. The default keeps everything, so no version is ever
|
|
1173
|
+
* removed unless an operator opts in.
|
|
1174
|
+
*/
|
|
1175
|
+
type VersionRetentionPolicy = {
|
|
1176
|
+
kind: "KEEP_ALL";
|
|
1177
|
+
} | {
|
|
1178
|
+
kind: "KEEP_LATEST_N";
|
|
1179
|
+
count: number;
|
|
1180
|
+
} | {
|
|
1181
|
+
kind: "KEEP_FOR_DAYS";
|
|
1182
|
+
days: number;
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1168
1185
|
interface OperationSink {
|
|
1169
1186
|
info(record: Record<string, unknown>, message: string): void;
|
|
1170
1187
|
warn(record: Record<string, unknown>, message: string): void;
|
|
@@ -1330,6 +1347,13 @@ declare class FileService {
|
|
|
1330
1347
|
message: string;
|
|
1331
1348
|
}[];
|
|
1332
1349
|
}>;
|
|
1350
|
+
/**
|
|
1351
|
+
* Removes historical versions the policy no longer keeps. For each version the
|
|
1352
|
+
* Telegram message is deleted first, and its row only after that succeeds, the
|
|
1353
|
+
* same order as a permanent delete. A failed remote delete leaves that version
|
|
1354
|
+
* in place. The current version is never removed. Returns how many were removed.
|
|
1355
|
+
*/
|
|
1356
|
+
pruneVersions(userId: string, fileId: string, policy: VersionRetentionPolicy, now?: Date): Promise<number>;
|
|
1333
1357
|
private assertFolder;
|
|
1334
1358
|
}
|
|
1335
1359
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1001,6 +1001,8 @@ interface FileRepository {
|
|
|
1001
1001
|
findVersionById(versionId: string): Promise<FileVersionRecord | null>;
|
|
1002
1002
|
countVersions(fileId: string): Promise<number>;
|
|
1003
1003
|
deleteVersionsByFileIds(fileIds: string[]): Promise<void>;
|
|
1004
|
+
/** Removes one version row. Callers must delete its Telegram object first. */
|
|
1005
|
+
deleteVersion(versionId: string): Promise<void>;
|
|
1004
1006
|
}
|
|
1005
1007
|
interface ActivityRepository {
|
|
1006
1008
|
record(input: {
|
|
@@ -1165,6 +1167,21 @@ declare class StorageEngine {
|
|
|
1165
1167
|
private withRetry;
|
|
1166
1168
|
}
|
|
1167
1169
|
|
|
1170
|
+
/**
|
|
1171
|
+
* Which historical versions to keep. The current version is never a candidate,
|
|
1172
|
+
* whatever the policy says. The default keeps everything, so no version is ever
|
|
1173
|
+
* removed unless an operator opts in.
|
|
1174
|
+
*/
|
|
1175
|
+
type VersionRetentionPolicy = {
|
|
1176
|
+
kind: "KEEP_ALL";
|
|
1177
|
+
} | {
|
|
1178
|
+
kind: "KEEP_LATEST_N";
|
|
1179
|
+
count: number;
|
|
1180
|
+
} | {
|
|
1181
|
+
kind: "KEEP_FOR_DAYS";
|
|
1182
|
+
days: number;
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1168
1185
|
interface OperationSink {
|
|
1169
1186
|
info(record: Record<string, unknown>, message: string): void;
|
|
1170
1187
|
warn(record: Record<string, unknown>, message: string): void;
|
|
@@ -1330,6 +1347,13 @@ declare class FileService {
|
|
|
1330
1347
|
message: string;
|
|
1331
1348
|
}[];
|
|
1332
1349
|
}>;
|
|
1350
|
+
/**
|
|
1351
|
+
* Removes historical versions the policy no longer keeps. For each version the
|
|
1352
|
+
* Telegram message is deleted first, and its row only after that succeeds, the
|
|
1353
|
+
* same order as a permanent delete. A failed remote delete leaves that version
|
|
1354
|
+
* in place. The current version is never removed. Returns how many were removed.
|
|
1355
|
+
*/
|
|
1356
|
+
pruneVersions(userId: string, fileId: string, policy: VersionRetentionPolicy, now?: Date): Promise<number>;
|
|
1333
1357
|
private assertFolder;
|
|
1334
1358
|
}
|
|
1335
1359
|
|
package/dist/index.js
CHANGED
|
@@ -1294,6 +1294,23 @@ async function resolveItemQuery(folders, userId, input) {
|
|
|
1294
1294
|
// ../core/src/services/auth-session-service.ts
|
|
1295
1295
|
import { createHash as createHash3, randomBytes } from "crypto";
|
|
1296
1296
|
|
|
1297
|
+
// ../core/src/services/version-retention.ts
|
|
1298
|
+
function versionsToPrune(versions, currentVersionId, policy, now) {
|
|
1299
|
+
const historical = versions.filter((version) => version.id !== currentVersionId).sort((a, b) => b.versionNumber - a.versionNumber);
|
|
1300
|
+
switch (policy.kind) {
|
|
1301
|
+
case "KEEP_ALL":
|
|
1302
|
+
return [];
|
|
1303
|
+
case "KEEP_LATEST_N": {
|
|
1304
|
+
const keep = Math.max(0, policy.count);
|
|
1305
|
+
return historical.slice(keep);
|
|
1306
|
+
}
|
|
1307
|
+
case "KEEP_FOR_DAYS": {
|
|
1308
|
+
const cutoff = now.getTime() - policy.days * 24 * 60 * 60 * 1e3;
|
|
1309
|
+
return historical.filter((version) => version.createdAt.getTime() < cutoff);
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1297
1314
|
// ../core/src/services/upload-operation.ts
|
|
1298
1315
|
function isValidOperationId(id) {
|
|
1299
1316
|
return /^[A-Za-z0-9_-]{8,64}$/.test(id);
|
|
@@ -1882,6 +1899,33 @@ var FileService = class {
|
|
|
1882
1899
|
};
|
|
1883
1900
|
}
|
|
1884
1901
|
// ── internals ────────────────────────────────────────────────────────────
|
|
1902
|
+
/**
|
|
1903
|
+
* Removes historical versions the policy no longer keeps. For each version the
|
|
1904
|
+
* Telegram message is deleted first, and its row only after that succeeds, the
|
|
1905
|
+
* same order as a permanent delete. A failed remote delete leaves that version
|
|
1906
|
+
* in place. The current version is never removed. Returns how many were removed.
|
|
1907
|
+
*/
|
|
1908
|
+
async pruneVersions(userId, fileId, policy, now = /* @__PURE__ */ new Date()) {
|
|
1909
|
+
const record = await this.get(userId, fileId);
|
|
1910
|
+
const versions = await this.files.listVersions(fileId);
|
|
1911
|
+
const doomed = versionsToPrune(versions, record.currentVersionId ?? null, policy, now);
|
|
1912
|
+
if (doomed.length === 0) return 0;
|
|
1913
|
+
const engine = await this.engineFor(userId);
|
|
1914
|
+
let removed = 0;
|
|
1915
|
+
for (const version of doomed) {
|
|
1916
|
+
await engine.remove({ messageId: String(version.telegramMessageId) });
|
|
1917
|
+
await this.files.deleteVersion(version.id);
|
|
1918
|
+
removed += 1;
|
|
1919
|
+
}
|
|
1920
|
+
await this.activity.record({
|
|
1921
|
+
userId,
|
|
1922
|
+
action: "delete",
|
|
1923
|
+
resourceType: "file",
|
|
1924
|
+
resourceId: fileId,
|
|
1925
|
+
resourceName: `${record.name} (${removed} old version${removed === 1 ? "" : "s"})`
|
|
1926
|
+
});
|
|
1927
|
+
return removed;
|
|
1928
|
+
}
|
|
1885
1929
|
async assertFolder(userId, folderId) {
|
|
1886
1930
|
const folder = await this.folders.findById(folderId);
|
|
1887
1931
|
if (!folder || folder.userId !== userId) {
|