@onlyworlds/sdk 4.8.0 → 4.8.1
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 +63 -63
- package/CHANGELOG.md +444 -434
- package/LICENSE +21 -21
- package/README.md +167 -167
- package/SCHEMA.md +631 -631
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +64 -64
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024-2025 OnlyWorlds
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2025 OnlyWorlds
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,167 +1,167 @@
|
|
|
1
|
-
# OnlyWorlds TypeScript SDK
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/@onlyworlds/sdk)
|
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
|
|
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).
|
|
7
|
-
|
|
8
|
-
## Install
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
npm install @onlyworlds/sdk
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## First run
|
|
15
|
-
|
|
16
|
-
Moppetopia is a public demo world. Its read-only key, `0000000001`, needs no account:
|
|
17
|
-
|
|
18
|
-
```typescript
|
|
19
|
-
import { OwV2Client } from '@onlyworlds/sdk';
|
|
20
|
-
|
|
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
|
-
```
|
|
31
|
-
|
|
32
|
-
## Your own world
|
|
33
|
-
|
|
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.
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
const writer = new OwV2Client({ apiKey: 'ow_w_…', apiPin: 'ow_s_…' });
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Reading and writing
|
|
46
|
-
|
|
47
|
-
```typescript
|
|
48
|
-
const location = await writer.create('location', {
|
|
49
|
-
name: 'Dragon Peak',
|
|
50
|
-
description: 'A mountain peak where dragons nest',
|
|
51
|
-
}); // the id is minted client-side when omitted, so a retry creates nothing twice
|
|
52
|
-
|
|
53
|
-
const dragon = await writer.create('creature', {
|
|
54
|
-
name: 'Vorrath the Ember-Scaled',
|
|
55
|
-
location: location.id, // a single link: a UUID or null
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const fetched = await writer.get('creature', dragon.id);
|
|
59
|
-
// fetched.location === location.id: a field reads the way it writes
|
|
60
|
-
|
|
61
|
-
// PATCH replaces the fields it sends; an array is replaced whole
|
|
62
|
-
await writer.patch('location', location.id, { supertype: 'Mountain' });
|
|
63
|
-
|
|
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: [] });
|
|
67
|
-
|
|
68
|
-
// Every page of a type
|
|
69
|
-
for await (const character of writer.listAll('character')) { /* ... */ }
|
|
70
|
-
```
|
|
71
|
-
|
|
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
|
|
75
|
-
|
|
76
|
-
`/bulk` answers 200 even when some items fail, so check `errors`:
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
const res = await writer.bulk(
|
|
80
|
-
[
|
|
81
|
-
{ type: 'character', element: { name: 'A' } },
|
|
82
|
-
{ type: 'event', element: { name: 'B' } },
|
|
83
|
-
],
|
|
84
|
-
{ idempotencyKey: crypto.randomUUID() }, // a new key per attempt: a failed batch is cached under its key
|
|
85
|
-
);
|
|
86
|
-
if (res.errors) {
|
|
87
|
-
for (const slot of res.items.filter((s) => s.status >= 400)) {
|
|
88
|
-
console.warn(slot.error?.code, slot.error?.message, slot.error?.doc_url);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
```
|
|
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
|
-
|
|
95
|
-
## Images
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
const image = await writer.uploadImage(file); // a Blob, File, ArrayBuffer or Uint8Array
|
|
99
|
-
await writer.patch('character', id, { image_url: image.url });
|
|
100
|
-
```
|
|
101
|
-
|
|
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>`.
|
|
103
|
-
|
|
104
|
-
```typescript
|
|
105
|
-
await writer.removeImage(image.url); // the image_url, or its object key
|
|
106
|
-
await writer.patch('character', id, { image_url: null });
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
The image's uploader or the world's owner can remove an uploaded image; the space goes back to the uploader's storage. Removal leaves elements as they are, so clear their `image_url` yourself (`createRemovalTicket(key).referenced` says how many still show it). A copy the network already holds can keep answering for a while.
|
|
110
|
-
|
|
111
|
-
## Sync
|
|
112
|
-
|
|
113
|
-
```typescript
|
|
114
|
-
let cursor; // opaque and never expires: keep it
|
|
115
|
-
for await (const change of client.changesAll(cursor)) {
|
|
116
|
-
// changes arrive in order; apply them in order and you converge
|
|
117
|
-
}
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
Edits to the world itself (its name, calendar, `public_read`) don't appear in the change feed. Read `client.getWorld()` and compare `updated_at`.
|
|
121
|
-
|
|
122
|
-
## Errors
|
|
123
|
-
|
|
124
|
-
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.
|
|
125
|
-
|
|
126
|
-
## Schema constants
|
|
127
|
-
|
|
128
|
-
```typescript
|
|
129
|
-
import {
|
|
130
|
-
ELEMENT_TYPES, // the 22 type slugs (and the ElementType union)
|
|
131
|
-
ELEMENT_ICONS, // a Material Symbols icon per type
|
|
132
|
-
ELEMENT_LABELS, // plural display labels
|
|
133
|
-
ELEMENT_SECTIONS, // field grouping and display order
|
|
134
|
-
FIELD_SCHEMA, // per-field type and link target
|
|
135
|
-
elementColor, // colour by family; the icon carries the type
|
|
136
|
-
} from '@onlyworlds/sdk';
|
|
137
|
-
|
|
138
|
-
elementColor('character', 'dark'); // '#3987e5'
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
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.
|
|
142
|
-
|
|
143
|
-
## Tokens
|
|
144
|
-
|
|
145
|
-
The account's token allowance and ratings, which some OnlyWorlds tools use.
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
import { TokenResource } from '@onlyworlds/sdk';
|
|
149
|
-
const tokens = new TokenResource(writer);
|
|
150
|
-
const status = await tokens.getStatus();
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
## SDK or MCP
|
|
154
|
-
|
|
155
|
-
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
|
-
|
|
157
|
-
## Version 3 and the old API
|
|
158
|
-
|
|
159
|
-
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
|
-
|
|
161
|
-
## Links
|
|
162
|
-
|
|
163
|
-
[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)
|
|
164
|
-
|
|
165
|
-
## License
|
|
166
|
-
|
|
167
|
-
MIT
|
|
1
|
+
# OnlyWorlds TypeScript SDK
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@onlyworlds/sdk)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
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).
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @onlyworlds/sdk
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## First run
|
|
15
|
+
|
|
16
|
+
Moppetopia is a public demo world. Its read-only key, `0000000001`, needs no account:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { OwV2Client } from '@onlyworlds/sdk';
|
|
20
|
+
|
|
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
|
+
```
|
|
31
|
+
|
|
32
|
+
## Your own world
|
|
33
|
+
|
|
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.
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
const writer = new OwV2Client({ apiKey: 'ow_w_…', apiPin: 'ow_s_…' });
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Reading and writing
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const location = await writer.create('location', {
|
|
49
|
+
name: 'Dragon Peak',
|
|
50
|
+
description: 'A mountain peak where dragons nest',
|
|
51
|
+
}); // the id is minted client-side when omitted, so a retry creates nothing twice
|
|
52
|
+
|
|
53
|
+
const dragon = await writer.create('creature', {
|
|
54
|
+
name: 'Vorrath the Ember-Scaled',
|
|
55
|
+
location: location.id, // a single link: a UUID or null
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const fetched = await writer.get('creature', dragon.id);
|
|
59
|
+
// fetched.location === location.id: a field reads the way it writes
|
|
60
|
+
|
|
61
|
+
// PATCH replaces the fields it sends; an array is replaced whole
|
|
62
|
+
await writer.patch('location', location.id, { supertype: 'Mountain' });
|
|
63
|
+
|
|
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: [] });
|
|
67
|
+
|
|
68
|
+
// Every page of a type
|
|
69
|
+
for await (const character of writer.listAll('character')) { /* ... */ }
|
|
70
|
+
```
|
|
71
|
+
|
|
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
|
|
75
|
+
|
|
76
|
+
`/bulk` answers 200 even when some items fail, so check `errors`:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const res = await writer.bulk(
|
|
80
|
+
[
|
|
81
|
+
{ type: 'character', element: { name: 'A' } },
|
|
82
|
+
{ type: 'event', element: { name: 'B' } },
|
|
83
|
+
],
|
|
84
|
+
{ idempotencyKey: crypto.randomUUID() }, // a new key per attempt: a failed batch is cached under its key
|
|
85
|
+
);
|
|
86
|
+
if (res.errors) {
|
|
87
|
+
for (const slot of res.items.filter((s) => s.status >= 400)) {
|
|
88
|
+
console.warn(slot.error?.code, slot.error?.message, slot.error?.doc_url);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
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
|
+
|
|
95
|
+
## Images
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
const image = await writer.uploadImage(file); // a Blob, File, ArrayBuffer or Uint8Array
|
|
99
|
+
await writer.patch('character', id, { image_url: image.url });
|
|
100
|
+
```
|
|
101
|
+
|
|
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>`.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
await writer.removeImage(image.url); // the image_url, or its object key
|
|
106
|
+
await writer.patch('character', id, { image_url: null });
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The image's uploader or the world's owner can remove an uploaded image; the space goes back to the uploader's storage. Removal leaves elements as they are, so clear their `image_url` yourself (`createRemovalTicket(key).referenced` says how many still show it). A copy the network already holds can keep answering for a while.
|
|
110
|
+
|
|
111
|
+
## Sync
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
let cursor; // opaque and never expires: keep it
|
|
115
|
+
for await (const change of client.changesAll(cursor)) {
|
|
116
|
+
// changes arrive in order; apply them in order and you converge
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Edits to the world itself (its name, calendar, `public_read`) don't appear in the change feed. Read `client.getWorld()` and compare `updated_at`.
|
|
121
|
+
|
|
122
|
+
## Errors
|
|
123
|
+
|
|
124
|
+
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.
|
|
125
|
+
|
|
126
|
+
## Schema constants
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import {
|
|
130
|
+
ELEMENT_TYPES, // the 22 type slugs (and the ElementType union)
|
|
131
|
+
ELEMENT_ICONS, // a Material Symbols icon per type
|
|
132
|
+
ELEMENT_LABELS, // plural display labels
|
|
133
|
+
ELEMENT_SECTIONS, // field grouping and display order
|
|
134
|
+
FIELD_SCHEMA, // per-field type and link target
|
|
135
|
+
elementColor, // colour by family; the icon carries the type
|
|
136
|
+
} from '@onlyworlds/sdk';
|
|
137
|
+
|
|
138
|
+
elementColor('character', 'dark'); // '#3987e5'
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
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.
|
|
142
|
+
|
|
143
|
+
## Tokens
|
|
144
|
+
|
|
145
|
+
The account's token allowance and ratings, which some OnlyWorlds tools use.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
import { TokenResource } from '@onlyworlds/sdk';
|
|
149
|
+
const tokens = new TokenResource(writer);
|
|
150
|
+
const status = await tokens.getStatus();
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## SDK or MCP
|
|
154
|
+
|
|
155
|
+
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
|
+
|
|
157
|
+
## Version 3 and the old API
|
|
158
|
+
|
|
159
|
+
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
|
+
|
|
161
|
+
## Links
|
|
162
|
+
|
|
163
|
+
[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)
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
MIT
|