@crowdedkingdoms/crowdyjs 8.1.0 → 8.2.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 CHANGED
@@ -12,7 +12,7 @@ npm install @crowdedkingdoms/crowdyjs
12
12
 
13
13
  CrowdyJS v4 targets browsers by default and uses native `fetch`, `WebSocket`, `crypto`, `btoa`, and `atob`. Node tools can still use the SDK, but must provide browser-compatible globals when opening realtime connections.
14
14
 
15
- > **Server compatibility:** v5.2+ targets environments on release **v0.1.19 or later** (`cks-game-api >= v0.10.3`, `cks-management-api >= v0.1.70`). The destructive mutations send an `idempotencyKey` argument that older servers don't define. v6.1's `client.gameApps.deleteGrid` additionally requires release **v0.1.33+** (`cks-game-api >= v0.12.3`). The game-model **permission effects** fields (`permissionEffects` on `gameModel.upsertFunction`/`seed`, `permissionEffectsAppliedJson` on events) require a `cks-game-api` build with the `2026-07-17-model-permission-effects` migration; older servers reject queries/mutations that include them (omit the fields and everything else keeps working).
15
+ > **Server compatibility:** v5.2+ targets environments on release **v0.1.19 or later** (`cks-game-api >= v0.10.3`, `cks-management-api >= v0.1.70`). The destructive mutations send an `idempotencyKey` argument that older servers don't define. v6.1's `client.gameApps.deleteGrid` additionally requires release **v0.1.33+** (`cks-game-api >= v0.12.3`). The game-model **permission effects** fields (`permissionEffects` on `gameModel.upsertFunction`/`seed`, `permissionEffectsAppliedJson` on events) require a `cks-game-api` build with the `2026-07-17-model-permission-effects` migration (v0.13.11+); older servers reject queries/mutations that include them (omit the fields and everything else keeps working). The **permission-read** surface (the `has_grid_permission`/`grid_at`/`has_chunk_permission` expression builtins the kit's `chunkPermission` locks compile to, and selector `*PermissionWhere` predicates) additionally requires `cks-game-api` **v0.13.12+**.
16
16
 
17
17
  ## Standalone builds and schema refresh
18
18
 
@@ -106,7 +106,7 @@ If `managementUrl` is omitted, the SDK falls back to `httpUrl` for backwards-com
106
106
  | `client.udp` | UDP proxy subscriptions + spatial mutations (`sendActorUpdate`, `sendVoxelUpdate`, `sendAudioPacket`, `sendTextPacket`, `sendClientEvent`). |
107
107
  | `client.realtime` | Connection status, manual `connect()` / `disconnect()`, `onStatus()` listener. |
108
108
  | `client.world(appId)` | Higher-level helpers for browser games (`actor.join`, `actor.sendState`, `actor.sendText`). |
109
- | `client.kit(appId)` | Game Kit: ready-made mappings of game concepts onto the game model — `kit.inventory`, `kit.objects` (lockable doors/chests with custom permissions), `kit.npcs`, plus blueprint builders + `kit.deploy(...)` for the admin "load the rules" step. |
109
+ | `client.kit(appId)` | Game Kit: ready-made mappings of game concepts onto the game model — `kit.inventory`, `kit.objects` (lockable doors/chests with custom permissions), `kit.npcs`, `kit.plots` (buy/rent land with transactional, replication-enforced grid grants), plus blueprint builders + `kit.deploy(...)` for the admin "load the rules" step. |
110
110
 
111
111
  **Studio-admin surface** (privileged; drive with a server-side / studio token, grouped under `client.admin`):
112
112
 
@@ -304,6 +304,27 @@ const result = await kit.objects.open(doorId, { keyId });
304
304
  if (!result.success) console.warn('locked:', result.errorMessage);
305
305
  ```
306
306
 
307
+ Land sale closes the permission loop end to end (requires game-api v0.13.11+ for
308
+ effects, v0.13.12+ for the chunk-permission reads):
309
+
310
+ ```ts
311
+ // Studio: sell a plot over a grid; doors on it honor the purchase automatically.
312
+ await admin.kit(appId).deploy([
313
+ plotBlueprint({ rentable: true }),
314
+ lockBlueprint({ objectTypeName: 'PlotDoor',
315
+ authority: { kind: 'chunkPermission', key: 'access', mode: 'smallest' } }),
316
+ ]);
317
+
318
+ // Game client: buying spends gold AND grants enforced grid access atomically.
319
+ const buy = await kit.plots.buy(plotId, walletId);
320
+ if (buy.success) await kit.objects.open(doorId); // has_chunk_permission passes now
321
+ ```
322
+
323
+ NPC blueprints can target by permissions too — e.g. a guard automation whose
324
+ selector has `candidatePermissionWhere: [{ userFrom: { property: 'owner_user_id' },
325
+ op: 'lacks', key: 'access', grid: { property: 'grid_id' } }]` reacts only to
326
+ intruders.
327
+
307
328
  See the docs guides [Modeling game concepts](https://docs.crowdedkingdoms.com/game-api/modeling-game-concepts)
308
329
  (the underlying model) and [Game Kit](https://docs.crowdedkingdoms.com/crowdyjs/game-kit)
309
330
  (the SDK surface).
@@ -155,7 +155,7 @@ export class CrowdyClient {
155
155
  * non-default type names/prefixes.
156
156
  */
157
157
  kit(appId, options) {
158
- return new GameKitClient(appId, this.gameModel, options);
158
+ return new GameKitClient(appId, this.gameModel, this.gameApps, options);
159
159
  }
160
160
  /** Closes the WebSocket and clears the in-memory auth token. */
161
161
  close() {
@@ -6026,7 +6026,7 @@ export type UpsertAutomationInput = {
6026
6026
  runTimeoutMs?: InputMaybe<Scalars['Int']['input']>;
6027
6027
  /** For schedule triggers: interval | cron. */
6028
6028
  scheduleKind?: InputMaybe<Scalars['String']['input']>;
6029
- /** JSON selector resolving candidate refs/scalars over model data into params (e.g. {"pick":"nearest","ofType":"Unit","where":[...],"by":"manhattan","bindAs":{...}}). */
6029
+ /** JSON selector resolving candidate refs/scalars over model data into params (e.g. {"pick":"nearest","ofType":"Unit","where":[...],"by":"manhattan","bindAs":{...}}). Also supports grid-permission filters "selfPermissionWhere"/"candidatePermissionWhere": arrays of {"userFrom":"owner"|{"property":k},"op":"has"|"lacks","key":<runtime permission key>,"grid":<id>|{"property":k}} checked against the live grid ACL (omit "grid" for any-grid). */
6030
6030
  selectorJson?: InputMaybe<Scalars['String']['input']>;
6031
6031
  /** For target_mode=container: the self container UUID. */
6032
6032
  selfContainerId?: InputMaybe<Scalars['String']['input']>;