@benmore/bm 2.7.329 → 2.7.331

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 (3) hide show
  1. package/index.d.ts +4 -1
  2. package/index.js +35 -16
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -434,8 +434,11 @@ export const query: {
434
434
  fetch<T = unknown>(key: unknown, fetcher: () => Promise<T> | T, opts?: QueryFetchOpts): Promise<T>;
435
435
  refetch<T = unknown>(key: unknown): Promise<T | undefined>;
436
436
  invalidate(match: unknown | ((rawKey: unknown, stableKey: string) => boolean), opts?: { refetch?: boolean }): string[];
437
- tableKey(table: string, spec?: Record<string, unknown>): unknown[];
437
+ /** The key table(table, opts) caches under, for the same arguments: opts.key when given, else derived from the request. Pass it to subscribe/get/set/invalidate/mutate. */
438
+ tableKey(table: string, opts?: Omit<QuerySpec, "table"> & QueryFetchOpts): unknown;
439
+ /** Cached under opts.key when given: name one to subscribe to the result. */
438
440
  read<T = unknown>(spec: QuerySpec, opts?: QueryFetchOpts): Promise<T[]>;
441
+ /** Cached under tableKey(table, opts). */
439
442
  table<T = unknown>(table: string, opts?: Omit<QuerySpec, "table"> & QueryFetchOpts): Promise<T[]>;
440
443
  invalidateTable(table: string, opts?: { refetch?: boolean }): string[];
441
444
  mutate<T = unknown>(opts: QueryMutateOpts<T>): Promise<T>;
package/index.js CHANGED
@@ -897,7 +897,10 @@ export function room(name) {
897
897
  try { msg = JSON.parse(ev.data); } catch { return; }
898
898
  if (!msg || typeof msg !== 'object') return;
899
899
  if (msg.type === 'error') {
900
- // The server's only error frames refuse a join; on this room's own
900
+ // An error frame with `tables` answers a table subscribe sent on
901
+ // this socket (unknown table names): it is not about the room.
902
+ if (Array.isArray(msg.tables)) return;
903
+ // Every other error frame refuses a join; on this room's own
901
904
  // connection that refusal is final.
902
905
  const message = typeof msg.body === 'string' && msg.body ? msg.body : 'room error';
903
906
  const code = roomErrorCode(msg.body);
@@ -2251,6 +2254,26 @@ function rememberTableKey(tableName, key) {
2251
2254
  _queryTableKeys.get(tableName).add(k);
2252
2255
  }
2253
2256
 
2257
+ // The key a table read is cached under, and the request it sends. One
2258
+ // function answers both bm.query.table and bm.query.tableKey, so a subscriber
2259
+ // to tableKey(name, opts) reads the entry table(name, opts) writes.
2260
+ function defaultReadKey(spec) {
2261
+ return ['query', spec];
2262
+ }
2263
+
2264
+ function tableRead(tableName, opts) {
2265
+ // Separate client control options (which never affect the server result)
2266
+ // from the server-affecting query spec. Only the spec may influence the
2267
+ // cache key, otherwise two identical reads that differ only in staleTime/
2268
+ // force/live would fragment into distinct cache entries and defeat dedupe.
2269
+ const { staleTime, staleMs, force, live, key, ...serverOpts } = opts || {};
2270
+ const spec = { ...serverOpts, table: tableName };
2271
+ // The default is read()'s ['query', spec] key shape, so that a
2272
+ // bm.query.table('posts') and bm.query.read({ table: 'posts' }) targeting
2273
+ // identical rows collapse onto one shared cache entry.
2274
+ return { spec, key: key || defaultReadKey(spec), control: { staleTime, staleMs, force, live } };
2275
+ }
2276
+
2254
2277
  function ensureQueryLiveInvalidation() {
2255
2278
  if (_queryLiveStop || typeof live !== 'function' || typeof EventSource === 'undefined') return;
2256
2279
  const stop = live('*', (ev) => {
@@ -2355,7 +2378,7 @@ export const query = {
2355
2378
  // We deliberately avoid raw string startsWith on the stable-stringified key
2356
2379
  // because that produced false positives (e.g. {a:1} matching {a:1,b:2}, or
2357
2380
  // ['user'] matching ['username']). Array-prefix is predictable for the
2358
- // common ['table', name, spec] / ['query', spec] key shapes used here.
2381
+ // ['query', spec] key shape used here and for an app's own array keys.
2359
2382
  const matchExact = typeof match !== 'function' ? queryKey(match) : null;
2360
2383
  const matchPrefix = (typeof match !== 'function' && Array.isArray(match)) ? match : null;
2361
2384
  const isArrayPrefix = (prefix, raw) => {
@@ -2379,12 +2402,15 @@ export const query = {
2379
2402
  }
2380
2403
  return keys;
2381
2404
  },
2382
- tableKey(tableName, spec = {}) {
2383
- return ['table', tableName, spec];
2405
+ // The key bm.query.table(tableName, opts) caches under, for subscribe/get/
2406
+ // set/invalidate/mutate: opts.key when the caller names one, otherwise the
2407
+ // key derived from the request.
2408
+ tableKey(tableName, opts = {}) {
2409
+ return tableRead(tableName, opts).key;
2384
2410
  },
2385
2411
  async read(spec, opts = {}) {
2386
2412
  if (!spec || !spec.table) throw new Error('bm.query.read({ table, ... }) requires table');
2387
- const key = opts.key || ['query', spec];
2413
+ const key = opts.key || defaultReadKey(spec);
2388
2414
  if (opts.live !== false) {
2389
2415
  rememberTableKey(spec.table, key);
2390
2416
  ensureQueryLiveInvalidation();
@@ -2395,17 +2421,10 @@ export const query = {
2395
2421
  }, opts);
2396
2422
  },
2397
2423
  table(tableName, opts = {}) {
2398
- // Separate client control options (which never affect the server result)
2399
- // from the server-affecting query spec. Only the spec may influence the
2400
- // cache key, otherwise two identical reads that differ only in staleTime/
2401
- // force/live would fragment into distinct cache entries and defeat dedupe.
2402
- const { staleTime, staleMs, force, live, key, ...serverOpts } = opts;
2403
- const spec = { ...serverOpts, table: tableName };
2404
- // Route through read() with the same ['query', spec] key shape so that a
2405
- // bm.query.table('posts') and bm.query.read({ table: 'posts' }) targeting
2406
- // identical rows collapse onto one shared cache entry. Forward every client
2407
- // control option (staleTime/staleMs/force/live) so none are silently dropped.
2408
- return query.read(spec, { key: key, staleTime, staleMs, force, live });
2424
+ // Forward every client control option (staleTime/staleMs/force/live) so
2425
+ // none are silently dropped.
2426
+ const { spec, key, control } = tableRead(tableName, opts);
2427
+ return query.read(spec, { ...control, key });
2409
2428
  },
2410
2429
  invalidateTable(tableName, opts = {}) {
2411
2430
  const keys = _queryTableKeys.get(tableName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@benmore/bm",
3
- "version": "2.7.329",
3
+ "version": "2.7.331",
4
4
  "description": "Zero-dependency browser SDK for external Benmore frontends",
5
5
  "type": "module",
6
6
  "module": "./index.js",