@abloatai/humans 0.64.1 → 0.64.3

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.
@@ -249,10 +249,11 @@ export declare class BaseSyncedStore<TCollaboration extends EventMap<TCollaborat
249
249
  /**
250
250
  * Bring a scope into view and subscribe to its sync groups. With
251
251
  * `{ hydrate: true }`, also backfill the groups' current state into the pool
252
- * once the subscription is active. The order matters: subscribing first
253
- * guarantees no live delta is missed in the gap before the snapshot lands.
254
- * Hydration is best-effort — a failed backfill never rejects `enterScope`,
255
- * and the live delta stream keeps flowing regardless.
252
+ * after subscription reconciliation. Offline reconciliation may only record
253
+ * interest locally; it is not proof that the server is delivering changes.
254
+ * Hydration is best-effort: failure leaves the groups unmarked for retry and
255
+ * does not reject `enterScope`. Snapshot application uses version guards so
256
+ * older baseline rows cannot overwrite newer deltas already in the pool.
256
257
  */
257
258
  enterScope(scope: GroupScope, opts?: {
258
259
  hydrate?: boolean;
@@ -167,28 +167,26 @@ export class BaseSyncedStore {
167
167
  sendCollaborationEvent(messageType, payload) {
168
168
  this.syncWebSocket.sendCollaborationEvent(messageType, payload);
169
169
  }
170
- // ── Area-of-interest (dynamic read subscription) ─────────────────
170
+ // ── Group interest and loading ──────────────────────────────────
171
171
  //
172
- // `enterScope`/`leaveScope` move the connection's read interest as the
173
- // user navigates (open or close a record); `pinScope`/`unpinScope`
174
- // express prominence (an active claim keeps a group subscribed). All four
175
- // resolve the scope to sync-group strings through the same resolver the
176
- // claim path uses (`resolveParticipantSyncGroups`), so read interest and
177
- // write claims always agree on the string for a given entity. Before the
178
- // connection opens they record interest without a wire send, and they
179
- // never reject when the transport is offline (see
180
- // {@link SubscriptionManager.reconcile}); the on-connect `resync` pushes
181
- // whatever interest accumulated.
172
+ // Authority comes from the server-issued session. Enter/leave track what
173
+ // this connection wants to receive; pin/unpin keep an active scope subscribed.
174
+ // All resolve selectors through scopeToGroups. Hydration separately loads
175
+ // a scoped baseline into the local pool. Leaving interest does not revoke
176
+ // authority or selectively evict cached records.
177
+ // Offline interest is recorded locally and reconciled when the connection
178
+ // opens; recording interest is not confirmation of a server subscription.
182
179
  scopeToGroups(scope) {
183
180
  return resolveScopeGroups(scope, this.schema);
184
181
  }
185
182
  /**
186
183
  * Bring a scope into view and subscribe to its sync groups. With
187
184
  * `{ hydrate: true }`, also backfill the groups' current state into the pool
188
- * once the subscription is active. The order matters: subscribing first
189
- * guarantees no live delta is missed in the gap before the snapshot lands.
190
- * Hydration is best-effort — a failed backfill never rejects `enterScope`,
191
- * and the live delta stream keeps flowing regardless.
185
+ * after subscription reconciliation. Offline reconciliation may only record
186
+ * interest locally; it is not proof that the server is delivering changes.
187
+ * Hydration is best-effort: failure leaves the groups unmarked for retry and
188
+ * does not reject `enterScope`. Snapshot application uses version guards so
189
+ * older baseline rows cannot overwrite newer deltas already in the pool.
192
190
  */
193
191
  enterScope(scope, opts) {
194
192
  const groups = this.scopeToGroups(scope);
@@ -1,10 +1,13 @@
1
1
  /**
2
2
  * Handles the delta types that change which sync groups a session can see. A
3
- * sync group is a fan-out scope the server uses to decide which entities a
4
- * client receives. When a session's membership changes, these handlers update
3
+ * sync group connects shared state to authorized participant subscriptions.
4
+ * This module owns the client side of membership changes and local-state
5
+ * rebuilding; it neither grants server authority nor configures per-group loading.
6
+ * When a session's membership changes, these handlers update
5
7
  * the client's subscription list; when access is revoked, they clear cached
6
- * data and trigger a full re-bootstrap so revoked rows cannot linger on the
7
- * device.
8
+ * managed data and request re-bootstrap. Clients without automatic bootstrap
9
+ * rely on covering deltas or explicit reads instead. This cannot retract copies
10
+ * retained outside the managed cache.
8
11
  *
9
12
  * Every handler takes a {@link GroupChangeContext}, the narrow facade through
10
13
  * which it reaches the client's local storage and connection lifecycle hooks.
@@ -1,10 +1,13 @@
1
1
  /**
2
2
  * Handles the delta types that change which sync groups a session can see. A
3
- * sync group is a fan-out scope the server uses to decide which entities a
4
- * client receives. When a session's membership changes, these handlers update
3
+ * sync group connects shared state to authorized participant subscriptions.
4
+ * This module owns the client side of membership changes and local-state
5
+ * rebuilding; it neither grants server authority nor configures per-group loading.
6
+ * When a session's membership changes, these handlers update
5
7
  * the client's subscription list; when access is revoked, they clear cached
6
- * data and trigger a full re-bootstrap so revoked rows cannot linger on the
7
- * device.
8
+ * managed data and request re-bootstrap. Clients without automatic bootstrap
9
+ * rely on covering deltas or explicit reads instead. This cannot retract copies
10
+ * retained outside the managed cache.
8
11
  *
9
12
  * Every handler takes a {@link GroupChangeContext}, the narrow facade through
10
13
  * which it reaches the client's local storage and connection lifecycle hooks.
@@ -1,6 +1,9 @@
1
1
  import type { ClaimTarget } from '@abloatai/transaction/types/streams';
2
2
  import type { Schema } from '@abloatai/transaction/schema/schema';
3
- /** A schema-shaped selector used to narrow connection groups and presence reads. */
3
+ /**
4
+ * Selects group interest using model records or explicit group names. Resolving
5
+ * a selector names a requested scope; the server still checks authority.
6
+ */
4
7
  export type GroupScope = ClaimTarget | readonly ClaimTarget[] | string | readonly string[] | {
5
8
  readonly syncGroup: string;
6
9
  } | {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abloatai/humans",
3
- "version": "0.64.1",
3
+ "version": "0.64.3",
4
4
  "description": "The optional human-facing local-state package for Ablo: presence, live queries, and React bindings.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -85,7 +85,8 @@
85
85
  "directory": "packages/humans"
86
86
  },
87
87
  "dependencies": {
88
- "@abloatai/transaction": "0.64.1",
88
+ "@abloatai/transaction": "0.64.3",
89
+ "events": "^3.3.0",
89
90
  "mobx": "^6.13.7",
90
91
  "uuid": "^11.1.0",
91
92
  "zod": "^4.4.3"
@@ -379,18 +379,15 @@ export class BaseSyncedStore<
379
379
  this.syncWebSocket.sendCollaborationEvent(messageType, payload);
380
380
  }
381
381
 
382
- // ── Area-of-interest (dynamic read subscription) ─────────────────
382
+ // ── Group interest and loading ──────────────────────────────────
383
383
  //
384
- // `enterScope`/`leaveScope` move the connection's read interest as the
385
- // user navigates (open or close a record); `pinScope`/`unpinScope`
386
- // express prominence (an active claim keeps a group subscribed). All four
387
- // resolve the scope to sync-group strings through the same resolver the
388
- // claim path uses (`resolveParticipantSyncGroups`), so read interest and
389
- // write claims always agree on the string for a given entity. Before the
390
- // connection opens they record interest without a wire send, and they
391
- // never reject when the transport is offline (see
392
- // {@link SubscriptionManager.reconcile}); the on-connect `resync` pushes
393
- // whatever interest accumulated.
384
+ // Authority comes from the server-issued session. Enter/leave track what
385
+ // this connection wants to receive; pin/unpin keep an active scope subscribed.
386
+ // All resolve selectors through scopeToGroups. Hydration separately loads
387
+ // a scoped baseline into the local pool. Leaving interest does not revoke
388
+ // authority or selectively evict cached records.
389
+ // Offline interest is recorded locally and reconciled when the connection
390
+ // opens; recording interest is not confirmation of a server subscription.
394
391
 
395
392
  private scopeToGroups(scope: GroupScope): string[] {
396
393
  return resolveScopeGroups(scope, this.schema);
@@ -399,10 +396,11 @@ export class BaseSyncedStore<
399
396
  /**
400
397
  * Bring a scope into view and subscribe to its sync groups. With
401
398
  * `{ hydrate: true }`, also backfill the groups' current state into the pool
402
- * once the subscription is active. The order matters: subscribing first
403
- * guarantees no live delta is missed in the gap before the snapshot lands.
404
- * Hydration is best-effort — a failed backfill never rejects `enterScope`,
405
- * and the live delta stream keeps flowing regardless.
399
+ * after subscription reconciliation. Offline reconciliation may only record
400
+ * interest locally; it is not proof that the server is delivering changes.
401
+ * Hydration is best-effort: failure leaves the groups unmarked for retry and
402
+ * does not reject `enterScope`. Snapshot application uses version guards so
403
+ * older baseline rows cannot overwrite newer deltas already in the pool.
406
404
  */
407
405
  enterScope(scope: GroupScope, opts?: { hydrate?: boolean }): Promise<void> {
408
406
  const groups = this.scopeToGroups(scope);
@@ -1,10 +1,13 @@
1
1
  /**
2
2
  * Handles the delta types that change which sync groups a session can see. A
3
- * sync group is a fan-out scope the server uses to decide which entities a
4
- * client receives. When a session's membership changes, these handlers update
3
+ * sync group connects shared state to authorized participant subscriptions.
4
+ * This module owns the client side of membership changes and local-state
5
+ * rebuilding; it neither grants server authority nor configures per-group loading.
6
+ * When a session's membership changes, these handlers update
5
7
  * the client's subscription list; when access is revoked, they clear cached
6
- * data and trigger a full re-bootstrap so revoked rows cannot linger on the
7
- * device.
8
+ * managed data and request re-bootstrap. Clients without automatic bootstrap
9
+ * rely on covering deltas or explicit reads instead. This cannot retract copies
10
+ * retained outside the managed cache.
8
11
  *
9
12
  * Every handler takes a {@link GroupChangeContext}, the narrow facade through
10
13
  * which it reaches the client's local storage and connection lifecycle hooks.
@@ -2,7 +2,10 @@ import type { ClaimTarget } from '@abloatai/transaction/types/streams';
2
2
  import type { Schema } from '@abloatai/transaction/schema/schema';
3
3
  import { scopeKindOf, type ModelDef } from '@abloatai/transaction/schema/model';
4
4
 
5
- /** A schema-shaped selector used to narrow connection groups and presence reads. */
5
+ /**
6
+ * Selects group interest using model records or explicit group names. Resolving
7
+ * a selector names a requested scope; the server still checks authority.
8
+ */
6
9
  export type GroupScope =
7
10
  | ClaimTarget
8
11
  | readonly ClaimTarget[]