@onlyworlds/sdk 4.0.0-alpha.0 → 4.0.0-alpha.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 +34 -34
- package/CHANGELOG.md +22 -5
- package/README.md +144 -144
- package/dist/index.d.ts +14 -4
- package/dist/index.js +25 -10
- package/package.json +61 -61
package/AGENTS.md
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
# For AI agents using @onlyworlds/sdk
|
|
2
|
-
|
|
3
|
-
**Start with [SCHEMA.md](SCHEMA.md)** (in this package): the full generated schema reference —
|
|
4
|
-
every type, every field with its meaning, link directions, families, icons, display sections.
|
|
5
|
-
It is generated from the same canonical YAML as the types, so it cannot drift.
|
|
6
|
-
|
|
7
|
-
**What this package is**: the canonical typed TypeScript client for the OnlyWorlds v2 API,
|
|
8
|
-
plus the canonical constants (element types, icons, colour families, field schema).
|
|
9
|
-
OnlyWorlds is an open standard for portable world data — 22 element types, UUID-linked.
|
|
10
|
-
|
|
11
|
-
**Use the v2 surface.** `OwV2Client` + the `V2ElementType` slug union + the generated
|
|
12
|
-
interfaces in `types.generated.ts` (emitted from the canonical schema YAML, validated
|
|
13
|
-
against live data). The v1 surface (`OnlyWorldsClient`, the `ElementType` enum) is frozen
|
|
14
|
-
legacy — do not build new work on it.
|
|
15
|
-
|
|
16
|
-
**SDK vs MCP server — pick correctly**:
|
|
17
|
-
- Known, deterministic operations (CRUD, sync, bulk) → **this SDK**. Typed calls, typed
|
|
18
|
-
responses, far cheaper than tool-schema reasoning.
|
|
19
|
-
- Live exploration of a user's world from a chat/agent context → the **MCP server** at
|
|
20
|
-
`https://www.onlyworlds.com/mcp` (same `API-Key`/`API-Pin` headers, 11 tools).
|
|
21
|
-
|
|
22
|
-
**Wire facts that bite** (full details in README):
|
|
23
|
-
- Never send a `"world"` field in payloads — world identity comes from the API key (422 otherwise).
|
|
24
|
-
- v2 link fields use ONE name both directions (no `_ids` suffix — that is v1 dialect only).
|
|
25
|
-
- PATCH is destructive on sent fields; use `editLinks` (atomic add/remove) for relationships.
|
|
26
|
-
- World-meta changes do NOT appear in `/changes` — poll `GET /world` separately.
|
|
27
|
-
- Extension fields: `x_<toolname>_*` is the sanctioned namespace for tool-specific state;
|
|
28
|
-
unknown unprefixed fields 422.
|
|
29
|
-
- Colour carries the element's FAMILY (`elementColor(type, mode)`); the icon
|
|
30
|
-
(`ELEMENT_ICONS`) carries the TYPE. Icon + label are required alongside colour, not optional.
|
|
31
|
-
|
|
32
|
-
**Auth**: prefixed keys — `ow_w_` (read+write), `ow_r_` (read-only, no PIN — the share
|
|
33
|
-
primitive), `ow_a_` (account Bearer). Demo keys `0000000000`–`0000000009` are read-only
|
|
34
|
-
test credentials against real data.
|
|
1
|
+
# For AI agents using @onlyworlds/sdk
|
|
2
|
+
|
|
3
|
+
**Start with [SCHEMA.md](SCHEMA.md)** (in this package): the full generated schema reference —
|
|
4
|
+
every type, every field with its meaning, link directions, families, icons, display sections.
|
|
5
|
+
It is generated from the same canonical YAML as the types, so it cannot drift.
|
|
6
|
+
|
|
7
|
+
**What this package is**: the canonical typed TypeScript client for the OnlyWorlds v2 API,
|
|
8
|
+
plus the canonical constants (element types, icons, colour families, field schema).
|
|
9
|
+
OnlyWorlds is an open standard for portable world data — 22 element types, UUID-linked.
|
|
10
|
+
|
|
11
|
+
**Use the v2 surface.** `OwV2Client` + the `V2ElementType` slug union + the generated
|
|
12
|
+
interfaces in `types.generated.ts` (emitted from the canonical schema YAML, validated
|
|
13
|
+
against live data). The v1 surface (`OnlyWorldsClient`, the `ElementType` enum) is frozen
|
|
14
|
+
legacy — do not build new work on it.
|
|
15
|
+
|
|
16
|
+
**SDK vs MCP server — pick correctly**:
|
|
17
|
+
- Known, deterministic operations (CRUD, sync, bulk) → **this SDK**. Typed calls, typed
|
|
18
|
+
responses, far cheaper than tool-schema reasoning.
|
|
19
|
+
- Live exploration of a user's world from a chat/agent context → the **MCP server** at
|
|
20
|
+
`https://www.onlyworlds.com/mcp` (same `API-Key`/`API-Pin` headers, 11 tools).
|
|
21
|
+
|
|
22
|
+
**Wire facts that bite** (full details in README):
|
|
23
|
+
- Never send a `"world"` field in payloads — world identity comes from the API key (422 otherwise).
|
|
24
|
+
- v2 link fields use ONE name both directions (no `_ids` suffix — that is v1 dialect only).
|
|
25
|
+
- PATCH is destructive on sent fields; use `editLinks` (atomic add/remove) for relationships.
|
|
26
|
+
- World-meta changes do NOT appear in `/changes` — poll `GET /world` separately.
|
|
27
|
+
- Extension fields: `x_<toolname>_*` is the sanctioned namespace for tool-specific state;
|
|
28
|
+
unknown unprefixed fields 422.
|
|
29
|
+
- Colour carries the element's FAMILY (`elementColor(type, mode)`); the icon
|
|
30
|
+
(`ELEMENT_ICONS`) carries the TYPE. Icon + label are required alongside colour, not optional.
|
|
31
|
+
|
|
32
|
+
**Auth**: prefixed keys — `ow_w_` (read+write), `ow_r_` (read-only, no PIN — the share
|
|
33
|
+
primitive), `ow_a_` (account Bearer). Demo keys `0000000000`–`0000000009` are read-only
|
|
34
|
+
test credentials against real data.
|
package/CHANGELOG.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
All notable changes to `@onlyworlds/sdk`. Maintained from 3.1.0 onward (Kael, Assembly);
|
|
4
4
|
earlier history lives in git log only.
|
|
5
5
|
|
|
6
|
-
## [
|
|
6
|
+
## [4.0.0] — 2026-07-23
|
|
7
7
|
|
|
8
8
|
**v2-native only.** See `docs/migrating-3-to-4.md`. 3.x stays published forever for
|
|
9
9
|
pinned consumers.
|
|
@@ -40,10 +40,27 @@ pinned consumers.
|
|
|
40
40
|
- README rewritten v2-native (v1 sections, branded types, and the encrypted-key
|
|
41
41
|
walkthrough removed; bulk partial-failure and idempotency-key hygiene promoted).
|
|
42
42
|
|
|
43
|
-
###
|
|
44
|
-
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
### alpha.1 — consumer-pin fixes (Temper's atlas review, same night)
|
|
44
|
+
- **`parseEnvelope` → `parseErrorEnvelope`** (it parses the platform *error* envelope;
|
|
45
|
+
renamed before the 4.0 name freeze to avoid collision with the world-export envelope).
|
|
46
|
+
- The never-whitelist LAW now lives as a comment on `READ_ONLY_FIELDS` itself.
|
|
47
|
+
- Stale v1 example in the shipped d.ts fixed (TokenResource JSDoc).
|
|
48
|
+
|
|
49
|
+
### Release gates — ALL GREEN (2026-07-23 night)
|
|
50
|
+
- **Gate 3 (wire-log v1-traffic query, Skeld)**: GREEN — no unknown v1-SDK consumer on
|
|
51
|
+
the wire; observed v1 traffic is pinned deployed builds (council proxy, legacy plugin
|
|
52
|
+
walks) that an npm major cannot touch. The v1 API dialect stays served regardless.
|
|
53
|
+
- **`/api/v2/tokens/` live on prod + staging** (keel `e181689`; three-base byte
|
|
54
|
+
agreement test-pinned). `TokenResource` annotates a 404 on token routes as
|
|
55
|
+
"older server", not "no tokens". Requirement noted in the migration guide.
|
|
56
|
+
- **`ONLYWORLDS_VERSION` now GENERATED** from canonical's `VERSION` file (carried
|
|
57
|
+
into keel `schema/` by the refresh script, keel `492168c`) — the last hand-synced
|
|
58
|
+
constant is dead. Consumer soak: Temper pinned the alpha against atlas's full
|
|
59
|
+
static surface — strict-clean compile, correct runtime, package shape approved.
|
|
60
|
+
- **No `npm deprecate` on 3.x** (landscape research; 3.x stays plainly supported).
|
|
61
|
+
- 4.x wishlist: account client (list/mint/create — atlas first consumer), world-export
|
|
62
|
+
envelope reader (§8c), per-status error classes, richer codegen JSDoc, retry/backoff
|
|
63
|
+
parity audit, FIELD_SCHEMA generation with `required:` from YAML.
|
|
47
64
|
|
|
48
65
|
## [3.1.0] — 2026-07-23
|
|
49
66
|
|
package/README.md
CHANGED
|
@@ -1,144 +1,144 @@
|
|
|
1
|
-
# OnlyWorlds TypeScript SDK
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/@onlyworlds/sdk)
|
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
|
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
|
-
same schema source the server runs on.
|
|
9
|
-
|
|
10
|
-
**4.x is v2-native and ESM-only (Node 18+).** If you need the legacy v1 API dialect
|
|
11
|
-
(`OnlyWorldsClient`) or CommonJS `require()`, stay on 3.x — it remains published and the v1 API
|
|
12
|
-
remains served. See [docs/migrating-3-to-4.md](docs/migrating-3-to-4.md).
|
|
13
|
-
|
|
14
|
-
## Installation
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npm install @onlyworlds/sdk
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Quick Start
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
import { OwV2Client } from '@onlyworlds/sdk';
|
|
24
|
-
|
|
25
|
-
const client = new OwV2Client({ apiKey: 'ow_r_your_key' }); // read-only key: that's all you need
|
|
26
|
-
const page = await client.list('character'); // { data, has_more, next_cursor }
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Key kinds: `ow_w_` write / `ow_r_` read-only (no PIN — the "give this to your players" key) /
|
|
30
|
-
`ow_a_` account Bearer / 10-digit legacy. Writes on a PIN-protected world also pass `apiPin`.
|
|
31
|
-
Demo keys `0000000000`–`0000000009` read real sample worlds.
|
|
32
|
-
|
|
33
|
-
## The full round-trip
|
|
34
|
-
|
|
35
|
-
```typescript
|
|
36
|
-
const writer = new OwV2Client({ apiKey: 'ow_w_your_key', apiPin: '1234' });
|
|
37
|
-
|
|
38
|
-
// v2 dialect rules, worth internalizing once:
|
|
39
|
-
// - link fields use ONE bare name both directions (no _ids suffix — that's v1)
|
|
40
|
-
// - NEVER send a "world" field (identity comes from the key; the client strips it anyway)
|
|
41
|
-
const location = await writer.create('location', {
|
|
42
|
-
name: 'Dragon Peak',
|
|
43
|
-
description: 'A treacherous mountain peak where dragons nest',
|
|
44
|
-
}); // id minted client-side when omitted (retries stay idempotent)
|
|
45
|
-
|
|
46
|
-
const dragon = await writer.create('creature', {
|
|
47
|
-
name: 'Vorrath the Ember-Scaled',
|
|
48
|
-
location: location.id, // single link: UUID (or null)
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const fetched = await writer.get('creature', dragon.id);
|
|
52
|
-
// fetched.location === location.id — reads the way it writes
|
|
53
|
-
|
|
54
|
-
// PATCH is destructive on sent fields; arrays replace wholesale
|
|
55
|
-
await writer.patch('location', location.id, { supertype: 'Mountain' });
|
|
56
|
-
|
|
57
|
-
// For relationships, use the atomic link merge — returns the full updated element
|
|
58
|
-
const fireBreath = await writer.create('ability', { name: 'Ember Breath' });
|
|
59
|
-
await writer.editLinks('creature', dragon.id, 'abilities', { add: [fireBreath.id], remove: [] });
|
|
60
|
-
|
|
61
|
-
// Walk every page of a type
|
|
62
|
-
for await (const character of writer.listAll('character')) { /* ... */ }
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## Bulk writes — always check `errors`
|
|
66
|
-
|
|
67
|
-
`/bulk` **succeeds partially by default** (HTTP 200 with per-slot statuses). The one mistake to
|
|
68
|
-
never make: treating a 200 as "everything landed."
|
|
69
|
-
|
|
70
|
-
```typescript
|
|
71
|
-
const res = await writer.bulk(
|
|
72
|
-
[
|
|
73
|
-
{ type: 'character', element: { name: 'A' } },
|
|
74
|
-
{ type: 'event', element: { name: 'B' } },
|
|
75
|
-
],
|
|
76
|
-
{ idempotencyKey: crypto.randomUUID() }, // mint FRESH per attempt — a failed batch is
|
|
77
|
-
); // cached under its key; never reuse across retries
|
|
78
|
-
if (res.errors) {
|
|
79
|
-
for (const slot of res.items.filter((s) => s.status >= 400)) {
|
|
80
|
-
console.warn(slot.error?.code, slot.error?.message, slot.error?.doc_url);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
// Pass { atomic: true } for all-or-nothing instead. res.wasReplay flags idempotent replays.
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## Sync
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
let cursor; // opaque, never expires; persist it
|
|
90
|
-
for await (const change of client.changesAll(cursor)) {
|
|
91
|
-
// ops arrive in (change_seq, id) order — apply in order → convergence
|
|
92
|
-
}
|
|
93
|
-
// GOTCHA: world-meta edits (name, calendar, public_read) do NOT enter /changes.
|
|
94
|
-
// Poll client.getWorld() and compare updated_at separately.
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Errors
|
|
98
|
-
|
|
99
|
-
Every non-2xx throws `OwApiError` carrying the platform envelope: `.status`, `.type`, `.code`,
|
|
100
|
-
`.param` (the exact field that failed), and `.docUrl` — surface `docUrl` in your UX. Transport
|
|
101
|
-
failures throw `OwNetworkError`. `err.isValidationError` is the common branch.
|
|
102
|
-
|
|
103
|
-
## Canonical constants (all generated or test-gated from schema)
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
import {
|
|
107
|
-
ELEMENT_TYPES, // the 22 slugs (and the ElementType union)
|
|
108
|
-
ELEMENT_ICONS, // Material Symbols icon per type
|
|
109
|
-
ELEMENT_LABELS, // plural display labels
|
|
110
|
-
ELEMENT_SECTIONS, // canonical field grouping + display order
|
|
111
|
-
FIELD_SCHEMA, // per-field type/target metadata
|
|
112
|
-
elementColor, // canonical colour: family carries COLOUR, icon carries TYPE
|
|
113
|
-
} from '@onlyworlds/sdk';
|
|
114
|
-
|
|
115
|
-
elementColor('character', 'dark'); // '#3987e5' — four CVD-validated families
|
|
116
|
-
// Always pair colour with icon + label; colour alone is not accessible.
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
The full schema with per-field meaning lives in [SCHEMA.md](SCHEMA.md) (generated, ships in this
|
|
120
|
-
package). AI agents: read [AGENTS.md](AGENTS.md) first.
|
|
121
|
-
|
|
122
|
-
## Token rating system
|
|
123
|
-
|
|
124
|
-
```typescript
|
|
125
|
-
import { TokenResource } from '@onlyworlds/sdk';
|
|
126
|
-
const tokens = new TokenResource(writer); // OwV2Client.request() satisfies TokenTransport
|
|
127
|
-
const status = await tokens.getStatus();
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## AI access — when to use which
|
|
131
|
-
|
|
132
|
-
For **known, deterministic operations** (CRUD, sync, bulk) use this SDK — typed calls, no
|
|
133
|
-
tool-schema overhead. For **live exploration of a user's world from a chat/agent context**, use
|
|
134
|
-
the MCP server at `https://www.onlyworlds.com/mcp` (same `API-Key`/`API-Pin` headers, 11 tools;
|
|
135
|
-
unaffected by SDK versioning).
|
|
136
|
-
|
|
137
|
-
## License
|
|
138
|
-
|
|
139
|
-
MIT
|
|
140
|
-
|
|
141
|
-
## Links
|
|
142
|
-
|
|
143
|
-
- [OnlyWorlds](https://www.onlyworlds.com) · [Docs](https://onlyworlds.github.io) · [API reference](https://www.onlyworlds.com/api/docs)
|
|
144
|
-
- [Issues](https://github.com/OnlyWorlds/sdk/issues) · [CHANGELOG](CHANGELOG.md) · [Migration 3→4](docs/migrating-3-to-4.md)
|
|
1
|
+
# OnlyWorlds TypeScript SDK
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@onlyworlds/sdk)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
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
|
+
same schema source the server runs on.
|
|
9
|
+
|
|
10
|
+
**4.x is v2-native and ESM-only (Node 18+).** If you need the legacy v1 API dialect
|
|
11
|
+
(`OnlyWorldsClient`) or CommonJS `require()`, stay on 3.x — it remains published and the v1 API
|
|
12
|
+
remains served. See [docs/migrating-3-to-4.md](docs/migrating-3-to-4.md).
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @onlyworlds/sdk
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { OwV2Client } from '@onlyworlds/sdk';
|
|
24
|
+
|
|
25
|
+
const client = new OwV2Client({ apiKey: 'ow_r_your_key' }); // read-only key: that's all you need
|
|
26
|
+
const page = await client.list('character'); // { data, has_more, next_cursor }
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Key kinds: `ow_w_` write / `ow_r_` read-only (no PIN — the "give this to your players" key) /
|
|
30
|
+
`ow_a_` account Bearer / 10-digit legacy. Writes on a PIN-protected world also pass `apiPin`.
|
|
31
|
+
Demo keys `0000000000`–`0000000009` read real sample worlds.
|
|
32
|
+
|
|
33
|
+
## The full round-trip
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
const writer = new OwV2Client({ apiKey: 'ow_w_your_key', apiPin: '1234' });
|
|
37
|
+
|
|
38
|
+
// v2 dialect rules, worth internalizing once:
|
|
39
|
+
// - link fields use ONE bare name both directions (no _ids suffix — that's v1)
|
|
40
|
+
// - NEVER send a "world" field (identity comes from the key; the client strips it anyway)
|
|
41
|
+
const location = await writer.create('location', {
|
|
42
|
+
name: 'Dragon Peak',
|
|
43
|
+
description: 'A treacherous mountain peak where dragons nest',
|
|
44
|
+
}); // id minted client-side when omitted (retries stay idempotent)
|
|
45
|
+
|
|
46
|
+
const dragon = await writer.create('creature', {
|
|
47
|
+
name: 'Vorrath the Ember-Scaled',
|
|
48
|
+
location: location.id, // single link: UUID (or null)
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const fetched = await writer.get('creature', dragon.id);
|
|
52
|
+
// fetched.location === location.id — reads the way it writes
|
|
53
|
+
|
|
54
|
+
// PATCH is destructive on sent fields; arrays replace wholesale
|
|
55
|
+
await writer.patch('location', location.id, { supertype: 'Mountain' });
|
|
56
|
+
|
|
57
|
+
// For relationships, use the atomic link merge — returns the full updated element
|
|
58
|
+
const fireBreath = await writer.create('ability', { name: 'Ember Breath' });
|
|
59
|
+
await writer.editLinks('creature', dragon.id, 'abilities', { add: [fireBreath.id], remove: [] });
|
|
60
|
+
|
|
61
|
+
// Walk every page of a type
|
|
62
|
+
for await (const character of writer.listAll('character')) { /* ... */ }
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Bulk writes — always check `errors`
|
|
66
|
+
|
|
67
|
+
`/bulk` **succeeds partially by default** (HTTP 200 with per-slot statuses). The one mistake to
|
|
68
|
+
never make: treating a 200 as "everything landed."
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
const res = await writer.bulk(
|
|
72
|
+
[
|
|
73
|
+
{ type: 'character', element: { name: 'A' } },
|
|
74
|
+
{ type: 'event', element: { name: 'B' } },
|
|
75
|
+
],
|
|
76
|
+
{ idempotencyKey: crypto.randomUUID() }, // mint FRESH per attempt — a failed batch is
|
|
77
|
+
); // cached under its key; never reuse across retries
|
|
78
|
+
if (res.errors) {
|
|
79
|
+
for (const slot of res.items.filter((s) => s.status >= 400)) {
|
|
80
|
+
console.warn(slot.error?.code, slot.error?.message, slot.error?.doc_url);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Pass { atomic: true } for all-or-nothing instead. res.wasReplay flags idempotent replays.
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Sync
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
let cursor; // opaque, never expires; persist it
|
|
90
|
+
for await (const change of client.changesAll(cursor)) {
|
|
91
|
+
// ops arrive in (change_seq, id) order — apply in order → convergence
|
|
92
|
+
}
|
|
93
|
+
// GOTCHA: world-meta edits (name, calendar, public_read) do NOT enter /changes.
|
|
94
|
+
// Poll client.getWorld() and compare updated_at separately.
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Errors
|
|
98
|
+
|
|
99
|
+
Every non-2xx throws `OwApiError` carrying the platform envelope: `.status`, `.type`, `.code`,
|
|
100
|
+
`.param` (the exact field that failed), and `.docUrl` — surface `docUrl` in your UX. Transport
|
|
101
|
+
failures throw `OwNetworkError`. `err.isValidationError` is the common branch.
|
|
102
|
+
|
|
103
|
+
## Canonical constants (all generated or test-gated from schema)
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import {
|
|
107
|
+
ELEMENT_TYPES, // the 22 slugs (and the ElementType union)
|
|
108
|
+
ELEMENT_ICONS, // Material Symbols icon per type
|
|
109
|
+
ELEMENT_LABELS, // plural display labels
|
|
110
|
+
ELEMENT_SECTIONS, // canonical field grouping + display order
|
|
111
|
+
FIELD_SCHEMA, // per-field type/target metadata
|
|
112
|
+
elementColor, // canonical colour: family carries COLOUR, icon carries TYPE
|
|
113
|
+
} from '@onlyworlds/sdk';
|
|
114
|
+
|
|
115
|
+
elementColor('character', 'dark'); // '#3987e5' — four CVD-validated families
|
|
116
|
+
// Always pair colour with icon + label; colour alone is not accessible.
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The full schema with per-field meaning lives in [SCHEMA.md](SCHEMA.md) (generated, ships in this
|
|
120
|
+
package). AI agents: read [AGENTS.md](AGENTS.md) first.
|
|
121
|
+
|
|
122
|
+
## Token rating system
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { TokenResource } from '@onlyworlds/sdk';
|
|
126
|
+
const tokens = new TokenResource(writer); // OwV2Client.request() satisfies TokenTransport
|
|
127
|
+
const status = await tokens.getStatus();
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## AI access — when to use which
|
|
131
|
+
|
|
132
|
+
For **known, deterministic operations** (CRUD, sync, bulk) use this SDK — typed calls, no
|
|
133
|
+
tool-schema overhead. For **live exploration of a user's world from a chat/agent context**, use
|
|
134
|
+
the MCP server at `https://www.onlyworlds.com/mcp` (same `API-Key`/`API-Pin` headers, 11 tools;
|
|
135
|
+
unaffected by SDK versioning).
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT
|
|
140
|
+
|
|
141
|
+
## Links
|
|
142
|
+
|
|
143
|
+
- [OnlyWorlds](https://www.onlyworlds.com) · [Docs](https://onlyworlds.github.io) · [API reference](https://www.onlyworlds.com/api/docs)
|
|
144
|
+
- [Issues](https://github.com/OnlyWorlds/sdk/issues) · [CHANGELOG](CHANGELOG.md) · [Migration 3→4](docs/migrating-3-to-4.md)
|
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ interface OwElementBase {
|
|
|
26
26
|
}
|
|
27
27
|
type ElementType = 'ability' | 'character' | 'collective' | 'construct' | 'creature' | 'event' | 'family' | 'institution' | 'language' | 'law' | 'location' | 'map' | 'marker' | 'narrative' | 'object' | 'phenomenon' | 'pin' | 'relation' | 'species' | 'title' | 'trait' | 'zone';
|
|
28
28
|
declare const ELEMENT_TYPES: ElementType[];
|
|
29
|
+
/** Canonical OnlyWorlds schema version. Source: canonical VERSION file, carried into keel schema/ by the refresh script (keel 492168c). */
|
|
30
|
+
declare const ONLYWORLDS_VERSION: "00.30.00";
|
|
29
31
|
/** The four semantic families (colour carries the family; ELEMENT_ICONS carries the type). */
|
|
30
32
|
type ElementFamily = 'agents' | 'world' | 'abstract' | 'temporal';
|
|
31
33
|
/** Per-type semantic family. Source: keel's PRESENTATION-WRAPPER schema key `family:`
|
|
@@ -218,7 +220,9 @@ declare class OwNetworkError extends Error {
|
|
|
218
220
|
constructor(message: string, cause: unknown);
|
|
219
221
|
}
|
|
220
222
|
/** Parse a wire envelope into OwApiError parts (exported for the error type-tests). */
|
|
221
|
-
|
|
223
|
+
/** Parse the platform ERROR envelope into an OwApiError. (Renamed from parseEnvelope in 4.0 —
|
|
224
|
+
* distinct from the world-export envelope, which is a different artifact entirely.) */
|
|
225
|
+
declare function parseErrorEnvelope(status: number, body: unknown): OwApiError;
|
|
222
226
|
/** Build an OwApiError from a non-2xx response, tolerating non-JSON bodies. */
|
|
223
227
|
declare function errorFromResponse(res: Response): Promise<OwApiError>;
|
|
224
228
|
|
|
@@ -422,7 +426,6 @@ declare const FAMILY_ORDER: readonly ElementFamily[];
|
|
|
422
426
|
* Current OnlyWorlds version
|
|
423
427
|
* Synced with https://github.com/OnlyWorlds/OnlyWorlds/blob/main/VERSION
|
|
424
428
|
*/
|
|
425
|
-
declare const ONLYWORLDS_VERSION: "00.30.00";
|
|
426
429
|
/**
|
|
427
430
|
* Field type definitions for OnlyWorlds elements
|
|
428
431
|
*/
|
|
@@ -2373,7 +2376,8 @@ interface TokenTransport {
|
|
|
2373
2376
|
*
|
|
2374
2377
|
* Example usage:
|
|
2375
2378
|
* ```typescript
|
|
2376
|
-
* const client = new
|
|
2379
|
+
* const client = new OwV2Client({ apiKey: "ow_w_...", apiPin: "1234" });
|
|
2380
|
+
* const tokens = new TokenResource(client);
|
|
2377
2381
|
*
|
|
2378
2382
|
* // Check token status
|
|
2379
2383
|
* const status = await client.tokens.getStatus();
|
|
@@ -2390,6 +2394,12 @@ interface TokenTransport {
|
|
|
2390
2394
|
declare class TokenResource {
|
|
2391
2395
|
private client;
|
|
2392
2396
|
constructor(client: TokenTransport);
|
|
2397
|
+
/**
|
|
2398
|
+
* All token routes go through here: a 404 on /tokens/* almost always means
|
|
2399
|
+
* the SERVER predates the v2 token mount (keel >= 2026-07-23, e181689) —
|
|
2400
|
+
* not "user has no tokens". Annotate so the failure reads correctly.
|
|
2401
|
+
*/
|
|
2402
|
+
private req;
|
|
2393
2403
|
/**
|
|
2394
2404
|
* Get current token status for authenticated user
|
|
2395
2405
|
*
|
|
@@ -2508,4 +2518,4 @@ declare class TokenResource {
|
|
|
2508
2518
|
getEncryptionInfo(): Promise<EncryptionInfo>;
|
|
2509
2519
|
}
|
|
2510
2520
|
|
|
2511
|
-
export { type AccessKeyResponse, ELEMENT_FAMILIES, ELEMENT_ICONS, ELEMENT_LABELS, ELEMENT_SECTIONS, ELEMENT_TYPES, type ElementFamily, type ElementType, type EncryptionInfo, FAMILY_COLORS, FAMILY_ORDER, FIELD_SCHEMA, type FieldInfo, type FieldType, GameTier, type ListParams, ONLYWORLDS_VERSION, OwApiError, type OwAuthErrorCode, type OwBulkItem, type OwBulkItemResult, type OwBulkResponse, type OwChange, type OwChangesPage, type OwClientConfig, type OwElement, type OwElementBase, type OwErrorBody, type OwKeyKind, type OwLinkEdit, OwNetworkError, type OwPage, OwV2Client, type OwWorldMeta, type RevokeAllSessionsResponse, type RevokeSessionResponse, SPATIAL_TYPES, type SectionInfo, type TokenConsumeParams, type TokenConsumeResponse, TokenResource, type TokenStatus, type TokenTransport, detectKeyKind, elementColor, errorFromResponse, familyOf, getElementIcon, getElementLabel, isDemoKey, kindCanWrite,
|
|
2521
|
+
export { type AccessKeyResponse, ELEMENT_FAMILIES, ELEMENT_ICONS, ELEMENT_LABELS, ELEMENT_SECTIONS, ELEMENT_TYPES, type ElementFamily, type ElementType, type EncryptionInfo, FAMILY_COLORS, FAMILY_ORDER, FIELD_SCHEMA, type FieldInfo, type FieldType, GameTier, type ListParams, ONLYWORLDS_VERSION, OwApiError, type OwAuthErrorCode, type OwBulkItem, type OwBulkItemResult, type OwBulkResponse, type OwChange, type OwChangesPage, type OwClientConfig, type OwElement, type OwElementBase, type OwErrorBody, type OwKeyKind, type OwLinkEdit, OwNetworkError, type OwPage, OwV2Client, type OwWorldMeta, type RevokeAllSessionsResponse, type RevokeSessionResponse, SPATIAL_TYPES, type SectionInfo, type TokenConsumeParams, type TokenConsumeResponse, TokenResource, type TokenStatus, type TokenTransport, detectKeyKind, elementColor, errorFromResponse, familyOf, getElementIcon, getElementLabel, isDemoKey, kindCanWrite, parseErrorEnvelope, pinExpectation };
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,7 @@ var OwNetworkError = class extends Error {
|
|
|
29
29
|
this.cause2 = cause;
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
|
-
function
|
|
32
|
+
function parseErrorEnvelope(status, body) {
|
|
33
33
|
const env = body && typeof body === "object" ? body : {};
|
|
34
34
|
const nested = typeof env.error === "object" && env.error !== null ? env.error : void 0;
|
|
35
35
|
const code = env.code ?? nested?.code ?? (typeof env.error === "string" ? env.error : null) ?? null;
|
|
@@ -48,7 +48,7 @@ async function errorFromResponse(res) {
|
|
|
48
48
|
} catch {
|
|
49
49
|
body = text || null;
|
|
50
50
|
}
|
|
51
|
-
return
|
|
51
|
+
return parseErrorEnvelope(res.status, body);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
// src/v2/keys.ts
|
|
@@ -314,6 +314,7 @@ function buildQuery(params) {
|
|
|
314
314
|
|
|
315
315
|
// src/v2/types.generated.ts
|
|
316
316
|
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"];
|
|
317
|
+
var ONLYWORLDS_VERSION = "00.30.00";
|
|
317
318
|
var ELEMENT_FAMILIES = {
|
|
318
319
|
ability: "abstract",
|
|
319
320
|
character: "agents",
|
|
@@ -485,7 +486,6 @@ function elementColor(type, mode = "dark") {
|
|
|
485
486
|
var FAMILY_ORDER = ["agents", "world", "abstract", "temporal"];
|
|
486
487
|
|
|
487
488
|
// src/v2/constants.ts
|
|
488
|
-
var ONLYWORLDS_VERSION = "00.30.00";
|
|
489
489
|
var ELEMENT_LABELS = {
|
|
490
490
|
ability: "Abilities",
|
|
491
491
|
character: "Characters",
|
|
@@ -1150,6 +1150,21 @@ var TokenResource = class {
|
|
|
1150
1150
|
constructor(client) {
|
|
1151
1151
|
this.client = client;
|
|
1152
1152
|
}
|
|
1153
|
+
/**
|
|
1154
|
+
* All token routes go through here: a 404 on /tokens/* almost always means
|
|
1155
|
+
* the SERVER predates the v2 token mount (keel >= 2026-07-23, e181689) —
|
|
1156
|
+
* not "user has no tokens". Annotate so the failure reads correctly.
|
|
1157
|
+
*/
|
|
1158
|
+
async req(method, path, opts) {
|
|
1159
|
+
try {
|
|
1160
|
+
return await this.client.request(method, path, opts);
|
|
1161
|
+
} catch (err) {
|
|
1162
|
+
if (err && typeof err === "object" && err.status === 404) {
|
|
1163
|
+
err.message += " [token routes require keel >= 2026-07-23 (e181689) on /api/v2 \u2014 a 404 here usually means an older server, not zero tokens]";
|
|
1164
|
+
}
|
|
1165
|
+
throw err;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1153
1168
|
/**
|
|
1154
1169
|
* Get current token status for authenticated user
|
|
1155
1170
|
*
|
|
@@ -1166,7 +1181,7 @@ var TokenResource = class {
|
|
|
1166
1181
|
* ```
|
|
1167
1182
|
*/
|
|
1168
1183
|
async getStatus() {
|
|
1169
|
-
return this.
|
|
1184
|
+
return this.req("GET", "/tokens/status/");
|
|
1170
1185
|
}
|
|
1171
1186
|
/**
|
|
1172
1187
|
* Consume tokens for service usage
|
|
@@ -1197,7 +1212,7 @@ var TokenResource = class {
|
|
|
1197
1212
|
* ```
|
|
1198
1213
|
*/
|
|
1199
1214
|
async consume(params) {
|
|
1200
|
-
return this.
|
|
1215
|
+
return this.req("POST", "/tokens/consume/", {
|
|
1201
1216
|
body: {
|
|
1202
1217
|
amount: params.amount,
|
|
1203
1218
|
service: params.service || "sdk_client",
|
|
@@ -1233,7 +1248,7 @@ var TokenResource = class {
|
|
|
1233
1248
|
* ```
|
|
1234
1249
|
*/
|
|
1235
1250
|
async getAccessKey() {
|
|
1236
|
-
return this.
|
|
1251
|
+
return this.req("GET", "/tokens/access-key/");
|
|
1237
1252
|
}
|
|
1238
1253
|
/**
|
|
1239
1254
|
* Revoke a specific token session
|
|
@@ -1249,7 +1264,7 @@ var TokenResource = class {
|
|
|
1249
1264
|
* ```
|
|
1250
1265
|
*/
|
|
1251
1266
|
async revokeSession(sessionId) {
|
|
1252
|
-
return this.
|
|
1267
|
+
return this.req(
|
|
1253
1268
|
"POST",
|
|
1254
1269
|
`/tokens/revoke-session/?session_id=${encodeURIComponent(sessionId)}`
|
|
1255
1270
|
);
|
|
@@ -1268,7 +1283,7 @@ var TokenResource = class {
|
|
|
1268
1283
|
* ```
|
|
1269
1284
|
*/
|
|
1270
1285
|
async revokeAllSessions() {
|
|
1271
|
-
return this.
|
|
1286
|
+
return this.req("POST", "/tokens/revoke-all-sessions/");
|
|
1272
1287
|
}
|
|
1273
1288
|
/**
|
|
1274
1289
|
* Get public encryption info (no auth required)
|
|
@@ -1286,7 +1301,7 @@ var TokenResource = class {
|
|
|
1286
1301
|
* ```
|
|
1287
1302
|
*/
|
|
1288
1303
|
async getEncryptionInfo() {
|
|
1289
|
-
return this.
|
|
1304
|
+
return this.req("GET", "/tokens/encryption-info/");
|
|
1290
1305
|
}
|
|
1291
1306
|
};
|
|
1292
1307
|
|
|
@@ -1324,6 +1339,6 @@ export {
|
|
|
1324
1339
|
getElementLabel,
|
|
1325
1340
|
isDemoKey,
|
|
1326
1341
|
kindCanWrite,
|
|
1327
|
-
|
|
1342
|
+
parseErrorEnvelope,
|
|
1328
1343
|
pinExpectation
|
|
1329
1344
|
};
|
package/package.json
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@onlyworlds/sdk",
|
|
3
|
-
"version": "4.0.0-alpha.
|
|
4
|
-
"description": "TypeScript SDK for the OnlyWorlds API - build world-building applications with type safety",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"exports": {
|
|
7
|
-
".": {
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
9
|
-
"import": "./dist/index.js"
|
|
10
|
-
},
|
|
11
|
-
"./package.json": "./package.json"
|
|
12
|
-
},
|
|
13
|
-
"types": "dist/index.d.ts",
|
|
14
|
-
"sideEffects": false,
|
|
15
|
-
"files": [
|
|
16
|
-
"dist",
|
|
17
|
-
"README.md",
|
|
18
|
-
"AGENTS.md",
|
|
19
|
-
"CHANGELOG.md",
|
|
20
|
-
"SCHEMA.md"
|
|
21
|
-
],
|
|
22
|
-
"scripts": {
|
|
23
|
-
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
24
|
-
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
25
|
-
"pretest": "npm run build",
|
|
26
|
-
"test": "node --test \"test/**/*.test.mjs\"",
|
|
27
|
-
"codegen": "python codegen/generate_types.py",
|
|
28
|
-
"codegen:check": "python codegen/generate_types.py --check",
|
|
29
|
-
"prepublishOnly": "npm run build"
|
|
30
|
-
},
|
|
31
|
-
"keywords": [
|
|
32
|
-
"onlyworlds",
|
|
33
|
-
"worldbuilding",
|
|
34
|
-
"api",
|
|
35
|
-
"sdk",
|
|
36
|
-
"typescript",
|
|
37
|
-
"rpg",
|
|
38
|
-
"ttrpg",
|
|
39
|
-
"game-development"
|
|
40
|
-
],
|
|
41
|
-
"author": "OnlyWorlds",
|
|
42
|
-
"license": "MIT",
|
|
43
|
-
"repository": {
|
|
44
|
-
"type": "git",
|
|
45
|
-
"url": "git+https://github.com/OnlyWorlds/sdk.git"
|
|
46
|
-
},
|
|
47
|
-
"homepage": "https://onlyworlds.github.io/",
|
|
48
|
-
"bugs": {
|
|
49
|
-
"url": "https://github.com/OnlyWorlds/sdk/issues"
|
|
50
|
-
},
|
|
51
|
-
"devDependencies": {
|
|
52
|
-
"tsup": "^8.0.1",
|
|
53
|
-
"typescript": "^5.3.3"
|
|
54
|
-
},
|
|
55
|
-
"peerDependencies": {
|
|
56
|
-
"typescript": ">=4.5.0"
|
|
57
|
-
},
|
|
58
|
-
"engines": {
|
|
59
|
-
"node": ">=18.0.0"
|
|
60
|
-
}
|
|
61
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@onlyworlds/sdk",
|
|
3
|
+
"version": "4.0.0-alpha.1",
|
|
4
|
+
"description": "TypeScript SDK for the OnlyWorlds API - build world-building applications with type safety",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./package.json": "./package.json"
|
|
12
|
+
},
|
|
13
|
+
"types": "dist/index.d.ts",
|
|
14
|
+
"sideEffects": false,
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"AGENTS.md",
|
|
19
|
+
"CHANGELOG.md",
|
|
20
|
+
"SCHEMA.md"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
24
|
+
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
25
|
+
"pretest": "npm run build",
|
|
26
|
+
"test": "node --test \"test/**/*.test.mjs\"",
|
|
27
|
+
"codegen": "python codegen/generate_types.py",
|
|
28
|
+
"codegen:check": "python codegen/generate_types.py --check",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"onlyworlds",
|
|
33
|
+
"worldbuilding",
|
|
34
|
+
"api",
|
|
35
|
+
"sdk",
|
|
36
|
+
"typescript",
|
|
37
|
+
"rpg",
|
|
38
|
+
"ttrpg",
|
|
39
|
+
"game-development"
|
|
40
|
+
],
|
|
41
|
+
"author": "OnlyWorlds",
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/OnlyWorlds/sdk.git"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://onlyworlds.github.io/",
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/OnlyWorlds/sdk/issues"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"tsup": "^8.0.1",
|
|
53
|
+
"typescript": "^5.3.3"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"typescript": ">=4.5.0"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=18.0.0"
|
|
60
|
+
}
|
|
61
|
+
}
|