@lacrous/omnicloud 0.1.0 → 0.2.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.
- package/dist/index.cjs +2052 -268
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +346 -426
- package/dist/index.d.ts +346 -426
- package/dist/index.js +2039 -266
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/** Coarse category used for icon selection in the UI. */
|
|
7
|
-
declare function fileCategory(mimeType: string): FileCategory;
|
|
1
|
+
import { ListQuery } from './query';
|
|
2
|
+
export { ItemStatus, ListQuery, SortField, SortOrder } from './query';
|
|
3
|
+
export { ActivityEventRecord, ActivityRecorder, ActivityService, DomainError, EngineResolver, EngineRetryPolicy, EngineUploadResult, FileDownload, FileRecord, FileService, FileTypeBucket, FileVersionRecord, FolderMutationResult, FolderRecord, FolderService, IntegrityCheckOptions, IntegrityService, ItemQuery, PageRequest, Paged, RecentService, Repos, SearchService, StatsService, StorageEngine, StorageHealth, StorageProvider, StorageRecord, StorageStats, StorageUploadInput, StoredObject, StoredRef, TransferControl, TransferProgress, TrashService, UserRecord, mapProviderError, noopActivityRecorder, sanitizeFileName, sha256Hex } from './errors';
|
|
4
|
+
export { ConnectionStatus, TELEGRAM_PROVIDER, TelegramClientManager, TelegramConnectionService, TelegramCredentials, TelegramStorageOptions, TelegramStorageProvider, mapTelegramError } from './client';
|
|
5
|
+
export { FileCategory, fileCategory, isFileCategory, mimeFromFilename, mimeMatchersForType, paginationMeta, parseSearchQuery, parseSize } from './mime';
|
|
8
6
|
|
|
9
7
|
/**
|
|
10
|
-
* Data transfer objects and
|
|
11
|
-
* and the @lacrous/omnicloud SDK.
|
|
8
|
+
* Data transfer objects, constants and error codes shared between the API,
|
|
9
|
+
* the web app, and the @lacrous/omnicloud SDK.
|
|
12
10
|
*
|
|
13
11
|
* Telegram identifiers that may exceed JavaScript's safe integer range are
|
|
14
12
|
* transported as strings across the API boundary.
|
|
@@ -25,11 +23,31 @@ interface StorageDTO {
|
|
|
25
23
|
title: string;
|
|
26
24
|
createdAt: string;
|
|
27
25
|
}
|
|
26
|
+
/** Connection state of the underlying storage backend. */
|
|
27
|
+
type ConnectionState$1 = "DISCONNECTED" | "CONNECTING" | "CONNECTED" | "RECONNECTING" | "ERROR" | "AUTH_REQUIRED";
|
|
28
|
+
type HealthStatus = "healthy" | "degraded" | "unavailable" | "unknown";
|
|
29
|
+
interface StorageHealthDTO {
|
|
30
|
+
provider: string;
|
|
31
|
+
state: ConnectionState$1;
|
|
32
|
+
status: HealthStatus;
|
|
33
|
+
latencyMs: number | null;
|
|
34
|
+
message: string | null;
|
|
35
|
+
channelTitle: string | null;
|
|
36
|
+
checkedAt: string;
|
|
37
|
+
}
|
|
28
38
|
/** Returned by GET /api/auth/me. `user` is null when not signed in. */
|
|
29
39
|
interface SessionInfo {
|
|
30
40
|
user: UserDTO | null;
|
|
31
41
|
storage: StorageDTO | null;
|
|
42
|
+
health: StorageHealthDTO | null;
|
|
32
43
|
}
|
|
44
|
+
/** POST /api/auth/telegram/verify response. */
|
|
45
|
+
type TelegramVerifyResponse = {
|
|
46
|
+
status: "ok";
|
|
47
|
+
user: UserDTO;
|
|
48
|
+
} | {
|
|
49
|
+
status: "password_required";
|
|
50
|
+
};
|
|
33
51
|
interface FileDTO {
|
|
34
52
|
id: string;
|
|
35
53
|
name: string;
|
|
@@ -37,6 +55,11 @@ interface FileDTO {
|
|
|
37
55
|
mimeType: string;
|
|
38
56
|
sha256: string;
|
|
39
57
|
folderId: string | null;
|
|
58
|
+
starred: boolean;
|
|
59
|
+
trashed: boolean;
|
|
60
|
+
deletedAt: string | null;
|
|
61
|
+
versionCount: number;
|
|
62
|
+
currentVersionId: string | null;
|
|
40
63
|
createdAt: string;
|
|
41
64
|
updatedAt: string;
|
|
42
65
|
}
|
|
@@ -44,56 +67,193 @@ interface FolderDTO {
|
|
|
44
67
|
id: string;
|
|
45
68
|
name: string;
|
|
46
69
|
parentId: string | null;
|
|
70
|
+
starred: boolean;
|
|
71
|
+
trashed: boolean;
|
|
72
|
+
deletedAt: string | null;
|
|
47
73
|
createdAt: string;
|
|
48
74
|
updatedAt: string;
|
|
49
75
|
}
|
|
76
|
+
interface FileVersionDTO {
|
|
77
|
+
id: string;
|
|
78
|
+
fileId: string;
|
|
79
|
+
versionNumber: number;
|
|
80
|
+
size: number;
|
|
81
|
+
mimeType: string;
|
|
82
|
+
sha256: string;
|
|
83
|
+
telegramMessageId: number;
|
|
84
|
+
isCurrent: boolean;
|
|
85
|
+
createdAt: string;
|
|
86
|
+
}
|
|
50
87
|
interface SearchResultDTO {
|
|
51
88
|
files: FileDTO[];
|
|
52
89
|
folders: FolderDTO[];
|
|
90
|
+
pagination: PaginationDTO;
|
|
53
91
|
}
|
|
54
|
-
|
|
55
|
-
|
|
92
|
+
/** Result of a recursive folder deletion / trash operation. */
|
|
93
|
+
interface FolderMutationResultDTO {
|
|
94
|
+
affectedFolders: number;
|
|
95
|
+
affectedFiles: number;
|
|
96
|
+
}
|
|
97
|
+
interface EmptyTrashResultDTO {
|
|
56
98
|
deletedFiles: number;
|
|
99
|
+
deletedFolders: number;
|
|
100
|
+
failedFiles: number;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface PaginationDTO {
|
|
104
|
+
page: number;
|
|
105
|
+
limit: number;
|
|
106
|
+
total: number;
|
|
107
|
+
hasMore: boolean;
|
|
108
|
+
}
|
|
109
|
+
interface FilesPageDTO {
|
|
110
|
+
files: FileDTO[];
|
|
111
|
+
pagination: PaginationDTO;
|
|
112
|
+
}
|
|
113
|
+
interface FoldersPageDTO {
|
|
114
|
+
folders: FolderDTO[];
|
|
115
|
+
pagination: PaginationDTO;
|
|
116
|
+
}
|
|
117
|
+
interface TrashPageDTO {
|
|
118
|
+
files: FileDTO[];
|
|
119
|
+
folders: FolderDTO[];
|
|
120
|
+
pagination: PaginationDTO;
|
|
121
|
+
}
|
|
122
|
+
interface RecentItemDTO {
|
|
123
|
+
file: FileDTO;
|
|
124
|
+
lastAction: ActivityAction;
|
|
125
|
+
lastActionAt: string;
|
|
126
|
+
}
|
|
127
|
+
interface RecentPageDTO {
|
|
128
|
+
items: RecentItemDTO[];
|
|
129
|
+
pagination: PaginationDTO;
|
|
130
|
+
}
|
|
131
|
+
declare const ACTIVITY_ACTIONS: readonly ["upload", "download", "open", "rename", "move", "star", "unstar", "trash", "restore", "delete", "create_folder", "replace"];
|
|
132
|
+
type ActivityAction = (typeof ACTIVITY_ACTIONS)[number];
|
|
133
|
+
declare const RESOURCE_TYPES: readonly ["file", "folder", "storage"];
|
|
134
|
+
type ResourceType = (typeof RESOURCE_TYPES)[number];
|
|
135
|
+
interface ActivityEventDTO {
|
|
136
|
+
id: string;
|
|
137
|
+
action: ActivityAction;
|
|
138
|
+
resourceType: ResourceType;
|
|
139
|
+
resourceId: string;
|
|
140
|
+
resourceName: string | null;
|
|
141
|
+
metadata: Record<string, unknown> | null;
|
|
142
|
+
createdAt: string;
|
|
143
|
+
}
|
|
144
|
+
interface ActivityPageDTO {
|
|
145
|
+
events: ActivityEventDTO[];
|
|
146
|
+
pagination: PaginationDTO;
|
|
147
|
+
}
|
|
148
|
+
interface StorageTypeBreakdownDTO {
|
|
149
|
+
category: string;
|
|
150
|
+
bytes: number;
|
|
151
|
+
count: number;
|
|
152
|
+
}
|
|
153
|
+
interface StorageStatsDTO {
|
|
154
|
+
fileCount: number;
|
|
155
|
+
folderCount: number;
|
|
156
|
+
totalBytes: number;
|
|
157
|
+
trashBytes: number;
|
|
158
|
+
trashFileCount: number;
|
|
159
|
+
starredCount: number;
|
|
160
|
+
byType: StorageTypeBreakdownDTO[];
|
|
161
|
+
largestFiles: FileDTO[];
|
|
162
|
+
quotaBytes: number | null;
|
|
163
|
+
}
|
|
164
|
+
interface HealthDTO {
|
|
165
|
+
status: HealthStatus;
|
|
166
|
+
database: HealthStatus;
|
|
167
|
+
storage: HealthStatus;
|
|
168
|
+
uptimeSeconds: number;
|
|
169
|
+
version: string;
|
|
170
|
+
}
|
|
171
|
+
interface IntegrityIssueDTO {
|
|
172
|
+
fileId: string;
|
|
173
|
+
name: string;
|
|
174
|
+
kind: "missing" | "size_mismatch" | "unreadable" | "hash_mismatch";
|
|
175
|
+
detail: string | null;
|
|
176
|
+
}
|
|
177
|
+
interface IntegrityReportDTO {
|
|
178
|
+
checkedAt: string;
|
|
179
|
+
filesChecked: number;
|
|
180
|
+
healthy: number;
|
|
181
|
+
missing: number;
|
|
182
|
+
inconsistent: number;
|
|
183
|
+
unreadable: number;
|
|
184
|
+
issues: IntegrityIssueDTO[];
|
|
185
|
+
durationMs: number;
|
|
186
|
+
}
|
|
187
|
+
interface BatchResultDTO {
|
|
188
|
+
requested: number;
|
|
189
|
+
succeeded: number;
|
|
190
|
+
failed: number;
|
|
191
|
+
errors: {
|
|
192
|
+
id: string;
|
|
193
|
+
code: ErrorCode;
|
|
194
|
+
message: string;
|
|
195
|
+
}[];
|
|
57
196
|
}
|
|
58
|
-
/** POST /api/auth/telegram/verify response. */
|
|
59
|
-
type TelegramVerifyResponse = {
|
|
60
|
-
status: "ok";
|
|
61
|
-
user: UserDTO;
|
|
62
|
-
} | {
|
|
63
|
-
status: "password_required";
|
|
64
|
-
};
|
|
65
197
|
/** Stable machine-readable error codes returned in API error bodies. */
|
|
66
|
-
declare const ERROR_CODES
|
|
67
|
-
readonly
|
|
68
|
-
readonly
|
|
69
|
-
readonly
|
|
198
|
+
declare const ERROR_CODES: {
|
|
199
|
+
readonly AUTH_REQUIRED: "AUTH_REQUIRED";
|
|
200
|
+
readonly AUTH_INVALID: "AUTH_INVALID";
|
|
201
|
+
readonly PERMISSION_DENIED: "PERMISSION_DENIED";
|
|
202
|
+
readonly INVALID_REQUEST: "INVALID_REQUEST";
|
|
70
203
|
readonly NOT_FOUND: "NOT_FOUND";
|
|
204
|
+
readonly FILE_NOT_FOUND: "FILE_NOT_FOUND";
|
|
205
|
+
readonly FOLDER_NOT_FOUND: "FOLDER_NOT_FOUND";
|
|
71
206
|
readonly CONFLICT: "CONFLICT";
|
|
72
207
|
readonly PAYLOAD_TOO_LARGE: "PAYLOAD_TOO_LARGE";
|
|
73
208
|
readonly RATE_LIMITED: "RATE_LIMITED";
|
|
74
209
|
readonly STORAGE_NOT_INITIALIZED: "STORAGE_NOT_INITIALIZED";
|
|
75
|
-
readonly
|
|
210
|
+
readonly STORAGE_UNAVAILABLE: "STORAGE_UNAVAILABLE";
|
|
211
|
+
readonly TELEGRAM_AUTH_REQUIRED: "TELEGRAM_AUTH_REQUIRED";
|
|
212
|
+
readonly TELEGRAM_CONNECTION_FAILED: "TELEGRAM_CONNECTION_FAILED";
|
|
213
|
+
readonly TELEGRAM_FILE_NOT_FOUND: "TELEGRAM_FILE_NOT_FOUND";
|
|
214
|
+
readonly UPLOAD_FAILED: "UPLOAD_FAILED";
|
|
215
|
+
readonly DOWNLOAD_FAILED: "DOWNLOAD_FAILED";
|
|
216
|
+
readonly INTEGRITY_CHECK_FAILED: "INTEGRITY_CHECK_FAILED";
|
|
76
217
|
readonly INTERNAL: "INTERNAL_ERROR";
|
|
77
218
|
};
|
|
78
|
-
type ErrorCode
|
|
219
|
+
type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];
|
|
79
220
|
interface ApiErrorBody {
|
|
80
221
|
error: {
|
|
81
|
-
code: ErrorCode
|
|
222
|
+
code: ErrorCode;
|
|
82
223
|
message: string;
|
|
83
224
|
details?: unknown;
|
|
225
|
+
requestId?: string;
|
|
84
226
|
};
|
|
85
227
|
}
|
|
86
228
|
|
|
229
|
+
/**
|
|
230
|
+
* Errors surfaced by the SDK. `code` mirrors the server's stable error codes
|
|
231
|
+
* and `requestId` correlates with server logs.
|
|
232
|
+
*/
|
|
87
233
|
declare class OmniCloudError extends Error {
|
|
88
234
|
readonly status: number;
|
|
89
235
|
readonly code: string;
|
|
90
|
-
|
|
236
|
+
readonly requestId: string | undefined;
|
|
237
|
+
readonly details: unknown;
|
|
238
|
+
constructor(status: number, code: string, message: string, requestId?: string | undefined, details?: unknown);
|
|
239
|
+
}
|
|
240
|
+
interface RetryOptions {
|
|
241
|
+
/** Total attempts including the first. Default 3. */
|
|
242
|
+
attempts?: number;
|
|
243
|
+
/** Base backoff in ms (doubles per retry). Default 300. */
|
|
244
|
+
baseDelayMs?: number;
|
|
91
245
|
}
|
|
92
246
|
interface OmniCloudClientOptions {
|
|
93
|
-
/** Base URL of an OmniCloud server.
|
|
247
|
+
/** Base URL of an OmniCloud server (e.g. "https://cloud.example"). */
|
|
94
248
|
baseUrl?: string;
|
|
95
|
-
/**
|
|
249
|
+
/** Bearer token, when the deployment uses token auth instead of cookies. */
|
|
250
|
+
token?: string;
|
|
251
|
+
/** Custom fetch implementation (tests, polyfills). */
|
|
96
252
|
fetchImpl?: typeof fetch;
|
|
253
|
+
/** Retry policy for transient failures. */
|
|
254
|
+
retry?: RetryOptions;
|
|
255
|
+
/** Extra headers sent with every request. */
|
|
256
|
+
headers?: Record<string, string>;
|
|
97
257
|
}
|
|
98
258
|
interface UploadProgress {
|
|
99
259
|
loaded: number;
|
|
@@ -103,426 +263,186 @@ interface UploadProgress {
|
|
|
103
263
|
interface UploadOptions {
|
|
104
264
|
folderId?: string | null;
|
|
105
265
|
onProgress?: (progress: UploadProgress) => void;
|
|
266
|
+
/** Aborts the upload. */
|
|
267
|
+
signal?: AbortSignal;
|
|
268
|
+
/** Number of retry attempts for failed uploads. Default 2. */
|
|
269
|
+
retry?: number;
|
|
106
270
|
}
|
|
107
271
|
interface UploadInput {
|
|
108
|
-
/** File content:
|
|
272
|
+
/** File content: Blob/File in the browser, Buffer/Uint8Array in Node. */
|
|
109
273
|
data: Blob | Uint8Array;
|
|
274
|
+
/** Filename; also used to derive the MIME type server-side. */
|
|
110
275
|
name: string;
|
|
111
276
|
}
|
|
277
|
+
interface DownloadProgress {
|
|
278
|
+
loaded: number;
|
|
279
|
+
total: number | null;
|
|
280
|
+
percent: number | null;
|
|
281
|
+
}
|
|
282
|
+
interface DownloadResult {
|
|
283
|
+
data: Buffer | Uint8Array;
|
|
284
|
+
contentType: string;
|
|
285
|
+
size: number;
|
|
286
|
+
sha256: string | null;
|
|
287
|
+
integrityVerified: boolean | null;
|
|
288
|
+
}
|
|
112
289
|
/**
|
|
113
|
-
*
|
|
290
|
+
* Naming: every endpoint group is a namespaced sub-client so calls read like
|
|
114
291
|
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
292
|
+
* cloud.files.list({ folderId })
|
|
293
|
+
* cloud.trash.empty()
|
|
294
|
+
* cloud.storage.stats()
|
|
295
|
+
*
|
|
296
|
+
* Works in browsers (cookie sessions, XHR upload progress) and Node
|
|
297
|
+
* (fetch, Buffer downloads).
|
|
117
298
|
*/
|
|
118
299
|
declare class OmniCloudClient {
|
|
119
|
-
|
|
120
|
-
|
|
300
|
+
readonly files: FilesApi;
|
|
301
|
+
readonly folders: FoldersApi;
|
|
302
|
+
readonly trash: TrashApi;
|
|
303
|
+
readonly storage: StorageApi;
|
|
304
|
+
readonly search: SearchApi;
|
|
305
|
+
readonly recent: RecentApi;
|
|
306
|
+
readonly activity: ActivityApi;
|
|
307
|
+
readonly auth: AuthApi;
|
|
308
|
+
/** @internal */
|
|
309
|
+
readonly baseUrl: string;
|
|
310
|
+
/** @internal */
|
|
311
|
+
readonly fetchImpl: typeof fetch;
|
|
312
|
+
/** @internal */
|
|
313
|
+
readonly retry: Required<RetryOptions>;
|
|
314
|
+
/** @internal */
|
|
315
|
+
readonly defaultHeaders: Record<string, string>;
|
|
121
316
|
constructor(options?: OmniCloudClientOptions);
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
getFile(id: string): Promise<FileDTO>;
|
|
139
|
-
renameFile(id: string, name: string): Promise<FileDTO>;
|
|
140
|
-
moveFile(id: string, folderId: string | null): Promise<FileDTO>;
|
|
141
|
-
deleteFile(id: string): Promise<void>;
|
|
142
|
-
/** URL of the download endpoint (usable as href for direct downloads). */
|
|
143
|
-
fileDownloadUrl(id: string): string;
|
|
317
|
+
/** Low-level request helper (retries transient failures). */
|
|
318
|
+
request<T>(method: string, path: string, body?: unknown): Promise<T>;
|
|
319
|
+
/** @internal */
|
|
320
|
+
rawRequest<T>(method: string, path: string, body?: unknown): Promise<T>;
|
|
321
|
+
/** @internal */
|
|
322
|
+
withRetry<T>(operation: () => Promise<T>): Promise<T>;
|
|
323
|
+
/** @internal */
|
|
324
|
+
requestBinary(path: string, onProgress?: (p: DownloadProgress) => void): Promise<DownloadResult>;
|
|
325
|
+
}
|
|
326
|
+
declare class FilesApi {
|
|
327
|
+
private readonly client;
|
|
328
|
+
constructor(client: OmniCloudClient);
|
|
329
|
+
/** `folderId: null` = root; omit it to list every active file. */
|
|
330
|
+
list(query?: ListQuery): Promise<FilesPageDTO>;
|
|
331
|
+
get(id: string): Promise<FileDTO>;
|
|
332
|
+
versions(id: string): Promise<FileVersionDTO[]>;
|
|
144
333
|
/**
|
|
145
|
-
* Uploads a file. Uses XMLHttpRequest when
|
|
146
|
-
*
|
|
334
|
+
* Uploads a file with progress and retry support. Uses XMLHttpRequest when
|
|
335
|
+
* available (browsers) so progress and cancellation work; falls back to
|
|
336
|
+
* fetch elsewhere.
|
|
147
337
|
*/
|
|
148
|
-
|
|
149
|
-
|
|
338
|
+
upload(input: UploadInput, options?: UploadOptions): Promise<FileDTO>;
|
|
339
|
+
private uploadOnce;
|
|
150
340
|
private uploadViaXhr;
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
readonly INTERNAL: "INTERNAL_ERROR";
|
|
166
|
-
};
|
|
167
|
-
type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Base class for all domain errors. The API maps these to structured HTTP
|
|
171
|
-
* responses; everything else becomes a 500.
|
|
172
|
-
*/
|
|
173
|
-
declare class DomainError extends Error {
|
|
174
|
-
readonly code: ErrorCode;
|
|
175
|
-
readonly status: number;
|
|
176
|
-
readonly details?: unknown;
|
|
177
|
-
constructor(code: ErrorCode, status: number, message: string, details?: unknown);
|
|
178
|
-
}
|
|
179
|
-
/** The underlying storage backend (e.g. Telegram) failed. */
|
|
180
|
-
declare class StorageProviderError extends DomainError {
|
|
181
|
-
constructor(message: string, details?: unknown);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Domain records. Repository implementations (e.g. the Prisma layer) map
|
|
186
|
-
* their persistence models onto these records; the rest of the application
|
|
187
|
-
* only ever works with them.
|
|
188
|
-
*
|
|
189
|
-
* Telegram identifiers are represented as strings/numbers that fit in
|
|
190
|
-
* JavaScript's safe integer range; the persistence layer converts as needed.
|
|
191
|
-
*/
|
|
192
|
-
interface UserRecord {
|
|
193
|
-
id: string;
|
|
194
|
-
telegramUserId: string;
|
|
195
|
-
username: string | null;
|
|
196
|
-
firstName: string | null;
|
|
197
|
-
lastName: string | null;
|
|
198
|
-
phone: string | null;
|
|
199
|
-
createdAt: Date;
|
|
200
|
-
}
|
|
201
|
-
interface TelegramSessionRecord {
|
|
202
|
-
userId: string;
|
|
203
|
-
stringSession: string;
|
|
204
|
-
}
|
|
205
|
-
interface StorageRecord {
|
|
206
|
-
id: string;
|
|
207
|
-
userId: string;
|
|
208
|
-
provider: string;
|
|
209
|
-
title: string;
|
|
210
|
-
telegramChatId: string;
|
|
211
|
-
telegramAccessHash: string;
|
|
212
|
-
createdAt: Date;
|
|
213
|
-
}
|
|
214
|
-
interface FolderRecord {
|
|
215
|
-
id: string;
|
|
216
|
-
userId: string;
|
|
217
|
-
parentId: string | null;
|
|
218
|
-
name: string;
|
|
219
|
-
createdAt: Date;
|
|
220
|
-
updatedAt: Date;
|
|
221
|
-
}
|
|
222
|
-
interface FileRecord {
|
|
223
|
-
id: string;
|
|
224
|
-
userId: string;
|
|
225
|
-
folderId: string | null;
|
|
226
|
-
name: string;
|
|
227
|
-
size: number;
|
|
228
|
-
mimeType: string;
|
|
229
|
-
sha256: string;
|
|
230
|
-
telegramMessageId: number;
|
|
231
|
-
createdAt: Date;
|
|
232
|
-
updatedAt: Date;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Repository interfaces. The application depends on these, not on a specific
|
|
237
|
-
* database — the Prisma implementation lives in @omnicloud/database, and
|
|
238
|
-
* tests use in-memory implementations.
|
|
239
|
-
*/
|
|
240
|
-
interface UserRepository {
|
|
241
|
-
findById(id: string): Promise<UserRecord | null>;
|
|
242
|
-
findByTelegramId(telegramUserId: string): Promise<UserRecord | null>;
|
|
243
|
-
upsertFromTelegram(input: {
|
|
244
|
-
telegramUserId: string;
|
|
245
|
-
username: string | null;
|
|
246
|
-
firstName: string | null;
|
|
247
|
-
lastName: string | null;
|
|
248
|
-
phone: string | null;
|
|
249
|
-
}): Promise<UserRecord>;
|
|
250
|
-
}
|
|
251
|
-
interface SessionRepository {
|
|
252
|
-
get(userId: string): Promise<TelegramSessionRecord | null>;
|
|
253
|
-
save(userId: string, stringSession: string): Promise<void>;
|
|
254
|
-
delete(userId: string): Promise<void>;
|
|
255
|
-
}
|
|
256
|
-
interface StorageRepository {
|
|
257
|
-
findByUserAndProvider(userId: string, provider: string): Promise<StorageRecord | null>;
|
|
258
|
-
create(input: {
|
|
259
|
-
userId: string;
|
|
260
|
-
provider: string;
|
|
261
|
-
title: string;
|
|
262
|
-
telegramChatId: string;
|
|
263
|
-
telegramAccessHash: string;
|
|
264
|
-
}): Promise<StorageRecord>;
|
|
265
|
-
}
|
|
266
|
-
interface FolderRepository {
|
|
267
|
-
create(input: {
|
|
268
|
-
userId: string;
|
|
269
|
-
parentId: string | null;
|
|
270
|
-
name: string;
|
|
271
|
-
}): Promise<FolderRecord>;
|
|
272
|
-
findById(id: string): Promise<FolderRecord | null>;
|
|
273
|
-
/** Every folder belonging to the user (used for trees and cascade deletes). */
|
|
274
|
-
listByUser(userId: string): Promise<FolderRecord[]>;
|
|
275
|
-
listChildren(userId: string, parentId: string | null): Promise<FolderRecord[]>;
|
|
276
|
-
update(id: string, patch: {
|
|
277
|
-
name?: string;
|
|
278
|
-
parentId?: string | null;
|
|
279
|
-
}): Promise<FolderRecord>;
|
|
280
|
-
deleteMany(ids: string[]): Promise<void>;
|
|
281
|
-
searchByName(userId: string, query: string, limit: number): Promise<FolderRecord[]>;
|
|
282
|
-
}
|
|
283
|
-
interface FileRepository {
|
|
284
|
-
create(input: {
|
|
285
|
-
userId: string;
|
|
286
|
-
folderId: string | null;
|
|
287
|
-
name: string;
|
|
288
|
-
size: number;
|
|
289
|
-
mimeType: string;
|
|
290
|
-
sha256: string;
|
|
291
|
-
telegramMessageId: number;
|
|
292
|
-
}): Promise<FileRecord>;
|
|
293
|
-
findById(id: string): Promise<FileRecord | null>;
|
|
294
|
-
listByFolder(userId: string, folderId: string | null): Promise<FileRecord[]>;
|
|
295
|
-
listByUser(userId: string): Promise<FileRecord[]>;
|
|
296
|
-
update(id: string, patch: {
|
|
297
|
-
name?: string;
|
|
341
|
+
/** Uploads a new version of an existing file. */
|
|
342
|
+
replace(id: string, input: UploadInput): Promise<FileDTO>;
|
|
343
|
+
download(id: string, onProgress?: (p: DownloadProgress) => void): Promise<DownloadResult>;
|
|
344
|
+
/** URL suitable for direct download (anchor href). */
|
|
345
|
+
downloadUrl(id: string): string;
|
|
346
|
+
rename(id: string, name: string): Promise<FileDTO>;
|
|
347
|
+
star(id: string, starred?: boolean): Promise<FileDTO>;
|
|
348
|
+
move(id: string, folderId: string | null): Promise<FileDTO>;
|
|
349
|
+
trash(id: string): Promise<FileDTO>;
|
|
350
|
+
restore(id: string): Promise<FileDTO>;
|
|
351
|
+
/** Permanently deletes a file and its Telegram objects. */
|
|
352
|
+
delete(id: string): Promise<void>;
|
|
353
|
+
/** Batch operation: trash | restore | delete | star | unstar | move. */
|
|
354
|
+
batch(operation: "trash" | "restore" | "delete" | "star" | "unstar" | "move", ids: string[], options?: {
|
|
298
355
|
folderId?: string | null;
|
|
299
|
-
}): Promise<
|
|
300
|
-
deleteMany(ids: string[]): Promise<void>;
|
|
301
|
-
searchByName(userId: string, query: string, limit: number): Promise<FileRecord[]>;
|
|
302
|
-
}
|
|
303
|
-
interface Repos {
|
|
304
|
-
users: UserRepository;
|
|
305
|
-
sessions: SessionRepository;
|
|
306
|
-
storages: StorageRepository;
|
|
307
|
-
folders: FolderRepository;
|
|
308
|
-
files: FileRepository;
|
|
356
|
+
}): Promise<BatchResultDTO>;
|
|
309
357
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
interface StorageProvider {
|
|
330
|
-
readonly name: string;
|
|
331
|
-
/** Uploads the object and returns the stored reference. */
|
|
332
|
-
put(input: StorageUploadInput): Promise<StoredObject>;
|
|
333
|
-
/** Downloads the object's content. */
|
|
334
|
-
get(ref: StoredRef): Promise<Buffer>;
|
|
335
|
-
/** Deletes the object. Deleting an already-missing object must not throw. */
|
|
336
|
-
delete(ref: StoredRef): Promise<void>;
|
|
337
|
-
exists(ref: StoredRef): Promise<boolean>;
|
|
338
|
-
stat(ref: StoredRef): Promise<StoredObject | null>;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
declare function sha256Hex(data: Uint8Array): string;
|
|
342
|
-
|
|
343
|
-
interface EngineUploadResult {
|
|
344
|
-
stored: StoredObject;
|
|
345
|
-
sha256: string;
|
|
346
|
-
size: number;
|
|
347
|
-
}
|
|
348
|
-
/**
|
|
349
|
-
* Sits between the application and the raw StorageProvider and adds the
|
|
350
|
-
* cross-cutting guarantees: SHA-256 integrity and consistent error mapping.
|
|
351
|
-
*
|
|
352
|
-
* The active provider is chosen per user by the host application (each user
|
|
353
|
-
* has their own Telegram storage channel).
|
|
354
|
-
*/
|
|
355
|
-
declare class StorageEngine {
|
|
356
|
-
private readonly provider;
|
|
357
|
-
constructor(provider: StorageProvider);
|
|
358
|
-
get providerName(): string;
|
|
359
|
-
/** Uploads an object and computes its checksum in one step. */
|
|
360
|
-
upload(input: StorageUploadInput): Promise<EngineUploadResult>;
|
|
361
|
-
download(ref: StoredRef): Promise<Buffer>;
|
|
362
|
-
remove(ref: StoredRef): Promise<void>;
|
|
363
|
-
verifyIntegrity(data: Buffer, expectedSha256: string): Promise<boolean>;
|
|
364
|
-
}
|
|
365
|
-
declare function mapProviderError(message: string, error: unknown): StorageProviderError;
|
|
366
|
-
|
|
367
|
-
interface FileDownload {
|
|
368
|
-
record: FileRecord;
|
|
369
|
-
data: Buffer;
|
|
370
|
-
integrityVerified: boolean;
|
|
371
|
-
}
|
|
372
|
-
type EngineResolver = (userId: string) => Promise<StorageEngine>;
|
|
373
|
-
/**
|
|
374
|
-
* All file metadata operations. Every method verifies ownership: records
|
|
375
|
-
* belonging to other users are reported as missing.
|
|
376
|
-
*/
|
|
377
|
-
declare class FileService {
|
|
378
|
-
private readonly files;
|
|
379
|
-
private readonly folders;
|
|
380
|
-
private readonly engineFor;
|
|
381
|
-
constructor(files: FileRepository, folders: FolderRepository, engineFor: EngineResolver);
|
|
382
|
-
upload(userId: string, input: {
|
|
383
|
-
folderId: string | null;
|
|
384
|
-
name: string;
|
|
385
|
-
data: Buffer;
|
|
386
|
-
}): Promise<FileRecord>;
|
|
387
|
-
list(userId: string, folderId: string | null): Promise<FileRecord[]>;
|
|
388
|
-
get(userId: string, id: string): Promise<FileRecord>;
|
|
389
|
-
rename(userId: string, id: string, name: string): Promise<FileRecord>;
|
|
390
|
-
move(userId: string, id: string, folderId: string | null): Promise<FileRecord>;
|
|
391
|
-
delete(userId: string, id: string): Promise<void>;
|
|
392
|
-
download(userId: string, id: string): Promise<FileDownload>;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
interface FolderDeletionResult {
|
|
396
|
-
deletedFolders: number;
|
|
397
|
-
deletedFiles: number;
|
|
358
|
+
declare class FoldersApi {
|
|
359
|
+
private readonly client;
|
|
360
|
+
constructor(client: OmniCloudClient);
|
|
361
|
+
list(query?: ListQuery & {
|
|
362
|
+
parentId?: string | null;
|
|
363
|
+
}): Promise<FoldersPageDTO>;
|
|
364
|
+
/** The full active folder tree (for move dialogs). */
|
|
365
|
+
tree(): Promise<FolderDTO[]>;
|
|
366
|
+
create(name: string, parentId?: string | null): Promise<FolderDTO>;
|
|
367
|
+
rename(id: string, name: string): Promise<FolderDTO>;
|
|
368
|
+
star(id: string, starred?: boolean): Promise<FolderDTO>;
|
|
369
|
+
move(id: string, parentId: string | null): Promise<FolderDTO>;
|
|
370
|
+
trash(id: string): Promise<FolderMutationResultDTO>;
|
|
371
|
+
restore(id: string): Promise<FolderMutationResultDTO>;
|
|
372
|
+
/** Permanently deletes the folder subtree and its Telegram objects. */
|
|
373
|
+
delete(id: string): Promise<FolderMutationResultDTO>;
|
|
374
|
+
batch(operation: "trash" | "restore" | "delete" | "star" | "unstar" | "move", ids: string[], options?: {
|
|
375
|
+
parentId?: string | null;
|
|
376
|
+
}): Promise<BatchResultDTO>;
|
|
398
377
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
declare class FolderService {
|
|
406
|
-
private readonly folders;
|
|
407
|
-
private readonly files;
|
|
408
|
-
private readonly engineFor;
|
|
409
|
-
constructor(folders: FolderRepository, files: FileRepository, engineFor: EngineResolver);
|
|
410
|
-
create(userId: string, input: {
|
|
411
|
-
name: string;
|
|
412
|
-
parentId: string | null;
|
|
413
|
-
}): Promise<FolderRecord>;
|
|
414
|
-
listChildren(userId: string, parentId: string | null): Promise<FolderRecord[]>;
|
|
415
|
-
tree(userId: string): Promise<FolderRecord[]>;
|
|
416
|
-
get(userId: string, id: string): Promise<FolderRecord>;
|
|
417
|
-
rename(userId: string, id: string, name: string): Promise<FolderRecord>;
|
|
418
|
-
move(userId: string, id: string, newParentId: string | null): Promise<FolderRecord>;
|
|
419
|
-
delete(userId: string, id: string): Promise<FolderDeletionResult>;
|
|
378
|
+
declare class TrashApi {
|
|
379
|
+
private readonly client;
|
|
380
|
+
constructor(client: OmniCloudClient);
|
|
381
|
+
list(query?: ListQuery): Promise<TrashPageDTO>;
|
|
382
|
+
/** Permanently removes everything in the Trash. */
|
|
383
|
+
empty(): Promise<EmptyTrashResultDTO>;
|
|
420
384
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
private
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
385
|
+
declare class StorageApi {
|
|
386
|
+
private readonly client;
|
|
387
|
+
constructor(client: OmniCloudClient);
|
|
388
|
+
/** Creates the private storage channel if it does not exist yet. */
|
|
389
|
+
ensure(): Promise<StorageDTO>;
|
|
390
|
+
stats(): Promise<StorageStatsDTO>;
|
|
391
|
+
health(): Promise<{
|
|
392
|
+
health: StorageHealthDTO;
|
|
393
|
+
stats: StorageStatsDTO;
|
|
430
394
|
}>;
|
|
395
|
+
/** Probes the storage backend; `deep` performs a real Telegram round-trip. */
|
|
396
|
+
check(deep?: boolean): Promise<StorageHealthDTO>;
|
|
397
|
+
/** Read-only integrity scan; nothing is repaired or deleted. */
|
|
398
|
+
integrityCheck(options?: {
|
|
399
|
+
deep?: boolean;
|
|
400
|
+
}): Promise<IntegrityReportDTO>;
|
|
401
|
+
/** Public server health (no authentication required). */
|
|
402
|
+
serverHealth(): Promise<HealthDTO>;
|
|
403
|
+
}
|
|
404
|
+
declare class SearchApi {
|
|
405
|
+
private readonly client;
|
|
406
|
+
constructor(client: OmniCloudClient);
|
|
407
|
+
/**
|
|
408
|
+
* Searches with the v0.2 query language:
|
|
409
|
+
* `type:pdf`, `size:>100MB`, `folder:Projects`, `starred:true`, `after:2026-01-01`
|
|
410
|
+
*/
|
|
411
|
+
query(q: string, page?: {
|
|
412
|
+
page?: number;
|
|
413
|
+
limit?: number;
|
|
414
|
+
}): Promise<SearchResultDTO>;
|
|
431
415
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
interface TelegramCredentials {
|
|
440
|
-
apiId: number;
|
|
441
|
-
apiHash: string;
|
|
442
|
-
}
|
|
443
|
-
/**
|
|
444
|
-
* Keeps one connected TelegramClient per authenticated user. Clients are
|
|
445
|
-
* restored from the persisted MTProto session string and cached for the
|
|
446
|
-
* lifetime of the process.
|
|
447
|
-
*/
|
|
448
|
-
declare class TelegramClientManager {
|
|
449
|
-
private readonly credentials;
|
|
450
|
-
private readonly sessions;
|
|
451
|
-
private clients;
|
|
452
|
-
constructor(credentials: TelegramCredentials, sessions: SessionRepository);
|
|
453
|
-
getForUser(userId: string): Promise<TelegramClient>;
|
|
454
|
-
/** Registers an already-authenticated client (e.g. from the login flow). */
|
|
455
|
-
cacheClient(userId: string, client: TelegramClient): void;
|
|
456
|
-
disconnectAll(): Promise<void>;
|
|
457
|
-
private connect;
|
|
416
|
+
declare class RecentApi {
|
|
417
|
+
private readonly client;
|
|
418
|
+
constructor(client: OmniCloudClient);
|
|
419
|
+
list(page?: {
|
|
420
|
+
page?: number;
|
|
421
|
+
limit?: number;
|
|
422
|
+
}): Promise<RecentPageDTO>;
|
|
458
423
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
interface TelegramStorageOptions {
|
|
467
|
-
/** Raw channel id of the user's private storage channel. */
|
|
468
|
-
chatId: string;
|
|
469
|
-
/** Channel access hash required to build the input peer. */
|
|
470
|
-
accessHash: string;
|
|
424
|
+
declare class ActivityApi {
|
|
425
|
+
private readonly client;
|
|
426
|
+
constructor(client: OmniCloudClient);
|
|
427
|
+
list(page?: {
|
|
428
|
+
page?: number;
|
|
429
|
+
limit?: number;
|
|
430
|
+
}): Promise<ActivityPageDTO>;
|
|
471
431
|
}
|
|
472
|
-
|
|
473
|
-
* StorageProvider implementation backed by the user's private Telegram
|
|
474
|
-
* channel. Files are sent as force-downloaded documents (no compression),
|
|
475
|
-
* so every upload is a document message in the channel.
|
|
476
|
-
*/
|
|
477
|
-
declare class TelegramStorageProvider implements StorageProvider {
|
|
432
|
+
declare class AuthApi {
|
|
478
433
|
private readonly client;
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
434
|
+
constructor(client: OmniCloudClient);
|
|
435
|
+
me(): Promise<SessionInfo>;
|
|
436
|
+
startTelegramLogin(phone: string): Promise<void>;
|
|
437
|
+
verifyTelegramCode(phone: string, code: string): Promise<TelegramVerifyResponse>;
|
|
438
|
+
submitTelegramPassword(phone: string, password: string): Promise<{
|
|
439
|
+
status: "ok";
|
|
440
|
+
user: UserDTO;
|
|
441
|
+
}>;
|
|
442
|
+
logout(): Promise<void>;
|
|
488
443
|
}
|
|
489
444
|
|
|
490
|
-
|
|
491
|
-
type
|
|
492
|
-
status: "ok";
|
|
493
|
-
user: UserRecord;
|
|
494
|
-
} | {
|
|
495
|
-
status: "password_required";
|
|
496
|
-
};
|
|
497
|
-
/**
|
|
498
|
-
* Orchestrates the full Telegram account connection flow:
|
|
499
|
-
* phone → code (→ 2FA password) → session persisted → user upserted →
|
|
500
|
-
* private storage channel created.
|
|
501
|
-
*/
|
|
502
|
-
declare class TelegramConnectionService {
|
|
503
|
-
private readonly repos;
|
|
504
|
-
private readonly clientManager;
|
|
505
|
-
private readonly credentials;
|
|
506
|
-
private flows;
|
|
507
|
-
constructor(repos: Repos, clientManager: TelegramClientManager, credentials: TelegramCredentials);
|
|
508
|
-
/** Sends the Telegram confirmation code for the phone number. */
|
|
509
|
-
startLogin(phone: string): Promise<void>;
|
|
510
|
-
/** Verifies the confirmation code. Returns `password_required` for 2FA accounts. */
|
|
511
|
-
verifyCode(phone: string, code: string): Promise<VerifyCodeResult>;
|
|
512
|
-
/** Completes sign-in for accounts with two-factor authentication enabled. */
|
|
513
|
-
verifyPassword(phone: string, password: string): Promise<VerifyCodeResult>;
|
|
514
|
-
/** Aborts a pending login flow (disconnects the client). */
|
|
515
|
-
cancelLogin(phone: string): Promise<void>;
|
|
516
|
-
/**
|
|
517
|
-
* Ensures the user has a registered private storage channel, creating it
|
|
518
|
-
* on first use. Idempotent.
|
|
519
|
-
*/
|
|
520
|
-
ensureStorage(userId: string): Promise<StorageRecord>;
|
|
521
|
-
ensureStorageForClient(userId: string, client: TelegramClient): Promise<StorageRecord>;
|
|
522
|
-
private requireFlow;
|
|
523
|
-
private finalizeLogin;
|
|
524
|
-
private sweepExpiredFlows;
|
|
525
|
-
private disconnectQuietly;
|
|
526
|
-
}
|
|
445
|
+
/** Connection state of the underlying storage backend. */
|
|
446
|
+
type ConnectionState = "DISCONNECTED" | "CONNECTING" | "CONNECTED" | "RECONNECTING" | "ERROR" | "AUTH_REQUIRED";
|
|
527
447
|
|
|
528
|
-
export { type ApiErrorBody, type
|
|
448
|
+
export { type ActivityEventDTO, type ActivityPageDTO, type ApiErrorBody, type BatchResultDTO, type ConnectionState, type DownloadProgress, type DownloadResult, ERROR_CODES, type EmptyTrashResultDTO, type ErrorCode, type FileDTO, type FileVersionDTO, type FilesPageDTO, type FolderDTO, type FolderMutationResultDTO, type FoldersPageDTO, type HealthDTO, type HealthStatus, type IntegrityIssueDTO, type IntegrityReportDTO, OmniCloudClient, type OmniCloudClientOptions, OmniCloudError, type PaginationDTO, type RecentItemDTO, type RecentPageDTO, type RetryOptions, type SearchResultDTO, type SessionInfo, type StorageDTO, type StorageHealthDTO, type StorageStatsDTO, type StorageTypeBreakdownDTO, type TelegramVerifyResponse, type TrashPageDTO, type UploadInput, type UploadOptions, type UploadProgress, type UserDTO };
|