lazypock 0.2.0 → 0.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 +135 -0
- package/dist/index.cjs +509 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +284 -1
- package/dist/index.d.ts +284 -1
- package/dist/index.global.js +507 -10
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +507 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cache.ts +314 -0
- package/src/collection.ts +71 -5
- package/src/collections.ts +41 -5
- package/src/http.ts +190 -0
- package/src/index.ts +5 -0
- package/src/lazypock.ts +144 -0
- package/src/types.ts +23 -0
package/README.md
CHANGED
|
@@ -179,6 +179,7 @@ The main client class.
|
|
|
179
179
|
| `storage` | `StorageAdapter` | `memoryStorage` | Custom storage adapter for token persistence |
|
|
180
180
|
| `authStore` | `AuthStore` | auto-created | Explicit auth store instance |
|
|
181
181
|
| `realtime` | `RealtimeService` | auto-created | Real-time service for WebSocket subscriptions |
|
|
182
|
+
| `cache` | [`CacheConfig`](#query-cache) | disabled | Query-cache configuration (opt-in) |
|
|
182
183
|
|
|
183
184
|
#### Auto-Cancellation Methods
|
|
184
185
|
|
|
@@ -186,6 +187,14 @@ The main client class.
|
|
|
186
187
|
- `cancelRequest(requestKey)` — Abort a single pending request by key (default `HTTP_METHOD + path`)
|
|
187
188
|
- `cancelAllRequests()` — Abort all pending requests
|
|
188
189
|
|
|
190
|
+
#### Query-Cache Methods
|
|
191
|
+
|
|
192
|
+
- `cache(config?)` — Enable/configure the query cache at runtime (see [Query Cache](#query-cache))
|
|
193
|
+
- `clearCache()` — Drop every cached entry
|
|
194
|
+
- `invalidateCache(namespace)` — Invalidate entries for a collection / custom namespace
|
|
195
|
+
- `cacheStats()` — `{ hits, misses, entries }` cache statistics
|
|
196
|
+
- `invalidateCacheOnRealtime(collection)` — Subscribe the cache to realtime events for a collection; returns an unsubscribe fn
|
|
197
|
+
|
|
189
198
|
#### Authentication Methods
|
|
190
199
|
|
|
191
200
|
- `login(email, password, collection?)` — Login as superuser or auth collection user
|
|
@@ -349,6 +358,132 @@ client.cancelRequest('GET /api/posts?page=1');
|
|
|
349
358
|
client.cancelAllRequests();
|
|
350
359
|
```
|
|
351
360
|
|
|
361
|
+
#### Single-flight dedup (`getFullList`)
|
|
362
|
+
|
|
363
|
+
`getFullList()` (and `collections.getFullList()`) are **single-flight**: concurrent
|
|
364
|
+
calls with the same effective options share one in-flight request instead of
|
|
365
|
+
firing duplicates. This means the common pattern below results in **one**
|
|
366
|
+
network request, and **both** callers resolve with the same data — no abort
|
|
367
|
+
rejection:
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
const [a, b] = await Promise.all([
|
|
371
|
+
client.collection('posts').getFullList(),
|
|
372
|
+
client.collection('posts').getFullList(),
|
|
373
|
+
]);
|
|
374
|
+
// one GET fired; a === b
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Calls with **different** options (e.g. different `sort`/`filter`) are still
|
|
378
|
+
distinct requests. Multi-page fetches continue to work normally — each page
|
|
379
|
+
request is unique (page number is part of the URL), so pages never cancel each
|
|
380
|
+
other.
|
|
381
|
+
|
|
382
|
+
The underlying `singleFlight` option is also available on any request when you
|
|
383
|
+
want to coalesce concurrent identical calls yourself:
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
await client.collection('posts').getList(1, 20, { singleFlight: true });
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## Query Cache
|
|
390
|
+
|
|
391
|
+
Lazypock has a built-in query cache for **GET** requests — disabled by default.
|
|
392
|
+
It's useful for read-heavy UIs (lists, dashboards) to avoid hammering the server.
|
|
393
|
+
|
|
394
|
+
### Enabling
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
import { createClient } from "lazypock";
|
|
398
|
+
|
|
399
|
+
const client = createClient({
|
|
400
|
+
baseUrl: "https://api.example.com",
|
|
401
|
+
cache: {
|
|
402
|
+
enabled: true,
|
|
403
|
+
defaultTTL: 30_000, // 30s
|
|
404
|
+
// store: myStorage, // optional: reuse any StorageAdapter (localStorage/AsyncStorage)
|
|
405
|
+
},
|
|
406
|
+
});
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
When enabled, **all** GET requests are cached with the default TTL, and
|
|
410
|
+
mutations (`create`/`update`/`delete`) automatically invalidate the affected
|
|
411
|
+
collection's cached entries.
|
|
412
|
+
|
|
413
|
+
### Per-request control
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
// Cache this request (works even when the global cache is off)
|
|
417
|
+
await client.collection('posts').getList(1, 20, { cache: true });
|
|
418
|
+
|
|
419
|
+
// Bypass the cache — always fetch fresh (and don't store the result)
|
|
420
|
+
const fresh = await client.collection('posts').getList(1, 20, { cache: false });
|
|
421
|
+
|
|
422
|
+
// Custom TTL for this request
|
|
423
|
+
await client.collection('posts').getOne('abc', { ttl: 120_000 });
|
|
424
|
+
|
|
425
|
+
// Cache with a custom key (dedupe/override the default `METHOD path|token` key)
|
|
426
|
+
await client.collection('posts').getList(1, 20, { cache: { ttl: 60_000, key: 'my-list' } });
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Prefix deletion (per-operation invalidation)
|
|
430
|
+
|
|
431
|
+
Every cached entry is tagged with its operation and collection, so you can
|
|
432
|
+
invalidate a whole class of caches without touching the rest:
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
client.cache.deleteByPrefix('getList:posts'); // delete all getList cache for posts
|
|
436
|
+
client.cache.deleteByPrefix('getOne:posts'); // delete all getOne cache for posts
|
|
437
|
+
client.cache.deleteByPrefix('collections:getList'); // admin collection list caches
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
The `client.cache` namespace also exposes `invalidate(ns)`, `clear()`, `stats()`,
|
|
441
|
+
and is callable to (re)configure (`client.cache({ enabled: true })`).
|
|
442
|
+
|
|
443
|
+
### Invalidation
|
|
444
|
+
|
|
445
|
+
```typescript
|
|
446
|
+
// Mutations invalidate the collection automatically:
|
|
447
|
+
await client.collection('posts').create({ title: 'New' });
|
|
448
|
+
await client.collection('posts').getList(1, 20); // re-fetched (cache cleared)
|
|
449
|
+
|
|
450
|
+
// Invalidate extra namespaces explicitly:
|
|
451
|
+
await client.collection('posts').create(
|
|
452
|
+
{ title: 'New' },
|
|
453
|
+
{ invalidate: ['users'] },
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
// Manual / out-of-band invalidation:
|
|
457
|
+
client.invalidateCache('posts');
|
|
458
|
+
client.clearCache();
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Cache key scoping
|
|
462
|
+
|
|
463
|
+
Cache keys are **scoped by auth token** — a logged-in user's cached data can
|
|
464
|
+
never leak to another user (or to anonymous visitors). Logging out/in changes
|
|
465
|
+
the token, so cached entries are naturally isolated per identity.
|
|
466
|
+
|
|
467
|
+
### Realtime-driven invalidation
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
// Keep the posts cache fresh: any create/update/delete event clears it.
|
|
471
|
+
const stop = client.invalidateCacheOnRealtime('posts');
|
|
472
|
+
// later:
|
|
473
|
+
stop();
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
When a realtime event arrives for the collection, its cached entries are
|
|
477
|
+
cleared so the next read fetches fresh data. This is **invalidate-only** —
|
|
478
|
+
cached list payloads are never mutated in place (a filter/sort change could
|
|
479
|
+
make an in-place patch serve wrong data).
|
|
480
|
+
|
|
481
|
+
### Stats
|
|
482
|
+
|
|
483
|
+
```typescript
|
|
484
|
+
client.cacheStats(); // { hits, misses, entries }
|
|
485
|
+
```
|
|
486
|
+
|
|
352
487
|
## Error Handling
|
|
353
488
|
|
|
354
489
|
The SDK throws `ApiError` on non-2xx responses:
|