@org-quicko/silo-client 1.0.1 → 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.
Files changed (46) hide show
  1. package/README.md +49 -1
  2. package/dist/cache/cache-mode.d.cts +2 -0
  3. package/dist/cache/cache-mode.d.ts +2 -0
  4. package/dist/cache/response-cache.d.cts +16 -0
  5. package/dist/cache/response-cache.d.ts +16 -0
  6. package/dist/cache/silo-cache-options.d.cts +7 -0
  7. package/dist/cache/silo-cache-options.d.ts +7 -0
  8. package/dist/cache/silo-cache.d.cts +11 -0
  9. package/dist/cache/silo-cache.d.ts +11 -0
  10. package/dist/errors/network-error.d.cts +5 -0
  11. package/dist/errors/network-error.d.ts +5 -0
  12. package/dist/index.cjs +264 -74
  13. package/dist/index.d.cts +4 -0
  14. package/dist/index.d.ts +4 -0
  15. package/dist/index.js +264 -74
  16. package/dist/media/media-asset.d.cts +17 -0
  17. package/dist/media/media-asset.d.ts +17 -0
  18. package/dist/media/media-file.d.cts +16 -0
  19. package/dist/media/media-file.d.ts +16 -0
  20. package/dist/media/media-page.d.cts +1 -0
  21. package/dist/media/media-page.d.ts +1 -0
  22. package/dist/media/media-replace.d.cts +17 -0
  23. package/dist/media/media-replace.d.ts +17 -0
  24. package/dist/media/media-usage-page.d.cts +1 -0
  25. package/dist/media/media-usage-page.d.ts +1 -0
  26. package/dist/media/media.d.cts +0 -4
  27. package/dist/media/media.d.ts +0 -4
  28. package/dist/request-options.d.cts +3 -0
  29. package/dist/request-options.d.ts +3 -0
  30. package/dist/silo-options.d.cts +4 -0
  31. package/dist/silo-options.d.ts +4 -0
  32. package/dist/silo.d.cts +3 -0
  33. package/dist/silo.d.ts +3 -0
  34. package/dist/transport/api-path.d.cts +1 -0
  35. package/dist/transport/api-path.d.ts +1 -0
  36. package/dist/transport/caching-transport.d.cts +14 -0
  37. package/dist/transport/caching-transport.d.ts +14 -0
  38. package/dist/transport/fetch-transport.d.cts +31 -0
  39. package/dist/transport/fetch-transport.d.ts +31 -0
  40. package/dist/transport/prepared-transport-request.d.cts +6 -0
  41. package/dist/transport/prepared-transport-request.d.ts +6 -0
  42. package/dist/transport/transport-request.d.cts +2 -0
  43. package/dist/transport/transport-request.d.ts +2 -0
  44. package/dist/transport/transport.d.cts +2 -39
  45. package/dist/transport/transport.d.ts +2 -39
  46. package/package.json +6 -3
package/README.md CHANGED
@@ -8,7 +8,8 @@ an environment holds collections, and a collection holds entries.
8
8
  npm install @org-quicko/silo-client
9
9
  ```
10
10
 
11
- Runs on Node 18+, Bun, Deno, browsers and workers. It has no dependencies.
11
+ Runs on Node 18+, Bun, Deno, browsers and workers. Its optional cache uses one
12
+ runtime dependency, `@isaacs/ttlcache`.
12
13
 
13
14
  The examples below build moviespace, a small film database.
14
15
 
@@ -208,6 +209,7 @@ value you store. Storing the URL instead is what a later rename breaks.
208
209
  await poster.rename("arrival-2016.jpg")
209
210
  await poster.moveTo("posters/2016")
210
211
  await poster.setTags(["poster"]) // replaces the whole list
212
+ await poster.replace(file) // new bytes, same id, name and URL
211
213
  await poster.delete() // refused while an entry refers to it
212
214
  await poster.delete({ force: true })
213
215
 
@@ -217,6 +219,12 @@ usage.total // the true count
217
219
  usage.visible // how many of them this key may see
218
220
  ```
219
221
 
222
+ `replace` swaps the file behind an asset. The id, the reference, the name and
223
+ the URL all stay, so every entry that refers to it shows the new file and none
224
+ of them is rewritten. The new file must keep the same extension. It needs the
225
+ `media:replace` claim, and `entries:update` on each scope that refers to the
226
+ asset.
227
+
220
228
  Folders, and a bulk delete that takes up to 100 ids:
221
229
 
222
230
  ```ts
@@ -312,6 +320,46 @@ await movies.get(id, { timeoutMilliseconds: 2_000 })
312
320
  Nothing is retried for you. A retried `POST` creates a second entry, and only
313
321
  the caller knows whether a call was safe to repeat.
314
322
 
323
+ ## Optional read cache
324
+
325
+ Reads go to the server unless you enable caching. Choose a positive finite
326
+ integer TTL in milliseconds. It starts when a response is stored and does
327
+ not reset on a hit. `maxEntries` is optional; set it to bound memory use in a
328
+ long-running client. When full, the soonest-expiring entry is removed first.
329
+
330
+ ```ts
331
+ const silo = new Silo({
332
+ url: "https://cms.moviespace.com",
333
+ cache: { ttlMilliseconds: 5_000, maxEntries: 100 },
334
+ })
335
+ const movies = silo.scope("moviespace", "prod").collection<Movie>("movies")
336
+
337
+ await movies.get(id) // may use a cached response
338
+ await movies.get(id, { cache: "bypass" }) // fetch without reading or storing
339
+ await movies.get(id, { cache: "refresh" }) // fetch and store on success
340
+ silo.cache.clear() // after a change made elsewhere
341
+ ```
342
+
343
+ Only successful GET JSON responses are cached, with separate entries for
344
+ different URLs, queries and headers, including API keys. Returned objects
345
+ are independent copies. A failed refresh leaves the existing cache unchanged.
346
+ Your writes clear the shared cache before dispatch and after settlement,
347
+ including failures. Pending reads cannot refill it after a clear or overwrite
348
+ a newer read. `health()` always bypasses; `MediaAsset.refresh()` refreshes by
349
+ default and accepts an explicit bypass. Modes do nothing when caching is off.
350
+
351
+ `withKey()` and `withUrl()` share the cache. To share it explicitly, pass
352
+ `cache: otherClient.cache`, or construct `new SiloCache({ ttlMilliseconds: 5000 })`.
353
+ The facade exposes only `enabled`, `size` and `clear()`. Sharing preserves
354
+ isolation by URL and headers. If a custom fetch adds authentication or changes
355
+ the destination, include that context in the client's URL/headers or bypass
356
+ caching.
357
+
358
+ The cache lives in the tab, worker or process. Changes made elsewhere can
359
+ remain hidden until expiry or a fresh read. Infinite TTLs are unsupported;
360
+ `maxEntries` defaults to unlimited and may be `Infinity`. On Deno, an active
361
+ expiry timer can keep the process alive; call `clear()` when finished.
362
+
315
363
  ## Anonymous reads
316
364
 
317
365
  A key is optional. Without one you reach the collections whose schema does not
@@ -0,0 +1,2 @@
1
+ /** Controls an enabled cache for one read. */
2
+ export type CacheMode = "bypass" | "refresh";
@@ -0,0 +1,2 @@
1
+ /** Controls an enabled cache for one read. */
2
+ export type CacheMode = "bypass" | "refresh";
@@ -0,0 +1,16 @@
1
+ import type { SiloCacheOptions } from "./silo-cache-options.cjs";
2
+ interface CachedResponse {
3
+ body: unknown;
4
+ }
5
+ /** The cache's values and pending-read tickets. */
6
+ export declare class ResponseCache {
7
+ #private;
8
+ constructor(options: SiloCacheOptions);
9
+ get size(): number;
10
+ get(key: string): CachedResponse | undefined;
11
+ set(key: string, ticket: symbol, body: unknown): void;
12
+ start(key: string): symbol;
13
+ finish(key: string, ticket: symbol): void;
14
+ clear(): void;
15
+ }
16
+ export {};
@@ -0,0 +1,16 @@
1
+ import type { SiloCacheOptions } from "./silo-cache-options.js";
2
+ interface CachedResponse {
3
+ body: unknown;
4
+ }
5
+ /** The cache's values and pending-read tickets. */
6
+ export declare class ResponseCache {
7
+ #private;
8
+ constructor(options: SiloCacheOptions);
9
+ get size(): number;
10
+ get(key: string): CachedResponse | undefined;
11
+ set(key: string, ticket: symbol, body: unknown): void;
12
+ start(key: string): symbol;
13
+ finish(key: string, ticket: symbol): void;
14
+ clear(): void;
15
+ }
16
+ export {};
@@ -0,0 +1,7 @@
1
+ /** Bounds an opt-in in-memory read cache. */
2
+ export interface SiloCacheOptions {
3
+ /** Positive finite safe integer in milliseconds, counted from storage. */
4
+ ttlMilliseconds: number;
5
+ /** Positive safe integer or Infinity. Omit for no count limit. */
6
+ maxEntries?: number;
7
+ }
@@ -0,0 +1,7 @@
1
+ /** Bounds an opt-in in-memory read cache. */
2
+ export interface SiloCacheOptions {
3
+ /** Positive finite safe integer in milliseconds, counted from storage. */
4
+ ttlMilliseconds: number;
5
+ /** Positive safe integer or Infinity. Omit for no count limit. */
6
+ maxEntries?: number;
7
+ }
@@ -0,0 +1,11 @@
1
+ import type { SiloCacheOptions } from "./silo-cache-options.cjs";
2
+ /** An optional, in-memory cache shared by one or more `Silo` instances. */
3
+ export declare class SiloCache {
4
+ #private;
5
+ constructor(options?: SiloCacheOptions);
6
+ get enabled(): boolean;
7
+ get size(): number;
8
+ /** Clears responses and prevents pending reads from storing their results. */
9
+ clear(): void;
10
+ private static validate;
11
+ }
@@ -0,0 +1,11 @@
1
+ import type { SiloCacheOptions } from "./silo-cache-options.js";
2
+ /** An optional, in-memory cache shared by one or more `Silo` instances. */
3
+ export declare class SiloCache {
4
+ #private;
5
+ constructor(options?: SiloCacheOptions);
6
+ get enabled(): boolean;
7
+ get size(): number;
8
+ /** Clears responses and prevents pending reads from storing their results. */
9
+ clear(): void;
10
+ private static validate;
11
+ }
@@ -8,4 +8,9 @@ export declare class NetworkError extends Error {
8
8
  readonly method: string;
9
9
  readonly path: string;
10
10
  constructor(method: string, path: string, cause: unknown);
11
+ /** What `fetch` rejected with, in the message itself: a `cause` chain is
12
+ * printed by some consoles and by no log line, and "never reached the
13
+ * server" alone reads as a verdict on the network when the fault can be the
14
+ * call. */
15
+ private static reason;
11
16
  }
@@ -8,4 +8,9 @@ export declare class NetworkError extends Error {
8
8
  readonly method: string;
9
9
  readonly path: string;
10
10
  constructor(method: string, path: string, cause: unknown);
11
+ /** What `fetch` rejected with, in the message itself: a `cause` chain is
12
+ * printed by some consoles and by no log line, and "never reached the
13
+ * server" alone reads as a verdict on the network when the fault can be the
14
+ * call. */
15
+ private static reason;
11
16
  }