@darseen/vaze 2.2.0 → 2.4.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 +102 -3
- package/dist/index.cjs +303 -17
- package/dist/index.d.cts +688 -2
- package/dist/index.d.ts +688 -2
- package/dist/index.js +301 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
// src/utils/index.ts
|
|
2
|
+
function env(name) {
|
|
3
|
+
return typeof process === "undefined" ? void 0 : process.env?.[name];
|
|
4
|
+
}
|
|
2
5
|
function constructFileUrls({
|
|
3
6
|
vazeUrl,
|
|
4
7
|
files
|
|
@@ -25,21 +28,26 @@ function parseContentDispositionFilename(header) {
|
|
|
25
28
|
// src/base.ts
|
|
26
29
|
var Base = class {
|
|
27
30
|
apiKey;
|
|
31
|
+
headers;
|
|
32
|
+
// wrapped so the global fetch is never called with this class as `this`
|
|
33
|
+
fetch;
|
|
28
34
|
vazeUrl;
|
|
29
35
|
constructor(options = {}) {
|
|
30
|
-
const vazeUrl = options.vazeUrl ||
|
|
31
|
-
const apiKey = options.apiKey ||
|
|
36
|
+
const vazeUrl = options.vazeUrl || env("VAZE_URL");
|
|
37
|
+
const apiKey = options.apiKey || env("VAZE_API_KEY");
|
|
32
38
|
if (!vazeUrl) {
|
|
33
39
|
throw new Error(
|
|
34
40
|
"You must provide a Vaze URL or set the VAZE_URL environment variable."
|
|
35
41
|
);
|
|
36
42
|
}
|
|
37
|
-
if (!apiKey) {
|
|
43
|
+
if (!apiKey && !options.headers) {
|
|
38
44
|
throw new Error(
|
|
39
|
-
"You must provide an API key or set the VAZE_API_KEY environment variable."
|
|
45
|
+
"You must provide an API key or headers, or set the VAZE_API_KEY environment variable."
|
|
40
46
|
);
|
|
41
47
|
}
|
|
42
48
|
this.apiKey = apiKey;
|
|
49
|
+
this.headers = options.headers;
|
|
50
|
+
this.fetch = options.fetch ?? ((input, init) => fetch(input, init));
|
|
43
51
|
this.vazeUrl = vazeUrl.endsWith("/") ? vazeUrl : `${vazeUrl}/`;
|
|
44
52
|
}
|
|
45
53
|
apiUrl(path, params) {
|
|
@@ -51,35 +59,45 @@ var Base = class {
|
|
|
51
59
|
}
|
|
52
60
|
return url.toString();
|
|
53
61
|
}
|
|
62
|
+
/** The headers every request carries, for clients fetching an SDK URL themselves. */
|
|
63
|
+
async authHeaders() {
|
|
64
|
+
const headers = typeof this.headers === "function" ? await this.headers() : this.headers;
|
|
65
|
+
return this.apiKey ? { ...headers, "API-Key": this.apiKey } : { ...headers };
|
|
66
|
+
}
|
|
54
67
|
async request(method, url, body, headers) {
|
|
55
68
|
try {
|
|
56
69
|
const fetchHeaders = {
|
|
57
|
-
|
|
70
|
+
...await this.authHeaders(),
|
|
58
71
|
...headers
|
|
59
72
|
};
|
|
60
73
|
const isFormData = body instanceof FormData;
|
|
61
74
|
if (body !== void 0 && !isFormData && !fetchHeaders["Content-Type"]) {
|
|
62
75
|
fetchHeaders["Content-Type"] = "application/json";
|
|
63
76
|
}
|
|
64
|
-
const response = await fetch(url, {
|
|
77
|
+
const response = await this.fetch(url, {
|
|
65
78
|
method,
|
|
66
79
|
headers: fetchHeaders,
|
|
67
80
|
body: isFormData ? body : body !== void 0 ? JSON.stringify(body) : null
|
|
68
81
|
});
|
|
82
|
+
const { status } = response;
|
|
69
83
|
const contentType = response.headers.get("content-type") ?? "";
|
|
70
84
|
if (!contentType.includes("application/json")) {
|
|
71
85
|
return {
|
|
72
86
|
data: null,
|
|
73
87
|
error: {
|
|
74
|
-
message: `Unexpected non-JSON response from server (status ${
|
|
88
|
+
message: `Unexpected non-JSON response from server (status ${status}).`,
|
|
89
|
+
status
|
|
75
90
|
}
|
|
76
91
|
};
|
|
77
92
|
}
|
|
78
93
|
const result = await response.json();
|
|
79
|
-
if (!response.ok
|
|
94
|
+
if (!response.ok) {
|
|
80
95
|
return {
|
|
81
96
|
data: null,
|
|
82
|
-
error: {
|
|
97
|
+
error: {
|
|
98
|
+
message: result.error?.message ?? `Request failed with status ${status}.`,
|
|
99
|
+
status
|
|
100
|
+
}
|
|
83
101
|
};
|
|
84
102
|
}
|
|
85
103
|
return result;
|
|
@@ -94,22 +112,25 @@ var Base = class {
|
|
|
94
112
|
}
|
|
95
113
|
async requestBlob(url, method = "GET", body) {
|
|
96
114
|
try {
|
|
97
|
-
const headers =
|
|
115
|
+
const headers = await this.authHeaders();
|
|
98
116
|
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
99
|
-
const response = await fetch(url, {
|
|
117
|
+
const response = await this.fetch(url, {
|
|
100
118
|
method,
|
|
101
119
|
headers,
|
|
102
120
|
body: body !== void 0 ? JSON.stringify(body) : null
|
|
103
121
|
});
|
|
122
|
+
const { status } = response;
|
|
104
123
|
const contentType = response.headers.get("content-type") ?? "";
|
|
105
124
|
if (!response.ok) {
|
|
106
125
|
if (contentType.includes("application/json")) {
|
|
107
126
|
const result = await response.json();
|
|
108
|
-
if (result.error)
|
|
127
|
+
if (result.error) {
|
|
128
|
+
return { data: null, error: { ...result.error, status } };
|
|
129
|
+
}
|
|
109
130
|
}
|
|
110
131
|
return {
|
|
111
132
|
data: null,
|
|
112
|
-
error: { message: `Request failed with status ${
|
|
133
|
+
error: { message: `Request failed with status ${status}.`, status }
|
|
113
134
|
};
|
|
114
135
|
}
|
|
115
136
|
return {
|
|
@@ -133,6 +154,70 @@ var Base = class {
|
|
|
133
154
|
}
|
|
134
155
|
};
|
|
135
156
|
|
|
157
|
+
// src/account.ts
|
|
158
|
+
var Account = class extends Base {
|
|
159
|
+
/** Changes the display name, the sign-in email, or both. */
|
|
160
|
+
async update(changes) {
|
|
161
|
+
return await this.request("PUT", this.apiUrl("/api/me"), changes);
|
|
162
|
+
}
|
|
163
|
+
async changePassword({
|
|
164
|
+
currentPassword,
|
|
165
|
+
newPassword,
|
|
166
|
+
revokeOtherSessions = false
|
|
167
|
+
}) {
|
|
168
|
+
return await this.request("PUT", this.apiUrl("/api/me/password"), {
|
|
169
|
+
currentPassword,
|
|
170
|
+
newPassword,
|
|
171
|
+
revokeOtherSessions
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/** Every device signed in to the account, the current one first. */
|
|
175
|
+
async getSessions() {
|
|
176
|
+
return await this.request(
|
|
177
|
+
"GET",
|
|
178
|
+
this.apiUrl("/api/me/sessions")
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
/** Signs out another device. The current session ends with a sign-out instead. */
|
|
182
|
+
async revokeSession(id) {
|
|
183
|
+
return await this.request("DELETE", this.apiUrl("/api/me/sessions"), {
|
|
184
|
+
id
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/** Signs out every device but the current one. */
|
|
188
|
+
async revokeOtherSessions() {
|
|
189
|
+
return await this.request("DELETE", this.apiUrl("/api/me/sessions"), {
|
|
190
|
+
others: true
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// src/activity.ts
|
|
196
|
+
var Activity = class extends Base {
|
|
197
|
+
/** The most recent entries, newest first. */
|
|
198
|
+
async getAll() {
|
|
199
|
+
return await this.request(
|
|
200
|
+
"GET",
|
|
201
|
+
this.apiUrl("/api/activity")
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
async delete(ids) {
|
|
205
|
+
return await this.request(
|
|
206
|
+
"DELETE",
|
|
207
|
+
this.apiUrl("/api/activity"),
|
|
208
|
+
{ ids }
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
/** Deletes every entry. Files, keys and accounts are not affected. */
|
|
212
|
+
async clear() {
|
|
213
|
+
return await this.request(
|
|
214
|
+
"DELETE",
|
|
215
|
+
this.apiUrl("/api/activity"),
|
|
216
|
+
{ all: true }
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
136
221
|
// src/files.ts
|
|
137
222
|
var Files = class extends Base {
|
|
138
223
|
async getAll(options) {
|
|
@@ -220,8 +305,15 @@ var Files = class extends Base {
|
|
|
220
305
|
};
|
|
221
306
|
}
|
|
222
307
|
async download(id) {
|
|
223
|
-
|
|
224
|
-
|
|
308
|
+
return await this.requestBlob(this.downloadUrl(id));
|
|
309
|
+
}
|
|
310
|
+
/** Where `download` reads from; fetch it yourself with `authHeaders()`. */
|
|
311
|
+
downloadUrl(id) {
|
|
312
|
+
return this.apiUrl(`/api/files/download/${encodeURIComponent(id)}`);
|
|
313
|
+
}
|
|
314
|
+
/** A WebP thumbnail of an image file; fetch it with `authHeaders()`. */
|
|
315
|
+
thumbnailUrl(id) {
|
|
316
|
+
return this.apiUrl(`/api/files/thumbnail/${encodeURIComponent(id)}`);
|
|
225
317
|
}
|
|
226
318
|
/** Download several files as one zip, with paths below their shared folder. */
|
|
227
319
|
async downloadMany(ids) {
|
|
@@ -235,6 +327,37 @@ var Files = class extends Base {
|
|
|
235
327
|
async setVisibility(data) {
|
|
236
328
|
return await this.request("PUT", this.apiUrl("/api/files"), data);
|
|
237
329
|
}
|
|
330
|
+
/** Move a file into another folder; its key and URL change with it. */
|
|
331
|
+
async move(data) {
|
|
332
|
+
const { data: responseData, error } = await this.request("POST", this.apiUrl("/api/files/move"), data);
|
|
333
|
+
return {
|
|
334
|
+
error,
|
|
335
|
+
data: responseData ? {
|
|
336
|
+
file: constructFileUrls({
|
|
337
|
+
vazeUrl: this.vazeUrl,
|
|
338
|
+
files: [responseData.file]
|
|
339
|
+
})[0]
|
|
340
|
+
} : null
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
/** Move several files into one folder; each id reports its own outcome. */
|
|
344
|
+
async moveMany(ids, destination) {
|
|
345
|
+
const { data, error } = await this.request(
|
|
346
|
+
"POST",
|
|
347
|
+
this.apiUrl("/api/files/move"),
|
|
348
|
+
{ ids, ...destination }
|
|
349
|
+
);
|
|
350
|
+
return {
|
|
351
|
+
error,
|
|
352
|
+
data: data ? {
|
|
353
|
+
files: constructFileUrls({
|
|
354
|
+
vazeUrl: this.vazeUrl,
|
|
355
|
+
files: data.files
|
|
356
|
+
}),
|
|
357
|
+
failed: data.failed
|
|
358
|
+
} : null
|
|
359
|
+
};
|
|
360
|
+
}
|
|
238
361
|
/** Mint a time-limited URL that reads a file without an API key. */
|
|
239
362
|
async sign(options) {
|
|
240
363
|
const { data, error } = await this.request(
|
|
@@ -294,6 +417,14 @@ var Folders = class extends Base {
|
|
|
294
417
|
async rename(data) {
|
|
295
418
|
return await this.request("PUT", this.apiUrl("/api/folders"), data);
|
|
296
419
|
}
|
|
420
|
+
/** Move a folder, and everything inside it, into another folder. */
|
|
421
|
+
async move(data) {
|
|
422
|
+
return await this.request(
|
|
423
|
+
"POST",
|
|
424
|
+
this.apiUrl("/api/folders/move"),
|
|
425
|
+
data
|
|
426
|
+
);
|
|
427
|
+
}
|
|
297
428
|
/** Apply a visibility to every file at or below this folder. */
|
|
298
429
|
async setVisibility(data) {
|
|
299
430
|
return await this.request("PUT", this.apiUrl("/api/folders"), data);
|
|
@@ -305,14 +436,140 @@ var Folders = class extends Base {
|
|
|
305
436
|
}
|
|
306
437
|
};
|
|
307
438
|
|
|
439
|
+
// src/keys.ts
|
|
440
|
+
var Keys = class extends Base {
|
|
441
|
+
/** Every key the caller owns, newest first. */
|
|
442
|
+
async getAll() {
|
|
443
|
+
return await this.request(
|
|
444
|
+
"GET",
|
|
445
|
+
this.apiUrl("/api/keys")
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
/** The response holds the key's secret, which can't be read again later. */
|
|
449
|
+
async create({ name, scopes, expiresAt }) {
|
|
450
|
+
return await this.request(
|
|
451
|
+
"POST",
|
|
452
|
+
this.apiUrl("/api/keys"),
|
|
453
|
+
{
|
|
454
|
+
name,
|
|
455
|
+
scopes,
|
|
456
|
+
expiresAt: expiresAt instanceof Date ? expiresAt.toISOString() : expiresAt
|
|
457
|
+
}
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
async rename(data) {
|
|
461
|
+
return await this.request("PUT", this.apiUrl("/api/keys"), data);
|
|
462
|
+
}
|
|
463
|
+
/** Revokes the key at once for anything using it. */
|
|
464
|
+
async delete(id) {
|
|
465
|
+
return await this.request("DELETE", this.apiUrl("/api/keys"), {
|
|
466
|
+
id
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
// src/settings.ts
|
|
472
|
+
var Settings = class extends Base {
|
|
473
|
+
async get() {
|
|
474
|
+
return await this.request(
|
|
475
|
+
"GET",
|
|
476
|
+
this.apiUrl("/api/settings")
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
/** Limits left out keep their current values. */
|
|
480
|
+
async update(changes) {
|
|
481
|
+
return await this.request(
|
|
482
|
+
"PUT",
|
|
483
|
+
this.apiUrl("/api/settings"),
|
|
484
|
+
changes
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
/** Gives every existing file this visibility. */
|
|
488
|
+
async applyVisibility(visibility) {
|
|
489
|
+
return await this.request(
|
|
490
|
+
"POST",
|
|
491
|
+
this.apiUrl("/api/settings/apply-visibility"),
|
|
492
|
+
{ visibility }
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// src/users.ts
|
|
498
|
+
var Users = class extends Base {
|
|
499
|
+
/** Every account, oldest first. */
|
|
500
|
+
async getAll() {
|
|
501
|
+
return await this.request(
|
|
502
|
+
"GET",
|
|
503
|
+
this.apiUrl("/api/users")
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
async create(options) {
|
|
507
|
+
return await this.request(
|
|
508
|
+
"POST",
|
|
509
|
+
this.apiUrl("/api/users"),
|
|
510
|
+
options
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
/** Applies right away, to the user's sessions and API keys alike. */
|
|
514
|
+
async setAccess({
|
|
515
|
+
id,
|
|
516
|
+
role,
|
|
517
|
+
scopes = []
|
|
518
|
+
}) {
|
|
519
|
+
return await this.request(
|
|
520
|
+
"PUT",
|
|
521
|
+
this.apiUrl("/api/users"),
|
|
522
|
+
{ id, role, scopes }
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
/** Also signs the user out of every device. */
|
|
526
|
+
async resetPassword({
|
|
527
|
+
id,
|
|
528
|
+
password
|
|
529
|
+
}) {
|
|
530
|
+
return await this.request(
|
|
531
|
+
"PUT",
|
|
532
|
+
this.apiUrl("/api/users"),
|
|
533
|
+
{ id, password }
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
/** A disabled user is signed out and their API keys stop until re-enabled. */
|
|
537
|
+
async setDisabled({
|
|
538
|
+
id,
|
|
539
|
+
disabled
|
|
540
|
+
}) {
|
|
541
|
+
return await this.request(
|
|
542
|
+
"PUT",
|
|
543
|
+
this.apiUrl("/api/users"),
|
|
544
|
+
{ id, disabled }
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
/** Removes the account, its API keys and its history. Files stay. */
|
|
548
|
+
async delete(id) {
|
|
549
|
+
return await this.request("DELETE", this.apiUrl("/api/users"), {
|
|
550
|
+
id
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
|
|
308
555
|
// src/index.ts
|
|
309
556
|
var Vaze = class extends Base {
|
|
310
557
|
files;
|
|
311
558
|
folders;
|
|
559
|
+
keys;
|
|
560
|
+
account;
|
|
561
|
+
activity;
|
|
562
|
+
users;
|
|
563
|
+
settings;
|
|
312
564
|
constructor(options = {}) {
|
|
313
565
|
super(options);
|
|
314
566
|
this.files = new Files(options);
|
|
315
567
|
this.folders = new Folders(options);
|
|
568
|
+
this.keys = new Keys(options);
|
|
569
|
+
this.account = new Account(options);
|
|
570
|
+
this.activity = new Activity(options);
|
|
571
|
+
this.users = new Users(options);
|
|
572
|
+
this.settings = new Settings(options);
|
|
316
573
|
}
|
|
317
574
|
async health() {
|
|
318
575
|
return await this.request(
|
|
@@ -320,6 +577,35 @@ var Vaze = class extends Base {
|
|
|
320
577
|
this.apiUrl("/api/health")
|
|
321
578
|
);
|
|
322
579
|
}
|
|
580
|
+
/** The caller's account and the scopes it may use. */
|
|
581
|
+
async me() {
|
|
582
|
+
return await this.request("GET", this.apiUrl("/api/me"));
|
|
583
|
+
}
|
|
584
|
+
/** Dashboard numbers, with each section limited to the caller's scopes. */
|
|
585
|
+
async stats() {
|
|
586
|
+
const { data, error } = await this.request(
|
|
587
|
+
"GET",
|
|
588
|
+
this.apiUrl("/api/stats")
|
|
589
|
+
);
|
|
590
|
+
const files = data?.files;
|
|
591
|
+
return {
|
|
592
|
+
error,
|
|
593
|
+
data: data ? {
|
|
594
|
+
...data,
|
|
595
|
+
files: files ? {
|
|
596
|
+
...files,
|
|
597
|
+
largest: constructFileUrls({
|
|
598
|
+
vazeUrl: this.vazeUrl,
|
|
599
|
+
files: files.largest
|
|
600
|
+
}),
|
|
601
|
+
recent: constructFileUrls({
|
|
602
|
+
vazeUrl: this.vazeUrl,
|
|
603
|
+
files: files.recent
|
|
604
|
+
})
|
|
605
|
+
} : null
|
|
606
|
+
} : null
|
|
607
|
+
};
|
|
608
|
+
}
|
|
323
609
|
};
|
|
324
610
|
export {
|
|
325
611
|
Vaze as default
|