@onlyworlds/sdk 4.51.0 → 4.53.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/CHANGELOG.md +12 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +32 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,18 @@ earlier history lives in git log only.
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [4.53.0] - 2026-10-22
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **The last seven options objects refuse an unknown key** too: `patch` and `editLinks` (`ifMatch`; the edit itself is `{add, remove}`), `uploadImage`, `createFileTicket`, `uploadFile`, `createWorldLink` and `createSeat`. With 4.51.0 and 4.52.0 every method of the client that takes an object now names a stray key before anything is sent; a client that drops a key it does not know has no place left.
|
|
13
|
+
|
|
14
|
+
## [4.52.0] - 2026-10-22
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **Every options object refuses an unknown key** the way `list()` did in 4.51.0: `draught`, `get`, `create`, `bulk`, `changes`, `changesAll`, `removeImage`, `redeemJoin`, `signInWithPassword`, `mintWorldKey`, `signInWithOnlyWorlds`, `completeSignIn`, `ask` and `sort` throw a TypeError naming the key and the known keys before anything is sent. A dropped key was never harmless: `atomc: true` ran a batch non-atomically, `idempotency_key` let a retry create twice, `afetr` read the whole feed, `mode` misspelt widened a draught to the caller's view. TypeScript callers were already refused at compile time; this is for plain JavaScript.
|
|
19
|
+
|
|
8
20
|
## [4.51.0] - 2026-10-22
|
|
9
21
|
|
|
10
22
|
### Changed
|
package/dist/index.d.ts
CHANGED
|
@@ -2726,6 +2726,11 @@ interface OwFileDownload {
|
|
|
2726
2726
|
kind: OwFileKind;
|
|
2727
2727
|
size: number;
|
|
2728
2728
|
}
|
|
2729
|
+
/**
|
|
2730
|
+
* The parameters of `list()` and `listAll()`. A wire filter goes under `filter`; any key not named
|
|
2731
|
+
* here is a TypeError before anything is sent (since 4.51.0; before, an unknown key was dropped and the
|
|
2732
|
+
* list came back whole).
|
|
2733
|
+
*/
|
|
2729
2734
|
interface ListParams {
|
|
2730
2735
|
limit?: number;
|
|
2731
2736
|
cursor?: string;
|
package/dist/index.js
CHANGED
|
@@ -575,13 +575,7 @@ var OwV2Client = class {
|
|
|
575
575
|
// -- Element CRUD --------------------------------------------------------
|
|
576
576
|
/** GET /{type}/ -- one cursor page. */
|
|
577
577
|
async list(type, params = {}) {
|
|
578
|
-
|
|
579
|
-
if (!LIST_PARAM_KEYS.has(k)) {
|
|
580
|
-
throw new TypeError(
|
|
581
|
-
`list: unknown parameter '${k}'. A wire filter (name, name__icontains, supertype, subtype, characters) goes under filter: { ${k}: ... }; the other keys are ${[...LIST_PARAM_KEYS].join(", ")}. Nothing was sent: an unknown key was once dropped, and the list came back whole.`
|
|
582
|
-
);
|
|
583
|
-
}
|
|
584
|
-
}
|
|
578
|
+
only("list", params, LIST_PARAM_KEYS, "A wire filter (name, name__icontains, supertype, subtype, characters) goes under filter: { ... }.");
|
|
585
579
|
const query = buildQuery({
|
|
586
580
|
limit: params.limit ?? this.pageSize,
|
|
587
581
|
cursor: params.cursor,
|
|
@@ -606,6 +600,7 @@ var OwV2Client = class {
|
|
|
606
600
|
* empty means the serving is partial. Served `Cache-Control: private, no-store`.
|
|
607
601
|
*/
|
|
608
602
|
async draught(characterId, policy = {}) {
|
|
603
|
+
only("draught", policy, ["components", "mode", "asOf", "undated", "since", "budget", "depth"]);
|
|
609
604
|
const query = buildQuery({
|
|
610
605
|
components: policy.components?.join(","),
|
|
611
606
|
mode: policy.mode,
|
|
@@ -631,6 +626,7 @@ var OwV2Client = class {
|
|
|
631
626
|
* #421: the owner reads as another reader; see ListParams.viewAs).
|
|
632
627
|
*/
|
|
633
628
|
async get(type, id, opts = {}) {
|
|
629
|
+
only("get", opts, ["expand", "fields", "viewAs"]);
|
|
634
630
|
const query = buildQuery({ expand: opts.expand?.join(","), fields: opts.fields?.join(","), as: opts.viewAs });
|
|
635
631
|
return this.request("GET", `/${type}/${id}/`, { query });
|
|
636
632
|
}
|
|
@@ -645,6 +641,7 @@ var OwV2Client = class {
|
|
|
645
641
|
* `null` are accepted and stored as `''` (nameless Markers exist).
|
|
646
642
|
*/
|
|
647
643
|
async create(type, element, opts = {}) {
|
|
644
|
+
only("create", opts, ["idempotencyKey"]);
|
|
648
645
|
refuseKnownOf(element, "create");
|
|
649
646
|
const body = sanitizePayload(element);
|
|
650
647
|
if (body.id === void 0 || body.id === null || body.id === "") {
|
|
@@ -676,6 +673,7 @@ var OwV2Client = class {
|
|
|
676
673
|
* it for today's unconditional write.
|
|
677
674
|
*/
|
|
678
675
|
async patch(type, id, partial, opts = {}) {
|
|
676
|
+
only("patch", opts, ["ifMatch"]);
|
|
679
677
|
refuseKnownOf(partial, "patch");
|
|
680
678
|
return this.request("PATCH", `/${type}/${id}/`, { write: true, body: sanitizePayload(partial), ifMatch: opts.ifMatch });
|
|
681
679
|
}
|
|
@@ -695,6 +693,8 @@ var OwV2Client = class {
|
|
|
695
693
|
* moves the element too.
|
|
696
694
|
*/
|
|
697
695
|
async editLinks(type, id, field, edit, opts = {}) {
|
|
696
|
+
only("editLinks", opts, ["ifMatch"]);
|
|
697
|
+
only("editLinks", edit, ["add", "remove"], "The edit is { add?: string[], remove?: string[] }.");
|
|
698
698
|
return this.request("POST", `/${type}/${id}/links/${field}`, { write: true, body: edit, ifMatch: opts.ifMatch });
|
|
699
699
|
}
|
|
700
700
|
/**
|
|
@@ -731,6 +731,7 @@ var OwV2Client = class {
|
|
|
731
731
|
* fresh UUIDv7. Ids you supply are kept.
|
|
732
732
|
*/
|
|
733
733
|
async bulk(items, opts = {}) {
|
|
734
|
+
only("bulk", opts, ["atomic", "idempotencyKey"]);
|
|
734
735
|
items.forEach((it, index) => refuseKnownOf(it.element, `bulk: items[${index}]`));
|
|
735
736
|
const body = {
|
|
736
737
|
items: items.map((it, index) => {
|
|
@@ -772,6 +773,7 @@ var OwV2Client = class {
|
|
|
772
773
|
* that is not a date and time is a 422 naming `after`.
|
|
773
774
|
*/
|
|
774
775
|
async changes(opts = {}) {
|
|
776
|
+
only("changes", opts, ["since", "limit", "after"]);
|
|
775
777
|
const query = buildQuery({ since: opts.since, limit: opts.limit ?? this.changesPageSize, after: opts.after });
|
|
776
778
|
const page = await this.request("GET", "/changes/", { query });
|
|
777
779
|
return { ...page, cursor: String(page.cursor) };
|
|
@@ -802,6 +804,7 @@ var OwV2Client = class {
|
|
|
802
804
|
* `head` and `epoch`: the view epoch the walk ran under, for a guest or a contributor).
|
|
803
805
|
*/
|
|
804
806
|
async *changesAll(since, opts = {}) {
|
|
807
|
+
only("changesAll", opts, ["after"]);
|
|
805
808
|
let cursor = since;
|
|
806
809
|
let page;
|
|
807
810
|
do {
|
|
@@ -841,6 +844,7 @@ var OwV2Client = class {
|
|
|
841
844
|
* needs a new one.
|
|
842
845
|
*/
|
|
843
846
|
async uploadImage(image, opts = {}) {
|
|
847
|
+
only("uploadImage", opts, ["key", "ticket"]);
|
|
844
848
|
const ticket = opts.ticket ?? await this.createMediaTicket();
|
|
845
849
|
const size = typeof Blob !== "undefined" && image instanceof Blob ? image.size : image.byteLength;
|
|
846
850
|
if (size > ticket.max_bytes) {
|
|
@@ -891,6 +895,7 @@ var OwV2Client = class {
|
|
|
891
895
|
* ticket is still unspent).
|
|
892
896
|
*/
|
|
893
897
|
async removeImage(keyOrUrl, opts = {}) {
|
|
898
|
+
only("removeImage", opts, ["ticket"]);
|
|
894
899
|
const ticket = opts.ticket ?? await this.createRemovalTicket(keyOrUrl);
|
|
895
900
|
let res;
|
|
896
901
|
try {
|
|
@@ -943,6 +948,7 @@ var OwV2Client = class {
|
|
|
943
948
|
* `retryAfter`; 503 `media_unavailable`.
|
|
944
949
|
*/
|
|
945
950
|
async createFileTicket(type, id, req) {
|
|
951
|
+
only("createFileTicket", req, ["name", "kind", "size", "label"]);
|
|
946
952
|
const { name, size } = req;
|
|
947
953
|
if (typeof name !== "string" || name.trim() === "") {
|
|
948
954
|
throw new TypeError("createFileTicket needs the file's name, with its extension");
|
|
@@ -983,6 +989,7 @@ var OwV2Client = class {
|
|
|
983
989
|
* upload succeeds: another file needs a new one.
|
|
984
990
|
*/
|
|
985
991
|
async uploadFile(type, id, file, opts = {}) {
|
|
992
|
+
only("uploadFile", opts, ["name", "kind", "label", "ticket", "onProgress"]);
|
|
986
993
|
const size = typeof Blob !== "undefined" && file instanceof Blob ? file.size : file.byteLength;
|
|
987
994
|
let ticket = opts.ticket;
|
|
988
995
|
if (!ticket) {
|
|
@@ -1076,6 +1083,7 @@ var OwV2Client = class {
|
|
|
1076
1083
|
* for one ignores `character`.
|
|
1077
1084
|
*/
|
|
1078
1085
|
async redeemJoin(code, opts = {}) {
|
|
1086
|
+
only("redeemJoin", opts, ["name", "agentName", "character"]);
|
|
1079
1087
|
const body = { code };
|
|
1080
1088
|
if (opts.name !== void 0) body.name = opts.name;
|
|
1081
1089
|
if (opts.agentName !== void 0) body.agent_name = opts.agentName;
|
|
@@ -1104,6 +1112,7 @@ var OwV2Client = class {
|
|
|
1104
1112
|
* `failed` (anything else, with keel's message). The password is never in an error.
|
|
1105
1113
|
*/
|
|
1106
1114
|
async signInWithPassword(opts) {
|
|
1115
|
+
only("signInWithPassword", opts, ["email", "username", "password", "tokenName"]);
|
|
1107
1116
|
const { email, username, password, tokenName } = opts ?? {};
|
|
1108
1117
|
const login = typeof email === "string" ? email.trim() : "";
|
|
1109
1118
|
const user = typeof username === "string" ? username.trim() : "";
|
|
@@ -1246,6 +1255,7 @@ var OwV2Client = class {
|
|
|
1246
1255
|
* `not_found` (`err.isNotFound`). A world key is a TypeError before anything is sent.
|
|
1247
1256
|
*/
|
|
1248
1257
|
async createWorldLink(worldId, opts) {
|
|
1258
|
+
only("createWorldLink", opts, ["reader", "role", "days", "inviterName", "withCharacter", "character", "preview", "maxUses", "characters"]);
|
|
1249
1259
|
if (this.keyKind !== "account") {
|
|
1250
1260
|
throw new TypeError("createWorldLink needs an account token (ow_a_): only the world's owner makes links");
|
|
1251
1261
|
}
|
|
@@ -1297,6 +1307,7 @@ var OwV2Client = class {
|
|
|
1297
1307
|
* its key: rekeySeat gives it a new one (or removeSeat and make another). Needs the client's `ow_a_` token.
|
|
1298
1308
|
*/
|
|
1299
1309
|
async createSeat(worldId, opts) {
|
|
1310
|
+
only("createSeat", opts, ["name", "role", "character"]);
|
|
1300
1311
|
if (this.keyKind !== "account") {
|
|
1301
1312
|
throw new TypeError("createSeat needs an account token (ow_a_): a seat is made by the person who answers for it");
|
|
1302
1313
|
}
|
|
@@ -1384,6 +1395,7 @@ var OwV2Client = class {
|
|
|
1384
1395
|
* token only; no Idempotency-Key.
|
|
1385
1396
|
*/
|
|
1386
1397
|
async mintWorldKey(worldId, opts = {}) {
|
|
1398
|
+
only("mintWorldKey", opts, ["scope", "name"]);
|
|
1387
1399
|
if (this.keyKind !== "account") {
|
|
1388
1400
|
throw new TypeError("mintWorldKey needs an account token (ow_a_)");
|
|
1389
1401
|
}
|
|
@@ -1403,6 +1415,7 @@ var OwV2Client = class {
|
|
|
1403
1415
|
* is sent; any client, keyless included. The handoff sheet: Orrery `keel/signin-handoff.md` §3.
|
|
1404
1416
|
*/
|
|
1405
1417
|
async signInWithOnlyWorlds(opts) {
|
|
1418
|
+
only("signInWithOnlyWorlds", opts, ["clientId", "redirectUri", "resume", "storage", "navigate"]);
|
|
1406
1419
|
return beginSignIn(this.baseUrl, opts);
|
|
1407
1420
|
}
|
|
1408
1421
|
/**
|
|
@@ -1415,6 +1428,7 @@ var OwV2Client = class {
|
|
|
1415
1428
|
* 400: used, expired, or another client's code), `rate_limited`, `offline`, `failed`.
|
|
1416
1429
|
*/
|
|
1417
1430
|
async completeSignIn(opts) {
|
|
1431
|
+
only("completeSignIn", opts, ["clientId", "storage", "url"]);
|
|
1418
1432
|
return completeSignIn(this.baseUrl, this.fetchImpl, opts);
|
|
1419
1433
|
}
|
|
1420
1434
|
// -- Ask your world (keel #159) -------------------------------------------
|
|
@@ -1429,6 +1443,7 @@ var OwV2Client = class {
|
|
|
1429
1443
|
* them counts. 422 for a question over 500 characters or context past its limits.
|
|
1430
1444
|
*/
|
|
1431
1445
|
async ask(req) {
|
|
1446
|
+
only("ask", req, ["worldId", "question", "context"]);
|
|
1432
1447
|
if (this.keyKind !== "account") {
|
|
1433
1448
|
throw new TypeError("ask needs an account token (ow_a_): the proxy meters per account");
|
|
1434
1449
|
}
|
|
@@ -1448,6 +1463,7 @@ var OwV2Client = class {
|
|
|
1448
1463
|
* to 200 characters, anchors up to 120.
|
|
1449
1464
|
*/
|
|
1450
1465
|
async sort(req) {
|
|
1466
|
+
only("sort", req, ["worldId", "notes", "slice"]);
|
|
1451
1467
|
if (this.keyKind !== "account") {
|
|
1452
1468
|
throw new TypeError("sort needs an account token (ow_a_): the proxy meters per account");
|
|
1453
1469
|
}
|
|
@@ -1645,7 +1661,15 @@ function objectKey(keyOrUrl) {
|
|
|
1645
1661
|
if (!/^https?:\/\//i.test(keyOrUrl)) return keyOrUrl;
|
|
1646
1662
|
return decodeURIComponent(new URL(keyOrUrl).pathname.replace(/^\/+/, ""));
|
|
1647
1663
|
}
|
|
1648
|
-
var LIST_PARAM_KEYS =
|
|
1664
|
+
var LIST_PARAM_KEYS = ["limit", "cursor", "ids", "createdBy", "expand", "fields", "filter", "viewAs"];
|
|
1665
|
+
function only(method, obj, keys, hint = "") {
|
|
1666
|
+
if (!obj || typeof obj !== "object") return;
|
|
1667
|
+
for (const k of Object.keys(obj)) {
|
|
1668
|
+
if (!keys.includes(k)) {
|
|
1669
|
+
throw new TypeError(`${method}: unknown parameter '${k}'. ${hint ? hint + " " : ""}The keys are ${keys.join(", ")}. Nothing was sent.`);
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1649
1673
|
function buildQuery(params) {
|
|
1650
1674
|
const q = new URLSearchParams();
|
|
1651
1675
|
for (const [k, v] of Object.entries(params)) {
|