@org-quicko/silo-client 1.1.0 → 1.1.1
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 +42 -1
- package/dist/cache/cache-mode.d.cts +2 -0
- package/dist/cache/cache-mode.d.ts +2 -0
- package/dist/cache/response-cache.d.cts +16 -0
- package/dist/cache/response-cache.d.ts +16 -0
- package/dist/cache/silo-cache-options.d.cts +7 -0
- package/dist/cache/silo-cache-options.d.ts +7 -0
- package/dist/cache/silo-cache.d.cts +11 -0
- package/dist/cache/silo-cache.d.ts +11 -0
- package/dist/index.cjs +209 -60
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +209 -60
- package/dist/media/media-page.d.cts +1 -0
- package/dist/media/media-page.d.ts +1 -0
- package/dist/media/media-usage-page.d.cts +1 -0
- package/dist/media/media-usage-page.d.ts +1 -0
- package/dist/request-options.d.cts +3 -0
- package/dist/request-options.d.ts +3 -0
- package/dist/silo-options.d.cts +4 -0
- package/dist/silo-options.d.ts +4 -0
- package/dist/silo.d.cts +3 -0
- package/dist/silo.d.ts +3 -0
- package/dist/transport/caching-transport.d.cts +14 -0
- package/dist/transport/caching-transport.d.ts +14 -0
- package/dist/transport/fetch-transport.d.cts +31 -0
- package/dist/transport/fetch-transport.d.ts +31 -0
- package/dist/transport/prepared-transport-request.d.cts +6 -0
- package/dist/transport/prepared-transport-request.d.ts +6 -0
- package/dist/transport/transport-request.d.cts +2 -0
- package/dist/transport/transport-request.d.ts +2 -0
- package/dist/transport/transport.d.cts +2 -43
- package/dist/transport/transport.d.ts +2 -43
- package/package.json +6 -3
package/dist/index.js
CHANGED
|
@@ -208,12 +208,14 @@ var DefaultUsageLimit = 50;
|
|
|
208
208
|
class MediaUsagePage extends Page {
|
|
209
209
|
transport;
|
|
210
210
|
assetId;
|
|
211
|
+
requestOptions;
|
|
211
212
|
visible;
|
|
212
213
|
visibleCapped;
|
|
213
|
-
constructor(rows, total, visible, visibleCapped, window, transport, assetId) {
|
|
214
|
+
constructor(rows, total, visible, visibleCapped, window, transport, assetId, requestOptions) {
|
|
214
215
|
super(rows, total, window);
|
|
215
216
|
this.transport = transport;
|
|
216
217
|
this.assetId = assetId;
|
|
218
|
+
this.requestOptions = requestOptions;
|
|
217
219
|
this.visible = visible;
|
|
218
220
|
this.visibleCapped = visibleCapped;
|
|
219
221
|
}
|
|
@@ -228,11 +230,11 @@ class MediaUsagePage extends Page {
|
|
|
228
230
|
}
|
|
229
231
|
async next(options) {
|
|
230
232
|
const window = this.windowForNext();
|
|
231
|
-
return window ? MediaUsagePage.loadWindow(this.transport, this.assetId, window, options) : null;
|
|
233
|
+
return window ? MediaUsagePage.loadWindow(this.transport, this.assetId, window, { ...this.requestOptions, ...options }) : null;
|
|
232
234
|
}
|
|
233
235
|
async previous(options) {
|
|
234
236
|
const window = this.window.previous();
|
|
235
|
-
return window ? MediaUsagePage.loadWindow(this.transport, this.assetId, window, options) : null;
|
|
237
|
+
return window ? MediaUsagePage.loadWindow(this.transport, this.assetId, window, { ...this.requestOptions, ...options }) : null;
|
|
236
238
|
}
|
|
237
239
|
static load(transport, assetId, query, options) {
|
|
238
240
|
const window = new PageWindow(query.limit ?? DefaultUsageLimit, query.offset ?? 0);
|
|
@@ -244,10 +246,11 @@ class MediaUsagePage extends Page {
|
|
|
244
246
|
path: ApiPath.mediaAssetUsages(assetId),
|
|
245
247
|
query: { limit: window.limit, offset: window.offset },
|
|
246
248
|
signal: options?.signal,
|
|
247
|
-
timeoutMilliseconds: options?.timeoutMilliseconds
|
|
249
|
+
timeoutMilliseconds: options?.timeoutMilliseconds,
|
|
250
|
+
cache: options?.cache
|
|
248
251
|
});
|
|
249
252
|
const mapped = MediaAssetMapper.toUsagePage(body);
|
|
250
|
-
return new MediaUsagePage(mapped.items, mapped.total, mapped.visible, mapped.visibleCapped, window, transport, assetId);
|
|
253
|
+
return new MediaUsagePage(mapped.items, mapped.total, mapped.visible, mapped.visibleCapped, window, transport, assetId, options);
|
|
251
254
|
}
|
|
252
255
|
}
|
|
253
256
|
|
|
@@ -343,7 +346,8 @@ class MediaAsset {
|
|
|
343
346
|
method: "GET",
|
|
344
347
|
path: ApiPath.mediaAsset(this.id),
|
|
345
348
|
signal: options?.signal,
|
|
346
|
-
timeoutMilliseconds: options?.timeoutMilliseconds
|
|
349
|
+
timeoutMilliseconds: options?.timeoutMilliseconds,
|
|
350
|
+
cache: options?.cache ?? "refresh"
|
|
347
351
|
});
|
|
348
352
|
this.record = MediaAssetMapper.toRecord(payload);
|
|
349
353
|
return this;
|
|
@@ -405,7 +409,8 @@ class MediaFolders {
|
|
|
405
409
|
method: "GET",
|
|
406
410
|
path: ApiPath.mediaFolders(),
|
|
407
411
|
signal: options?.signal,
|
|
408
|
-
timeoutMilliseconds: options?.timeoutMilliseconds
|
|
412
|
+
timeoutMilliseconds: options?.timeoutMilliseconds,
|
|
413
|
+
cache: options?.cache
|
|
409
414
|
});
|
|
410
415
|
return body.items;
|
|
411
416
|
}
|
|
@@ -447,21 +452,23 @@ class MediaFolders {
|
|
|
447
452
|
class MediaPage extends Page {
|
|
448
453
|
transport;
|
|
449
454
|
wireQuery;
|
|
450
|
-
|
|
455
|
+
requestOptions;
|
|
456
|
+
constructor(rows, total, window, transport, wireQuery, requestOptions) {
|
|
451
457
|
super(rows, total, window);
|
|
452
458
|
this.transport = transport;
|
|
453
459
|
this.wireQuery = wireQuery;
|
|
460
|
+
this.requestOptions = requestOptions;
|
|
454
461
|
}
|
|
455
462
|
get files() {
|
|
456
463
|
return this.rows;
|
|
457
464
|
}
|
|
458
465
|
async next(options) {
|
|
459
466
|
const window = this.windowForNext();
|
|
460
|
-
return window ? MediaPage.loadWindow(this.transport, this.wireQuery, window, options) : null;
|
|
467
|
+
return window ? MediaPage.loadWindow(this.transport, this.wireQuery, window, { ...this.requestOptions, ...options }) : null;
|
|
461
468
|
}
|
|
462
469
|
async previous(options) {
|
|
463
470
|
const window = this.window.previous();
|
|
464
|
-
return window ? MediaPage.loadWindow(this.transport, this.wireQuery, window, options) : null;
|
|
471
|
+
return window ? MediaPage.loadWindow(this.transport, this.wireQuery, window, { ...this.requestOptions, ...options }) : null;
|
|
465
472
|
}
|
|
466
473
|
static async loadWindow(transport, wireQuery, window, options) {
|
|
467
474
|
const body = await transport.json({
|
|
@@ -469,10 +476,11 @@ class MediaPage extends Page {
|
|
|
469
476
|
path: ApiPath.media(),
|
|
470
477
|
query: { ...wireQuery, limit: window.limit, offset: window.offset },
|
|
471
478
|
signal: options?.signal,
|
|
472
|
-
timeoutMilliseconds: options?.timeoutMilliseconds
|
|
479
|
+
timeoutMilliseconds: options?.timeoutMilliseconds,
|
|
480
|
+
cache: options?.cache
|
|
473
481
|
});
|
|
474
482
|
const rows = body.items.map((payload) => new MediaAsset(transport, MediaAssetMapper.toRecord(payload)));
|
|
475
|
-
return new MediaPage(rows, body.total, new PageWindow(body.limit, body.offset), transport, wireQuery);
|
|
483
|
+
return new MediaPage(rows, body.total, new PageWindow(body.limit, body.offset), transport, wireQuery, options);
|
|
476
484
|
}
|
|
477
485
|
}
|
|
478
486
|
|
|
@@ -592,7 +600,8 @@ class Media {
|
|
|
592
600
|
method: "GET",
|
|
593
601
|
path: ApiPath.mediaAsset(id),
|
|
594
602
|
signal: options?.signal,
|
|
595
|
-
timeoutMilliseconds: options?.timeoutMilliseconds
|
|
603
|
+
timeoutMilliseconds: options?.timeoutMilliseconds,
|
|
604
|
+
cache: options?.cache
|
|
596
605
|
});
|
|
597
606
|
return new MediaAsset(this.transport, MediaAssetMapper.toRecord(payload));
|
|
598
607
|
}
|
|
@@ -601,7 +610,8 @@ class Media {
|
|
|
601
610
|
method: "GET",
|
|
602
611
|
path: ApiPath.mediaExtensions(),
|
|
603
612
|
signal: options?.signal,
|
|
604
|
-
timeoutMilliseconds: options?.timeoutMilliseconds
|
|
613
|
+
timeoutMilliseconds: options?.timeoutMilliseconds,
|
|
614
|
+
cache: options?.cache
|
|
605
615
|
});
|
|
606
616
|
return body.items;
|
|
607
617
|
}
|
|
@@ -1314,6 +1324,132 @@ class Projects {
|
|
|
1314
1324
|
}
|
|
1315
1325
|
}
|
|
1316
1326
|
|
|
1327
|
+
// src/transport/caching-transport.ts
|
|
1328
|
+
class CachingTransport {
|
|
1329
|
+
#fetchTransport;
|
|
1330
|
+
#cache;
|
|
1331
|
+
constructor(fetchTransport, cache) {
|
|
1332
|
+
this.#fetchTransport = fetchTransport;
|
|
1333
|
+
this.#cache = cache;
|
|
1334
|
+
}
|
|
1335
|
+
async json(request) {
|
|
1336
|
+
if (request.method !== "GET")
|
|
1337
|
+
return this.write(() => this.#fetchTransport.json(request));
|
|
1338
|
+
if (request.cache === "bypass")
|
|
1339
|
+
return this.#fetchTransport.json(request);
|
|
1340
|
+
if (request.signal?.aborted)
|
|
1341
|
+
throw new RequestAbortedError(request.method, request.path);
|
|
1342
|
+
let prepared;
|
|
1343
|
+
try {
|
|
1344
|
+
prepared = this.#fetchTransport.prepare(request);
|
|
1345
|
+
} catch (caught) {
|
|
1346
|
+
throw this.#fetchTransport.preparationFailure(request, caught);
|
|
1347
|
+
}
|
|
1348
|
+
const key = JSON.stringify([prepared.url, [...prepared.headers]]);
|
|
1349
|
+
if (request.cache !== "refresh") {
|
|
1350
|
+
const cached = this.#cache.get(key);
|
|
1351
|
+
if (cached)
|
|
1352
|
+
return cached.body;
|
|
1353
|
+
}
|
|
1354
|
+
const ticket = this.#cache.start(key);
|
|
1355
|
+
try {
|
|
1356
|
+
const body = await this.#fetchTransport.jsonPrepared(request, prepared);
|
|
1357
|
+
this.#cache.set(key, ticket, body);
|
|
1358
|
+
return body;
|
|
1359
|
+
} finally {
|
|
1360
|
+
this.#cache.finish(key, ticket);
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
empty(request) {
|
|
1364
|
+
return request.method === "GET" ? this.#fetchTransport.empty(request) : this.write(() => this.#fetchTransport.empty(request));
|
|
1365
|
+
}
|
|
1366
|
+
stream(request) {
|
|
1367
|
+
return request.method === "GET" ? this.#fetchTransport.stream(request) : this.write(() => this.#fetchTransport.stream(request));
|
|
1368
|
+
}
|
|
1369
|
+
upload(request, form) {
|
|
1370
|
+
return request.method === "GET" ? this.#fetchTransport.upload(request, form) : this.write(() => this.#fetchTransport.upload(request, form));
|
|
1371
|
+
}
|
|
1372
|
+
async write(dispatch) {
|
|
1373
|
+
this.#cache.clear();
|
|
1374
|
+
try {
|
|
1375
|
+
return await dispatch();
|
|
1376
|
+
} finally {
|
|
1377
|
+
this.#cache.clear();
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
// src/cache/response-cache.ts
|
|
1383
|
+
import { TTLCache } from "@isaacs/ttlcache";
|
|
1384
|
+
|
|
1385
|
+
class ResponseCache {
|
|
1386
|
+
#store;
|
|
1387
|
+
#pending = new Map;
|
|
1388
|
+
constructor(options) {
|
|
1389
|
+
this.#store = new TTLCache({
|
|
1390
|
+
ttl: options.ttlMilliseconds,
|
|
1391
|
+
...options.maxEntries === undefined || options.maxEntries === Infinity ? {} : { max: options.maxEntries },
|
|
1392
|
+
checkAgeOnGet: true,
|
|
1393
|
+
updateAgeOnGet: false
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
get size() {
|
|
1397
|
+
return this.#store.size;
|
|
1398
|
+
}
|
|
1399
|
+
get(key) {
|
|
1400
|
+
const cached = this.#store.get(key);
|
|
1401
|
+
return cached === undefined ? undefined : { body: structuredClone(cached.body) };
|
|
1402
|
+
}
|
|
1403
|
+
set(key, ticket, body) {
|
|
1404
|
+
if (this.#pending.get(key) !== ticket)
|
|
1405
|
+
return;
|
|
1406
|
+
this.#store.set(key, { body: structuredClone(body) });
|
|
1407
|
+
}
|
|
1408
|
+
start(key) {
|
|
1409
|
+
const ticket = Symbol();
|
|
1410
|
+
this.#pending.set(key, ticket);
|
|
1411
|
+
return ticket;
|
|
1412
|
+
}
|
|
1413
|
+
finish(key, ticket) {
|
|
1414
|
+
if (this.#pending.get(key) === ticket)
|
|
1415
|
+
this.#pending.delete(key);
|
|
1416
|
+
}
|
|
1417
|
+
clear() {
|
|
1418
|
+
this.#pending.clear();
|
|
1419
|
+
this.#store.clear();
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
// src/cache/silo-cache.ts
|
|
1424
|
+
class SiloCache {
|
|
1425
|
+
#responseCache;
|
|
1426
|
+
constructor(options) {
|
|
1427
|
+
if (options !== undefined)
|
|
1428
|
+
SiloCache.validate(options);
|
|
1429
|
+
this.#responseCache = options === undefined ? undefined : new ResponseCache(options);
|
|
1430
|
+
}
|
|
1431
|
+
get enabled() {
|
|
1432
|
+
return this.#responseCache !== undefined;
|
|
1433
|
+
}
|
|
1434
|
+
get size() {
|
|
1435
|
+
return this.#responseCache?.size ?? 0;
|
|
1436
|
+
}
|
|
1437
|
+
clear() {
|
|
1438
|
+
this.#responseCache?.clear();
|
|
1439
|
+
}
|
|
1440
|
+
wrap(fetchTransport) {
|
|
1441
|
+
return this.#responseCache ? new CachingTransport(fetchTransport, this.#responseCache) : fetchTransport;
|
|
1442
|
+
}
|
|
1443
|
+
static validate(options) {
|
|
1444
|
+
if (!Number.isSafeInteger(options.ttlMilliseconds) || options.ttlMilliseconds <= 0) {
|
|
1445
|
+
throw new TypeError("SiloOptions.cache.ttlMilliseconds must be a positive finite safe integer");
|
|
1446
|
+
}
|
|
1447
|
+
if (options.maxEntries !== undefined && options.maxEntries !== Infinity && (!Number.isSafeInteger(options.maxEntries) || options.maxEntries <= 0)) {
|
|
1448
|
+
throw new TypeError("SiloOptions.cache.maxEntries must be a positive safe integer or Infinity");
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1317
1453
|
// src/errors/silo-error.ts
|
|
1318
1454
|
class SiloError extends Error {
|
|
1319
1455
|
status;
|
|
@@ -1608,61 +1744,80 @@ class ResponseDecoder {
|
|
|
1608
1744
|
}
|
|
1609
1745
|
}
|
|
1610
1746
|
|
|
1611
|
-
// src/transport/transport.ts
|
|
1612
|
-
class
|
|
1613
|
-
url;
|
|
1614
|
-
key;
|
|
1615
|
-
headers;
|
|
1616
|
-
timeoutMilliseconds;
|
|
1617
|
-
fetchFunction;
|
|
1747
|
+
// src/transport/fetch-transport.ts
|
|
1748
|
+
class FetchTransport {
|
|
1749
|
+
#url;
|
|
1750
|
+
#key;
|
|
1751
|
+
#headers;
|
|
1752
|
+
#timeoutMilliseconds;
|
|
1753
|
+
#fetchFunction;
|
|
1618
1754
|
constructor(options) {
|
|
1619
|
-
this
|
|
1620
|
-
this
|
|
1621
|
-
this
|
|
1622
|
-
this
|
|
1623
|
-
this
|
|
1755
|
+
this.#url = FetchTransport.normalizeUrl(options.url);
|
|
1756
|
+
this.#key = options.key;
|
|
1757
|
+
this.#headers = options.headers ?? {};
|
|
1758
|
+
this.#timeoutMilliseconds = options.timeoutMilliseconds;
|
|
1759
|
+
this.#fetchFunction = FetchTransport.resolveFetch(options.fetch);
|
|
1624
1760
|
}
|
|
1625
1761
|
async json(request) {
|
|
1626
1762
|
const response = await this.execute(request);
|
|
1627
1763
|
return await ResponseDecoder.decode(response, request, true);
|
|
1628
1764
|
}
|
|
1765
|
+
async jsonPrepared(request, prepared) {
|
|
1766
|
+
const response = await this.execute(request, prepared);
|
|
1767
|
+
return await ResponseDecoder.decode(response, request, true);
|
|
1768
|
+
}
|
|
1629
1769
|
async empty(request) {
|
|
1630
1770
|
const response = await this.execute(request);
|
|
1631
1771
|
await ResponseDecoder.decode(response, request, false);
|
|
1632
1772
|
}
|
|
1633
1773
|
async stream(request) {
|
|
1634
|
-
|
|
1635
|
-
return response.body;
|
|
1774
|
+
return (await this.execute(request)).body;
|
|
1636
1775
|
}
|
|
1637
1776
|
async upload(request, form) {
|
|
1638
|
-
const response = await this.execute(request, form);
|
|
1777
|
+
const response = await this.execute(request, undefined, form);
|
|
1639
1778
|
return await ResponseDecoder.decode(response, request, true);
|
|
1640
1779
|
}
|
|
1641
1780
|
withKey(key) {
|
|
1642
|
-
return new
|
|
1781
|
+
return new FetchTransport({ ...this.snapshot(), key });
|
|
1643
1782
|
}
|
|
1644
1783
|
withUrl(url) {
|
|
1645
|
-
return new
|
|
1784
|
+
return new FetchTransport({ ...this.snapshot(), url });
|
|
1785
|
+
}
|
|
1786
|
+
prepare(request, form) {
|
|
1787
|
+
const rawHeaders = { ...this.#headers, ...request.headers };
|
|
1788
|
+
if (this.#key)
|
|
1789
|
+
rawHeaders.Authorization = `Bearer ${this.#key}`;
|
|
1790
|
+
if (!form && request.body !== undefined && !("Content-Type" in rawHeaders)) {
|
|
1791
|
+
rawHeaders["Content-Type"] = "application/json";
|
|
1792
|
+
}
|
|
1793
|
+
return {
|
|
1794
|
+
url: `${this.#url}${request.path}${QueryString.build(request.query)}`,
|
|
1795
|
+
headers: new Headers(rawHeaders),
|
|
1796
|
+
body: form ?? (request.body === undefined ? undefined : JSON.stringify(request.body))
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1799
|
+
preparationFailure(request, caught) {
|
|
1800
|
+
return new NetworkError(request.method, request.path, caught);
|
|
1646
1801
|
}
|
|
1647
1802
|
snapshot() {
|
|
1648
1803
|
return {
|
|
1649
|
-
url: this
|
|
1650
|
-
key: this
|
|
1651
|
-
headers: this
|
|
1652
|
-
timeoutMilliseconds: this
|
|
1653
|
-
fetch: this
|
|
1804
|
+
url: this.#url,
|
|
1805
|
+
key: this.#key,
|
|
1806
|
+
headers: this.#headers,
|
|
1807
|
+
timeoutMilliseconds: this.#timeoutMilliseconds,
|
|
1808
|
+
fetch: this.#fetchFunction
|
|
1654
1809
|
};
|
|
1655
1810
|
}
|
|
1656
|
-
async execute(request, form) {
|
|
1657
|
-
const abortSignals = new AbortSignals(request.signal, request.timeoutMilliseconds ?? this
|
|
1658
|
-
const
|
|
1659
|
-
const sendRequest = this.fetchFunction;
|
|
1811
|
+
async execute(request, prepared, form) {
|
|
1812
|
+
const abortSignals = new AbortSignals(request.signal, request.timeoutMilliseconds ?? this.#timeoutMilliseconds);
|
|
1813
|
+
const sendRequest = this.#fetchFunction;
|
|
1660
1814
|
let response;
|
|
1661
1815
|
try {
|
|
1662
|
-
|
|
1816
|
+
const outbound = prepared ?? this.prepare(request, form);
|
|
1817
|
+
response = await sendRequest(outbound.url, {
|
|
1663
1818
|
method: request.method,
|
|
1664
|
-
headers:
|
|
1665
|
-
body:
|
|
1819
|
+
headers: outbound.headers,
|
|
1820
|
+
body: outbound.body,
|
|
1666
1821
|
signal: abortSignals.signal
|
|
1667
1822
|
});
|
|
1668
1823
|
} catch (caught) {
|
|
@@ -1676,24 +1831,13 @@ class Transport {
|
|
|
1676
1831
|
return response;
|
|
1677
1832
|
}
|
|
1678
1833
|
transportFailure(request, abortSignals, caught) {
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
return new TimeoutError(request.method, request.path, request.timeoutMilliseconds ?? this.timeoutMilliseconds ?? 0);
|
|
1834
|
+
if (abortSignals.firedBy() === "timeout") {
|
|
1835
|
+
return new TimeoutError(request.method, request.path, request.timeoutMilliseconds ?? this.#timeoutMilliseconds ?? 0);
|
|
1682
1836
|
}
|
|
1683
|
-
if (firedBy === "caller")
|
|
1837
|
+
if (abortSignals.firedBy() === "caller")
|
|
1684
1838
|
return new RequestAbortedError(request.method, request.path);
|
|
1685
|
-
}
|
|
1686
1839
|
return new NetworkError(request.method, request.path, caught);
|
|
1687
1840
|
}
|
|
1688
|
-
buildHeaders(request, isUpload) {
|
|
1689
|
-
const headers = { ...this.headers, ...request.headers };
|
|
1690
|
-
if (this.key)
|
|
1691
|
-
headers["Authorization"] = `Bearer ${this.key}`;
|
|
1692
|
-
if (!isUpload && request.body !== undefined && !("Content-Type" in headers)) {
|
|
1693
|
-
headers["Content-Type"] = "application/json";
|
|
1694
|
-
}
|
|
1695
|
-
return headers;
|
|
1696
|
-
}
|
|
1697
1841
|
static normalizeUrl(url) {
|
|
1698
1842
|
return url.replace(/\/+$/, "");
|
|
1699
1843
|
}
|
|
@@ -1711,17 +1855,20 @@ class Transport {
|
|
|
1711
1855
|
class Silo {
|
|
1712
1856
|
projects;
|
|
1713
1857
|
media;
|
|
1858
|
+
cache;
|
|
1714
1859
|
options;
|
|
1715
1860
|
transport;
|
|
1716
1861
|
constructor(options) {
|
|
1717
|
-
this.
|
|
1718
|
-
this.
|
|
1862
|
+
this.cache = options.cache instanceof SiloCache ? options.cache : new SiloCache(options.cache);
|
|
1863
|
+
this.options = { ...options, cache: this.cache };
|
|
1864
|
+
const fetchTransport = new FetchTransport({
|
|
1719
1865
|
url: options.url,
|
|
1720
1866
|
key: options.key,
|
|
1721
1867
|
headers: options.headers,
|
|
1722
1868
|
timeoutMilliseconds: options.timeoutMilliseconds,
|
|
1723
1869
|
fetch: options.fetch
|
|
1724
1870
|
});
|
|
1871
|
+
this.transport = this.cache.wrap(fetchTransport);
|
|
1725
1872
|
this.projects = new Projects(this.transport);
|
|
1726
1873
|
this.media = new Media(this.transport);
|
|
1727
1874
|
}
|
|
@@ -1739,7 +1886,8 @@ class Silo {
|
|
|
1739
1886
|
method: "GET",
|
|
1740
1887
|
path: ApiPath.health(),
|
|
1741
1888
|
signal: options?.signal,
|
|
1742
|
-
timeoutMilliseconds: options?.timeoutMilliseconds
|
|
1889
|
+
timeoutMilliseconds: options?.timeoutMilliseconds,
|
|
1890
|
+
cache: "bypass"
|
|
1743
1891
|
});
|
|
1744
1892
|
}
|
|
1745
1893
|
withKey(key) {
|
|
@@ -1922,6 +2070,7 @@ export {
|
|
|
1922
2070
|
SortTerm,
|
|
1923
2071
|
Sort,
|
|
1924
2072
|
SiloError,
|
|
2073
|
+
SiloCache,
|
|
1925
2074
|
Silo,
|
|
1926
2075
|
SearchReach,
|
|
1927
2076
|
SearchPage,
|
|
@@ -9,6 +9,7 @@ import { MediaAsset } from "./media-asset.cjs";
|
|
|
9
9
|
export declare class MediaPage extends Page<MediaAsset> {
|
|
10
10
|
private readonly transport;
|
|
11
11
|
private readonly wireQuery;
|
|
12
|
+
private readonly requestOptions;
|
|
12
13
|
private constructor();
|
|
13
14
|
get files(): readonly MediaAsset[];
|
|
14
15
|
next(options?: RequestOptions): Promise<MediaPage | null>;
|
|
@@ -9,6 +9,7 @@ import { MediaAsset } from "./media-asset.js";
|
|
|
9
9
|
export declare class MediaPage extends Page<MediaAsset> {
|
|
10
10
|
private readonly transport;
|
|
11
11
|
private readonly wireQuery;
|
|
12
|
+
private readonly requestOptions;
|
|
12
13
|
private constructor();
|
|
13
14
|
get files(): readonly MediaAsset[];
|
|
14
15
|
next(options?: RequestOptions): Promise<MediaPage | null>;
|
|
@@ -20,6 +20,7 @@ export interface MediaUsageQuery {
|
|
|
20
20
|
export declare class MediaUsagePage extends Page<MediaUsage> {
|
|
21
21
|
private readonly transport;
|
|
22
22
|
private readonly assetId;
|
|
23
|
+
private readonly requestOptions;
|
|
23
24
|
readonly visible: number;
|
|
24
25
|
readonly visibleCapped: boolean;
|
|
25
26
|
private constructor();
|
|
@@ -20,6 +20,7 @@ export interface MediaUsageQuery {
|
|
|
20
20
|
export declare class MediaUsagePage extends Page<MediaUsage> {
|
|
21
21
|
private readonly transport;
|
|
22
22
|
private readonly assetId;
|
|
23
|
+
private readonly requestOptions;
|
|
23
24
|
readonly visible: number;
|
|
24
25
|
readonly visibleCapped: boolean;
|
|
25
26
|
private constructor();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CacheMode } from "./cache/cache-mode.cjs";
|
|
1
2
|
/**
|
|
2
3
|
* The one cancellation convention on every call: the last parameter of
|
|
3
4
|
* every method in the client. A per-call value wins over the client's own
|
|
@@ -6,4 +7,6 @@
|
|
|
6
7
|
export interface RequestOptions {
|
|
7
8
|
signal?: AbortSignal;
|
|
8
9
|
timeoutMilliseconds?: number;
|
|
10
|
+
/** `bypass` skips lookup and storage; `refresh` fetches and stores. Ignored on writes and disabled caches. */
|
|
11
|
+
cache?: CacheMode;
|
|
9
12
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CacheMode } from "./cache/cache-mode.js";
|
|
1
2
|
/**
|
|
2
3
|
* The one cancellation convention on every call: the last parameter of
|
|
3
4
|
* every method in the client. A per-call value wins over the client's own
|
|
@@ -6,4 +7,6 @@
|
|
|
6
7
|
export interface RequestOptions {
|
|
7
8
|
signal?: AbortSignal;
|
|
8
9
|
timeoutMilliseconds?: number;
|
|
10
|
+
/** `bypass` skips lookup and storage; `refresh` fetches and stores. Ignored on writes and disabled caches. */
|
|
11
|
+
cache?: CacheMode;
|
|
9
12
|
}
|
package/dist/silo-options.d.cts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { FetchFunction } from "./transport/fetch-function.cjs";
|
|
2
|
+
import type { SiloCache } from "./cache/silo-cache.cjs";
|
|
3
|
+
import type { SiloCacheOptions } from "./cache/silo-cache-options.cjs";
|
|
2
4
|
/**
|
|
3
5
|
* Everything `new Silo(...)` accepts. Only `url` is required: a key is
|
|
4
6
|
* optional because anonymous reads are legal.
|
|
@@ -9,4 +11,6 @@ export interface SiloOptions {
|
|
|
9
11
|
timeoutMilliseconds?: number;
|
|
10
12
|
headers?: Record<string, string>;
|
|
11
13
|
fetch?: FetchFunction;
|
|
14
|
+
/** Enable read caching or share an existing cache. Omit to disable. */
|
|
15
|
+
cache?: SiloCacheOptions | SiloCache;
|
|
12
16
|
}
|
package/dist/silo-options.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { FetchFunction } from "./transport/fetch-function.js";
|
|
2
|
+
import type { SiloCache } from "./cache/silo-cache.js";
|
|
3
|
+
import type { SiloCacheOptions } from "./cache/silo-cache-options.js";
|
|
2
4
|
/**
|
|
3
5
|
* Everything `new Silo(...)` accepts. Only `url` is required: a key is
|
|
4
6
|
* optional because anonymous reads are legal.
|
|
@@ -9,4 +11,6 @@ export interface SiloOptions {
|
|
|
9
11
|
timeoutMilliseconds?: number;
|
|
10
12
|
headers?: Record<string, string>;
|
|
11
13
|
fetch?: FetchFunction;
|
|
14
|
+
/** Enable read caching or share an existing cache. Omit to disable. */
|
|
15
|
+
cache?: SiloCacheOptions | SiloCache;
|
|
12
16
|
}
|
package/dist/silo.d.cts
CHANGED
|
@@ -7,6 +7,7 @@ import type { EnvironmentHandle } from "./scope/environment-handle.cjs";
|
|
|
7
7
|
import type { SearchPage } from "./search/search-page.cjs";
|
|
8
8
|
import type { SearchQuery } from "./search/search-query.cjs";
|
|
9
9
|
import type { SiloOptions } from "./silo-options.cjs";
|
|
10
|
+
import { SiloCache } from "./cache/silo-cache.cjs";
|
|
10
11
|
/**
|
|
11
12
|
* One silo instance. Navigate it the way the API is shaped:
|
|
12
13
|
* `silo.project("acme").environment("prod").collection<Post>("posts")`.
|
|
@@ -20,6 +21,8 @@ export declare class Silo {
|
|
|
20
21
|
readonly projects: Projects;
|
|
21
22
|
/** The media catalog. Media is instance-global, so it takes no scope. */
|
|
22
23
|
readonly media: Media;
|
|
24
|
+
/** This instance's optional read cache. */
|
|
25
|
+
readonly cache: SiloCache;
|
|
23
26
|
private readonly options;
|
|
24
27
|
private readonly transport;
|
|
25
28
|
constructor(options: SiloOptions);
|
package/dist/silo.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { EnvironmentHandle } from "./scope/environment-handle.js";
|
|
|
7
7
|
import type { SearchPage } from "./search/search-page.js";
|
|
8
8
|
import type { SearchQuery } from "./search/search-query.js";
|
|
9
9
|
import type { SiloOptions } from "./silo-options.js";
|
|
10
|
+
import { SiloCache } from "./cache/silo-cache.js";
|
|
10
11
|
/**
|
|
11
12
|
* One silo instance. Navigate it the way the API is shaped:
|
|
12
13
|
* `silo.project("acme").environment("prod").collection<Post>("posts")`.
|
|
@@ -20,6 +21,8 @@ export declare class Silo {
|
|
|
20
21
|
readonly projects: Projects;
|
|
21
22
|
/** The media catalog. Media is instance-global, so it takes no scope. */
|
|
22
23
|
readonly media: Media;
|
|
24
|
+
/** This instance's optional read cache. */
|
|
25
|
+
readonly cache: SiloCache;
|
|
23
26
|
private readonly options;
|
|
24
27
|
private readonly transport;
|
|
25
28
|
constructor(options: SiloOptions);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ResponseCache } from "../cache/response-cache.cjs";
|
|
2
|
+
import type { FetchTransport } from "./fetch-transport.cjs";
|
|
3
|
+
import type { TransportRequest } from "./transport-request.cjs";
|
|
4
|
+
import type { Transport } from "./transport.cjs";
|
|
5
|
+
/** Adds opt-in GET JSON caching to the fetch transport. */
|
|
6
|
+
export declare class CachingTransport implements Transport {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(fetchTransport: FetchTransport, cache: ResponseCache);
|
|
9
|
+
json<T>(request: TransportRequest): Promise<T>;
|
|
10
|
+
empty(request: TransportRequest): Promise<void>;
|
|
11
|
+
stream(request: TransportRequest): Promise<ReadableStream<Uint8Array> | null>;
|
|
12
|
+
upload<T>(request: TransportRequest, form: FormData): Promise<T>;
|
|
13
|
+
private write;
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ResponseCache } from "../cache/response-cache.js";
|
|
2
|
+
import type { FetchTransport } from "./fetch-transport.js";
|
|
3
|
+
import type { TransportRequest } from "./transport-request.js";
|
|
4
|
+
import type { Transport } from "./transport.js";
|
|
5
|
+
/** Adds opt-in GET JSON caching to the fetch transport. */
|
|
6
|
+
export declare class CachingTransport implements Transport {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(fetchTransport: FetchTransport, cache: ResponseCache);
|
|
9
|
+
json<T>(request: TransportRequest): Promise<T>;
|
|
10
|
+
empty(request: TransportRequest): Promise<void>;
|
|
11
|
+
stream(request: TransportRequest): Promise<ReadableStream<Uint8Array> | null>;
|
|
12
|
+
upload<T>(request: TransportRequest, form: FormData): Promise<T>;
|
|
13
|
+
private write;
|
|
14
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { NetworkError } from "../errors/network-error.cjs";
|
|
2
|
+
import type { FetchFunction } from "./fetch-function.cjs";
|
|
3
|
+
import type { PreparedTransportRequest } from "./prepared-transport-request.cjs";
|
|
4
|
+
import type { TransportRequest } from "./transport-request.cjs";
|
|
5
|
+
import type { Transport } from "./transport.cjs";
|
|
6
|
+
export interface FetchTransportOptions {
|
|
7
|
+
url: string;
|
|
8
|
+
key?: string;
|
|
9
|
+
headers?: Record<string, string>;
|
|
10
|
+
timeoutMilliseconds?: number;
|
|
11
|
+
fetch?: FetchFunction;
|
|
12
|
+
}
|
|
13
|
+
/** The fetch-backed implementation behind the internal transport seam. */
|
|
14
|
+
export declare class FetchTransport implements Transport {
|
|
15
|
+
#private;
|
|
16
|
+
constructor(options: FetchTransportOptions);
|
|
17
|
+
json<T>(request: TransportRequest): Promise<T>;
|
|
18
|
+
jsonPrepared<T>(request: TransportRequest, prepared: PreparedTransportRequest): Promise<T>;
|
|
19
|
+
empty(request: TransportRequest): Promise<void>;
|
|
20
|
+
stream(request: TransportRequest): Promise<ReadableStream<Uint8Array> | null>;
|
|
21
|
+
upload<T>(request: TransportRequest, form: FormData): Promise<T>;
|
|
22
|
+
withKey(key: string | undefined): FetchTransport;
|
|
23
|
+
withUrl(url: string): FetchTransport;
|
|
24
|
+
prepare(request: TransportRequest, form?: FormData): PreparedTransportRequest;
|
|
25
|
+
preparationFailure(request: TransportRequest, caught: unknown): NetworkError;
|
|
26
|
+
private snapshot;
|
|
27
|
+
private execute;
|
|
28
|
+
private transportFailure;
|
|
29
|
+
private static normalizeUrl;
|
|
30
|
+
private static resolveFetch;
|
|
31
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { NetworkError } from "../errors/network-error.js";
|
|
2
|
+
import type { FetchFunction } from "./fetch-function.js";
|
|
3
|
+
import type { PreparedTransportRequest } from "./prepared-transport-request.js";
|
|
4
|
+
import type { TransportRequest } from "./transport-request.js";
|
|
5
|
+
import type { Transport } from "./transport.js";
|
|
6
|
+
export interface FetchTransportOptions {
|
|
7
|
+
url: string;
|
|
8
|
+
key?: string;
|
|
9
|
+
headers?: Record<string, string>;
|
|
10
|
+
timeoutMilliseconds?: number;
|
|
11
|
+
fetch?: FetchFunction;
|
|
12
|
+
}
|
|
13
|
+
/** The fetch-backed implementation behind the internal transport seam. */
|
|
14
|
+
export declare class FetchTransport implements Transport {
|
|
15
|
+
#private;
|
|
16
|
+
constructor(options: FetchTransportOptions);
|
|
17
|
+
json<T>(request: TransportRequest): Promise<T>;
|
|
18
|
+
jsonPrepared<T>(request: TransportRequest, prepared: PreparedTransportRequest): Promise<T>;
|
|
19
|
+
empty(request: TransportRequest): Promise<void>;
|
|
20
|
+
stream(request: TransportRequest): Promise<ReadableStream<Uint8Array> | null>;
|
|
21
|
+
upload<T>(request: TransportRequest, form: FormData): Promise<T>;
|
|
22
|
+
withKey(key: string | undefined): FetchTransport;
|
|
23
|
+
withUrl(url: string): FetchTransport;
|
|
24
|
+
prepare(request: TransportRequest, form?: FormData): PreparedTransportRequest;
|
|
25
|
+
preparationFailure(request: TransportRequest, caught: unknown): NetworkError;
|
|
26
|
+
private snapshot;
|
|
27
|
+
private execute;
|
|
28
|
+
private transportFailure;
|
|
29
|
+
private static normalizeUrl;
|
|
30
|
+
private static resolveFetch;
|
|
31
|
+
}
|