@darseen/vaze 2.5.0 → 2.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.
package/README.md CHANGED
@@ -10,6 +10,8 @@
10
10
 
11
11
  **@darseen/vaze** The official JavaScript/TypeScript SDK for Vaze, a self-hosted, local-first file storage and hosting service. This SDK provides a simple and type-safe way to interact with your Vaze instance's API from your Node.js backend or frontend applications.
12
12
 
13
+ **[Website](https://vaze.darseen.dev)**  |  **[SDK documentation](https://vaze.darseen.dev/docs/sdk)**
14
+
13
15
  ## </div>
14
16
 
15
17
  # Installation
@@ -147,10 +149,11 @@ const { data, error } = await vaze.files.rename({
147
149
  });
148
150
  ```
149
151
 
150
- `delete(id)` Delete a file by its ID.
152
+ `delete(id, options?)` Delete a file by its ID. It moves to Recently deleted, where it can be restored until it is purged. Pass `{ permanent: true }` to remove it from storage right away. `deleteMany(ids, options?)` does the same for several files.
151
153
 
152
154
  ```ts
153
155
  const { data, error } = await vaze.files.delete("file-id-123");
156
+ await vaze.files.delete("file-id-456", { permanent: true });
154
157
  ```
155
158
 
156
159
  Folders API Access folder-related methods via `vaze.folders`. `get(options?)` Retrieve folders and their contents.
@@ -207,12 +210,21 @@ if (data) {
207
210
  }
208
211
  ```
209
212
 
210
- `delete(id)` Delete a folder by its ID.
213
+ `delete(id, options?)` Delete a folder by its ID. It moves to Recently deleted with everything inside it, unless you pass `{ permanent: true }`.
211
214
 
212
215
  ```ts
213
216
  const { data, error } = await vaze.folders.delete("folder-id");
214
217
  ```
215
218
 
219
+ Recently Deleted API Restore or purge deleted files and folders via `vaze.deleted`. Listing needs `files:read`, and restoring and purging need `files:delete`. Items are purged on their own once they are older than the instance's `deletedRetentionDays`.
220
+
221
+ ```ts
222
+ const { data } = await vaze.deleted.getAll(); // items, newest first, and retentionDays
223
+ await vaze.deleted.restore(["file-id-123", "folder-id"]); // back where they were
224
+ await vaze.deleted.purge(["file-id-456"]); // gone for good
225
+ await vaze.deleted.empty();
226
+ ```
227
+
216
228
  Keys API Manage the caller's API keys via `vaze.keys`. These calls need a client that acts as a signed-in user (`headers`) holding `api-keys:manage`; a client built with an API key gets a `403`.
217
229
 
218
230
  `getAll()` List the caller's keys, newest first.
@@ -301,7 +313,7 @@ if (data) {
301
313
 
302
314
  # Account and Stats
303
315
 
304
- `vaze.me()` returns the caller's account and the scopes it may use. `vaze.stats()` returns the dashboard's numbers, with each section `null` when the caller lacks its scope.
316
+ `vaze.me()` returns the caller's account and the scopes it may use. `vaze.stats()` returns the dashboard's numbers: storage, files added per day, public hosting traffic, API key usage, accounts and alerts, with each section `null` when the caller lacks its scope. Fields added in later server versions, such as `hosting` and `alerts`, are absent on older servers.
305
317
 
306
318
  ```ts
307
319
  const { data } = await vaze.me();
@@ -312,4 +324,4 @@ Failed requests carry the HTTP status in `error.status`, such as `401` once a se
312
324
 
313
325
  # Types
314
326
 
315
- This SDK is built with TypeScript and exports all necessary types to ensure type safety in your applications. Types such as `File`, `Folder`, `ApiKey`, `Activity`, `User`, `Session`, `InstanceSettings`, `ApiResponse`, `ListOptions`, and `VazeOptions`.
327
+ This SDK is built with TypeScript and exports all necessary types to ensure type safety in your applications. Types such as `File`, `Folder`, `DeletedItem`, `ApiKey`, `Activity`, `User`, `Session`, `InstanceSettings`, `Stats`, `StatsAlert`, `TrafficDay`, `ApiKeyUsage`, `ApiResponse`, `ListOptions`, and `VazeOptions`.
package/dist/index.cjs CHANGED
@@ -218,6 +218,41 @@ var Activity = class extends Base {
218
218
  }
219
219
  };
220
220
 
221
+ // src/deleted.ts
222
+ var Deleted = class extends Base {
223
+ /** Most recently deleted first, with how many days items are kept. */
224
+ async getAll() {
225
+ return await this.request(
226
+ "GET",
227
+ this.apiUrl("/api/deleted")
228
+ );
229
+ }
230
+ /** Put items back where they were; one whose name is taken now fails. */
231
+ async restore(ids) {
232
+ return await this.request(
233
+ "POST",
234
+ this.apiUrl("/api/deleted/restore"),
235
+ { ids }
236
+ );
237
+ }
238
+ /** Delete items for good, before their time is up. */
239
+ async purge(ids) {
240
+ return await this.request(
241
+ "DELETE",
242
+ this.apiUrl("/api/deleted"),
243
+ { ids }
244
+ );
245
+ }
246
+ /** Delete everything in it for good. */
247
+ async empty() {
248
+ return await this.request(
249
+ "DELETE",
250
+ this.apiUrl("/api/deleted"),
251
+ { all: true }
252
+ );
253
+ }
254
+ };
255
+
221
256
  // src/files.ts
222
257
  var Files = class extends Base {
223
258
  async getAll(options) {
@@ -384,17 +419,19 @@ var Files = class extends Base {
384
419
  data: data ? { ...data, url: new URL(data.url, this.vazeUrl).toString() } : null
385
420
  };
386
421
  }
387
- async delete(id) {
422
+ /** Moves the file to Recently deleted, unless `permanent` is set. */
423
+ async delete(id, options) {
388
424
  return await this.request("DELETE", this.apiUrl("/api/files"), {
389
- id
425
+ id,
426
+ ...options
390
427
  });
391
428
  }
392
429
  /** Delete several files in one request; each id reports its own outcome. */
393
- async deleteMany(ids) {
430
+ async deleteMany(ids, options) {
394
431
  return await this.request(
395
432
  "DELETE",
396
433
  this.apiUrl("/api/files"),
397
- { ids }
434
+ { ids, ...options }
398
435
  );
399
436
  }
400
437
  };
@@ -445,9 +482,11 @@ var Folders = class extends Base {
445
482
  async setVisibility(data) {
446
483
  return await this.request("PUT", this.apiUrl("/api/folders"), data);
447
484
  }
448
- async delete(id) {
485
+ /** Moves the folder and everything in it to Recently deleted, unless `permanent` is set. */
486
+ async delete(id, options) {
449
487
  return await this.request("DELETE", this.apiUrl("/api/folders"), {
450
- id
488
+ id,
489
+ ...options
451
490
  });
452
491
  }
453
492
  };
@@ -577,10 +616,12 @@ var Vaze = class extends Base {
577
616
 
578
617
 
579
618
 
619
+
580
620
  constructor(options = {}) {
581
621
  super(options);
582
622
  this.files = new Files(options);
583
623
  this.folders = new Folders(options);
624
+ this.deleted = new Deleted(options);
584
625
  this.keys = new Keys(options);
585
626
  this.account = new Account(options);
586
627
  this.activity = new Activity(options);
@@ -606,27 +647,37 @@ var Vaze = class extends Base {
606
647
  }
607
648
  /** Dashboard numbers, with each section limited to the caller's scopes. */
608
649
  async stats() {
609
- const { data, error } = await this.request(
650
+ const response = await this.request(
610
651
  "GET",
611
652
  this.apiUrl("/api/stats")
612
653
  );
613
- const files = _optionalChain([data, 'optionalAccess', _7 => _7.files]);
654
+ if (response.data === null) return response;
655
+ const { files, hosting } = response.data;
656
+ const vazeUrl = this.vazeUrl;
657
+ const withUrl = (file) => ({
658
+ ...file,
659
+ url: constructFileUrls({ vazeUrl, files: [file] })[0].url
660
+ });
614
661
  return {
615
- error,
616
- data: data ? {
617
- ...data,
662
+ error: null,
663
+ data: {
664
+ ...response.data,
618
665
  files: files ? {
619
666
  ...files,
620
- largest: constructFileUrls({
621
- vazeUrl: this.vazeUrl,
622
- files: files.largest
623
- }),
624
- recent: constructFileUrls({
625
- vazeUrl: this.vazeUrl,
626
- files: files.recent
627
- })
628
- } : null
629
- } : null
667
+ largest: constructFileUrls({ vazeUrl, files: files.largest }),
668
+ recent: constructFileUrls({ vazeUrl, files: files.recent })
669
+ } : null,
670
+ // servers that predate traffic leave `hosting` out, so keep it out
671
+ ...hosting ? {
672
+ hosting: {
673
+ ...hosting,
674
+ top: hosting.top.map((entry) => ({
675
+ ...entry,
676
+ file: withUrl(entry.file)
677
+ }))
678
+ }
679
+ } : {}
680
+ }
630
681
  };
631
682
  }
632
683
  };
package/dist/index.d.cts CHANGED
@@ -941,6 +941,25 @@ declare const files: SQLiteTableWithColumns<{
941
941
  }, {}, {
942
942
  length: number | undefined;
943
943
  }>;
944
+ deletedAt: SQLiteColumn<{
945
+ name: "deleted_at";
946
+ tableName: "files";
947
+ dataType: "string";
948
+ columnType: "SQLiteText";
949
+ data: string;
950
+ driverParam: string;
951
+ notNull: false;
952
+ hasDefault: false;
953
+ isPrimaryKey: false;
954
+ isAutoincrement: false;
955
+ hasRuntimeDefault: false;
956
+ enumValues: [string, ...string[]];
957
+ baseColumn: never;
958
+ identity: undefined;
959
+ generated: undefined;
960
+ }, {}, {
961
+ length: number | undefined;
962
+ }>;
944
963
  };
945
964
  dialect: "sqlite";
946
965
  }>;
@@ -1065,6 +1084,25 @@ declare const folders: SQLiteTableWithColumns<{
1065
1084
  }, {}, {
1066
1085
  length: number | undefined;
1067
1086
  }>;
1087
+ deletedAt: SQLiteColumn<{
1088
+ name: "deleted_at";
1089
+ tableName: "folders";
1090
+ dataType: "string";
1091
+ columnType: "SQLiteText";
1092
+ data: string;
1093
+ driverParam: string;
1094
+ notNull: false;
1095
+ hasDefault: false;
1096
+ isPrimaryKey: false;
1097
+ isAutoincrement: false;
1098
+ hasRuntimeDefault: false;
1099
+ enumValues: [string, ...string[]];
1100
+ baseColumn: never;
1101
+ identity: undefined;
1102
+ generated: undefined;
1103
+ }, {}, {
1104
+ length: number | undefined;
1105
+ }>;
1068
1106
  };
1069
1107
  dialect: "sqlite";
1070
1108
  }>;
@@ -1136,6 +1174,8 @@ type Limits = {
1136
1174
  hostingCacheMaxAge: number;
1137
1175
  activityRetentionDays: number;
1138
1176
  apiRequestRetentionDays: number;
1177
+ /** Days a deleted file or folder can be restored before it is purged. */
1178
+ deletedRetentionDays: number;
1139
1179
  };
1140
1180
  type InstanceSettings = {
1141
1181
  /** Applied to uploads and new folders that don't ask for one. */
@@ -1144,14 +1184,97 @@ type InstanceSettings = {
1144
1184
  visibilityCounts: Record<Visibility, number>;
1145
1185
  limits: Limits;
1146
1186
  };
1187
+ /** A file or folder in Recently deleted, which a restore puts back at `key`. */
1188
+ type DeletedItem = {
1189
+ id: string;
1190
+ name: string;
1191
+ /** Where it was; a restore recreates any folders on the way that are gone. */
1192
+ key: string;
1193
+ /** Bytes it holds, everything inside it for a folder. */
1194
+ size: number;
1195
+ deletedAt: string;
1196
+ /** When it is deleted for good, unless restored first. */
1197
+ purgeAt: string;
1198
+ } & ({
1199
+ type: "file";
1200
+ mimeType: string;
1201
+ } | {
1202
+ type: "folder";
1203
+ /** Files anywhere inside it. */
1204
+ files: number;
1205
+ });
1206
+ /** One API key's share of the week's requests. */
1207
+ type ApiKeyUsage = {
1208
+ id: string;
1209
+ name: string;
1210
+ /** Requests over the same seven UTC days as `Stats["apiKeys"]["requests"]`. */
1211
+ requests: number;
1212
+ lastUsed: string | null;
1213
+ expiresAt: string | null;
1214
+ };
1215
+ /** Public hosting traffic for one UTC day. */
1216
+ type TrafficDay = {
1217
+ date: string;
1218
+ /** Responses that served a file: 200, 206 and 304. */
1219
+ requests: number;
1220
+ /** Body bytes streamed out. */
1221
+ bytes: number;
1222
+ /** Requests for keys that matched no file the caller could read. */
1223
+ notFound: number;
1224
+ };
1225
+ /** Something on the instance worth acting on. */
1226
+ type StatsAlert =
1227
+ /** The data volume has less than a tenth of its space left. */
1228
+ {
1229
+ type: "storage-low";
1230
+ available: number;
1231
+ capacity: number;
1232
+ }
1233
+ /** The caller's own uploads that failed over the last seven days. */
1234
+ | {
1235
+ type: "uploads-failed";
1236
+ count: number;
1237
+ latest: string;
1238
+ }
1239
+ /** The caller's own file and folder deletes that failed over the last seven days. */
1240
+ | {
1241
+ type: "deletes-failed";
1242
+ count: number;
1243
+ latest: string;
1244
+ }
1245
+ /** The caller's keys past their expiry date, which no longer work. */
1246
+ | {
1247
+ type: "keys-expired";
1248
+ count: number;
1249
+ }
1250
+ /** The caller's keys that expire within seven days. */
1251
+ | {
1252
+ type: "keys-expiring";
1253
+ count: number;
1254
+ }
1255
+ /** The caller's keys not used for 30 days. */
1256
+ | {
1257
+ type: "keys-unused";
1258
+ count: number;
1259
+ };
1260
+ /**
1261
+ * Fields marked optional were added after the first release of this endpoint.
1262
+ * Servers that predate them leave them out, so check before reading.
1263
+ */
1147
1264
  type Stats = {
1148
- /** Present when the caller holds `files:read`. */
1265
+ /** Present when the caller holds `files:read`. Files in Recently deleted aren't counted. */
1149
1266
  files: {
1150
1267
  total: number;
1151
1268
  folders: number;
1152
1269
  storage: {
1270
+ /** Bytes taken by stored files. */
1153
1271
  used: number;
1272
+ /** Bytes free on the data volume. */
1154
1273
  available: number;
1274
+ /** Usable size of the data volume, which other data may share. */
1275
+ capacity?: number;
1276
+ /** Bytes held by files in Recently deleted, not counted in `used`. */
1277
+ deleted?: number;
1155
1278
  };
1156
1279
  types: {
1157
1280
  mimeType: string;
@@ -1160,6 +1283,20 @@ type Stats = {
1160
1283
  }[];
1161
1284
  largest: FileWithUrl[];
1162
1285
  recent: FileWithUrl[];
1286
+ /** Files and bytes per visibility. */
1287
+ visibility?: Record<Visibility, {
1288
+ count: number;
1289
+ size: number;
1290
+ }>;
1291
+ /**
1292
+ * Files added per UTC day over the last 30 days, oldest first. Only files
1293
+ * still stored count, so deleting a file removes it from its day.
1294
+ */
1295
+ added?: {
1296
+ date: string;
1297
+ count: number;
1298
+ size: number;
1299
+ }[];
1163
1300
  } | null;
1164
1301
  /** Present for signed-in users holding `api-keys:manage`. */
1165
1302
  apiKeys: {
@@ -1169,7 +1306,36 @@ type Stats = {
1169
1306
  date: string;
1170
1307
  count: number;
1171
1308
  }[];
1309
+ /**
1310
+ * Every key with its requests over the same days, busiest first. Requests
1311
+ * made with keys deleted since count in `requests` but in no key here.
1312
+ */
1313
+ keys?: ApiKeyUsage[];
1314
+ } | null;
1315
+ /**
1316
+ * Public hosting traffic over the last 30 UTC days. Present when the caller
1317
+ * holds `files:read`. Requests made from a signed-in dashboard or app
1318
+ * session aren't counted.
1319
+ */
1320
+ hosting?: {
1321
+ /** Oldest first. */
1322
+ days: TrafficDay[];
1323
+ /** The five files requested most over those days. */
1324
+ top: {
1325
+ file: FileWithUrl;
1326
+ requests: number;
1327
+ bytes: number;
1328
+ }[];
1172
1329
  } | null;
1330
+ /** Present for signed-in users holding `users:manage`. */
1331
+ users?: {
1332
+ total: number;
1333
+ disabled: number;
1334
+ /** Devices signed in across every account. */
1335
+ sessions: number;
1336
+ } | null;
1337
+ /** Empty when nothing needs attention. New types may be added later. */
1338
+ alerts?: StatsAlert[];
1173
1339
  };
1174
1340
 
1175
1341
  /** The caller's activity history. These calls need a session, not a key. */
@@ -1187,6 +1353,21 @@ declare class Activity extends Base {
1187
1353
  }>>;
1188
1354
  }
1189
1355
 
1356
+ /** Files and folders that were deleted and can still be restored. */
1357
+ declare class Deleted extends Base {
1358
+ /** Most recently deleted first, with how many days items are kept. */
1359
+ getAll(): Promise<ApiResponse<{
1360
+ items: DeletedItem[];
1361
+ retentionDays: number;
1362
+ }>>;
1363
+ /** Put items back where they were; one whose name is taken now fails. */
1364
+ restore(ids: string[]): Promise<ApiResponse<BulkRestoreResult>>;
1365
+ /** Delete items for good, before their time is up. */
1366
+ purge(ids: string[]): Promise<ApiResponse<BulkDeleteResult>>;
1367
+ /** Delete everything in it for good. */
1368
+ empty(): Promise<ApiResponse<BulkDeleteResult>>;
1369
+ }
1370
+
1190
1371
  declare class Files extends Base {
1191
1372
  getAll(options?: ListOptions): Promise<{
1192
1373
  error: {
@@ -1303,9 +1484,10 @@ declare class Files extends Base {
1303
1484
  expiresAt: string;
1304
1485
  } | null;
1305
1486
  }>;
1306
- delete(id: string): Promise<ApiResponse<null>>;
1487
+ /** Moves the file to Recently deleted, unless `permanent` is set. */
1488
+ delete(id: string, options?: DeleteOptions): Promise<ApiResponse<null>>;
1307
1489
  /** Delete several files in one request; each id reports its own outcome. */
1308
- deleteMany(ids: string[]): Promise<ApiResponse<BulkDeleteResult>>;
1490
+ deleteMany(ids: string[], options?: DeleteOptions): Promise<ApiResponse<BulkDeleteResult>>;
1309
1491
  }
1310
1492
 
1311
1493
  declare class Folders extends Base {
@@ -1355,7 +1537,8 @@ declare class Folders extends Base {
1355
1537
  id: string;
1356
1538
  visibility: Visibility;
1357
1539
  }): Promise<ApiResponse<null>>;
1358
- delete(id: string): Promise<ApiResponse<null>>;
1540
+ /** Moves the folder and everything in it to Recently deleted, unless `permanent` is set. */
1541
+ delete(id: string, options?: DeleteOptions): Promise<ApiResponse<null>>;
1359
1542
  }
1360
1543
 
1361
1544
  /** The caller's API keys. These calls need a signed-in session, not a key. */
@@ -1423,6 +1606,7 @@ declare class Users extends Base {
1423
1606
  interface IVaze {
1424
1607
  files: Files;
1425
1608
  folders: Folders;
1609
+ deleted: Deleted;
1426
1610
  keys: Keys;
1427
1611
  account: Account;
1428
1612
  activity: Activity;
@@ -1517,6 +1701,17 @@ type BulkDeleteResult = {
1517
1701
  message: string;
1518
1702
  }[];
1519
1703
  };
1704
+ type BulkRestoreResult = {
1705
+ restored: string[];
1706
+ failed: {
1707
+ id: string;
1708
+ message: string;
1709
+ }[];
1710
+ };
1711
+ type DeleteOptions = {
1712
+ /** Skip Recently deleted and remove it from storage right away. */
1713
+ permanent?: boolean;
1714
+ };
1520
1715
 
1521
1716
  declare class Base {
1522
1717
  private apiKey;
@@ -1553,6 +1748,7 @@ declare class Account extends Base {
1553
1748
  declare class Vaze extends Base implements IVaze {
1554
1749
  files: Files;
1555
1750
  folders: Folders;
1751
+ deleted: Deleted;
1556
1752
  keys: Keys;
1557
1753
  account: Account;
1558
1754
  activity: Activity;
@@ -1569,36 +1765,7 @@ declare class Vaze extends Base implements IVaze {
1569
1765
  /** The caller's account and the scopes it may use. */
1570
1766
  me(): Promise<ApiResponse<Me>>;
1571
1767
  /** Dashboard numbers, with each section limited to the caller's scopes. */
1572
- stats(): Promise<{
1573
- error: {
1574
- message: string;
1575
- status?: number;
1576
- } | null;
1577
- data: {
1578
- files: {
1579
- largest: any[];
1580
- recent: any[];
1581
- total: number;
1582
- folders: number;
1583
- storage: {
1584
- used: number;
1585
- available: number;
1586
- };
1587
- types: {
1588
- mimeType: string;
1589
- size: number;
1590
- count: number;
1591
- }[];
1592
- } | null;
1593
- apiKeys: {
1594
- total: number;
1595
- requests: {
1596
- date: string;
1597
- count: number;
1598
- }[];
1599
- } | null;
1600
- } | null;
1601
- }>;
1768
+ stats(): Promise<ApiResponse<Stats>>;
1602
1769
  }
1603
1770
 
1604
- export { type ActivityEntry as Activity, type ActivityType, type ApiKeySummary as ApiKey, type ApiResponse, type BulkDeleteResult, type BulkMoveResult, type CreatedApiKey, type FileWithUrl as File, type FileReference, type Folder, type InstanceSettings, type Limits, type ListOptions, type Me, type MoveDestination, type NewKeyOptions, type NewUserOptions, type PasswordChange, type ProfileChanges, type Role, type Scope, type SessionSummary as Session, type SettingsChanges, type SignOptions, type SignedUrl, type Stats, type UserSummary as User, type UserAccess, type VazeHeaders, type VazeOptions, type Visibility, Vaze as default };
1771
+ export { type ActivityEntry as Activity, type ActivityType, type ApiKeySummary as ApiKey, type ApiKeyUsage, type ApiResponse, type BulkDeleteResult, type BulkMoveResult, type BulkRestoreResult, type CreatedApiKey, type DeleteOptions, type DeletedItem, type FileWithUrl as File, type FileReference, type Folder, type InstanceSettings, type Limits, type ListOptions, type Me, type MoveDestination, type NewKeyOptions, type NewUserOptions, type PasswordChange, type ProfileChanges, type Role, type Scope, type SessionSummary as Session, type SettingsChanges, type SignOptions, type SignedUrl, type Stats, type StatsAlert, type TrafficDay, type UserSummary as User, type UserAccess, type VazeHeaders, type VazeOptions, type Visibility, Vaze as default };
package/dist/index.d.ts CHANGED
@@ -941,6 +941,25 @@ declare const files: SQLiteTableWithColumns<{
941
941
  }, {}, {
942
942
  length: number | undefined;
943
943
  }>;
944
+ deletedAt: SQLiteColumn<{
945
+ name: "deleted_at";
946
+ tableName: "files";
947
+ dataType: "string";
948
+ columnType: "SQLiteText";
949
+ data: string;
950
+ driverParam: string;
951
+ notNull: false;
952
+ hasDefault: false;
953
+ isPrimaryKey: false;
954
+ isAutoincrement: false;
955
+ hasRuntimeDefault: false;
956
+ enumValues: [string, ...string[]];
957
+ baseColumn: never;
958
+ identity: undefined;
959
+ generated: undefined;
960
+ }, {}, {
961
+ length: number | undefined;
962
+ }>;
944
963
  };
945
964
  dialect: "sqlite";
946
965
  }>;
@@ -1065,6 +1084,25 @@ declare const folders: SQLiteTableWithColumns<{
1065
1084
  }, {}, {
1066
1085
  length: number | undefined;
1067
1086
  }>;
1087
+ deletedAt: SQLiteColumn<{
1088
+ name: "deleted_at";
1089
+ tableName: "folders";
1090
+ dataType: "string";
1091
+ columnType: "SQLiteText";
1092
+ data: string;
1093
+ driverParam: string;
1094
+ notNull: false;
1095
+ hasDefault: false;
1096
+ isPrimaryKey: false;
1097
+ isAutoincrement: false;
1098
+ hasRuntimeDefault: false;
1099
+ enumValues: [string, ...string[]];
1100
+ baseColumn: never;
1101
+ identity: undefined;
1102
+ generated: undefined;
1103
+ }, {}, {
1104
+ length: number | undefined;
1105
+ }>;
1068
1106
  };
1069
1107
  dialect: "sqlite";
1070
1108
  }>;
@@ -1136,6 +1174,8 @@ type Limits = {
1136
1174
  hostingCacheMaxAge: number;
1137
1175
  activityRetentionDays: number;
1138
1176
  apiRequestRetentionDays: number;
1177
+ /** Days a deleted file or folder can be restored before it is purged. */
1178
+ deletedRetentionDays: number;
1139
1179
  };
1140
1180
  type InstanceSettings = {
1141
1181
  /** Applied to uploads and new folders that don't ask for one. */
@@ -1144,14 +1184,97 @@ type InstanceSettings = {
1144
1184
  visibilityCounts: Record<Visibility, number>;
1145
1185
  limits: Limits;
1146
1186
  };
1187
+ /** A file or folder in Recently deleted, which a restore puts back at `key`. */
1188
+ type DeletedItem = {
1189
+ id: string;
1190
+ name: string;
1191
+ /** Where it was; a restore recreates any folders on the way that are gone. */
1192
+ key: string;
1193
+ /** Bytes it holds, everything inside it for a folder. */
1194
+ size: number;
1195
+ deletedAt: string;
1196
+ /** When it is deleted for good, unless restored first. */
1197
+ purgeAt: string;
1198
+ } & ({
1199
+ type: "file";
1200
+ mimeType: string;
1201
+ } | {
1202
+ type: "folder";
1203
+ /** Files anywhere inside it. */
1204
+ files: number;
1205
+ });
1206
+ /** One API key's share of the week's requests. */
1207
+ type ApiKeyUsage = {
1208
+ id: string;
1209
+ name: string;
1210
+ /** Requests over the same seven UTC days as `Stats["apiKeys"]["requests"]`. */
1211
+ requests: number;
1212
+ lastUsed: string | null;
1213
+ expiresAt: string | null;
1214
+ };
1215
+ /** Public hosting traffic for one UTC day. */
1216
+ type TrafficDay = {
1217
+ date: string;
1218
+ /** Responses that served a file: 200, 206 and 304. */
1219
+ requests: number;
1220
+ /** Body bytes streamed out. */
1221
+ bytes: number;
1222
+ /** Requests for keys that matched no file the caller could read. */
1223
+ notFound: number;
1224
+ };
1225
+ /** Something on the instance worth acting on. */
1226
+ type StatsAlert =
1227
+ /** The data volume has less than a tenth of its space left. */
1228
+ {
1229
+ type: "storage-low";
1230
+ available: number;
1231
+ capacity: number;
1232
+ }
1233
+ /** The caller's own uploads that failed over the last seven days. */
1234
+ | {
1235
+ type: "uploads-failed";
1236
+ count: number;
1237
+ latest: string;
1238
+ }
1239
+ /** The caller's own file and folder deletes that failed over the last seven days. */
1240
+ | {
1241
+ type: "deletes-failed";
1242
+ count: number;
1243
+ latest: string;
1244
+ }
1245
+ /** The caller's keys past their expiry date, which no longer work. */
1246
+ | {
1247
+ type: "keys-expired";
1248
+ count: number;
1249
+ }
1250
+ /** The caller's keys that expire within seven days. */
1251
+ | {
1252
+ type: "keys-expiring";
1253
+ count: number;
1254
+ }
1255
+ /** The caller's keys not used for 30 days. */
1256
+ | {
1257
+ type: "keys-unused";
1258
+ count: number;
1259
+ };
1260
+ /**
1261
+ * Fields marked optional were added after the first release of this endpoint.
1262
+ * Servers that predate them leave them out, so check before reading.
1263
+ */
1147
1264
  type Stats = {
1148
- /** Present when the caller holds `files:read`. */
1265
+ /** Present when the caller holds `files:read`. Files in Recently deleted aren't counted. */
1149
1266
  files: {
1150
1267
  total: number;
1151
1268
  folders: number;
1152
1269
  storage: {
1270
+ /** Bytes taken by stored files. */
1153
1271
  used: number;
1272
+ /** Bytes free on the data volume. */
1154
1273
  available: number;
1274
+ /** Usable size of the data volume, which other data may share. */
1275
+ capacity?: number;
1276
+ /** Bytes held by files in Recently deleted, not counted in `used`. */
1277
+ deleted?: number;
1155
1278
  };
1156
1279
  types: {
1157
1280
  mimeType: string;
@@ -1160,6 +1283,20 @@ type Stats = {
1160
1283
  }[];
1161
1284
  largest: FileWithUrl[];
1162
1285
  recent: FileWithUrl[];
1286
+ /** Files and bytes per visibility. */
1287
+ visibility?: Record<Visibility, {
1288
+ count: number;
1289
+ size: number;
1290
+ }>;
1291
+ /**
1292
+ * Files added per UTC day over the last 30 days, oldest first. Only files
1293
+ * still stored count, so deleting a file removes it from its day.
1294
+ */
1295
+ added?: {
1296
+ date: string;
1297
+ count: number;
1298
+ size: number;
1299
+ }[];
1163
1300
  } | null;
1164
1301
  /** Present for signed-in users holding `api-keys:manage`. */
1165
1302
  apiKeys: {
@@ -1169,7 +1306,36 @@ type Stats = {
1169
1306
  date: string;
1170
1307
  count: number;
1171
1308
  }[];
1309
+ /**
1310
+ * Every key with its requests over the same days, busiest first. Requests
1311
+ * made with keys deleted since count in `requests` but in no key here.
1312
+ */
1313
+ keys?: ApiKeyUsage[];
1314
+ } | null;
1315
+ /**
1316
+ * Public hosting traffic over the last 30 UTC days. Present when the caller
1317
+ * holds `files:read`. Requests made from a signed-in dashboard or app
1318
+ * session aren't counted.
1319
+ */
1320
+ hosting?: {
1321
+ /** Oldest first. */
1322
+ days: TrafficDay[];
1323
+ /** The five files requested most over those days. */
1324
+ top: {
1325
+ file: FileWithUrl;
1326
+ requests: number;
1327
+ bytes: number;
1328
+ }[];
1172
1329
  } | null;
1330
+ /** Present for signed-in users holding `users:manage`. */
1331
+ users?: {
1332
+ total: number;
1333
+ disabled: number;
1334
+ /** Devices signed in across every account. */
1335
+ sessions: number;
1336
+ } | null;
1337
+ /** Empty when nothing needs attention. New types may be added later. */
1338
+ alerts?: StatsAlert[];
1173
1339
  };
1174
1340
 
1175
1341
  /** The caller's activity history. These calls need a session, not a key. */
@@ -1187,6 +1353,21 @@ declare class Activity extends Base {
1187
1353
  }>>;
1188
1354
  }
1189
1355
 
1356
+ /** Files and folders that were deleted and can still be restored. */
1357
+ declare class Deleted extends Base {
1358
+ /** Most recently deleted first, with how many days items are kept. */
1359
+ getAll(): Promise<ApiResponse<{
1360
+ items: DeletedItem[];
1361
+ retentionDays: number;
1362
+ }>>;
1363
+ /** Put items back where they were; one whose name is taken now fails. */
1364
+ restore(ids: string[]): Promise<ApiResponse<BulkRestoreResult>>;
1365
+ /** Delete items for good, before their time is up. */
1366
+ purge(ids: string[]): Promise<ApiResponse<BulkDeleteResult>>;
1367
+ /** Delete everything in it for good. */
1368
+ empty(): Promise<ApiResponse<BulkDeleteResult>>;
1369
+ }
1370
+
1190
1371
  declare class Files extends Base {
1191
1372
  getAll(options?: ListOptions): Promise<{
1192
1373
  error: {
@@ -1303,9 +1484,10 @@ declare class Files extends Base {
1303
1484
  expiresAt: string;
1304
1485
  } | null;
1305
1486
  }>;
1306
- delete(id: string): Promise<ApiResponse<null>>;
1487
+ /** Moves the file to Recently deleted, unless `permanent` is set. */
1488
+ delete(id: string, options?: DeleteOptions): Promise<ApiResponse<null>>;
1307
1489
  /** Delete several files in one request; each id reports its own outcome. */
1308
- deleteMany(ids: string[]): Promise<ApiResponse<BulkDeleteResult>>;
1490
+ deleteMany(ids: string[], options?: DeleteOptions): Promise<ApiResponse<BulkDeleteResult>>;
1309
1491
  }
1310
1492
 
1311
1493
  declare class Folders extends Base {
@@ -1355,7 +1537,8 @@ declare class Folders extends Base {
1355
1537
  id: string;
1356
1538
  visibility: Visibility;
1357
1539
  }): Promise<ApiResponse<null>>;
1358
- delete(id: string): Promise<ApiResponse<null>>;
1540
+ /** Moves the folder and everything in it to Recently deleted, unless `permanent` is set. */
1541
+ delete(id: string, options?: DeleteOptions): Promise<ApiResponse<null>>;
1359
1542
  }
1360
1543
 
1361
1544
  /** The caller's API keys. These calls need a signed-in session, not a key. */
@@ -1423,6 +1606,7 @@ declare class Users extends Base {
1423
1606
  interface IVaze {
1424
1607
  files: Files;
1425
1608
  folders: Folders;
1609
+ deleted: Deleted;
1426
1610
  keys: Keys;
1427
1611
  account: Account;
1428
1612
  activity: Activity;
@@ -1517,6 +1701,17 @@ type BulkDeleteResult = {
1517
1701
  message: string;
1518
1702
  }[];
1519
1703
  };
1704
+ type BulkRestoreResult = {
1705
+ restored: string[];
1706
+ failed: {
1707
+ id: string;
1708
+ message: string;
1709
+ }[];
1710
+ };
1711
+ type DeleteOptions = {
1712
+ /** Skip Recently deleted and remove it from storage right away. */
1713
+ permanent?: boolean;
1714
+ };
1520
1715
 
1521
1716
  declare class Base {
1522
1717
  private apiKey;
@@ -1553,6 +1748,7 @@ declare class Account extends Base {
1553
1748
  declare class Vaze extends Base implements IVaze {
1554
1749
  files: Files;
1555
1750
  folders: Folders;
1751
+ deleted: Deleted;
1556
1752
  keys: Keys;
1557
1753
  account: Account;
1558
1754
  activity: Activity;
@@ -1569,36 +1765,7 @@ declare class Vaze extends Base implements IVaze {
1569
1765
  /** The caller's account and the scopes it may use. */
1570
1766
  me(): Promise<ApiResponse<Me>>;
1571
1767
  /** Dashboard numbers, with each section limited to the caller's scopes. */
1572
- stats(): Promise<{
1573
- error: {
1574
- message: string;
1575
- status?: number;
1576
- } | null;
1577
- data: {
1578
- files: {
1579
- largest: any[];
1580
- recent: any[];
1581
- total: number;
1582
- folders: number;
1583
- storage: {
1584
- used: number;
1585
- available: number;
1586
- };
1587
- types: {
1588
- mimeType: string;
1589
- size: number;
1590
- count: number;
1591
- }[];
1592
- } | null;
1593
- apiKeys: {
1594
- total: number;
1595
- requests: {
1596
- date: string;
1597
- count: number;
1598
- }[];
1599
- } | null;
1600
- } | null;
1601
- }>;
1768
+ stats(): Promise<ApiResponse<Stats>>;
1602
1769
  }
1603
1770
 
1604
- export { type ActivityEntry as Activity, type ActivityType, type ApiKeySummary as ApiKey, type ApiResponse, type BulkDeleteResult, type BulkMoveResult, type CreatedApiKey, type FileWithUrl as File, type FileReference, type Folder, type InstanceSettings, type Limits, type ListOptions, type Me, type MoveDestination, type NewKeyOptions, type NewUserOptions, type PasswordChange, type ProfileChanges, type Role, type Scope, type SessionSummary as Session, type SettingsChanges, type SignOptions, type SignedUrl, type Stats, type UserSummary as User, type UserAccess, type VazeHeaders, type VazeOptions, type Visibility, Vaze as default };
1771
+ export { type ActivityEntry as Activity, type ActivityType, type ApiKeySummary as ApiKey, type ApiKeyUsage, type ApiResponse, type BulkDeleteResult, type BulkMoveResult, type BulkRestoreResult, type CreatedApiKey, type DeleteOptions, type DeletedItem, type FileWithUrl as File, type FileReference, type Folder, type InstanceSettings, type Limits, type ListOptions, type Me, type MoveDestination, type NewKeyOptions, type NewUserOptions, type PasswordChange, type ProfileChanges, type Role, type Scope, type SessionSummary as Session, type SettingsChanges, type SignOptions, type SignedUrl, type Stats, type StatsAlert, type TrafficDay, type UserSummary as User, type UserAccess, type VazeHeaders, type VazeOptions, type Visibility, Vaze as default };
package/dist/index.js CHANGED
@@ -218,6 +218,41 @@ var Activity = class extends Base {
218
218
  }
219
219
  };
220
220
 
221
+ // src/deleted.ts
222
+ var Deleted = class extends Base {
223
+ /** Most recently deleted first, with how many days items are kept. */
224
+ async getAll() {
225
+ return await this.request(
226
+ "GET",
227
+ this.apiUrl("/api/deleted")
228
+ );
229
+ }
230
+ /** Put items back where they were; one whose name is taken now fails. */
231
+ async restore(ids) {
232
+ return await this.request(
233
+ "POST",
234
+ this.apiUrl("/api/deleted/restore"),
235
+ { ids }
236
+ );
237
+ }
238
+ /** Delete items for good, before their time is up. */
239
+ async purge(ids) {
240
+ return await this.request(
241
+ "DELETE",
242
+ this.apiUrl("/api/deleted"),
243
+ { ids }
244
+ );
245
+ }
246
+ /** Delete everything in it for good. */
247
+ async empty() {
248
+ return await this.request(
249
+ "DELETE",
250
+ this.apiUrl("/api/deleted"),
251
+ { all: true }
252
+ );
253
+ }
254
+ };
255
+
221
256
  // src/files.ts
222
257
  var Files = class extends Base {
223
258
  async getAll(options) {
@@ -384,17 +419,19 @@ var Files = class extends Base {
384
419
  data: data ? { ...data, url: new URL(data.url, this.vazeUrl).toString() } : null
385
420
  };
386
421
  }
387
- async delete(id) {
422
+ /** Moves the file to Recently deleted, unless `permanent` is set. */
423
+ async delete(id, options) {
388
424
  return await this.request("DELETE", this.apiUrl("/api/files"), {
389
- id
425
+ id,
426
+ ...options
390
427
  });
391
428
  }
392
429
  /** Delete several files in one request; each id reports its own outcome. */
393
- async deleteMany(ids) {
430
+ async deleteMany(ids, options) {
394
431
  return await this.request(
395
432
  "DELETE",
396
433
  this.apiUrl("/api/files"),
397
- { ids }
434
+ { ids, ...options }
398
435
  );
399
436
  }
400
437
  };
@@ -445,9 +482,11 @@ var Folders = class extends Base {
445
482
  async setVisibility(data) {
446
483
  return await this.request("PUT", this.apiUrl("/api/folders"), data);
447
484
  }
448
- async delete(id) {
485
+ /** Moves the folder and everything in it to Recently deleted, unless `permanent` is set. */
486
+ async delete(id, options) {
449
487
  return await this.request("DELETE", this.apiUrl("/api/folders"), {
450
- id
488
+ id,
489
+ ...options
451
490
  });
452
491
  }
453
492
  };
@@ -572,6 +611,7 @@ var Users = class extends Base {
572
611
  var Vaze = class extends Base {
573
612
  files;
574
613
  folders;
614
+ deleted;
575
615
  keys;
576
616
  account;
577
617
  activity;
@@ -581,6 +621,7 @@ var Vaze = class extends Base {
581
621
  super(options);
582
622
  this.files = new Files(options);
583
623
  this.folders = new Folders(options);
624
+ this.deleted = new Deleted(options);
584
625
  this.keys = new Keys(options);
585
626
  this.account = new Account(options);
586
627
  this.activity = new Activity(options);
@@ -606,27 +647,37 @@ var Vaze = class extends Base {
606
647
  }
607
648
  /** Dashboard numbers, with each section limited to the caller's scopes. */
608
649
  async stats() {
609
- const { data, error } = await this.request(
650
+ const response = await this.request(
610
651
  "GET",
611
652
  this.apiUrl("/api/stats")
612
653
  );
613
- const files = data?.files;
654
+ if (response.data === null) return response;
655
+ const { files, hosting } = response.data;
656
+ const vazeUrl = this.vazeUrl;
657
+ const withUrl = (file) => ({
658
+ ...file,
659
+ url: constructFileUrls({ vazeUrl, files: [file] })[0].url
660
+ });
614
661
  return {
615
- error,
616
- data: data ? {
617
- ...data,
662
+ error: null,
663
+ data: {
664
+ ...response.data,
618
665
  files: files ? {
619
666
  ...files,
620
- largest: constructFileUrls({
621
- vazeUrl: this.vazeUrl,
622
- files: files.largest
623
- }),
624
- recent: constructFileUrls({
625
- vazeUrl: this.vazeUrl,
626
- files: files.recent
627
- })
628
- } : null
629
- } : null
667
+ largest: constructFileUrls({ vazeUrl, files: files.largest }),
668
+ recent: constructFileUrls({ vazeUrl, files: files.recent })
669
+ } : null,
670
+ // servers that predate traffic leave `hosting` out, so keep it out
671
+ ...hosting ? {
672
+ hosting: {
673
+ ...hosting,
674
+ top: hosting.top.map((entry) => ({
675
+ ...entry,
676
+ file: withUrl(entry.file)
677
+ }))
678
+ }
679
+ } : {}
680
+ }
630
681
  };
631
682
  }
632
683
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darseen/vaze",
3
- "version": "2.5.0",
3
+ "version": "2.7.0",
4
4
  "description": "Vaze Self-Hosted file storage and hosting service SDK.",
5
5
  "keywords": [
6
6
  "api",
@@ -12,7 +12,7 @@
12
12
  "file-storage",
13
13
  "vaze"
14
14
  ],
15
- "homepage": "https://github.com/darseen/vaze#readme",
15
+ "homepage": "https://vaze.darseen.dev/docs/sdk",
16
16
  "bugs": {
17
17
  "url": "https://github.com/darseen/vaze/issues"
18
18
  },