@omelhorsite/sdk 0.4.5 → 0.5.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 +7 -3
- package/dist/index.js +206 -19
- package/dist/types/http.d.ts +14 -5
- package/dist/types/internal/xhr.d.ts +6 -0
- package/dist/types/resources/admin/index.d.ts +4 -0
- package/dist/types/resources/admin/users.d.ts +41 -0
- package/dist/types/resources/chests.d.ts +3 -1
- package/dist/types/resources/storage/upload.d.ts +1 -0
- package/dist/types/types.d.ts +9 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -163,9 +163,13 @@ const nodes = await oms.storage.upload(
|
|
|
163
163
|
);
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
In a browser or on React Native, progress is reported byte by byte (the bytes
|
|
167
|
+
travel through `XMLHttpRequest`); elsewhere it arrives per finished file or
|
|
168
|
+
part. The same goes for every other upload: pass `onUploadProgress` in the
|
|
169
|
+
options of `tools.*.create`, `library.books.create` or
|
|
170
|
+
`chests.entries.createWithUpload`. A file rejected on its own (quota, name
|
|
171
|
+
collision) does not throw; it is missing from the returned array, so compare
|
|
172
|
+
lengths when partial success matters.
|
|
169
173
|
|
|
170
174
|
## Long jobs: `create` / `get`, and `run`
|
|
171
175
|
|
package/dist/index.js
CHANGED
|
@@ -344,6 +344,87 @@ async function collect(first, limit = Number.POSITIVE_INFINITY) {
|
|
|
344
344
|
return out;
|
|
345
345
|
}
|
|
346
346
|
|
|
347
|
+
// src/internal/xhr.ts
|
|
348
|
+
function xhrAvailable() {
|
|
349
|
+
return typeof XMLHttpRequest === "function";
|
|
350
|
+
}
|
|
351
|
+
function xhrFetch(onUploadProgress) {
|
|
352
|
+
return (input, init) => new Promise((resolve, reject) => {
|
|
353
|
+
const xhr = new XMLHttpRequest;
|
|
354
|
+
xhr.open(init?.method ?? "GET", input, true);
|
|
355
|
+
xhr.responseType = "arraybuffer";
|
|
356
|
+
xhr.withCredentials = init?.credentials === "include";
|
|
357
|
+
applyHeaders(xhr, init?.headers);
|
|
358
|
+
const signal = init?.signal ?? undefined;
|
|
359
|
+
const onAbort = () => xhr.abort();
|
|
360
|
+
if (signal) {
|
|
361
|
+
if (signal.aborted) {
|
|
362
|
+
reject(abortError());
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
366
|
+
}
|
|
367
|
+
const settle = () => signal?.removeEventListener("abort", onAbort);
|
|
368
|
+
xhr.upload.onprogress = (event) => {
|
|
369
|
+
onUploadProgress({
|
|
370
|
+
phase: "upload",
|
|
371
|
+
loaded: event.loaded,
|
|
372
|
+
total: event.lengthComputable ? event.total : undefined
|
|
373
|
+
});
|
|
374
|
+
};
|
|
375
|
+
xhr.onload = () => {
|
|
376
|
+
settle();
|
|
377
|
+
if (xhr.status === 0) {
|
|
378
|
+
reject(new TypeError("Network request failed"));
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
resolve(toResponse(xhr));
|
|
382
|
+
};
|
|
383
|
+
xhr.onerror = () => {
|
|
384
|
+
settle();
|
|
385
|
+
reject(new TypeError("Network request failed"));
|
|
386
|
+
};
|
|
387
|
+
xhr.onabort = () => {
|
|
388
|
+
settle();
|
|
389
|
+
reject(abortError());
|
|
390
|
+
};
|
|
391
|
+
xhr.send(init?.body ?? null);
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
function applyHeaders(xhr, headers) {
|
|
395
|
+
if (!headers)
|
|
396
|
+
return;
|
|
397
|
+
if (headers instanceof Headers) {
|
|
398
|
+
headers.forEach((value, key) => xhr.setRequestHeader(key, value));
|
|
399
|
+
} else if (Array.isArray(headers)) {
|
|
400
|
+
for (const [key, value] of headers)
|
|
401
|
+
xhr.setRequestHeader(key, value);
|
|
402
|
+
} else {
|
|
403
|
+
for (const [key, value] of Object.entries(headers))
|
|
404
|
+
xhr.setRequestHeader(key, value);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function toResponse(xhr) {
|
|
408
|
+
const headers = new Headers;
|
|
409
|
+
for (const line of xhr.getAllResponseHeaders().split(/\r?\n/)) {
|
|
410
|
+
const separator = line.indexOf(":");
|
|
411
|
+
if (separator <= 0)
|
|
412
|
+
continue;
|
|
413
|
+
headers.append(line.slice(0, separator).trim(), line.slice(separator + 1).trim());
|
|
414
|
+
}
|
|
415
|
+
const bodyless = xhr.status === 204 || xhr.status === 205 || xhr.status === 304;
|
|
416
|
+
return new Response(bodyless ? null : xhr.response, {
|
|
417
|
+
status: xhr.status,
|
|
418
|
+
statusText: xhr.statusText,
|
|
419
|
+
headers
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
function abortError() {
|
|
423
|
+
const error = new Error("The operation was aborted.");
|
|
424
|
+
error.name = "AbortError";
|
|
425
|
+
return error;
|
|
426
|
+
}
|
|
427
|
+
|
|
347
428
|
// src/http.ts
|
|
348
429
|
var DEFAULT_BASE_URL = "https://backend.omelhorsite.pt";
|
|
349
430
|
function transportCapabilities() {
|
|
@@ -382,6 +463,7 @@ function supportsNativeFormDataFiles() {
|
|
|
382
463
|
class ApiClient {
|
|
383
464
|
baseUrl;
|
|
384
465
|
fetchImpl;
|
|
466
|
+
customFetch;
|
|
385
467
|
tokens;
|
|
386
468
|
sessionCookie;
|
|
387
469
|
baseHeaders;
|
|
@@ -394,6 +476,7 @@ class ApiClient {
|
|
|
394
476
|
throw new OmsNetworkError("No fetch implementation available. Pass one to the Oms constructor: new Oms({ fetch }).");
|
|
395
477
|
}
|
|
396
478
|
this.fetchImpl = (input, init) => injected(input, init);
|
|
479
|
+
this.customFetch = options.fetch !== undefined;
|
|
397
480
|
if (options.sessionCookie && options.tokens) {
|
|
398
481
|
throw new TypeError("Pass either `sessionCookie` or a token, not both: two credentials on one request means the server decides which identity wins, and the caller cannot tell which one it got.");
|
|
399
482
|
}
|
|
@@ -471,6 +554,15 @@ class ApiClient {
|
|
|
471
554
|
size: blob.size
|
|
472
555
|
};
|
|
473
556
|
}
|
|
557
|
+
transportFor(onUploadProgress) {
|
|
558
|
+
if (onUploadProgress && !this.customFetch && xhrAvailable())
|
|
559
|
+
return xhrFetch(onUploadProgress);
|
|
560
|
+
return this.fetchImpl;
|
|
561
|
+
}
|
|
562
|
+
async patchForm(path, fields, options = {}) {
|
|
563
|
+
const form = await buildFormData(fields);
|
|
564
|
+
return this.requestJson("PATCH", path, { ...options, body: form, isFormData: true });
|
|
565
|
+
}
|
|
474
566
|
url(path, query) {
|
|
475
567
|
const suffix = path.startsWith("/") ? path : `/${path}`;
|
|
476
568
|
const encoded = query ? encodeQuery(query) : "";
|
|
@@ -493,7 +585,7 @@ class ApiClient {
|
|
|
493
585
|
const deadline = createDeadline(timeoutMs, options.signal);
|
|
494
586
|
let response;
|
|
495
587
|
try {
|
|
496
|
-
response = await this.
|
|
588
|
+
response = await this.transportFor(options.onUploadProgress)(url, await this.buildInit(method, options, deadline.signal));
|
|
497
589
|
} catch (thrown) {
|
|
498
590
|
deadline.dispose();
|
|
499
591
|
const failure = classifyFetchFailure(thrown, { method, url, attempts: attempt, timeoutMs, options });
|
|
@@ -9532,11 +9624,13 @@ class StorageRateGate {
|
|
|
9532
9624
|
class UploadManager extends Resource {
|
|
9533
9625
|
gate;
|
|
9534
9626
|
transport;
|
|
9627
|
+
ownTransport;
|
|
9535
9628
|
md5;
|
|
9536
9629
|
constructor(http, options = {}) {
|
|
9537
9630
|
super(http);
|
|
9538
9631
|
this.gate = new StorageRateGate(FS_UPLOAD_RATE_LIMIT);
|
|
9539
9632
|
this.transport = options.fetch ?? objectStoreFetch(http);
|
|
9633
|
+
this.ownTransport = options.fetch === undefined;
|
|
9540
9634
|
this.md5 = options.md5 ?? md5Base64;
|
|
9541
9635
|
}
|
|
9542
9636
|
async upload(input, options = {}) {
|
|
@@ -9557,12 +9651,23 @@ class UploadManager extends Resource {
|
|
|
9557
9651
|
};
|
|
9558
9652
|
}));
|
|
9559
9653
|
const total = prepared.reduce((sum, entry) => sum + entry.blob.size, 0);
|
|
9560
|
-
let
|
|
9561
|
-
const
|
|
9562
|
-
|
|
9563
|
-
|
|
9654
|
+
let completed = 0;
|
|
9655
|
+
const inFlight = new Map;
|
|
9656
|
+
const emit = () => {
|
|
9657
|
+
let extra = 0;
|
|
9658
|
+
inFlight.forEach((bytes) => extra += bytes);
|
|
9659
|
+
options.onProgress?.({ phase: "upload", loaded: completed + extra, total });
|
|
9660
|
+
};
|
|
9661
|
+
const fileProgress = (clientId, size) => (progress) => {
|
|
9662
|
+
inFlight.set(clientId, Math.min(progress.loaded, size));
|
|
9663
|
+
emit();
|
|
9564
9664
|
};
|
|
9565
|
-
|
|
9665
|
+
const fileDone = (clientId, size) => {
|
|
9666
|
+
inFlight.delete(clientId);
|
|
9667
|
+
completed += size;
|
|
9668
|
+
emit();
|
|
9669
|
+
};
|
|
9670
|
+
emit();
|
|
9566
9671
|
const { onProgress: _runProgress, ...transfer } = options;
|
|
9567
9672
|
const batchSize = Math.min(MAX_BATCH, Math.max(1, Math.trunc(input.batchSize ?? DEFAULT_BATCH_SIZE)));
|
|
9568
9673
|
const concurrency = Math.max(1, Math.trunc(input.concurrency ?? DEFAULT_UPLOAD_CONCURRENCY));
|
|
@@ -9593,19 +9698,24 @@ class UploadManager extends Resource {
|
|
|
9593
9698
|
if (plan.strategy === "multipart") {
|
|
9594
9699
|
await this.uploadMultipart(plan.fs_node_id, entry.blob, {
|
|
9595
9700
|
...transfer,
|
|
9596
|
-
|
|
9701
|
+
onProgress: fileProgress(entry.clientId, entry.blob.size),
|
|
9597
9702
|
onSession: (token) => open.set(plan.fs_node_id, token)
|
|
9598
9703
|
});
|
|
9599
9704
|
open.delete(plan.fs_node_id);
|
|
9705
|
+
fileDone(entry.clientId, entry.blob.size);
|
|
9600
9706
|
} else {
|
|
9601
9707
|
if (!plan.upload) {
|
|
9602
9708
|
throw new OmsError(`The server planned a direct upload for "${entry.filename}" but sent no presigned URL.`, "api_error");
|
|
9603
9709
|
}
|
|
9604
|
-
await this.putDirect(plan.upload, entry.blob,
|
|
9710
|
+
await this.putDirect(plan.upload, entry.blob, {
|
|
9711
|
+
...transfer,
|
|
9712
|
+
onProgress: fileProgress(entry.clientId, entry.blob.size)
|
|
9713
|
+
});
|
|
9605
9714
|
attachments.push({ fs_node_id: plan.fs_node_id, blob_signed_id: plan.upload.blob_signed_id });
|
|
9606
|
-
|
|
9715
|
+
fileDone(entry.clientId, entry.blob.size);
|
|
9607
9716
|
}
|
|
9608
9717
|
} catch (thrown) {
|
|
9718
|
+
inFlight.delete(entry.clientId);
|
|
9609
9719
|
failed.set(entry.clientId, {
|
|
9610
9720
|
client_id: entry.clientId,
|
|
9611
9721
|
code: thrown instanceof OmsError ? thrown.code : "transfer_failed",
|
|
@@ -9666,8 +9776,18 @@ class UploadManager extends Resource {
|
|
|
9666
9776
|
};
|
|
9667
9777
|
}
|
|
9668
9778
|
async putDirect(target, body, options = {}) {
|
|
9669
|
-
const
|
|
9670
|
-
|
|
9779
|
+
const { onProgress, ...request } = options;
|
|
9780
|
+
const size = body.size;
|
|
9781
|
+
const etag = await this.putBytes(target.url, target.headers, body, {
|
|
9782
|
+
...request,
|
|
9783
|
+
...onProgress ? {
|
|
9784
|
+
onUploadProgress: (progress) => {
|
|
9785
|
+
if (progress.loaded < size)
|
|
9786
|
+
onProgress({ phase: "upload", loaded: progress.loaded, total: size });
|
|
9787
|
+
}
|
|
9788
|
+
} : {}
|
|
9789
|
+
});
|
|
9790
|
+
onProgress?.({ phase: "upload", loaded: size, total: size });
|
|
9671
9791
|
return etag;
|
|
9672
9792
|
}
|
|
9673
9793
|
async attachBlobs(attachments, options = {}) {
|
|
@@ -9728,7 +9848,13 @@ class UploadManager extends Resource {
|
|
|
9728
9848
|
let loaded = 0;
|
|
9729
9849
|
for (const partNumber of done.keys())
|
|
9730
9850
|
loaded += bytesOfPart(partNumber);
|
|
9731
|
-
|
|
9851
|
+
const inFlight = new Map;
|
|
9852
|
+
const report = () => {
|
|
9853
|
+
let extra = 0;
|
|
9854
|
+
inFlight.forEach((bytes) => extra += bytes);
|
|
9855
|
+
options.onProgress?.({ phase: "upload", loaded: loaded + extra, total: body.size });
|
|
9856
|
+
};
|
|
9857
|
+
report();
|
|
9732
9858
|
if (partCount > MAX_PARTS) {
|
|
9733
9859
|
throw new OmsError(`storage: ${body.size} bytes needs ${partCount} parts of ${partSize}, over the server's limit of ${MAX_PARTS}.`, "invalid_request");
|
|
9734
9860
|
}
|
|
@@ -9749,7 +9875,14 @@ class UploadManager extends Resource {
|
|
|
9749
9875
|
throw new OmsError(`storage: the server presigned no URL for part ${partNumber}.`, "api_error");
|
|
9750
9876
|
const from = (partNumber - 1) * partSize;
|
|
9751
9877
|
const chunk = body.slice(from, Math.min(from + partSize, body.size));
|
|
9752
|
-
const etag = await this.putBytes(url, {}, chunk,
|
|
9878
|
+
const etag = await this.putBytes(url, {}, chunk, {
|
|
9879
|
+
...options,
|
|
9880
|
+
onUploadProgress: (progress) => {
|
|
9881
|
+
inFlight.set(partNumber, Math.min(progress.loaded, Math.max(0, chunk.size - 1)));
|
|
9882
|
+
report();
|
|
9883
|
+
}
|
|
9884
|
+
});
|
|
9885
|
+
inFlight.delete(partNumber);
|
|
9753
9886
|
if (!etag) {
|
|
9754
9887
|
throw new OmsError("storage: the object store did not expose the part ETag. In a browser this means the bucket's CORS policy is missing ETag in Access-Control-Expose-Headers.", "unsupported");
|
|
9755
9888
|
}
|
|
@@ -9757,7 +9890,7 @@ class UploadManager extends Resource {
|
|
|
9757
9890
|
done.set(partNumber, part);
|
|
9758
9891
|
options.onPart?.(chunk.size, part);
|
|
9759
9892
|
loaded += chunk.size;
|
|
9760
|
-
|
|
9893
|
+
report();
|
|
9761
9894
|
});
|
|
9762
9895
|
}
|
|
9763
9896
|
return this.multipartComplete(fsNodeId, { uploadToken, parts: [...done.values()] }, options);
|
|
@@ -9765,10 +9898,11 @@ class UploadManager extends Resource {
|
|
|
9765
9898
|
async putBytes(url, headers, body, options) {
|
|
9766
9899
|
const retry = options.retry === false ? false : resolveRetry(options.retry ?? { maxAttempts: 4 });
|
|
9767
9900
|
const maxAttempts = retry === false ? 1 : Math.max(1, retry.maxAttempts);
|
|
9901
|
+
const transport = this.ownTransport && options.onUploadProgress ? this.http.transportFor(options.onUploadProgress) : this.transport;
|
|
9768
9902
|
for (let attempt = 1;; attempt += 1) {
|
|
9769
9903
|
let response;
|
|
9770
9904
|
try {
|
|
9771
|
-
response = await
|
|
9905
|
+
response = await transport(url, {
|
|
9772
9906
|
method: "PUT",
|
|
9773
9907
|
headers,
|
|
9774
9908
|
body,
|
|
@@ -10401,6 +10535,41 @@ class AdminShortLinksNamespace extends Resource {
|
|
|
10401
10535
|
}
|
|
10402
10536
|
}
|
|
10403
10537
|
|
|
10538
|
+
// src/resources/admin/users.ts
|
|
10539
|
+
class AdminUsersNamespace extends Resource {
|
|
10540
|
+
async update(id, input, options = {}) {
|
|
10541
|
+
const path = `/users/${encodeURIComponent(id)}`;
|
|
10542
|
+
const body = adminUpdateBody(input);
|
|
10543
|
+
if (input.picture === undefined)
|
|
10544
|
+
return this.http.patch(path, body, options);
|
|
10545
|
+
return this.http.patchForm(path, { ...body, picture: input.picture }, options);
|
|
10546
|
+
}
|
|
10547
|
+
}
|
|
10548
|
+
function adminUpdateBody(input) {
|
|
10549
|
+
const body = {};
|
|
10550
|
+
const set = (key, value) => {
|
|
10551
|
+
if (value !== undefined)
|
|
10552
|
+
body[key] = value;
|
|
10553
|
+
};
|
|
10554
|
+
set("handle", input.handle);
|
|
10555
|
+
set("name", input.name);
|
|
10556
|
+
set("bio", input.bio);
|
|
10557
|
+
set("country_code", input.countryCode);
|
|
10558
|
+
set("email_is_public", input.emailIsPublic);
|
|
10559
|
+
set("gender_is_public", input.genderIsPublic);
|
|
10560
|
+
set("gender", input.gender);
|
|
10561
|
+
set("library_public", input.libraryPublic);
|
|
10562
|
+
set("library_name", input.libraryName);
|
|
10563
|
+
set("library_description", input.libraryDescription);
|
|
10564
|
+
set("share_listening", input.shareListening);
|
|
10565
|
+
set("email", input.email);
|
|
10566
|
+
set("group", input.group);
|
|
10567
|
+
if (input.password)
|
|
10568
|
+
set("password", input.password);
|
|
10569
|
+
set("allowed_to_use_spotify", input.allowedToUseSpotify);
|
|
10570
|
+
return body;
|
|
10571
|
+
}
|
|
10572
|
+
|
|
10404
10573
|
// src/resources/admin/vocalSeparations.ts
|
|
10405
10574
|
var ADMIN_VOCAL_SEPARATION_FILTER_COLUMNS = Object.freeze([
|
|
10406
10575
|
"id",
|
|
@@ -10486,6 +10655,7 @@ class AdminNamespace extends Resource {
|
|
|
10486
10655
|
chests;
|
|
10487
10656
|
notepads;
|
|
10488
10657
|
eventAlerts;
|
|
10658
|
+
users;
|
|
10489
10659
|
constructor(http) {
|
|
10490
10660
|
super(http);
|
|
10491
10661
|
this.myApplications = new MyOauthApplicationsNamespace(http);
|
|
@@ -10499,6 +10669,7 @@ class AdminNamespace extends Resource {
|
|
|
10499
10669
|
this.chests = new AdminChestsNamespace(http);
|
|
10500
10670
|
this.notepads = new AdminNotepadsNamespace(http);
|
|
10501
10671
|
this.eventAlerts = new AdminEventAlertsNamespace(http);
|
|
10672
|
+
this.users = new AdminUsersNamespace(http);
|
|
10502
10673
|
}
|
|
10503
10674
|
}
|
|
10504
10675
|
|
|
@@ -10773,13 +10944,15 @@ class ChestEntriesNamespace extends Resource {
|
|
|
10773
10944
|
async createWithUpload(input, options = {}) {
|
|
10774
10945
|
const { blob, filename } = await readFileInput(input.file);
|
|
10775
10946
|
const name = input.name ?? filename;
|
|
10947
|
+
const { onReserved, ...operation } = options;
|
|
10776
10948
|
const entry = await this.http.post("/chest_entries", {
|
|
10777
10949
|
chest_id: input.chestId,
|
|
10778
10950
|
kind: "file",
|
|
10779
10951
|
name,
|
|
10780
10952
|
size: blob.size,
|
|
10781
10953
|
chest_token: input.chestToken
|
|
10782
|
-
}, { retry: false, ...
|
|
10954
|
+
}, { retry: false, ...operation });
|
|
10955
|
+
onReserved?.(entry);
|
|
10783
10956
|
try {
|
|
10784
10957
|
const checksum = await md5Base64(blob);
|
|
10785
10958
|
const { signed_url: target } = await this.http.post(`/chest_entries/${encodeURIComponent(entry.id)}/attachment_signed_url`, { checksum }, { retry: false, ...options });
|
|
@@ -14845,14 +15018,27 @@ class CaptionsNamespace extends Resource {
|
|
|
14845
15018
|
for (const offset of offsets)
|
|
14846
15019
|
if (done.has(offset))
|
|
14847
15020
|
loaded += Math.min(partSize, total - offset);
|
|
14848
|
-
|
|
15021
|
+
const inFlight = new Map;
|
|
15022
|
+
const report = () => {
|
|
15023
|
+
let extra = 0;
|
|
15024
|
+
inFlight.forEach((bytes) => extra += bytes);
|
|
15025
|
+
onProgress?.({ phase: "upload", loaded: loaded + extra, total });
|
|
15026
|
+
};
|
|
15027
|
+
report();
|
|
14849
15028
|
const concurrency = Math.max(1, Math.trunc(input.concurrency ?? CAPTION_UPLOAD_CONCURRENCY));
|
|
14850
15029
|
await runCaptionParts(pending, concurrency, async (offset) => {
|
|
14851
15030
|
const chunk = blob.slice(offset, Math.min(offset + partSize, total));
|
|
14852
|
-
await this.uploadPart(session, offset, chunk,
|
|
15031
|
+
await this.uploadPart(session, offset, chunk, {
|
|
15032
|
+
...request,
|
|
15033
|
+
onUploadProgress: (progress) => {
|
|
15034
|
+
inFlight.set(offset, Math.min(progress.loaded, Math.max(0, chunk.size - 1)));
|
|
15035
|
+
report();
|
|
15036
|
+
}
|
|
15037
|
+
});
|
|
15038
|
+
inFlight.delete(offset);
|
|
14853
15039
|
onPart?.(offset, chunk.size);
|
|
14854
15040
|
loaded += chunk.size;
|
|
14855
|
-
|
|
15041
|
+
report();
|
|
14856
15042
|
});
|
|
14857
15043
|
return this.finishUpload(session, request);
|
|
14858
15044
|
}
|
|
@@ -15819,6 +16005,7 @@ export {
|
|
|
15819
16005
|
ApiClient,
|
|
15820
16006
|
AnalysisNamespace,
|
|
15821
16007
|
AdminVocalSeparationsNamespace,
|
|
16008
|
+
AdminUsersNamespace,
|
|
15822
16009
|
AdminShortLinksNamespace,
|
|
15823
16010
|
AdminQuotasNamespace,
|
|
15824
16011
|
AdminOauthApplicationsNamespace,
|
package/dist/types/http.d.ts
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* polyfill after the SDK is imported, and in RN the fetch implementation is
|
|
24
24
|
* swapped by libraries often enough that a cached answer goes stale.
|
|
25
25
|
*/
|
|
26
|
-
import { type FetchLike, type FileInput, type FileOutput, type NativeFile, type QueryParams, type RequestOptions, type ResolvedRetry, type RetryOptions } from "./types";
|
|
26
|
+
import { type FetchLike, type FileInput, type FileOutput, type NativeFile, type ProgressCallback, type QueryParams, type RequestOptions, type ResolvedRetry, type RetryOptions } from "./types";
|
|
27
27
|
/** Production API root. Override only for a local backend or a test double. */
|
|
28
28
|
export declare const DEFAULT_BASE_URL = "https://backend.omelhorsite.pt";
|
|
29
29
|
/**
|
|
@@ -94,11 +94,11 @@ export declare function supportsResponseStreaming(): boolean;
|
|
|
94
94
|
* True in a browser and in React Native (RN's networking is XHR underneath and
|
|
95
95
|
* `xhr.upload.onprogress` fires there); false in a Worker-class isolate and in
|
|
96
96
|
* Bun's server runtime. See {@link Progress} for the whole argument and
|
|
97
|
-
* `
|
|
98
|
-
*
|
|
99
|
-
* per-file tick.
|
|
97
|
+
* `RequestOptions.onUploadProgress`; this reports whether that can work here,
|
|
98
|
+
* so a UI can decide between a real bar and a per-file tick.
|
|
100
99
|
*
|
|
101
|
-
*
|
|
100
|
+
* A request that asks for `onUploadProgress` travels through it when it is
|
|
101
|
+
* present; nothing else in the SDK touches it.
|
|
102
102
|
*/
|
|
103
103
|
export declare function supportsUploadProgress(): boolean;
|
|
104
104
|
/**
|
|
@@ -274,6 +274,7 @@ export declare class ApiClient {
|
|
|
274
274
|
/** API root with no trailing slash. */
|
|
275
275
|
readonly baseUrl: string;
|
|
276
276
|
private readonly fetchImpl;
|
|
277
|
+
private readonly customFetch;
|
|
277
278
|
private readonly tokens;
|
|
278
279
|
private readonly sessionCookie;
|
|
279
280
|
private readonly baseHeaders;
|
|
@@ -383,6 +384,14 @@ export declare class ApiClient {
|
|
|
383
384
|
* downloader instead of pulling it through JavaScript.
|
|
384
385
|
*/
|
|
385
386
|
download(path: string, options?: GetOptions): Promise<FileOutput>;
|
|
387
|
+
/**
|
|
388
|
+
* The transport a request should travel on: the client's fetch, or an
|
|
389
|
+
* `XMLHttpRequest` when upload progress was asked for and the runtime has
|
|
390
|
+
* one. A custom `fetch` is never bypassed.
|
|
391
|
+
*/
|
|
392
|
+
transportFor(onUploadProgress?: ProgressCallback): FetchLike;
|
|
393
|
+
/** `PATCH` with a multipart body, parsed as JSON. */
|
|
394
|
+
patchForm<T>(path: string, fields: FormFields, options?: GetOptions): Promise<T>;
|
|
386
395
|
/** Absolute URL for a path, with the query string applied. */
|
|
387
396
|
url(path: string, query?: QueryParams): string;
|
|
388
397
|
private requestJson;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** A fetch-shaped XMLHttpRequest, for the one thing fetch cannot do: report upload progress. */
|
|
2
|
+
import type { FetchLike, ProgressCallback } from "../types";
|
|
3
|
+
/** Whether this runtime can send a request through `XMLHttpRequest`. */
|
|
4
|
+
export declare function xhrAvailable(): boolean;
|
|
5
|
+
/** A {@link FetchLike} over `XMLHttpRequest` that reports the bytes sent to `onUploadProgress`. */
|
|
6
|
+
export declare function xhrFetch(onUploadProgress: ProgressCallback): FetchLike;
|
|
@@ -10,6 +10,7 @@ import { AdminNotepadsNamespace } from "./notepads";
|
|
|
10
10
|
import { AdminOauthApplicationsNamespace } from "./oauthApplications";
|
|
11
11
|
import { AdminQuotasNamespace } from "./quotas";
|
|
12
12
|
import { AdminShortLinksNamespace } from "./shortLinks";
|
|
13
|
+
import { AdminUsersNamespace } from "./users";
|
|
13
14
|
import { AdminVocalSeparationsNamespace } from "./vocalSeparations";
|
|
14
15
|
export * from "./authorizedApplications";
|
|
15
16
|
export * from "./chests";
|
|
@@ -22,6 +23,7 @@ export * from "./oauthApplications";
|
|
|
22
23
|
export * from "./quotas";
|
|
23
24
|
export * from "./shortLinks";
|
|
24
25
|
export * from "./types";
|
|
26
|
+
export * from "./users";
|
|
25
27
|
export * from "./vocalSeparations";
|
|
26
28
|
/**
|
|
27
29
|
* The `admin` namespace, reachable as `oms.admin`.
|
|
@@ -73,5 +75,7 @@ export declare class AdminNamespace extends Resource {
|
|
|
73
75
|
readonly notepads: AdminNotepadsNamespace;
|
|
74
76
|
/** The Discord alert catalogue. **Administrators only.** */
|
|
75
77
|
readonly eventAlerts: AdminEventAlertsNamespace;
|
|
78
|
+
/** Any account, admin-only fields included. */
|
|
79
|
+
readonly users: AdminUsersNamespace;
|
|
76
80
|
constructor(http: ConstructorParameters<typeof Resource>[0]);
|
|
77
81
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** `oms.admin.users`: editing any user's account. Administrators only. */
|
|
2
|
+
import { Resource } from "../../http";
|
|
3
|
+
import type { FileInput, Id, NativeFile, RequestOptions } from "../../types";
|
|
4
|
+
import type { User } from "../account";
|
|
5
|
+
/**
|
|
6
|
+
* Fields an administrator may change on any account. Everything is optional;
|
|
7
|
+
* omitted fields are left alone, `null` clears the nullable ones.
|
|
8
|
+
*
|
|
9
|
+
* `password` is only written when given and non-empty. `picture` makes the
|
|
10
|
+
* request multipart; the image is re-encoded server-side and capped at 1024px.
|
|
11
|
+
*/
|
|
12
|
+
export interface AdminUpdateUserInput {
|
|
13
|
+
readonly handle?: string;
|
|
14
|
+
readonly name?: string;
|
|
15
|
+
readonly bio?: string | null;
|
|
16
|
+
readonly countryCode?: string;
|
|
17
|
+
readonly emailIsPublic?: boolean;
|
|
18
|
+
readonly genderIsPublic?: boolean;
|
|
19
|
+
readonly gender?: string;
|
|
20
|
+
readonly libraryPublic?: boolean;
|
|
21
|
+
readonly libraryName?: string | null;
|
|
22
|
+
readonly libraryDescription?: string | null;
|
|
23
|
+
readonly shareListening?: boolean;
|
|
24
|
+
readonly email?: string;
|
|
25
|
+
/** Privilege group, e.g. `"administrator"`. */
|
|
26
|
+
readonly group?: string;
|
|
27
|
+
readonly password?: string;
|
|
28
|
+
readonly allowedToUseSpotify?: boolean;
|
|
29
|
+
readonly picture?: FileInput | NativeFile;
|
|
30
|
+
}
|
|
31
|
+
export declare class AdminUsersNamespace extends Resource {
|
|
32
|
+
/**
|
|
33
|
+
* `PATCH /users/:id` - edits any account, admin-only fields included.
|
|
34
|
+
*
|
|
35
|
+
* Answers the updated {@link User} as an administrator sees it.
|
|
36
|
+
*
|
|
37
|
+
* @throws {OmsAuthError} 401 for a non-administrator editing somebody else.
|
|
38
|
+
* @throws {OmsApiError} 400 with the validation messages.
|
|
39
|
+
*/
|
|
40
|
+
update(id: Id, input: AdminUpdateUserInput, options?: RequestOptions): Promise<User>;
|
|
41
|
+
}
|
|
@@ -137,7 +137,9 @@ export declare class ChestEntriesNamespace extends Resource {
|
|
|
137
137
|
* The file is buffered whole: the MD5 the presigned signature covers has to
|
|
138
138
|
* be computed over all of it.
|
|
139
139
|
*/
|
|
140
|
-
createWithUpload(input: CreateChestFileInput, options?: OperationOptions
|
|
140
|
+
createWithUpload(input: CreateChestFileInput, options?: OperationOptions & {
|
|
141
|
+
readonly onReserved?: (entry: ChestEntry) => void;
|
|
142
|
+
}): Promise<ChestEntry>;
|
|
141
143
|
/**
|
|
142
144
|
* `GET /chest_entries/:id/data` - the entry's bytes.
|
|
143
145
|
*
|
|
@@ -345,6 +345,7 @@ export declare class UploadManager extends Resource {
|
|
|
345
345
|
/** Paces every control-plane call against the 300-a-minute upload limit. */
|
|
346
346
|
readonly gate: StorageRateGate;
|
|
347
347
|
private readonly transport;
|
|
348
|
+
private readonly ownTransport;
|
|
348
349
|
private readonly md5;
|
|
349
350
|
constructor(http: ApiClient, options?: UploadManagerOptions);
|
|
350
351
|
/**
|
package/dist/types/types.d.ts
CHANGED
|
@@ -231,6 +231,15 @@ export interface RequestOptions {
|
|
|
231
231
|
readonly timeoutMs?: number;
|
|
232
232
|
/** Extra request headers. Merged over the client's, under `Authorization`. */
|
|
233
233
|
readonly headers?: Record<string, string>;
|
|
234
|
+
/**
|
|
235
|
+
* Called with the bytes sent so far while the request body goes up.
|
|
236
|
+
*
|
|
237
|
+
* Honoured where `XMLHttpRequest` exists (browsers, React Native) and the
|
|
238
|
+
* client was built without a custom `fetch`, which is when the request is
|
|
239
|
+
* sent through it instead. Elsewhere the request goes out as usual and this
|
|
240
|
+
* is never called.
|
|
241
|
+
*/
|
|
242
|
+
readonly onUploadProgress?: ProgressCallback;
|
|
234
243
|
/**
|
|
235
244
|
* Per-call retry override, and the ONLY way to put a mutating request in
|
|
236
245
|
* scope for a retry.
|
package/package.json
CHANGED