@onlyworlds/sdk 4.37.0 → 4.39.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/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.32.0-dist.23** (canonical 00.32.00).
3
+ **Current as of**: SDK **4.x** · schema-dist **v0.32.1-dist.27** (canonical 00.32.01).
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
@@ -5,6 +5,35 @@ earlier history lives in git log only.
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [4.39.0] - 2026-10-20
9
+
10
+ The party link (keel #422 PR 2, keel PR 110), live in production since 2026-10-20 13:15.
11
+
12
+ ### Added
13
+ - The party link (keel #422 PR 2, keel PR 110; for Lantern's pick screen, Temper): one player link for a
14
+ table of players. `createWorldLink(worldId, { reader: 'player', maxUses, characters })`, sent as `max_uses`
15
+ and `characters`: 2 to 50 uses, each player picking one Character from the owner's list, in its order; no
16
+ list, each player names a fresh Character after themselves. A table takes no `character`. A link for one
17
+ sends what it sent before. `OwWorldLink` and `OwCreatedWorldLink` gain a table's `max_uses` and
18
+ `characters` (`{ id, name, taken }`); `uses` counts a table's seats. `OwJoinPreview` gains a table's
19
+ `max_uses`, `uses_left`, `name_required` and `characters` (`{ id, name, image_url, taken }`).
20
+ `redeemJoin(code, { character })` sends the pick; with `name_required`, `name` alone. A pick a live seat
21
+ already plays is 422 `character_taken` (`err.isCharacterTaken`); a pick off the list, hidden or deleted
22
+ since the link was made, or missing, is 422 `invalid_request` with param `character`
23
+ (`err.isCharacterInvalid`, true for that param only); a world with its 50 players is 422 `world_full` (`err.isWorldFull`, its own code at my ask, Skeld h29 #8394); the last place
24
+ lost to another player is the one 404 (`err.isNotFound`).
25
+
26
+ ### Changed
27
+ - Repinned to schema-dist v0.32.1-dist.27: only `example/world-export.json` moved (its `schema_version` now 00.32.01, Skeld h29 #8455); no schema file moved, so the generated files change only their source lines.
28
+
29
+ ## [4.38.0] - 2026-10-20
30
+
31
+ Schema 00.32.01 (the Captain's word, h55 #8395): repinned to schema-dist v0.32.1-dist.26.
32
+
33
+ ### Changed
34
+ - **An Event's `characters`** reads "Characters who know about the event: they were present, aware of it, or involved in it" (it read "Key characters relevant to the event"), in the generated doc comment and `SCHEMA.md`. No field, type or link changed.
35
+ - **`ONLYWORLDS_VERSION`** is `'00.32.01'`. It is an `as const` export, so its literal type moves too, which is why this is a minor and not a patch.
36
+
8
37
  ## [4.37.0] - 2026-10-20
9
38
 
10
39
  The hidden mark (keel #421), live in production since 2026-10-20 09:24; walked on staging with the mark on, 25 of 25.
package/SCHEMA.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # OnlyWorlds Schema Reference
2
2
 
3
- **Source**: https://github.com/OnlyWorlds/schema-dist @ **v0.32.0-dist.23** — canonical schema **00.32.00**, published 2026-10-12.
3
+ **Source**: https://github.com/OnlyWorlds/schema-dist @ **v0.32.1-dist.27** — canonical schema **00.32.01**, published 2026-10-20.
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.
@@ -206,7 +206,7 @@ Families (colour semantics; icon carries the type): agents · world · abstract
206
206
 
207
207
  ### Involves
208
208
 
209
- - `characters` (multi link → character) — Key characters relevant to the event
209
+ - `characters` (multi link → character) — Characters who know about the event: they were present, aware of it, or involved in it
210
210
  - `objects` (multi link → object) — Objects relevant to the event
211
211
  - `locations` (multi link → location) — Locations relevant to the event
212
212
  - `species` (multi link → species) — Species relevant to the event
package/dist/index.d.ts CHANGED
@@ -37,7 +37,7 @@ type ElementType = 'ability' | 'character' | 'collective' | 'construct' | 'creat
37
37
  declare const ELEMENT_TYPES: ElementType[];
38
38
  /** Canonical OnlyWorlds schema version. Source: the `canonical:` value of the pinned
39
39
  * distribution's VERSION file (see the provenance block at the top of this file). */
40
- declare const ONLYWORLDS_VERSION: "00.32.00";
40
+ declare const ONLYWORLDS_VERSION: "00.32.01";
41
41
  /** The four semantic families (colour carries the family; ELEMENT_ICONS carries the type). */
42
42
  type ElementFamily = 'agents' | 'world' | 'abstract' | 'temporal';
43
43
  /** Per-type semantic family. Source: the distribution's `presentation.json` sidecar
@@ -2254,6 +2254,19 @@ interface OwJoinPreview {
2254
2254
  with_character: boolean | null;
2255
2255
  /** ISO 8601, UTC. */
2256
2256
  expires_at: string;
2257
+ /** A table only (a player link that works 2 to 50 times, keel #422 PR 2): how many times it works. Absent on a link for one. */
2258
+ max_uses?: number;
2259
+ /** A table only: how many places are left. */
2260
+ uses_left?: number;
2261
+ /** A table only: true when the owner listed no Characters, so each player sends a `name` to redeemJoin and gets a fresh Character with it. */
2262
+ name_required?: boolean;
2263
+ /** A table only: the Characters a player may pick, in the owner's order; empty when `name_required`. `taken` while a live seat in the world plays it (a pick screen keeps the order and puts taken ones last). A Character hidden or deleted since the link was made is left out. */
2264
+ characters?: Array<{
2265
+ id: string;
2266
+ name: string;
2267
+ image_url: string | null;
2268
+ taken: boolean;
2269
+ }>;
2257
2270
  [k: string]: unknown;
2258
2271
  }
2259
2272
  /** One of a world's invite links, as GET /account/worlds/{id}/links lists it (keel C1, 48c10d4). */
@@ -2275,16 +2288,25 @@ interface OwWorldLink {
2275
2288
  created_at: string;
2276
2289
  /** ISO 8601, UTC. */
2277
2290
  expires_at: string;
2278
- /** 0 or 1: a link works once. */
2291
+ /** 0 or 1 for a link for one; a table's seats made, removed ones included (keel #422 PR 2). */
2279
2292
  uses: number;
2293
+ /** A table is `pending` while `uses < max_uses` (and neither revoked nor expired), `used` once full. */
2280
2294
  status: 'pending' | 'used' | 'revoked' | 'expired';
2281
2295
  /** Whether the link shows the world's name and picture when it is pasted into a chat (keel #422): then the link is `/join/<world_id>#<code>`, else `/join#<code>`. Never on an agent link. */
2282
2296
  preview?: boolean;
2283
- /** A player link only: the Character the player reads as; null while a link for a fresh Character is unused. `name` is null if that Character was deleted (the redeem then makes a fresh one). */
2297
+ /** A player link only: the Character the player reads as; null while a link for a fresh Character is unused, and always null on a table. `name` is null if that Character was deleted (the redeem then makes a fresh one). */
2284
2298
  character?: {
2285
2299
  id: string;
2286
2300
  name: string | null;
2287
2301
  } | null;
2302
+ /** A table only (a player link that works 2 to 50 times, keel #422 PR 2): how many times it works. Absent on a link for one. */
2303
+ max_uses?: number;
2304
+ /** A table only: the Characters its players may pick, in the owner's order; empty when each player gets a fresh Character named after them. `taken`: a live seat in the world plays it. `name` is null if the Character was deleted. */
2305
+ characters?: Array<{
2306
+ id: string;
2307
+ name: string | null;
2308
+ taken: boolean;
2309
+ }>;
2288
2310
  [k: string]: unknown;
2289
2311
  }
2290
2312
  /** POST /account/worlds/{id}/links: the new link, with its code. The code is in this answer only: keel keeps a hash. */
@@ -2715,6 +2737,28 @@ declare class OwApiError extends Error {
2715
2737
  get isPreconditionFailed(): boolean;
2716
2738
  /** 404 `not_found`: no such element or route, or a join code that is unknown, used, revoked or expired. */
2717
2739
  get isNotFound(): boolean;
2740
+ /**
2741
+ * redeemJoin on a table (keel #422 PR 2): the picked Character is one a live seat in the
2742
+ * world already plays (422 `character_taken`, `param` character). Pick another from a fresh
2743
+ * previewJoin, whose `characters` mark each `taken`. The code is not spent.
2744
+ */
2745
+ get isCharacterTaken(): boolean;
2746
+ /**
2747
+ * The `character` sent was refused (422 `invalid_request`, `param` character). On redeemJoin
2748
+ * at a table (keel #422 PR 2): the pick is off the link's list, hidden or deleted since the
2749
+ * link was made, or missing, or sent to a table with no list (send `name` instead); one
2750
+ * answer for all, so read previewJoin again and pick from its `characters`. The code is not
2751
+ * spent. On createWorldLink: a `character` keel refused (not a Character of the world, a
2752
+ * hidden one, or any `character` on a table). Never true for another param's 422, nor for
2753
+ * `character_taken` (see isCharacterTaken).
2754
+ */
2755
+ get isCharacterInvalid(): boolean;
2756
+ /**
2757
+ * redeemJoin (keel #422 PR 2): the world already has its 50 live players (422 `world_full`),
2758
+ * at any player link, a table's or a link for one's. Nothing is spent; a place frees when the
2759
+ * owner removes a player.
2760
+ */
2761
+ get isWorldFull(): boolean;
2718
2762
  /** acceptJoin: the account is already a member of that world (409 `already_member`). The code is not spent. */
2719
2763
  get isAlreadyMember(): boolean;
2720
2764
  /** acceptJoin: the account has no PIN yet, and a member writes with their own (409 `pin_required`). The code is not spent. */
@@ -3155,7 +3199,9 @@ declare class OwV2Client {
3155
3199
  * which world, in what role, and `reader` (`person`: accept it with acceptJoin;
3156
3200
  * `agent`: an AI agent redeems it at POST /join). Sends no credential, whatever key
3157
3201
  * this client holds. Every bad code (unknown, used, revoked, expired) is the same
3158
- * 404 `not_found` (`err.isNotFound`). `code` is the part of the link after `#`.
3202
+ * 404 `not_found` (`err.isNotFound`). `code` is the part of the link after `#`. A table
3203
+ * (keel #422 PR 2) adds `max_uses`, `uses_left`, `name_required` and `characters`, the
3204
+ * pick screen's list; a link for one answers without them.
3159
3205
  */
3160
3206
  previewJoin(code: string): Promise<OwJoinPreview>;
3161
3207
  /**
@@ -3168,10 +3214,22 @@ declare class OwV2Client {
3168
3214
  * Character's name or "Player" when left out) and `agentName` (an agent's, required for an
3169
3215
  * agent code). Every bad code is the same 404 `not_found`; a person's code is redeemed with
3170
3216
  * acceptJoin instead.
3217
+ *
3218
+ * A table (a player code whose preview carries `max_uses`, keel #422 PR 2) seats one player
3219
+ * per redeem, until `uses_left` is 0. With a list, `character` is the player's pick, the `id`
3220
+ * of one of the preview's `characters` not `taken`: a Character a live seat already plays is
3221
+ * 422 `character_taken` (`err.isCharacterTaken`; pick another), one off the list, hidden or
3222
+ * deleted since, or none sent, is 422 `invalid_request`, param `character`
3223
+ * (`err.isCharacterInvalid`; read the preview again). With no list
3224
+ * (`name_required`), send `name` and no `character`: the player's fresh Character takes the
3225
+ * name (missing: 422, param `name`). A world with its 50 players is 422 `invalid_request`;
3226
+ * the last place taken by someone else first is the one 404. A refusal spends nothing. A link
3227
+ * for one ignores `character`.
3171
3228
  */
3172
3229
  redeemJoin(code: string, opts?: {
3173
3230
  name?: string;
3174
3231
  agentName?: string;
3232
+ character?: string;
3175
3233
  }): Promise<OwJoined>;
3176
3234
  /**
3177
3235
  * Sign in with an email address (or a username) and password, and get a new account token
@@ -3218,7 +3276,14 @@ declare class OwV2Client {
3218
3276
  * whoever opens the link first reads as it, until removed. `preview` (person and player links,
3219
3277
  * keel #422) to false: true puts the world's id in the link's path, so a chat that unfurls it
3220
3278
  * shows the world's name and picture (the code stays after `#`); true on an agent link is
3221
- * 422, param `preview`. 201 with the code, shown in this
3279
+ * 422, param `preview`. `maxUses` (player links only, keel #422 PR 2) to 1, a link for one:
3280
+ * 2 to 50 makes a table, one link that seats that many players, each picking one of
3281
+ * `characters` (Character ids of the world, in the order a pick screen shows them; a hidden
3282
+ * one is 422, param `characters`). `characters` empty or left out: each player names a fresh
3283
+ * Character after themselves. A table takes no `character`, not even `new` (422, param
3284
+ * `character`), and `characters` on a link for one is 422, even empty. A table counts once
3285
+ * against the 50 pending invites; its seats count against the world's 50 players as each is
3286
+ * made, so a full world refuses the pick, never the link. 201 with the code, shown in this
3222
3287
  * answer only. Owner only: anyone else, and a world that doesn't exist, gets 404
3223
3288
  * `not_found` (`err.isNotFound`). A world key is a TypeError before anything is sent.
3224
3289
  */
@@ -3230,6 +3295,8 @@ declare class OwV2Client {
3230
3295
  withCharacter?: boolean;
3231
3296
  character?: string;
3232
3297
  preview?: boolean;
3298
+ maxUses?: number;
3299
+ characters?: string[];
3233
3300
  }): Promise<OwCreatedWorldLink>;
3234
3301
  /**
3235
3302
  * GET /account/worlds/{worldId}/links -- the world's invite links, without their codes:
package/dist/index.js CHANGED
@@ -173,6 +173,34 @@ var OwApiError = class extends Error {
173
173
  get isNotFound() {
174
174
  return this.status === 404 && this.code === "not_found";
175
175
  }
176
+ /**
177
+ * redeemJoin on a table (keel #422 PR 2): the picked Character is one a live seat in the
178
+ * world already plays (422 `character_taken`, `param` character). Pick another from a fresh
179
+ * previewJoin, whose `characters` mark each `taken`. The code is not spent.
180
+ */
181
+ get isCharacterTaken() {
182
+ return this.status === 422 && this.code === "character_taken";
183
+ }
184
+ /**
185
+ * The `character` sent was refused (422 `invalid_request`, `param` character). On redeemJoin
186
+ * at a table (keel #422 PR 2): the pick is off the link's list, hidden or deleted since the
187
+ * link was made, or missing, or sent to a table with no list (send `name` instead); one
188
+ * answer for all, so read previewJoin again and pick from its `characters`. The code is not
189
+ * spent. On createWorldLink: a `character` keel refused (not a Character of the world, a
190
+ * hidden one, or any `character` on a table). Never true for another param's 422, nor for
191
+ * `character_taken` (see isCharacterTaken).
192
+ */
193
+ get isCharacterInvalid() {
194
+ return this.status === 422 && this.code === "invalid_request" && this.param === "character";
195
+ }
196
+ /**
197
+ * redeemJoin (keel #422 PR 2): the world already has its 50 live players (422 `world_full`),
198
+ * at any player link, a table's or a link for one's. Nothing is spent; a place frees when the
199
+ * owner removes a player.
200
+ */
201
+ get isWorldFull() {
202
+ return this.status === 422 && this.code === "world_full";
203
+ }
176
204
  /** acceptJoin: the account is already a member of that world (409 `already_member`). The code is not spent. */
177
205
  get isAlreadyMember() {
178
206
  return this.status === 409 && this.code === "already_member";
@@ -772,7 +800,9 @@ var OwV2Client = class {
772
800
  * which world, in what role, and `reader` (`person`: accept it with acceptJoin;
773
801
  * `agent`: an AI agent redeems it at POST /join). Sends no credential, whatever key
774
802
  * this client holds. Every bad code (unknown, used, revoked, expired) is the same
775
- * 404 `not_found` (`err.isNotFound`). `code` is the part of the link after `#`.
803
+ * 404 `not_found` (`err.isNotFound`). `code` is the part of the link after `#`. A table
804
+ * (keel #422 PR 2) adds `max_uses`, `uses_left`, `name_required` and `characters`, the
805
+ * pick screen's list; a link for one answers without them.
776
806
  */
777
807
  async previewJoin(code) {
778
808
  return this.request("POST", "/join/preview", { auth: false, body: { code } });
@@ -787,11 +817,23 @@ var OwV2Client = class {
787
817
  * Character's name or "Player" when left out) and `agentName` (an agent's, required for an
788
818
  * agent code). Every bad code is the same 404 `not_found`; a person's code is redeemed with
789
819
  * acceptJoin instead.
820
+ *
821
+ * A table (a player code whose preview carries `max_uses`, keel #422 PR 2) seats one player
822
+ * per redeem, until `uses_left` is 0. With a list, `character` is the player's pick, the `id`
823
+ * of one of the preview's `characters` not `taken`: a Character a live seat already plays is
824
+ * 422 `character_taken` (`err.isCharacterTaken`; pick another), one off the list, hidden or
825
+ * deleted since, or none sent, is 422 `invalid_request`, param `character`
826
+ * (`err.isCharacterInvalid`; read the preview again). With no list
827
+ * (`name_required`), send `name` and no `character`: the player's fresh Character takes the
828
+ * name (missing: 422, param `name`). A world with its 50 players is 422 `invalid_request`;
829
+ * the last place taken by someone else first is the one 404. A refusal spends nothing. A link
830
+ * for one ignores `character`.
790
831
  */
791
832
  async redeemJoin(code, opts = {}) {
792
833
  const body = { code };
793
834
  if (opts.name !== void 0) body.name = opts.name;
794
835
  if (opts.agentName !== void 0) body.agent_name = opts.agentName;
836
+ if (opts.character !== void 0) body.character = opts.character;
795
837
  return this.request("POST", "/join", { auth: false, body });
796
838
  }
797
839
  // -- Signing in with a password (keel #211) --------------------------------
@@ -943,7 +985,14 @@ var OwV2Client = class {
943
985
  * whoever opens the link first reads as it, until removed. `preview` (person and player links,
944
986
  * keel #422) to false: true puts the world's id in the link's path, so a chat that unfurls it
945
987
  * shows the world's name and picture (the code stays after `#`); true on an agent link is
946
- * 422, param `preview`. 201 with the code, shown in this
988
+ * 422, param `preview`. `maxUses` (player links only, keel #422 PR 2) to 1, a link for one:
989
+ * 2 to 50 makes a table, one link that seats that many players, each picking one of
990
+ * `characters` (Character ids of the world, in the order a pick screen shows them; a hidden
991
+ * one is 422, param `characters`). `characters` empty or left out: each player names a fresh
992
+ * Character after themselves. A table takes no `character`, not even `new` (422, param
993
+ * `character`), and `characters` on a link for one is 422, even empty. A table counts once
994
+ * against the 50 pending invites; its seats count against the world's 50 players as each is
995
+ * made, so a full world refuses the pick, never the link. 201 with the code, shown in this
947
996
  * answer only. Owner only: anyone else, and a world that doesn't exist, gets 404
948
997
  * `not_found` (`err.isNotFound`). A world key is a TypeError before anything is sent.
949
998
  */
@@ -958,6 +1007,8 @@ var OwV2Client = class {
958
1007
  if (opts.withCharacter !== void 0) body.with_character = opts.withCharacter;
959
1008
  if (opts.character !== void 0) body.character = opts.character;
960
1009
  if (opts.preview !== void 0) body.preview = opts.preview;
1010
+ if (opts.maxUses !== void 0) body.max_uses = opts.maxUses;
1011
+ if (opts.characters !== void 0) body.characters = opts.characters;
961
1012
  return this.request("POST", `/account/worlds/${encodeURIComponent(worldId)}/links`, { body });
962
1013
  }
963
1014
  /**
@@ -1271,7 +1322,7 @@ function buildQuery(params) {
1271
1322
 
1272
1323
  // src/v2/types.generated.ts
1273
1324
  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"];
1274
- var ONLYWORLDS_VERSION = "00.32.00";
1325
+ var ONLYWORLDS_VERSION = "00.32.01";
1275
1326
  var ELEMENT_FAMILIES = {
1276
1327
  ability: "abstract",
1277
1328
  character: "agents",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlyworlds/sdk",
3
- "version": "4.37.0",
3
+ "version": "4.39.0",
4
4
  "description": "TypeScript SDK for the OnlyWorlds API - build world-building applications with type safety",
5
5
  "type": "module",
6
6
  "exports": {