@onlyworlds/sdk 4.3.0 → 4.4.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 +5 -0
- package/CHANGELOG.md +30 -0
- package/SCHEMA.md +1 -1
- package/dist/index.d.ts +12 -11
- package/dist/index.js +19 -10
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -44,6 +44,11 @@ against live data). The v1 surface (`OnlyWorldsClient`, the `ElementType` enum)
|
|
|
44
44
|
- Under load keel answers 503 `server_busy` with `Retry-After` (`err.isBusy`, `err.retryAfter`
|
|
45
45
|
in seconds). The client does not retry for you; back off and retry yourself. Works the same
|
|
46
46
|
in browsers.
|
|
47
|
+
- `created_by` rides every element read: the id of the membership that created it, `null` for
|
|
48
|
+
the world's owner and for anything made before memberships existed. It is read-only; a write
|
|
49
|
+
body that carries it has it dropped, never an error. A **contributor** can change only what
|
|
50
|
+
they created: anything else is 403 `not_author` (`err.isNotAuthor`; retrying will not help).
|
|
51
|
+
`/bulk` reports it per slot, not as a throw.
|
|
47
52
|
- A string holding an unpaired surrogate (text cut mid-emoji) is a 422 naming the field.
|
|
48
53
|
Slice strings by code point, not by UTF-16 unit.
|
|
49
54
|
- Colour carries the element's FAMILY (`elementColor(type, mode)`); the icon
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,36 @@ earlier history lives in git log only.
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [4.4.0] — 2026-10-04 (staged, not published)
|
|
9
|
+
|
|
10
|
+
Membership, as far as the server has shipped it: who created an element, and the refusal a
|
|
11
|
+
contributor meets on someone else's. Additive; nothing is removed or narrows.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- **`created_by`** on `OwElementBase` (so on every element type): `string | null`, the id of the
|
|
15
|
+
membership that created the element, `null` for the world's owner and for anything made
|
|
16
|
+
before memberships existed (keel D72 phase 2, live 2026-09-28; keel spec §4). Read-only. The
|
|
17
|
+
schema does not carry it (like `created_at` it is server bookkeeping), so the generator adds
|
|
18
|
+
it to the wire base under the declared mapping. A write body that carries it has it dropped
|
|
19
|
+
by the server, so the client does not strip it and a read body still round-trips.
|
|
20
|
+
- **`OwApiError.isNotAuthor`**: 403 `not_author`, a contributor changing, replacing, relinking
|
|
21
|
+
or deleting an element someone else created. `/bulk` answers 200 and reports it in the item
|
|
22
|
+
slot, so check the slot (documented on `OwBulkItemResult`).
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- **`FIELD_SCHEMA` no longer marks `marker.map/zone/x/y/order` and `pin.map/element_type/element_id/x/y`
|
|
26
|
+
as `required: true`.** The wire requires `name` and nothing else (rulings.yaml `nullable-by-default`,
|
|
27
|
+
Captain 2026-07-28; keel's OpenAPI write schemas say `required: [name]`), but the schema files still
|
|
28
|
+
list those fields and the generator copied the lists, so a form built from the table demanded
|
|
29
|
+
coordinates the server never did. Found by comparing the SDK with keel's OpenAPI document (the
|
|
30
|
+
new `verify-sdk-wire` gate in Assembly). **If you read `required` from this table, marker and pin
|
|
31
|
+
fields now read as optional**, which is what the server accepts. The generator notes the lists it
|
|
32
|
+
ignores on every run and says when canonical stops carrying them.
|
|
33
|
+
|
|
34
|
+
### Not yet
|
|
35
|
+
- `me()` and `members()` wait for the server routes (keel's M2b). Nothing in this release
|
|
36
|
+
guesses at their names.
|
|
37
|
+
|
|
8
38
|
## [4.3.0] — 2026-09-28
|
|
9
39
|
|
|
10
40
|
Errors you can act on: the two 409s told apart, and the busy server's `Retry-After`, in Node and
|
package/SCHEMA.md
CHANGED
|
@@ -6,7 +6,7 @@ GENERATED from the canonical schema YAML — do not hand-edit (regenerate: `pyth
|
|
|
6
6
|
Written for both humans and AI agents reading this package locally.
|
|
7
7
|
|
|
8
8
|
**The shape rules** (v2 wire dialect): every element carries `id` (UUID), `name`, optional
|
|
9
|
-
`description`/`supertype`/`subtype`/`image_url`, server-managed `type`/`created_at`/`updated_at`/`change_seq`,
|
|
9
|
+
`description`/`supertype`/`subtype`/`image_url`, server-managed `type`/`created_at`/`updated_at`/`change_seq`/`created_by`,
|
|
10
10
|
and namespaced extension fields (`x_*` etc.) returned verbatim. Link fields use ONE bare
|
|
11
11
|
name in both read and write (no `_ids` suffix). Single links are `UUID | null`; multi links
|
|
12
12
|
are `UUID[]`. **Links are owned one-way**: the type listed below owns the field (e.g.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Every element carries these. The extension index signature admits namespaced
|
|
2
2
|
* pass-through fields (atlas_* / shadow_* / x_*) returned verbatim by the server.
|
|
3
3
|
* Derived from base_properties.yaml: `World` is dropped (the API rejects it in
|
|
4
|
-
* bodies -- the key determines the world) and the
|
|
4
|
+
* bodies -- the key determines the world) and the five server-managed fields are
|
|
5
5
|
* added, since they ride every wire body and appear in no element YAML. */
|
|
6
6
|
interface OwElementBase {
|
|
7
7
|
/** Element type slug (server-managed, read-only). */
|
|
@@ -24,6 +24,8 @@ interface OwElementBase {
|
|
|
24
24
|
updated_at?: string;
|
|
25
25
|
/** Per-world change cursor, stamped on every write (server-managed, read-only). */
|
|
26
26
|
change_seq?: number;
|
|
27
|
+
/** The membership that created this element (server-managed, read-only); null for the world's owner and for anything created before memberships existed. */
|
|
28
|
+
created_by?: string | null;
|
|
27
29
|
/** Namespaced extension fields (atlas_* / shadow_* / x_*), returned verbatim. */
|
|
28
30
|
[ext: string]: unknown;
|
|
29
31
|
}
|
|
@@ -1100,27 +1102,22 @@ declare const FIELD_SCHEMA: {
|
|
|
1100
1102
|
readonly map: {
|
|
1101
1103
|
readonly type: "single_link";
|
|
1102
1104
|
readonly target: "map";
|
|
1103
|
-
readonly required: true;
|
|
1104
1105
|
};
|
|
1105
1106
|
readonly zone: {
|
|
1106
1107
|
readonly type: "single_link";
|
|
1107
1108
|
readonly target: "zone";
|
|
1108
|
-
readonly required: true;
|
|
1109
1109
|
};
|
|
1110
1110
|
readonly x: {
|
|
1111
1111
|
readonly type: "integer";
|
|
1112
|
-
readonly required: true;
|
|
1113
1112
|
};
|
|
1114
1113
|
readonly y: {
|
|
1115
1114
|
readonly type: "integer";
|
|
1116
|
-
readonly required: true;
|
|
1117
1115
|
};
|
|
1118
1116
|
readonly z: {
|
|
1119
1117
|
readonly type: "integer";
|
|
1120
1118
|
};
|
|
1121
1119
|
readonly order: {
|
|
1122
1120
|
readonly type: "integer";
|
|
1123
|
-
readonly required: true;
|
|
1124
1121
|
};
|
|
1125
1122
|
};
|
|
1126
1123
|
readonly narrative: {
|
|
@@ -1407,24 +1404,19 @@ declare const FIELD_SCHEMA: {
|
|
|
1407
1404
|
readonly map: {
|
|
1408
1405
|
readonly type: "single_link";
|
|
1409
1406
|
readonly target: "map";
|
|
1410
|
-
readonly required: true;
|
|
1411
1407
|
};
|
|
1412
1408
|
readonly element_type: {
|
|
1413
1409
|
readonly type: "text";
|
|
1414
|
-
readonly required: true;
|
|
1415
1410
|
};
|
|
1416
1411
|
readonly element_id: {
|
|
1417
1412
|
readonly type: "single_link";
|
|
1418
1413
|
readonly target: "any";
|
|
1419
|
-
readonly required: true;
|
|
1420
1414
|
};
|
|
1421
1415
|
readonly x: {
|
|
1422
1416
|
readonly type: "integer";
|
|
1423
|
-
readonly required: true;
|
|
1424
1417
|
};
|
|
1425
1418
|
readonly y: {
|
|
1426
1419
|
readonly type: "integer";
|
|
1427
|
-
readonly required: true;
|
|
1428
1420
|
};
|
|
1429
1421
|
readonly z: {
|
|
1430
1422
|
readonly type: "integer";
|
|
@@ -1918,6 +1910,8 @@ interface OwBulkItem {
|
|
|
1918
1910
|
* One slot of a /bulk response. WIRE-CORRECTED (fixtures P2a/P2c): `status` is
|
|
1919
1911
|
* the NUMERIC HTTP status of that slot (201/400/...), success slots echo
|
|
1920
1912
|
* created_at/updated_at, error slots carry an OwErrorBody under `error`.
|
|
1913
|
+
* A contributor's write on someone else's element fails in its slot as
|
|
1914
|
+
* `{status: 403, error: {code: 'not_author'}}` (keel D72), never as a thrown error.
|
|
1921
1915
|
*/
|
|
1922
1916
|
interface OwBulkItemResult {
|
|
1923
1917
|
status: number;
|
|
@@ -2042,6 +2036,13 @@ declare class OwApiError extends Error {
|
|
|
2042
2036
|
get isIdConflict(): boolean;
|
|
2043
2037
|
/** keel's admission control turned the request away (503 `server_busy`); see retryAfter. */
|
|
2044
2038
|
get isBusy(): boolean;
|
|
2039
|
+
/**
|
|
2040
|
+
* A contributor tried to change, replace, relink or delete an element someone else
|
|
2041
|
+
* created (403 `not_author`, keel D72 membership phase 2). Retrying will not help; the
|
|
2042
|
+
* element is not theirs. `/bulk` never throws for this: it answers 200 with a per-item
|
|
2043
|
+
* slot `{status: 403, error: {code: 'not_author'}}`. Owners and co-builders never see it.
|
|
2044
|
+
*/
|
|
2045
|
+
get isNotAuthor(): boolean;
|
|
2045
2046
|
}
|
|
2046
2047
|
/** Network-level failure (fetch rejected) -- no envelope to parse. */
|
|
2047
2048
|
declare class OwNetworkError extends Error {
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,15 @@ var OwApiError = class extends Error {
|
|
|
39
39
|
get isBusy() {
|
|
40
40
|
return this.status === 503 && this.code === "server_busy";
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* A contributor tried to change, replace, relink or delete an element someone else
|
|
44
|
+
* created (403 `not_author`, keel D72 membership phase 2). Retrying will not help; the
|
|
45
|
+
* element is not theirs. `/bulk` never throws for this: it answers 200 with a per-item
|
|
46
|
+
* slot `{status: 403, error: {code: 'not_author'}}`. Owners and co-builders never see it.
|
|
47
|
+
*/
|
|
48
|
+
get isNotAuthor() {
|
|
49
|
+
return this.status === 403 && this.code === "not_author";
|
|
50
|
+
}
|
|
42
51
|
};
|
|
43
52
|
var OwNetworkError = class extends Error {
|
|
44
53
|
constructor(message, cause) {
|
|
@@ -846,12 +855,12 @@ var FIELD_SCHEMA = {
|
|
|
846
855
|
subtype: { type: "text", required: false },
|
|
847
856
|
image_url: { type: "text", required: false },
|
|
848
857
|
// Details
|
|
849
|
-
map: { type: "single_link", target: "map"
|
|
850
|
-
zone: { type: "single_link", target: "zone"
|
|
851
|
-
x: { type: "integer"
|
|
852
|
-
y: { type: "integer"
|
|
858
|
+
map: { type: "single_link", target: "map" },
|
|
859
|
+
zone: { type: "single_link", target: "zone" },
|
|
860
|
+
x: { type: "integer" },
|
|
861
|
+
y: { type: "integer" },
|
|
853
862
|
z: { type: "integer" },
|
|
854
|
-
order: { type: "integer"
|
|
863
|
+
order: { type: "integer" }
|
|
855
864
|
},
|
|
856
865
|
narrative: {
|
|
857
866
|
// Base fields (shared by all elements)
|
|
@@ -944,11 +953,11 @@ var FIELD_SCHEMA = {
|
|
|
944
953
|
subtype: { type: "text", required: false },
|
|
945
954
|
image_url: { type: "text", required: false },
|
|
946
955
|
// Details
|
|
947
|
-
map: { type: "single_link", target: "map"
|
|
948
|
-
element_type: { type: "text"
|
|
949
|
-
element_id: { type: "single_link", target: "any"
|
|
950
|
-
x: { type: "integer"
|
|
951
|
-
y: { type: "integer"
|
|
956
|
+
map: { type: "single_link", target: "map" },
|
|
957
|
+
element_type: { type: "text" },
|
|
958
|
+
element_id: { type: "single_link", target: "any" },
|
|
959
|
+
x: { type: "integer" },
|
|
960
|
+
y: { type: "integer" },
|
|
952
961
|
z: { type: "integer" }
|
|
953
962
|
},
|
|
954
963
|
relation: {
|