@onlyworlds/sdk 4.7.0 → 4.7.2

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/AGENTS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # For AI agents using @onlyworlds/sdk
2
2
 
3
- **Current as of**: SDK **4.x** · schema-dist **v0.30.1-dist.15** (canonical 00.30.01).
3
+ **Current as of**: SDK **4.x** · schema-dist **v0.31.0-dist.18** (canonical 00.31.00).
4
4
  This line is asserted by `codegen:check` in CI — if the pin moves and this file is not
5
5
  re-read against it, the check fails rather than letting this document rot quietly.
6
6
 
package/CHANGELOG.md CHANGED
@@ -1,10 +1,38 @@
1
1
  # Changelog
2
2
 
3
- All notable changes to `@onlyworlds/sdk`. Maintained from 3.1.0 onward (Kael, Assembly);
3
+ All notable changes to `@onlyworlds/sdk`. Maintained from 3.1.0 onward;
4
4
  earlier history lives in git log only.
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [4.7.2] — 2026-10-09
9
+
10
+ ### Changed
11
+ - **README first run** finds Admiral Fluffington by name (the demo world's default list order moves with every edit, so "the first three" could not be promised); the npm page shows the corrected output.
12
+ - **Schema repinned `v0.30.2-dist.16` → `v0.31.0-dist.18`** (canonical **00.31.00**).
13
+ `ONLYWORLDS_VERSION` is now `'00.31.00'`. The World gains three optional free-text settings,
14
+ `length_unit`, `mass_unit` and `distance_unit`; the nine element fields that promised "world
15
+ LENGTH / MASS / DISTANCE units" now name them in their descriptions (Ability `range`, Character
16
+ and Creature `height` and `weight`, Creature `speed`, Location `elevation`, Object and Species
17
+ `weight`). No element field shape and no `FIELD_SCHEMA` entry changed. The world body is not
18
+ typed per field (`OwWorldMeta` is open), so `getWorld` returns the three keys and `patchWorld`
19
+ sends them with no code change; a test says so.
20
+
21
+ ## [4.7.1] — 2026-10-08
22
+
23
+ ### Changed
24
+ - **README rewritten**: install, a first run against the public demo world (its output shown,
25
+ run as written), your own world with an agent seat for writes, then the reference. It no
26
+ longer calls a `world` field in a payload an error: the API ignores it.
27
+ - Comments, the RFC and pin-file prose no longer name people or internal places.
28
+ - **Schema repinned `v0.30.1-dist.15` → `v0.30.2-dist.16`** (canonical **00.30.02**).
29
+ `ONLYWORLDS_VERSION` is now `'00.30.02'`. Field descriptions move with the schema: Location's
30
+ `rivalries` and `partnerships`, Marker's `order`, and Pin's `element` pair. No field shape and
31
+ no `FIELD_SCHEMA` entry changed: canonical now requires only `name` on every type, which is
32
+ what `FIELD_SCHEMA` already said, so its hand-made exception for the old Pin and Marker
33
+ lists is gone. If the schema lists more than `name` again, codegen stops and asks for a
34
+ ruling instead of dropping the list. 31/31 file hashes recomputed from the tag.
35
+
8
36
  ## [4.7.0] — 2026-10-08
9
37
 
10
38
  ### Added
@@ -36,7 +64,7 @@ Includes 4.5.1's documentation fixes: 4.5.1 was staged and never published.
36
64
  refusals (`ticket_used`, `ticket_expired`, `bad_key`, `exists`, `unsupported_type`, ...) arrive
37
65
  as `OwApiError` with their code. Set the returned `url` as an element's `image_url` yourself.
38
66
  Checked live on 2026-10-06: one upload through keel's ticket to the edge (201), and the same
39
- ticket again refused with 401 `ticket_used` (Keel #59).
67
+ ticket again refused with 401 `ticket_used`.
40
68
  - **`createMediaTicket()`**: the first step alone, for callers that upload themselves (progress
41
69
  bars, say). Types `OwMediaTicket` and `OwUploadedImage`.
42
70
 
@@ -51,11 +79,11 @@ Docs only: no code path changes.
51
79
  ### Documented
52
80
  - **`isOwnerOnly`'s JSDoc in 4.5.0 was wrong about who sees `owner_only`.** It said owners and
53
81
  co-builders never see it. A member key, a co-builder's too, gets it on `PATCH /world`; only the
54
- owner's key is exempt (keel spec section 9; confirmed from keel's `patch_world` by Skeld,
82
+ owner's key is exempt (keel spec section 9; confirmed from keel's `patch_world`,
55
83
  2026-10-04).
56
84
  - **`world_gone` is reserved.** `OwAuthErrorCode` and `isAuthError` still carry it, but keel never
57
85
  emits it: a deleted world's keys are deleted with it, so the key answers 401 `invalid_credentials`
58
- (Skeld, 2026-10-04; keel spec section 2, T6b). Found by the wire gate reading the SDK's own
86
+ (2026-10-04; keel spec section 2). Found by the wire gate reading the SDK's own
59
87
  built file for the codes it keys on.
60
88
 
61
89
  ## [4.5.0] — 2026-10-04
@@ -66,7 +94,7 @@ three behaviours the server has always had that no client doc said. Additive; no
66
94
  ### Added
67
95
  - **`OwApiError.isOwnerOnly`**: 403 `owner_only`, a contributor attempting a world-level change
68
96
  (`patchWorld`, publishing a show page). Owners and co-builders never see it. keel's OpenAPI
69
- document does not name the code yet (Skeld has that to close); the wire returns it.
97
+ document does not name the code yet (the schema side has that to close); the wire returns it.
70
98
 
71
99
  ### Documented
72
100
  - **An atomic `/bulk` rollback still returns 201 slots** for the items that would have
@@ -95,10 +123,10 @@ contributor meets on someone else's. Additive; nothing is removed or narrows.
95
123
  ### Fixed
96
124
  - **`FIELD_SCHEMA` no longer marks `marker.map/zone/x/y/order` and `pin.map/element_type/element_id/x/y`
97
125
  as `required: true`.** The wire requires `name` and nothing else (rulings.yaml `nullable-by-default`,
98
- Captain 2026-07-28; keel's OpenAPI write schemas say `required: [name]`), but the schema files still
126
+ ruling 2026-07-28; keel's OpenAPI write schemas say `required: [name]`), but the schema files still
99
127
  list those fields and the generator copied the lists, so a form built from the table demanded
100
128
  coordinates the server never did. Found by comparing the SDK with keel's OpenAPI document (the
101
- new `verify-sdk-wire` gate in Assembly). **If you read `required` from this table, marker and pin
129
+ new `verify-sdk-wire` gate). **If you read `required` from this table, marker and pin
102
130
  fields now read as optional**, which is what the server accepts. The generator notes the lists it
103
131
  ignores on every run and says when canonical stops carrying them.
104
132
 
@@ -146,7 +174,7 @@ Ids, honest filter docs, and the schema repin. Nothing is removed; no call needs
146
174
  order elements by id. For creation order use `created_at`; `change_seq` is last-write
147
175
  order. This is a **default, not a
148
176
  requirement**: a v4 or v7 id a caller supplies is still accepted as-is, and
149
- every id already stored stays valid. Keel mints v7 server-side too (Captain's ruling,
177
+ every id already stored stays valid. Keel mints v7 server-side too (ruling,
150
178
  2026-09-28). Pinned by six tests: version and variant, the big-endian timestamp above
151
179
  bit 32, fractional and pre-1970 clocks floored consistently, creation order across 50
152
180
  consecutive milliseconds, 1,000 distinct ids inside one millisecond, and the no-`crypto`
@@ -156,7 +184,7 @@ Ids, honest filter docs, and the schema repin. Nothing is removed; no call needs
156
184
  edges, and keel's `uuid7()` agrees on timestamp, version and variant for a pinned clock.
157
185
  - **`elementColor()` on an unknown type now throws a `TypeError` that names the type.** It
158
186
  used to crash with `Cannot read properties of undefined (reading 'dark')`. Found while
159
- building the Forge's colour gate: atlas's own copy falls back to the `world` family for an
187
+ building a colour gate: atlas's own copy falls back to the `world` family for an
160
188
  unknown type, so swapping it for this export is not a pure re-export for that input, and the
161
189
  docstring now says so. Whether the package should fall back is left to its consumers.
162
190
  - The generated field-schema comment no longer calls `maximum:` an open question or counts
@@ -303,7 +331,7 @@ pinned consumers.
303
331
  ### Added (post-alpha.0, same night)
304
332
  - **`ELEMENT_ICONS` GENERATED** from keel's `icon:` wrapper key (keel `56c124a`).
305
333
  - **`ELEMENT_SECTIONS` DERIVED** from the canonical schema's own document structure
306
- (Skeld's ruling: sections are the standard tier's property groups; document order is
334
+ (ruling: sections are the standard tier's property groups; document order is
307
335
  display order). Divergence check vs the old hand table found and fixed three fossils:
308
336
  creature "Behaviour"→"Behavior", pin's triple-listed generic link → `element`,
309
337
  relation "Involves" listing a nonexistent `relations` field. Canonical is truth.
@@ -312,18 +340,18 @@ pinned consumers.
312
340
  covered by the codegen drift guard. AGENTS.md points agents at it first.
313
341
  - **`OwV2Client.request()` is public** (typed escape hatch; does not sanitize) and
314
342
  structurally satisfies `TokenTransport` — `new TokenResource(client)` just works.
315
- Token ruling (Skeld): keel keeps `/tokens/*` long-term; ported, not deleted.
343
+ Token ruling: keel keeps `/tokens/*` long-term; ported, not deleted.
316
344
  - README rewritten v2-native (v1 sections, branded types, and the encrypted-key
317
345
  walkthrough removed; bulk partial-failure and idempotency-key hygiene promoted).
318
346
 
319
- ### alpha.1 — consumer-pin fixes (Temper's atlas review, same night)
347
+ ### alpha.1 — consumer-pin fixes (atlas review, same night)
320
348
  - **`parseEnvelope` → `parseErrorEnvelope`** (it parses the platform *error* envelope;
321
349
  renamed before the 4.0 name freeze to avoid collision with the world-export envelope).
322
350
  - The never-whitelist LAW now lives as a comment on `READ_ONLY_FIELDS` itself.
323
351
  - Stale v1 example in the shipped d.ts fixed (TokenResource JSDoc).
324
352
 
325
353
  ### Release gates — ALL GREEN (2026-07-23 night)
326
- - **Gate 3 (wire-log v1-traffic query, Skeld)**: GREEN — no unknown v1-SDK consumer on
354
+ - **Gate 3 (wire-log v1-traffic query)**: GREEN — no unknown v1-SDK consumer on
327
355
  the wire; observed v1 traffic is pinned deployed builds (council proxy, legacy plugin
328
356
  walks) that an npm major cannot touch. The v1 API dialect stays served regardless.
329
357
  - **`/api/v2/tokens/` live on prod + staging** (keel `e181689`; three-base byte
@@ -331,7 +359,7 @@ pinned consumers.
331
359
  "older server", not "no tokens". Requirement noted in the migration guide.
332
360
  - **`ONLYWORLDS_VERSION` now GENERATED** from canonical's `VERSION` file (carried
333
361
  into keel `schema/` by the refresh script, keel `492168c`) — the last hand-synced
334
- constant is dead. Consumer soak: Temper pinned the alpha against atlas's full
362
+ constant is dead. Consumer soak: the atlas app pinned the alpha against its full
335
363
  static surface — strict-clean compile, correct runtime, package shape approved.
336
364
  - **No `npm deprecate` on 3.x** (landscape research; 3.x stays plainly supported).
337
365
  - 4.x wishlist: account client (list/mint/create — atlas first consumer), world-export
@@ -345,7 +373,7 @@ pinned consumers.
345
373
  `ELEMENT_FAMILIES` (type → family), `FAMILY_COLORS` (family → `{light, dark}` hex),
346
374
  `familyOf(type)`, `elementColor(type, mode)`, `FAMILY_ORDER`, type `ElementFamily`.
347
375
  Four semantic families (agents / world / abstract / temporal) ruled 2026-07-22 after
348
- CVD-validated measurement (Orrery `product/schema/element-palette-measurements.md`).
376
+ CVD-validated measurement.
349
377
  Colour carries the FAMILY; `ELEMENT_ICONS` carries the TYPE. Keyed on the v2 slug
350
378
  union. First proven live in atlas and council, whose local copies become re-exports.
351
379
  **`ELEMENT_FAMILIES` is GENERATED** from the `family:` key in keel's schema YAML
@@ -373,7 +401,7 @@ pinned consumers.
373
401
 
374
402
  ## [3.0.0] — 2026-07-18
375
403
 
376
- - v2-native client (`OwV2Client`) absorbed from Assembly's ow-v2-client v0.9.0 (Kael),
404
+ - v2-native client (`OwV2Client`) absorbed from an earlier v2 client (ow-v2-client v0.9.0),
377
405
  wire-corrected against live staging fixtures (S22). Generated element types from the
378
406
  canonical keel schema YAML (`src/v2/types.generated.ts`), validated against all 1,086
379
407
  live W11 elements. v1 surface unchanged and frozen.
package/README.md CHANGED
@@ -3,74 +3,77 @@
3
3
  [![npm version](https://badge.fury.io/js/@onlyworlds%2Fsdk.svg)](https://www.npmjs.com/package/@onlyworlds/sdk)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- The canonical typed client for the [OnlyWorlds](https://onlyworlds.github.io) v2 API, plus the
7
- canonical constants (element types, icons, colour families, field schema) — generated from the
8
- canonical OnlyWorlds schema, obtained through the public
9
- [schema distribution](https://github.com/OnlyWorlds/schema-dist) at a pinned, hash-verified
10
- tag. The generated files carry that tag and commit in their header, so what these types were
11
- built from is checkable rather than asserted.
6
+ OnlyWorlds is an open standard for worldbuilding data: 22 element types (characters, locations, events, laws and the rest) that any tool can read and write. This is a typed client for its API, with the schema's constants (element types, icons, colour families, field metadata) generated from the published [schema distribution](https://github.com/OnlyWorlds/schema-dist). It runs in Node 18+ and in the browser through a bundler (ESM only).
12
7
 
13
- **4.x is v2-native and ESM-only (Node 18+).** If you need the legacy v1 API dialect
14
- (`OnlyWorldsClient`) or CommonJS `require()`, stay on 3.x — it remains published and the v1 API
15
- remains served. See [docs/migrating-3-to-4.md](docs/migrating-3-to-4.md).
16
-
17
- ## Installation
8
+ ## Install
18
9
 
19
10
  ```bash
20
11
  npm install @onlyworlds/sdk
21
12
  ```
22
13
 
23
- ## Quick Start
14
+ ## First run
15
+
16
+ Moppetopia is a public demo world. Its read-only key, `0000000001`, needs no account:
24
17
 
25
18
  ```typescript
26
19
  import { OwV2Client } from '@onlyworlds/sdk';
27
20
 
28
- const client = new OwV2Client({ apiKey: 'ow_r_your_key' }); // read-only key: that's all you need
29
- const page = await client.list('character'); // { data, has_more, next_cursor }
21
+ const client = new OwV2Client({ apiKey: '0000000001' });
22
+ console.log((await client.getWorld()).name);
23
+ const { data } = await client.list('character', { filter: { name__icontains: 'fluffington' } });
24
+ for (const c of data) console.log(' ', c.name);
25
+ ```
26
+
27
+ ```
28
+ Moppetopia
29
+ Admiral Fluffington
30
30
  ```
31
31
 
32
- Key kinds: `ow_w_` write / `ow_r_` read-only (no PIN — the "give this to your players" key) /
33
- `ow_a_` account Bearer / 10-digit legacy. Writes on a PIN-protected world also pass `apiPin`.
34
- Demo keys `0000000000`–`0000000009` read real sample worlds.
32
+ ## Your own world
35
33
 
36
- ## The full round-trip
34
+ Create a world at [onlyworlds.com](https://www.onlyworlds.com); its keys are on the world's page. A new key is shown once, so copy it then.
35
+
36
+ - An `ow_r_` key reads, with no PIN. It is the key to give to players or a public site.
37
+ - An `ow_w_` key reads and writes. Writes also send a PIN as `apiPin`.
38
+ - Anyone who loads a web page can read the keys in its code. Ship only an `ow_r_` key to a browser, and keep write keys and seat secrets on a server.
39
+ - For code that writes, give it its own [agent seat](https://onlyworlds.github.io/docs/development/agents), a key for one tool or script. The seat's key and its `ow_s_` secret (sent as `apiPin`) work in one world, and you can remove them without touching your account PIN.
37
40
 
38
41
  ```typescript
39
- const writer = new OwV2Client({ apiKey: 'ow_w_your_key', apiPin: '1234' });
42
+ const writer = new OwV2Client({ apiKey: 'ow_w_…', apiPin: 'ow_s_…' });
43
+ ```
44
+
45
+ ## Reading and writing
40
46
 
41
- // v2 dialect rules, worth internalizing once:
42
- // - link fields use ONE bare name both directions (no _ids suffix — that's v1)
43
- // - NEVER send a "world" field (identity comes from the key; the client strips it anyway)
47
+ ```typescript
44
48
  const location = await writer.create('location', {
45
49
  name: 'Dragon Peak',
46
- description: 'A treacherous mountain peak where dragons nest',
47
- }); // id minted client-side when omitted (retries stay idempotent)
48
- // name is the one required field, and required means the key is present:
49
- // '' and null are accepted and stored as '' (nameless Markers exist).
50
+ description: 'A mountain peak where dragons nest',
51
+ }); // the id is minted client-side when omitted, so a retry creates nothing twice
50
52
 
51
53
  const dragon = await writer.create('creature', {
52
54
  name: 'Vorrath the Ember-Scaled',
53
- location: location.id, // single link: UUID (or null)
55
+ location: location.id, // a single link: a UUID or null
54
56
  });
55
57
 
56
58
  const fetched = await writer.get('creature', dragon.id);
57
- // fetched.location === location.id — reads the way it writes
59
+ // fetched.location === location.id: a field reads the way it writes
58
60
 
59
- // PATCH is destructive on sent fields; arrays replace wholesale
61
+ // PATCH replaces the fields it sends; an array is replaced whole
60
62
  await writer.patch('location', location.id, { supertype: 'Mountain' });
61
63
 
62
- // For relationships, use the atomic link merge — returns the full updated element
63
- const fireBreath = await writer.create('ability', { name: 'Ember Breath' });
64
- await writer.editLinks('creature', dragon.id, 'abilities', { add: [fireBreath.id], remove: [] });
64
+ // For links, the atomic merge; it returns the updated element
65
+ const breath = await writer.create('ability', { name: 'Ember Breath' });
66
+ await writer.editLinks('creature', dragon.id, 'abilities', { add: [breath.id], remove: [] });
65
67
 
66
- // Walk every page of a type
68
+ // Every page of a type
67
69
  for await (const character of writer.listAll('character')) { /* ... */ }
68
70
  ```
69
71
 
70
- ## Bulk writes — always check `errors`
72
+ A link field has one name in both directions (`location`, not `location_id`). Only `name` is required, and an empty name is stored as `''`. A `world` field in a payload is ignored: the key decides the world, and the client strips it anyway.
73
+
74
+ ## Bulk writes
71
75
 
72
- `/bulk` **succeeds partially by default** (HTTP 200 with per-slot statuses). The one mistake to
73
- never make: treating a 200 as "everything landed."
76
+ `/bulk` answers 200 even when some items fail, so check `errors`:
74
77
 
75
78
  ```typescript
76
79
  const res = await writer.bulk(
@@ -78,87 +81,80 @@ const res = await writer.bulk(
78
81
  { type: 'character', element: { name: 'A' } },
79
82
  { type: 'event', element: { name: 'B' } },
80
83
  ],
81
- { idempotencyKey: crypto.randomUUID() }, // mint FRESH per attempt — a failed batch is
82
- ); // cached under its key; never reuse across retries
84
+ { idempotencyKey: crypto.randomUUID() }, // a new key per attempt: a failed batch is cached under its key
85
+ );
83
86
  if (res.errors) {
84
87
  for (const slot of res.items.filter((s) => s.status >= 400)) {
85
88
  console.warn(slot.error?.code, slot.error?.message, slot.error?.doc_url);
86
89
  }
87
90
  }
88
- // Pass { atomic: true } for all-or-nothing instead. res.wasReplay flags idempotent replays.
89
- // After a failed atomic batch NOTHING was written, but the slots that would have succeeded
90
- // still say 201 (keel's counterfactual 201s): do not record those ids as created.
91
91
  ```
92
92
 
93
+ Pass `{ atomic: true }` for all or nothing. After a failed atomic batch nothing was written, but the slots that would have succeeded still read 201: don't record those ids as created. `res.wasReplay` marks an idempotent replay.
94
+
93
95
  ## Images
94
96
 
95
97
  ```typescript
96
- const image = await writer.uploadImage(file); // a Blob, File, ArrayBuffer or Uint8Array
98
+ const image = await writer.uploadImage(file); // a Blob, File, ArrayBuffer or Uint8Array
97
99
  await writer.patch('character', id, { image_url: image.url });
98
100
  ```
99
101
 
100
- Two requests: a single-use ticket from keel, then the bytes straight to the edge (keel never
101
- sees them, and the edge never sees your key). webp, png, jpeg or avif (never SVG or gif), read from the
102
- bytes. Each ticket counts toward the world's daily limit and the account's image
103
- storage. To upload yourself (for a progress bar), take `createMediaTicket()` and POST the bytes to
104
- its `upload_url` with `Authorization: Bearer <ticket>`.
102
+ The SDK asks the API for a single-use ticket, then sends the bytes straight to the upload host, which never sees your key. webp, png, jpeg or avif (no SVG or gif), up to 15 MB. Each upload counts toward the world's daily limit and the account's storage. To upload yourself (for a progress bar), call `createMediaTicket()` and POST the bytes to its `upload_url` with `Authorization: Bearer <ticket>`.
105
103
 
106
104
  ## Sync
107
105
 
108
106
  ```typescript
109
- let cursor; // opaque, never expires; persist it
107
+ let cursor; // opaque and never expires: keep it
110
108
  for await (const change of client.changesAll(cursor)) {
111
- // ops arrive in (change_seq, id) order — apply in order → convergence
109
+ // changes arrive in order; apply them in order and you converge
112
110
  }
113
- // GOTCHA: world-meta edits (name, calendar, public_read) do NOT enter /changes.
114
- // Poll client.getWorld() and compare updated_at separately.
115
111
  ```
116
112
 
113
+ Edits to the world itself (its name, calendar, `public_read`) don't appear in the change feed. Read `client.getWorld()` and compare `updated_at`.
114
+
117
115
  ## Errors
118
116
 
119
- Every non-2xx throws `OwApiError` carrying the platform envelope: `.status`, `.type`, `.code`,
120
- `.param` (the exact field that failed), and `.docUrl` — surface `docUrl` in your UX. Transport
121
- failures throw `OwNetworkError`. `err.isValidationError` is the common branch.
117
+ Every non-2xx response throws `OwApiError` with the API's envelope: `.status`, `.type`, `.code`, `.param` (the field that failed) and `.docUrl`, which is worth showing to your users. A transport failure throws `OwNetworkError`. `err.isValidationError` covers the common case.
122
118
 
123
- ## Canonical constants (all generated or test-gated from schema)
119
+ ## Schema constants
124
120
 
125
121
  ```typescript
126
122
  import {
127
- ELEMENT_TYPES, // the 22 slugs (and the ElementType union)
128
- ELEMENT_ICONS, // Material Symbols icon per type
129
- ELEMENT_LABELS, // plural display labels
130
- ELEMENT_SECTIONS, // canonical field grouping + display order
131
- FIELD_SCHEMA, // per-field type/target metadata
132
- elementColor, // canonical colour: family carries COLOUR, icon carries TYPE
123
+ ELEMENT_TYPES, // the 22 type slugs (and the ElementType union)
124
+ ELEMENT_ICONS, // a Material Symbols icon per type
125
+ ELEMENT_LABELS, // plural display labels
126
+ ELEMENT_SECTIONS, // field grouping and display order
127
+ FIELD_SCHEMA, // per-field type and link target
128
+ elementColor, // colour by family; the icon carries the type
133
129
  } from '@onlyworlds/sdk';
134
130
 
135
- elementColor('character', 'dark'); // '#3987e5' — four CVD-validated families
136
- // Always pair colour with icon + label; colour alone is not accessible.
131
+ elementColor('character', 'dark'); // '#3987e5'
137
132
  ```
138
133
 
139
- The full schema with per-field meaning lives in [SCHEMA.md](SCHEMA.md) (generated, ships in this
140
- package). AI agents: read [AGENTS.md](AGENTS.md) first.
134
+ The four colour families (agents, world, abstract, temporal) are checked for colour-blind separation. Show colour with the icon and label, never alone. [SCHEMA.md](SCHEMA.md) (generated, in the package) describes every field; AI agents should read [AGENTS.md](AGENTS.md) first.
135
+
136
+ ## Tokens
141
137
 
142
- ## Token rating system
138
+ The account's token allowance and ratings, which some OnlyWorlds tools use.
143
139
 
144
140
  ```typescript
145
141
  import { TokenResource } from '@onlyworlds/sdk';
146
- const tokens = new TokenResource(writer); // OwV2Client.request() satisfies TokenTransport
142
+ const tokens = new TokenResource(writer);
147
143
  const status = await tokens.getStatus();
148
144
  ```
149
145
 
150
- ## AI access — when to use which
146
+ ## SDK or MCP
151
147
 
152
- For **known, deterministic operations** (CRUD, sync, bulk) use this SDK — typed calls, no
153
- tool-schema overhead. For **live exploration of a user's world from a chat/agent context**, use
154
- the MCP server at `https://www.onlyworlds.com/mcp` (same `API-Key`/`API-Pin` headers, 12 tools;
155
- unaffected by SDK versioning).
148
+ Use this SDK for known operations in your own code (CRUD, sync, bulk). To let an AI assistant that speaks MCP (the Model Context Protocol) explore a world in a chat, connect it to `https://www.onlyworlds.com/mcp` with the same key and PIN as `API-Key` and `API-Pin` headers.
156
149
 
157
- ## License
150
+ ## Version 3 and the old API
158
151
 
159
- MIT
152
+ 4.x speaks the current (v2) API only. The v1 client (`OnlyWorldsClient`) and CommonJS `require()` stay on 3.x, which remains published and supported: see [the migration guide](docs/migrating-3-to-4.md).
160
153
 
161
154
  ## Links
162
155
 
163
- - [OnlyWorlds](https://www.onlyworlds.com) · [Docs](https://onlyworlds.github.io) · [API reference](https://www.onlyworlds.com/api/docs)
164
- - [Issues](https://github.com/OnlyWorlds/sdk/issues) · [CHANGELOG](CHANGELOG.md) · [Migration 3→4](docs/migrating-3-to-4.md)
156
+ [Docs](https://onlyworlds.github.io/docs/development/typescript) · [Games](https://onlyworlds.github.io/docs/development/games) · [API reference](https://www.onlyworlds.com/api/docs) · [Issues](https://github.com/OnlyWorlds/sdk/issues) · [Changelog](CHANGELOG.md)
157
+
158
+ ## License
159
+
160
+ MIT
package/SCHEMA.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # OnlyWorlds Schema Reference
2
2
 
3
- **Source**: https://github.com/OnlyWorlds/schema-dist @ **v0.30.1-dist.15** — canonical schema **00.30.01**, published 2026-09-18.
3
+ **Source**: https://github.com/OnlyWorlds/schema-dist @ **v0.31.0-dist.18** — canonical schema **00.31.00**, published 2026-10-09.
4
4
 
5
5
  GENERATED from the canonical schema YAML — do not hand-edit (regenerate: `python codegen/generate_types.py`).
6
6
  Written for both humans and AI agents reading this package locally.
@@ -24,7 +24,7 @@ Families (colour semantics; icon carries the type): agents · world · abstract
24
24
  - `activation` (text) — Method or conditions under which the ability is activated
25
25
  - `duration` (integer) — Length of time the ability remains active or its effects persist, measured in TIME units
26
26
  - `potency` (integer) — Relative measure of the ability's inherent potency or force, used for scaling or comparison purposes
27
- - `range` (integer) — Effective reach or distance at which the ability can be used, measured in DISTANCE units
27
+ - `range` (integer) — Effective reach or distance at which the ability can be used, in the world's distance unit (World distance_unit)
28
28
  - `effects` (multi link → phenomenon) — Phenomena that result from the ability's use, such as environmental changes or sensory effects
29
29
  - `challenges` (text) — Describes specific difficulties or constraints that make the ability hard to master or use effectively
30
30
  - `talents` (multi link → trait) — Traits that naturally enhance or improve performance with this ability
@@ -47,8 +47,8 @@ Families (colour semantics; icon carries the type): agents · world · abstract
47
47
 
48
48
  - `physicality` (text) — The character's visible physical features and body attributes
49
49
  - `mentality` (text) — The character's mindset, emotional tone, and style of thinking
50
- - `height` (integer) — The character's approximate or exact height, using world LENGTH units
51
- - `weight` (integer) — The character's approximate or exact weight, using world MASS units
50
+ - `height` (integer) — The character's approximate or exact height, in the world's length unit (World length_unit)
51
+ - `weight` (integer) — The character's approximate or exact weight, in the world's mass unit (World mass_unit)
52
52
  - `species` (multi link → species) — Species the character might belong to
53
53
  - `traits` (multi link → trait) — Traits for notable behavioral, physical, or systemic characteristics
54
54
  - `abilities` (multi link → ability) — Abilities the character might perform, control, or invoke
@@ -164,8 +164,8 @@ Families (colour semantics; icon carries the type): agents · world · abstract
164
164
  ### Biology
165
165
 
166
166
  - `appearance` (text) — Visual description of the creature
167
- - `weight` (integer) — Approximate or exact weight of the creature, using world MASS units
168
- - `height` (integer) — Approximate height of the creature, using the world's defined LENGTH units
167
+ - `weight` (integer) — Approximate or exact weight of the creature, in the world's mass unit (World mass_unit)
168
+ - `height` (integer) — Approximate height of the creature, in the world's length unit (World length_unit)
169
169
  - `species` (multi link → species) — Species this creature belongs to
170
170
 
171
171
  ### Behavior
@@ -188,7 +188,7 @@ Families (colour semantics; icon carries the type): agents · world · abstract
188
188
  - `challenge_rating` (integer) — Difficulty or threat level of the creature in a gameplay context
189
189
  - `hit_points` (integer) — Total health or durability value in combat
190
190
  - `armor_class` (integer) — Defense rating against physical attacks or effects
191
- - `speed` (integer) — Typical movement speed, measured in the world's DISTANCE unit per round
191
+ - `speed` (integer) — Typical movement speed, in the world's distance unit (World distance_unit) per round
192
192
  - `actions` (multi link → ability) — Combat or tactical abilities the creature can perform or use
193
193
 
194
194
 
@@ -326,8 +326,8 @@ Families (colour semantics; icon carries the type): agents · world · abstract
326
326
  - `governing_title` (single link → title) — Governing figure assigned by the location's primary power
327
327
  - `secondary_powers` (multi link → institution) — Institutions with significant political control
328
328
  - `zone` (single link → zone) — Zone of interest that is associated with the location
329
- - `rival` (single link → location) — Locations with active, traditional, or historical rivalries
330
- - `partner` (single link → location) — Locations with active, cooperative, or historical ties
329
+ - `rival` (single link → location) — Location with an active, traditional, or historical rivalry with this one
330
+ - `partner` (single link → location) — Location with active, cooperative, or historical ties to this one
331
331
 
332
332
  ### World
333
333
 
@@ -359,7 +359,7 @@ Families (colour semantics; icon carries the type): agents · world · abstract
359
359
  ### Defense
360
360
 
361
361
  - `defensibility` (text) — Qualities of natural, constructed, and implemented defenses at the location
362
- - `elevation` (integer) — Height or elevation of the location relative to surrounding terrain, defined in world DISTANCE units
362
+ - `elevation` (integer) — Height or elevation of the location relative to surrounding terrain, in the world's distance unit (World distance_unit)
363
363
  - `fighters` (multi link → construct) — Military units or forces responsible for defending the location
364
364
  - `defensive_objects` (multi link → object) — Objects or installations for defending the location
365
365
 
@@ -388,7 +388,7 @@ Families (colour semantics; icon carries the type): agents · world · abstract
388
388
  - `x` (integer) — x coordinate, from bottom left of the map
389
389
  - `y` (integer) — y coordinate, from bottom left of the map
390
390
  - `z` (integer) — z coordinate, in case of depth
391
- - `order` (integer) — Sequence position when markers define a polygon or line (0 = first point)
391
+ - `order` (integer) — Sequence position when markers define a polygon or line (0 = first point); without it, markers keep the order they were made in
392
392
 
393
393
 
394
394
  ## narrative · family: temporal · icon: menu_book
@@ -435,7 +435,7 @@ Families (colour semantics; icon carries the type): agents · world · abstract
435
435
  ### Form
436
436
 
437
437
  - `aesthetics` (text) — Appearance, design, or visual presentation of the object
438
- - `weight` (integer) — Approximate or exact mass of the object, defined by world MASS units
438
+ - `weight` (integer) — Approximate or exact mass of the object, in the world's mass unit (World mass_unit)
439
439
  - `amount` (integer) — The number of identical units in this object entry
440
440
  - `parent_object` (single link → object) — Larger object that this one is part of or contained within
441
441
  - `materials` (multi link → construct) — The physical matter that constitutes the object
@@ -482,7 +482,7 @@ Families (colour semantics; icon carries the type): agents · world · abstract
482
482
  ### Details
483
483
 
484
484
  - `map` (single link → map) — Map that the pin is placed on
485
- - `element` (generic link (any element type)) — Link to any Element (managed by ContentType + UUID)
485
+ - `element` (generic link (any element type)) — The element this pin places on the map, of any type
486
486
  - `x` (integer) — x coordinate, from bottom left of the map
487
487
  - `y` (integer) — y coordinate, from bottom left of the map
488
488
  - `z` (integer) — z coordinate, in case of depth (optional)
@@ -517,7 +517,6 @@ Families (colour semantics; icon carries the type): agents · world · abstract
517
517
  - `families` (multi link → family) — Families relevant to the relation
518
518
  - `titles` (multi link → title) — Titles relevant to the relation
519
519
  - `constructs` (multi link → construct) — Concepts, contracts, or principles relevant to the relation
520
- - `events` (multi link → event) — Events where the relation is involved or relevant
521
520
  - `narratives` (multi link → narrative) — Narratives relevant to the relation
522
521
 
523
522
 
@@ -528,7 +527,7 @@ Families (colour semantics; icon carries the type): agents · world · abstract
528
527
 
529
528
  - `appearance` (text) — Typical physical or form features of the species
530
529
  - `life_span` (integer) — Average or typical life expectancy of an individual, defined in world TIME units
531
- - `weight` (integer) — Average or typical adult weight, defined in world MASS units
530
+ - `weight` (integer) — Average or typical adult weight, in the world's mass unit (World mass_unit)
532
531
  - `nourishment` (multi link → species) — Other species consumed as food sources
533
532
  - `reproduction` (multi link → construct) — Reproductive method(s) of the species
534
533
  - `adaptations` (multi link → ability) — Special physiological or evolutionary abilities
package/dist/index.d.ts CHANGED
@@ -33,7 +33,7 @@ type ElementType = 'ability' | 'character' | 'collective' | 'construct' | 'creat
33
33
  declare const ELEMENT_TYPES: ElementType[];
34
34
  /** Canonical OnlyWorlds schema version. Source: the `canonical:` value of the pinned
35
35
  * distribution's VERSION file (see the provenance block at the top of this file). */
36
- declare const ONLYWORLDS_VERSION: "00.30.01";
36
+ declare const ONLYWORLDS_VERSION: "00.31.00";
37
37
  /** The four semantic families (colour carries the family; ELEMENT_ICONS carries the type). */
38
38
  type ElementFamily = 'agents' | 'world' | 'abstract' | 'temporal';
39
39
  /** Per-type semantic family. Source: the distribution's `presentation.json` sidecar
@@ -1844,7 +1844,7 @@ declare const FIELD_SCHEMA: {
1844
1844
  };
1845
1845
 
1846
1846
  /**
1847
- * keel v2 engine absorbed from Assembly's ow-v2-client v0.9.0 (Kael),
1847
+ * keel v2 engine absorbed from an earlier v2 client (ow-v2-client v0.9.0),
1848
1848
  * wire-corrected against live staging fixtures 2026-07-18.
1849
1849
  *
1850
1850
  * OnlyWorlds v2 (keel) wire types -- the NON-generated, hand-owned wire shapes
@@ -2024,7 +2024,7 @@ interface OwClientConfig {
2024
2024
  }
2025
2025
 
2026
2026
  /**
2027
- * keel v2 engine absorbed from Assembly's ow-v2-client v0.9.0 (Kael),
2027
+ * keel v2 engine absorbed from an earlier v2 client (ow-v2-client v0.9.0),
2028
2028
  * wire-corrected against live staging fixtures 2026-07-18.
2029
2029
  *
2030
2030
  * keel error envelope handling. The error contract is part of the contract:
@@ -2115,7 +2115,7 @@ declare function parseErrorEnvelope(status: number, body: unknown, retryAfter?:
2115
2115
  declare function errorFromResponse(res: Response): Promise<OwApiError>;
2116
2116
 
2117
2117
  /**
2118
- * keel v2 engine absorbed from Assembly's ow-v2-client v0.9.0 (Kael),
2118
+ * keel v2 engine absorbed from an earlier v2 client (ow-v2-client v0.9.0),
2119
2119
  * wire-corrected against live staging fixtures 2026-07-18.
2120
2120
  *
2121
2121
  * OnlyWorlds key-kind detection. Prefixes make leaked keys grep-scannable
@@ -2143,7 +2143,7 @@ declare function kindCanWrite(kind: OwKeyKind): boolean;
2143
2143
  declare function pinExpectation(kind: OwKeyKind): 'never' | 'optional' | 'required-for-private-reads';
2144
2144
 
2145
2145
  /**
2146
- * keel v2 engine absorbed from Assembly's ow-v2-client v0.9.0 (Kael),
2146
+ * keel v2 engine absorbed from an earlier v2 client (ow-v2-client v0.9.0),
2147
2147
  * wire-corrected against live staging fixtures 2026-07-18.
2148
2148
  *
2149
2149
  * OwV2Client -- thin typed fetch client for the keel v2 API.
@@ -2300,9 +2300,8 @@ declare class OwV2Client {
2300
2300
  /**
2301
2301
  * Canonical element colour palette — four semantic families.
2302
2302
  *
2303
- * Ruled by Captain 2026-07-22 after Skeld's measurement pass (Orrery
2304
- * `product/schema/element-palette-measurements.md`): 22 mutually-separable
2305
- * hues is structurally impossible; four families is the ceiling that passes
2303
+ * Ruled 2026-07-22 after a measurement pass: 22 mutually-separable hues
2304
+ * is structurally impossible; four families is the ceiling that passes
2306
2305
  * all-pairs CVD separation in both modes. **Colour carries the FAMILY; the
2307
2306
  * icon (`ELEMENT_ICONS`) carries the TYPE.** Dark-mode pairs land in the 6–8
2308
2307
  * CVD floor band, so secondary encoding (icon + label) is REQUIRED alongside
@@ -2493,7 +2492,7 @@ declare enum GameTier {
2493
2492
  /**
2494
2493
  * Minimal transport the token resource needs — structurally satisfied by
2495
2494
  * `OwV2Client` (its `request()` is public since 4.0): `new TokenResource(client)`.
2496
- * Wire ruling (Skeld 2026-07-23): keel keeps the /tokens/* economy long-term
2495
+ * Wire ruling (2026-07-23): keel keeps the /tokens/* economy long-term
2497
2496
  * (Tangle ratings write it, Council voting reads it) — port, don't delete.
2498
2497
  */
2499
2498
  interface TokenTransport {
package/dist/index.js CHANGED
@@ -433,7 +433,7 @@ function buildQuery(params) {
433
433
 
434
434
  // src/v2/types.generated.ts
435
435
  var ELEMENT_TYPES = ["ability", "character", "collective", "construct", "creature", "event", "family", "institution", "language", "law", "location", "map", "marker", "narrative", "object", "phenomenon", "pin", "relation", "species", "title", "trait", "zone"];
436
- var ONLYWORLDS_VERSION = "00.30.01";
436
+ var ONLYWORLDS_VERSION = "00.31.00";
437
437
  var ELEMENT_FAMILIES = {
438
438
  ability: "abstract",
439
439
  character: "agents",
@@ -564,7 +564,7 @@ var ELEMENT_SECTIONS = {
564
564
  ],
565
565
  relation: [
566
566
  { name: "Nature", order: 1, fields: ["background", "start_date", "end_date", "intensity", "actor", "events"] },
567
- { name: "Involves", order: 2, fields: ["characters", "objects", "locations", "species", "creatures", "institutions", "traits", "collectives", "zones", "abilities", "phenomena", "languages", "families", "titles", "constructs", "events", "narratives"] }
567
+ { name: "Involves", order: 2, fields: ["characters", "objects", "locations", "species", "creatures", "institutions", "traits", "collectives", "zones", "abilities", "phenomena", "languages", "families", "titles", "constructs", "narratives"] }
568
568
  ],
569
569
  species: [
570
570
  { name: "Biology", order: 1, fields: ["appearance", "life_span", "weight", "nourishment", "reproduction", "adaptations"] },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlyworlds/sdk",
3
- "version": "4.7.0",
3
+ "version": "4.7.2",
4
4
  "description": "TypeScript SDK for the OnlyWorlds API - build world-building applications with type safety",
5
5
  "type": "module",
6
6
  "exports": {