@onlyworlds/sdk 4.72.1 → 4.72.3
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 +6 -6
- package/CHANGELOG.md +13 -0
- package/README.md +2 -2
- package/SCHEMA.md +1 -1
- package/dist/index.d.ts +157 -159
- package/dist/index.js +71 -72
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -98,8 +98,8 @@ var OwApiError = class extends Error {
|
|
|
98
98
|
return this.status === 409 && this.code === "idempotency_error";
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
|
-
* A request with this Idempotency-Key is still running (409 `idempotency_in_flight
|
|
102
|
-
*
|
|
101
|
+
* A request with this Idempotency-Key is still running (409 `idempotency_in_flight`):
|
|
102
|
+
* two sends of one create or bulk overlapped. Nothing was written by this one.
|
|
103
103
|
* Wait `retryAfter` seconds (keel sends 1) and send again with the SAME key and body: once
|
|
104
104
|
* the first has answered, that retry replays its answer. Not a key conflict (see above).
|
|
105
105
|
*/
|
|
@@ -108,7 +108,7 @@ var OwApiError = class extends Error {
|
|
|
108
108
|
}
|
|
109
109
|
/**
|
|
110
110
|
* The id is already taken (409 `id_conflict`): a create with an id that exists
|
|
111
|
-
*
|
|
111
|
+
* or a PUT whose id belongs to another world. Retrying will not
|
|
112
112
|
* help; the id is the problem. `/bulk` never throws for this: it answers 200 with a
|
|
113
113
|
* per-item slot `{status: 409, error: {code: 'id_conflict'}}` — check the slot.
|
|
114
114
|
*/
|
|
@@ -118,18 +118,18 @@ var OwApiError = class extends Error {
|
|
|
118
118
|
/**
|
|
119
119
|
* `/changes` refused the cursor (409 `resync_required`): what this key may see changed
|
|
120
120
|
* (a guest's slice moved; an element hidden from a contributor was unhidden; the key's role
|
|
121
|
-
* moved to or from guest or contributor, whose cursors have other shapes
|
|
121
|
+
* moved to or from guest or contributor, whose cursors have other shapes). Drop
|
|
122
122
|
* the stored cursor and walk again from the start. What to do with what the local copy holds
|
|
123
123
|
* that the new walk does not name is `resyncReason`'s: `role`, keep it; `view`, drop it.
|
|
124
124
|
* Without a reason (keel's hidden mark off), keep it: a reset never empties a copy (keel PR
|
|
125
|
-
* 104,
|
|
125
|
+
* 104, ruled by Titus: sharing is forward-only). Never empty the copy on your own.
|
|
126
126
|
*/
|
|
127
127
|
get isResyncRequired() {
|
|
128
128
|
return this.status === 409 && this.code === "resync_required";
|
|
129
129
|
}
|
|
130
130
|
/**
|
|
131
131
|
* Why `/changes` refused the cursor, from the 409 `resync_required` envelope's `reason`
|
|
132
|
-
* (
|
|
132
|
+
* (only while keel's hidden mark is on): `role` (this key's own role or
|
|
133
133
|
* membership moved: keep what the local copy holds that the new walk does not name; it is
|
|
134
134
|
* out of view now, not gone) or `view` (something left this key's view: a delete, a hide, an
|
|
135
135
|
* unhide, a Character change; drop what the new walk does not name). When both happened
|
|
@@ -149,7 +149,7 @@ var OwApiError = class extends Error {
|
|
|
149
149
|
}
|
|
150
150
|
/**
|
|
151
151
|
* A contributor tried to change, replace, relink or delete an element someone else
|
|
152
|
-
* created (403 `not_author
|
|
152
|
+
* created (403 `not_author`). Retrying will not help; the
|
|
153
153
|
* element is not theirs. `/bulk` never throws for this: it answers 200 with a per-item
|
|
154
154
|
* slot `{status: 403, error: {code: 'not_author'}}`. Owners and co-builders never see it.
|
|
155
155
|
*/
|
|
@@ -158,7 +158,7 @@ var OwApiError = class extends Error {
|
|
|
158
158
|
}
|
|
159
159
|
/**
|
|
160
160
|
* A member key tried what only the owner may do: `patchWorld`, even with a co-builder's
|
|
161
|
-
* key (403 `owner_only
|
|
161
|
+
* key (403 `owner_only`; sharing's publish, republish and revoke answer
|
|
162
162
|
* contributors and guests with the same code). Retrying will not help. The owner's own
|
|
163
163
|
* key never sees it.
|
|
164
164
|
*/
|
|
@@ -166,7 +166,7 @@ var OwApiError = class extends Error {
|
|
|
166
166
|
return this.status === 403 && this.code === "owner_only";
|
|
167
167
|
}
|
|
168
168
|
/**
|
|
169
|
-
* A member key sent `viewAs` (403 `view_as_owner_only
|
|
169
|
+
* A member key sent `viewAs` (403 `view_as_owner_only`): reading as another
|
|
170
170
|
* reader is the owner's, from a key with no member. Retrying will not help. Only while
|
|
171
171
|
* keel's hidden mark is on; until then `viewAs` is an unknown parameter (422).
|
|
172
172
|
*/
|
|
@@ -185,7 +185,7 @@ var OwApiError = class extends Error {
|
|
|
185
185
|
}
|
|
186
186
|
/**
|
|
187
187
|
* A `patch` or `editLinks` sent with `ifMatch` found the element moved past that
|
|
188
|
-
* `change_seq` (412 `precondition_failed
|
|
188
|
+
* `change_seq` (412 `precondition_failed`): nothing was written and nothing
|
|
189
189
|
* merged. The error is an OwPreconditionFailedError; its `current` is the element as it
|
|
190
190
|
* is now, so no second read is needed.
|
|
191
191
|
*/
|
|
@@ -197,7 +197,7 @@ var OwApiError = class extends Error {
|
|
|
197
197
|
return this.status === 404 && this.code === "not_found";
|
|
198
198
|
}
|
|
199
199
|
/**
|
|
200
|
-
* redeemJoin on a table
|
|
200
|
+
* redeemJoin on a table: the picked Character is one a live seat in the
|
|
201
201
|
* world already plays (422 `character_taken`, `param` character). Pick another from a fresh
|
|
202
202
|
* previewJoin, whose `characters` mark each `taken`. The code is not spent.
|
|
203
203
|
*/
|
|
@@ -205,7 +205,7 @@ var OwApiError = class extends Error {
|
|
|
205
205
|
return this.status === 422 && this.code === "character_taken";
|
|
206
206
|
}
|
|
207
207
|
/**
|
|
208
|
-
* setMyCharacter, or the member PATCH's `character
|
|
208
|
+
* setMyCharacter, or the member PATCH's `character`: the picked Character is
|
|
209
209
|
* hidden (422 `character_hidden`, `param` character). Unhide it first, or pick another.
|
|
210
210
|
*/
|
|
211
211
|
get isCharacterHidden() {
|
|
@@ -213,7 +213,7 @@ var OwApiError = class extends Error {
|
|
|
213
213
|
}
|
|
214
214
|
/**
|
|
215
215
|
* The `character` sent was refused (422 `invalid_request`, `param` character). On redeemJoin
|
|
216
|
-
* at a table
|
|
216
|
+
* at a table: the pick is off the link's list, hidden or deleted since the
|
|
217
217
|
* link was made, or missing, or sent to a table with no list (send `name` instead); one
|
|
218
218
|
* answer for all, so read previewJoin again and pick from its `characters`. The code is not
|
|
219
219
|
* spent. On createWorldLink: a `character` keel refused (not a Character of the world, a
|
|
@@ -224,7 +224,7 @@ var OwApiError = class extends Error {
|
|
|
224
224
|
return this.status === 422 && this.code === "invalid_request" && this.param === "character";
|
|
225
225
|
}
|
|
226
226
|
/**
|
|
227
|
-
* redeemJoin
|
|
227
|
+
* redeemJoin: the world already has its 50 live players (422 `world_full`),
|
|
228
228
|
* at any player link, a table's or a link for one's. Nothing is spent; a place frees when the
|
|
229
229
|
* owner removes a player.
|
|
230
230
|
*/
|
|
@@ -241,14 +241,14 @@ var OwApiError = class extends Error {
|
|
|
241
241
|
}
|
|
242
242
|
/**
|
|
243
243
|
* A daily allowance is used up (429 `quota_exceeded`): the world's image tickets, its file
|
|
244
|
-
* tickets (200 a day
|
|
244
|
+
* tickets (200 a day), or the account's asks. See retryAfter.
|
|
245
245
|
*/
|
|
246
246
|
get isQuotaExceeded() {
|
|
247
247
|
return this.status === 429 && this.code === "quota_exceeded";
|
|
248
248
|
}
|
|
249
249
|
/**
|
|
250
250
|
* createFileTicket / uploadFile: the file is over the 25 MB a file may be (413
|
|
251
|
-
* `file_too_large`, `param` size
|
|
251
|
+
* `file_too_large`, `param` size); the message gives both sizes. Nothing was
|
|
252
252
|
* issued. Not the upload host's 413 `too_large` (bytes past a ticket's `max_bytes`).
|
|
253
253
|
*/
|
|
254
254
|
get isFileTooLarge() {
|
|
@@ -256,7 +256,7 @@ var OwApiError = class extends Error {
|
|
|
256
256
|
}
|
|
257
257
|
/**
|
|
258
258
|
* createFileTicket / uploadFile: the world's files have no room for this one (403
|
|
259
|
-
* `files_full
|
|
259
|
+
* `files_full`: 250 MB a world); the message gives the world's use, its cap and
|
|
260
260
|
* the file's size. Remove a file, or ask the owner. Nothing was issued.
|
|
261
261
|
*/
|
|
262
262
|
get isFilesFull() {
|
|
@@ -271,7 +271,7 @@ var OwApiError = class extends Error {
|
|
|
271
271
|
return this.status === 502 && this.code === "ask_failed";
|
|
272
272
|
}
|
|
273
273
|
/**
|
|
274
|
-
* patch, upsert or editLinks became a proposal (202
|
|
274
|
+
* patch, upsert or editLinks became a proposal (202): the world takes an agent seat's
|
|
275
275
|
* writes as proposals (`agent_writes_proposed`), so the element did not change. The error is an
|
|
276
276
|
* OwProposedError; its `proposal` is the row a keeper accepts or declines. Not a failure to retry:
|
|
277
277
|
* the write is waiting for a person.
|
|
@@ -281,7 +281,7 @@ var OwApiError = class extends Error {
|
|
|
281
281
|
}
|
|
282
282
|
/**
|
|
283
283
|
* propose named a field the proposer's own view of the element does not hold (422
|
|
284
|
-
* `field_not_visible`, `param` names it
|
|
284
|
+
* `field_not_visible`, `param` names it): the element reaches this key only as a
|
|
285
285
|
* stub (known_of), and a proposal changes only what its proposer can read.
|
|
286
286
|
*/
|
|
287
287
|
get isFieldNotVisible() {
|
|
@@ -289,7 +289,7 @@ var OwApiError = class extends Error {
|
|
|
289
289
|
}
|
|
290
290
|
/**
|
|
291
291
|
* propose: this proposer already has 5 open proposals on the element, or 50 in the world (422
|
|
292
|
-
* `too_many_open
|
|
292
|
+
* `too_many_open`). Wait for a keeper to decide, or withdraw one; a lapsed proposal
|
|
293
293
|
* no longer counts.
|
|
294
294
|
*/
|
|
295
295
|
get isTooManyOpen() {
|
|
@@ -297,7 +297,7 @@ var OwApiError = class extends Error {
|
|
|
297
297
|
}
|
|
298
298
|
/**
|
|
299
299
|
* acceptProposal found a proposed field moved since the proposal was made (409
|
|
300
|
-
* `stale_proposal
|
|
300
|
+
* `stale_proposal`). Nothing was written and the proposal stays open. The error is an
|
|
301
301
|
* OwStaleProposalError: `conflicts` lists each moved field with its `base` and `current` values,
|
|
302
302
|
* and `current` is the element as it is now. A change to a field the proposal does not name
|
|
303
303
|
* does not count. The proposer proposes again on the current text.
|
|
@@ -306,24 +306,24 @@ var OwApiError = class extends Error {
|
|
|
306
306
|
return this.status === 409 && this.code === "stale_proposal";
|
|
307
307
|
}
|
|
308
308
|
/**
|
|
309
|
-
* While the world takes agent seats' writes as proposals
|
|
309
|
+
* While the world takes agent seats' writes as proposals, an agent seat's key tried
|
|
310
310
|
* what it may not: delete an element it did not create, or accept or decline a proposal (403
|
|
311
|
-
* `proposed_only`). On any world, reviewNewElement by the member the mark names is the same 403
|
|
312
|
-
*
|
|
311
|
+
* `proposed_only`). On any world, reviewNewElement by the member the mark names is the same 403.
|
|
312
|
+
* Retrying will not help; a person decides.
|
|
313
313
|
*/
|
|
314
314
|
get isProposedOnly() {
|
|
315
315
|
return this.status === 403 && this.code === "proposed_only";
|
|
316
316
|
}
|
|
317
317
|
/**
|
|
318
|
-
* acceptProposal or declineProposal on the key's own proposal (403 `own_proposal
|
|
318
|
+
* acceptProposal or declineProposal on the key's own proposal (403 `own_proposal`):
|
|
319
319
|
* another keeper (the owner or a co-builder) decides it. Retrying will not help.
|
|
320
320
|
*/
|
|
321
321
|
get isOwnProposal() {
|
|
322
322
|
return this.status === 403 && this.code === "own_proposal";
|
|
323
323
|
}
|
|
324
324
|
/**
|
|
325
|
-
* reviewNewElement on an element that carries no `x_review_proposed` mark (422 `not_proposed
|
|
326
|
-
*
|
|
325
|
+
* reviewNewElement on an element that carries no `x_review_proposed` mark (422 `not_proposed`):
|
|
326
|
+
* nothing to settle. Someone settled it already, or it was never written as proposed.
|
|
327
327
|
*/
|
|
328
328
|
get isNotProposed() {
|
|
329
329
|
return this.status === 422 && this.code === "not_proposed";
|
|
@@ -593,7 +593,7 @@ var DEFAULT_PAGE_SIZE = 100;
|
|
|
593
593
|
var DEFAULT_CHANGES_PAGE_SIZE = 100;
|
|
594
594
|
var OwV2Client = class {
|
|
595
595
|
constructor(config = {}) {
|
|
596
|
-
/** The conditional head poll's state
|
|
596
|
+
/** The conditional head poll's state, per instance. */
|
|
597
597
|
this.headPoll = new HeadPollState();
|
|
598
598
|
only("new OwV2Client", config, CLIENT_CONFIG_KEYS);
|
|
599
599
|
this.clientName = clientNameOf(config.client);
|
|
@@ -625,9 +625,9 @@ var OwV2Client = class {
|
|
|
625
625
|
/**
|
|
626
626
|
* PATCH /world -- partial world-meta update. The element write's server-managed keys are
|
|
627
627
|
* stripped, and so are the world's own read-only ones (WORLD_READ_ONLY_FIELDS: `slug` and
|
|
628
|
-
* `public_page
|
|
629
|
-
* `origin
|
|
630
|
-
* written as `source` and `producer` (
|
|
628
|
+
* `public_page`; `agent_writes_proposed`; set on the world page, not here;
|
|
629
|
+
* `origin`; `id`), so a `getWorld()` body can be sent back. The world's origin is
|
|
630
|
+
* written as `source` and `producer` (each an object or null, served under `origin`);
|
|
631
631
|
* extension keys (`x_*`, `atlas_*`, `shadow_*`) are sent as given, and `null` removes one.
|
|
632
632
|
*/
|
|
633
633
|
async patchWorld(partial) {
|
|
@@ -643,8 +643,8 @@ var OwV2Client = class {
|
|
|
643
643
|
* token is a TypeError before sending.
|
|
644
644
|
*/
|
|
645
645
|
/**
|
|
646
|
-
* PUT /me/character -- pick the roster Character that is you in this world, or none
|
|
647
|
-
*
|
|
646
|
+
* PUT /me/character -- pick the roster Character that is you in this world, or none.
|
|
647
|
+
* A person member's write key with its PIN; answers GET /me's body. 422 for a hidden
|
|
648
648
|
* Character (`character_hidden`, `err.isCharacterHidden`), a guest's pick it did not make, or a
|
|
649
649
|
* taken Character (`invalid_request`, `param` character); 404 for one this key cannot see; 403 for
|
|
650
650
|
* an agent seat, a player, the owner (whose own is the world's `owner_character`, set with
|
|
@@ -718,8 +718,8 @@ var OwV2Client = class {
|
|
|
718
718
|
} while (cursor);
|
|
719
719
|
}
|
|
720
720
|
/**
|
|
721
|
-
* GET /{type}/{id}/ -- optional one-level stub expansion / sparse fields, and `viewAs` (
|
|
722
|
-
*
|
|
721
|
+
* GET /{type}/{id}/ -- optional one-level stub expansion / sparse fields, and `viewAs` (the owner reads as
|
|
722
|
+
* another reader; see ListParams.viewAs).
|
|
723
723
|
*/
|
|
724
724
|
async get(type, id, opts = {}) {
|
|
725
725
|
only("get", opts, ["expand", "fields", "viewAs"]);
|
|
@@ -754,8 +754,8 @@ var OwV2Client = class {
|
|
|
754
754
|
* PUT /{type}/{id}/ -- upsert-by-client-id. The local-first write primitive. A known-of
|
|
755
755
|
* stub (`known_of: true`, see isKnownOf) is a TypeError before sending, here and on every
|
|
756
756
|
* element write: a PUT of one would blank every field it does not keep.
|
|
757
|
-
* An agent seat's PUT on an existing element, in a world that takes its writes as proposals
|
|
758
|
-
*
|
|
757
|
+
* An agent seat's PUT on an existing element, in a world that takes its writes as proposals,
|
|
758
|
+
* answers 202 and is thrown as an OwProposedError: the element did not change.
|
|
759
759
|
*/
|
|
760
760
|
async upsert(type, id, element) {
|
|
761
761
|
refuseKnownOf(element, "upsert");
|
|
@@ -766,12 +766,12 @@ var OwV2Client = class {
|
|
|
766
766
|
* replace wholesale, omitted fields stay untouched. For link arrays prefer
|
|
767
767
|
* editLinks() -- atomic server-side merge, no read-before-write.
|
|
768
768
|
*
|
|
769
|
-
* `ifMatch
|
|
769
|
+
* `ifMatch`: the element's `change_seq` as you read it. The update lands
|
|
770
770
|
* only if nobody changed the element since; otherwise nothing is written and this throws
|
|
771
771
|
* an OwPreconditionFailedError (412) whose `current` is the element as it is now. Omit
|
|
772
772
|
* it for today's unconditional write.
|
|
773
773
|
*
|
|
774
|
-
* In a world that takes an agent seat's writes as proposals (
|
|
774
|
+
* In a world that takes an agent seat's writes as proposals (the world's
|
|
775
775
|
* `agent_writes_proposed`), a seat's patch answers 202 with `{proposal}`, never an element:
|
|
776
776
|
* this throws an OwProposedError (`err.isProposed`, the row under `err.proposal`) and the
|
|
777
777
|
* element did not change. If-Match is checked first: a stale one is still a 412.
|
|
@@ -786,7 +786,7 @@ var OwV2Client = class {
|
|
|
786
786
|
* tombstone AND scrubs the id from every other element's links in the same
|
|
787
787
|
* transaction -- no client-side unlink pass needed, ever.
|
|
788
788
|
*
|
|
789
|
-
* `ifMatch` (
|
|
789
|
+
* `ifMatch` (as on patch()): the element's `change_seq` as you read it. The delete
|
|
790
790
|
* lands only if nothing changed since; otherwise an OwPreconditionFailedError (412) whose
|
|
791
791
|
* `current` is the element as it is now, and nothing is deleted. On an element already gone it
|
|
792
792
|
* is the idempotent 204. Under a world's proposals switch a delete is never a proposal.
|
|
@@ -800,8 +800,8 @@ var OwV2Client = class {
|
|
|
800
800
|
* Dedupes, tolerates already-present/already-absent ids. Returns the FULL
|
|
801
801
|
* updated element (fixture P5). Use this for all relationship editing; it
|
|
802
802
|
* retires the read-merge-PATCH dance. `ifMatch` works as on patch(): a link write
|
|
803
|
-
* moves the element too. A 202 (an agent seat's link edit that became a proposal
|
|
804
|
-
*
|
|
803
|
+
* moves the element too. A 202 (an agent seat's link edit that became a proposal)
|
|
804
|
+
* is thrown as an OwProposedError, as on patch().
|
|
805
805
|
*/
|
|
806
806
|
async editLinks(type, id, field, edit, opts = {}) {
|
|
807
807
|
only("editLinks", opts, ["ifMatch"]);
|
|
@@ -809,7 +809,7 @@ var OwV2Client = class {
|
|
|
809
809
|
return this.request("POST", `/${type}/${id}/links/${field}`, { write: true, elementWrite: true, proposable: true, body: edit, ifMatch: opts.ifMatch });
|
|
810
810
|
}
|
|
811
811
|
/**
|
|
812
|
-
* POST /{type}/{id}/adopt with {member} -- change who made an element
|
|
812
|
+
* POST /{type}/{id}/adopt with {member} -- change who made an element.
|
|
813
813
|
* `member` is a membership id of this world (a person or an AI seat, as `members()` lists
|
|
814
814
|
* them) or `'owner'`, which sets `created_by` to null. The world's owner key or a
|
|
815
815
|
* co-builder's (a person's or a seat's) with its PIN; a contributor's is 403 `not_author`
|
|
@@ -837,7 +837,7 @@ var OwV2Client = class {
|
|
|
837
837
|
* the items that would have succeeded still say 201 with the ids and timestamps they
|
|
838
838
|
* would have had (keel's "counterfactual 201s"): do not record those ids as created.
|
|
839
839
|
* An agent seat's item on an existing element, in a world that takes its writes as
|
|
840
|
-
* proposals
|
|
840
|
+
* proposals, answers a slot `{status: 202, id, proposal}`: never thrown, the
|
|
841
841
|
* element unchanged, the slot's `proposal` the row a keeper decides.
|
|
842
842
|
* An element without an id gets one, as `create` mints it, by its position in `items`: with an
|
|
843
843
|
* `idempotencyKey`, derived from the key and the position (the ids the Python package mints),
|
|
@@ -869,18 +869,18 @@ var OwV2Client = class {
|
|
|
869
869
|
/**
|
|
870
870
|
* GET /changes -- one page of the world's ordered change feed.
|
|
871
871
|
* Cursor is OPAQUE: persist verbatim, never parse or build one (a guest's and a
|
|
872
|
-
* contributor's carry their view's epoch, since
|
|
872
|
+
* contributor's carry their view's epoch, since 2026-10-20 for a contributor).
|
|
873
873
|
* Zero/absent cursor = full export (byte-aligned with the Folder Format).
|
|
874
874
|
* Reset rule: a 409 `resync_required` (err.isResyncRequired) means the key's
|
|
875
875
|
* view changed (a guest's slice, an element unhidden from a contributor, or its role): drop
|
|
876
876
|
* the cursor and walk from zero. For what the local copy holds that the walk no longer names,
|
|
877
|
-
* read err.resyncReason (
|
|
877
|
+
* read err.resyncReason (while keel's hidden mark is on): `role`, keep it; `view`,
|
|
878
878
|
* drop it (as for a delete row with reason `hidden`). Without a reason, keep it (keel's own
|
|
879
879
|
* words since PR 104; sharing is forward-only). Never empty a copy on your own.
|
|
880
880
|
* Citizenship: heaviest route on the platform; default page size is polite.
|
|
881
881
|
* keel sends the cursor of a page at the head as a number (an empty page, for a key
|
|
882
882
|
* whose cursor carries no epoch); it is handed back as a string, like every cursor here.
|
|
883
|
-
* `after
|
|
883
|
+
* `after`: only the changes made at or after an ISO 8601 time (`updated_at` of an
|
|
884
884
|
* upsert, `deleted_at` of a delete; no offset means UTC). A filter, not a position: the order,
|
|
885
885
|
* `cursor`, `has_more` and `head` are as without it, so to read the whole window pass the cursor
|
|
886
886
|
* back as `since` with the same `after` until `has_more` is false (`changesAll` does). "Since
|
|
@@ -901,12 +901,12 @@ var OwV2Client = class {
|
|
|
901
901
|
* poll's, so a missed tick never drops a change) and walk changesAll only when it moved;
|
|
902
902
|
* a head below yours means the server rewound: walk again from zero. `epoch` is a
|
|
903
903
|
* guest's or a contributor's view epoch (null for other keys): it can move with `head` unchanged, so walk on
|
|
904
|
-
* either move. `epoch_reason` (
|
|
904
|
+
* either move. `epoch_reason` (while keel's hidden mark is on; absent otherwise)
|
|
905
905
|
* says why the epoch last moved, `role` or `view` (see OwChangesPage.epoch_reason).
|
|
906
906
|
* keel returns the owner's cursor as a number; it is handed back as a
|
|
907
907
|
* string, like every cursor here.
|
|
908
908
|
*
|
|
909
|
-
* Conditional (
|
|
909
|
+
* Conditional (4.57.0): keel tags the answer with an ETag that covers the head and
|
|
910
910
|
* the epoch, so a view change moves it too. The client keeps the last tag and sends it as
|
|
911
911
|
* If-None-Match on its next head read. When nothing moved, keel answers 304 with no body, and
|
|
912
912
|
* this returns the `head`, `cursor` and `epoch` from the last 200 with `unchanged: true`
|
|
@@ -1052,7 +1052,7 @@ var OwV2Client = class {
|
|
|
1052
1052
|
if (!res.ok) throw await errorFromResponse(res);
|
|
1053
1053
|
return await res.json();
|
|
1054
1054
|
}
|
|
1055
|
-
// -- Files on elements
|
|
1055
|
+
// -- Files on elements ---------------------------------------------
|
|
1056
1056
|
/**
|
|
1057
1057
|
* GET /{type}/{id}/files -- the element's files, newest first: each with its name, kind,
|
|
1058
1058
|
* size in bytes, label (or null), who added it (`added_by.agent` is true when an agent did)
|
|
@@ -1193,14 +1193,14 @@ var OwV2Client = class {
|
|
|
1193
1193
|
async removeFile(type, id, fileId) {
|
|
1194
1194
|
await this.request("DELETE", `/${type}/${encodeURIComponent(id)}/files/${encodeURIComponent(fileId)}`);
|
|
1195
1195
|
}
|
|
1196
|
-
// -- Joining a world by link
|
|
1196
|
+
// -- Joining a world by link ----------------------------------
|
|
1197
1197
|
/**
|
|
1198
1198
|
* POST /join/preview -- what a join code holds, without using it: who invites, to
|
|
1199
1199
|
* which world, in what role, and `reader` (`person`: accept it with acceptJoin;
|
|
1200
1200
|
* `agent`: an AI agent redeems it at POST /join). Sends no credential, whatever key
|
|
1201
1201
|
* this client holds. Every bad code (unknown, used, revoked, expired) is the same
|
|
1202
1202
|
* 404 `not_found` (`err.isNotFound`). `code` is the part of the link after `#`. A table
|
|
1203
|
-
*
|
|
1203
|
+
* adds `max_uses`, `uses_left`, `name_required` and `characters`, the
|
|
1204
1204
|
* pick screen's list; a link for one answers without them.
|
|
1205
1205
|
*/
|
|
1206
1206
|
async previewJoin(code) {
|
|
@@ -1208,7 +1208,7 @@ var OwV2Client = class {
|
|
|
1208
1208
|
}
|
|
1209
1209
|
/**
|
|
1210
1210
|
* POST /join -- redeem a join code that needs no account: a player's (a friend reading as
|
|
1211
|
-
* a guest
|
|
1211
|
+
* a guest) or an AI agent's. Sends no credential, whatever key this client holds.
|
|
1212
1212
|
* 201 with `kind` telling the two answers apart: `player` gives a read key (`ow_r_`, no PIN)
|
|
1213
1213
|
* and the Character it reads as; `agent` gives a seat's write key, secret and `.env` lines.
|
|
1214
1214
|
* Both are shown once, and the code is spent: a lost answer cannot be replayed (the owner
|
|
@@ -1217,7 +1217,7 @@ var OwV2Client = class {
|
|
|
1217
1217
|
* agent code). Every bad code is the same 404 `not_found`; a person's code is redeemed with
|
|
1218
1218
|
* acceptJoin instead.
|
|
1219
1219
|
*
|
|
1220
|
-
* A table (a player code whose preview carries `max_uses
|
|
1220
|
+
* A table (a player code whose preview carries `max_uses`) seats one player
|
|
1221
1221
|
* per redeem, until `uses_left` is 0. With a list, `character` is the player's pick, the `id`
|
|
1222
1222
|
* of one of the preview's `characters` not `taken`: a Character a live seat already plays is
|
|
1223
1223
|
* 422 `character_taken` (`err.isCharacterTaken`; pick another), one off the list, hidden or
|
|
@@ -1236,7 +1236,7 @@ var OwV2Client = class {
|
|
|
1236
1236
|
if (opts.character !== void 0) body.character = opts.character;
|
|
1237
1237
|
return this.request("POST", "/join", { auth: false, body });
|
|
1238
1238
|
}
|
|
1239
|
-
// -- Signing in with a password
|
|
1239
|
+
// -- Signing in with a password --------------------------------
|
|
1240
1240
|
/**
|
|
1241
1241
|
* Sign in with an email address (or a username) and password, and get a new account token
|
|
1242
1242
|
* (`ow_a_`) for this device, named `tokenName` (say, "Lantern on iPhone"): the name the
|
|
@@ -1366,8 +1366,7 @@ var OwV2Client = class {
|
|
|
1366
1366
|
* POST /account/join -- accept an invite link's code as the account this client's
|
|
1367
1367
|
* `ow_a_` token belongs to: 201 with the new membership. Refusals: 404 `not_found`
|
|
1368
1368
|
* (every bad code, and a code made for an AI agent) and 409 `already_member`
|
|
1369
|
-
* (`err.isAlreadyMember`). Accepting needs no account PIN, for any role (
|
|
1370
|
-
* ed73c90); a write key for the membership waits for one (`pin_required`). A refusal
|
|
1369
|
+
* (`err.isAlreadyMember`). Accepting needs no account PIN, for any role; a write key for the membership waits for one (`pin_required`). A refusal
|
|
1371
1370
|
* never spends the code. A world key here is a TypeError before anything is sent.
|
|
1372
1371
|
*/
|
|
1373
1372
|
async acceptJoin(code) {
|
|
@@ -1378,18 +1377,18 @@ var OwV2Client = class {
|
|
|
1378
1377
|
}
|
|
1379
1378
|
/**
|
|
1380
1379
|
* POST /account/worlds/{worldId}/links -- a new invite link for a world this client's
|
|
1381
|
-
* `ow_a_` token owns
|
|
1380
|
+
* `ow_a_` token owns: `reader` is required (`person`, accepted with acceptJoin;
|
|
1382
1381
|
* `agent`, redeemed at POST /join; `player`, a friend with no account, redeemed with
|
|
1383
|
-
* redeemJoin for a read key
|
|
1382
|
+
* redeemJoin for a read key); `role`, when left out, is keel's default: guest for a
|
|
1384
1383
|
* person link, contributor for an agent link (a player link is guest, and refuses any other), `days` (1, 7 or 30) to 7; `withCharacter` (agent links
|
|
1385
1384
|
* only) to true; `character` (player links only) a Character's id or `new` (the default):
|
|
1386
|
-
* whoever opens the link first reads as it, until removed. `preview` (person and player links
|
|
1387
|
-
*
|
|
1385
|
+
* whoever opens the link first reads as it, until removed. `preview` (person and player links)
|
|
1386
|
+
* to false: true puts the world's id in the link's path, so a chat that unfurls it
|
|
1388
1387
|
* shows the world's name and picture (the code stays after `#`); true on an agent link is
|
|
1389
1388
|
* 422, param `preview`. `maxUses` (person and player links; an agent link takes none) to 1, a
|
|
1390
|
-
* link for one. On a person link
|
|
1389
|
+
* link for one. On a person link 2 to 50 lets in that many accounts, each
|
|
1391
1390
|
* joining once with the link's role, until every use is taken, it expires or it is revoked;
|
|
1392
|
-
* who already joined stays. On a player link
|
|
1391
|
+
* who already joined stays. On a player link 2 to 50 makes a table, one
|
|
1393
1392
|
* link that seats that many players, each picking one of
|
|
1394
1393
|
* `characters` (Character ids of the world, in the order a pick screen shows them; a hidden
|
|
1395
1394
|
* one is 422, param `characters`). `characters` empty or left out: each player names a fresh
|
|
@@ -1440,7 +1439,7 @@ var OwV2Client = class {
|
|
|
1440
1439
|
}
|
|
1441
1440
|
await this.request("DELETE", `/account/worlds/${encodeURIComponent(worldId)}/links/${encodeURIComponent(linkId)}`);
|
|
1442
1441
|
}
|
|
1443
|
-
// -- Seats for your own AI
|
|
1442
|
+
// -- Seats for your own AI ------------------------------
|
|
1444
1443
|
/**
|
|
1445
1444
|
* POST /account/worlds/{worldId}/seats -- a seat for your own AI in a world you own or are a
|
|
1446
1445
|
* member of: its own membership, write key and `ow_s_` secret, no join link. You answer for
|
|
@@ -1497,9 +1496,9 @@ var OwV2Client = class {
|
|
|
1497
1496
|
}
|
|
1498
1497
|
await this.request("DELETE", `/account/worlds/${encodeURIComponent(worldId)}/seats/${encodeURIComponent(seatId)}`);
|
|
1499
1498
|
}
|
|
1500
|
-
// -- The hidden mark
|
|
1499
|
+
// -- The hidden mark ------------------------------------------
|
|
1501
1500
|
/**
|
|
1502
|
-
* PUT /{type}/{id}/hidden -- hide an element
|
|
1501
|
+
* PUT /{type}/{id}/hidden -- hide an element. The owner's key or a co-builder's
|
|
1503
1502
|
* (a person's or a seat's) with its PIN; hiding a hidden element again changes nothing, and
|
|
1504
1503
|
* the element's body and `change_seq` do not move. Hidden, it is seen only by the owner, the
|
|
1505
1504
|
* co-builders and the member who created it; to every other key it is a 404, left out of
|
|
@@ -1521,7 +1520,7 @@ var OwV2Client = class {
|
|
|
1521
1520
|
const page = await this.request("GET", "/world/hidden");
|
|
1522
1521
|
return page.data;
|
|
1523
1522
|
}
|
|
1524
|
-
// -- The proposed change
|
|
1523
|
+
// -- The proposed change ---------------------------------------
|
|
1525
1524
|
//
|
|
1526
1525
|
// A proposal is a record kept beside an element, never in its body: the element does not
|
|
1527
1526
|
// change until the world's owner or a co-builder accepts it. A proposal is seen by the owner,
|
|
@@ -1573,7 +1572,7 @@ var OwV2Client = class {
|
|
|
1573
1572
|
}
|
|
1574
1573
|
/**
|
|
1575
1574
|
* GET /world/proposals -- the world's queue, newest first by created_at, two kinds of row told
|
|
1576
|
-
* apart by `kind
|
|
1575
|
+
* apart by `kind`: `proposal`, a proposed change to an element (OwProposal), and
|
|
1577
1576
|
* `new_element`, an element written as proposed, carrying `x_review_proposed`
|
|
1578
1577
|
* (OwProposedNewElement: settle it with reviewNewElement). A marked element is listed under
|
|
1579
1578
|
* `open`, `lapsed` and `all`, never `accepted` or `declined`; keel reads at most the 500 newest.
|
|
@@ -1628,7 +1627,7 @@ var OwV2Client = class {
|
|
|
1628
1627
|
}
|
|
1629
1628
|
/**
|
|
1630
1629
|
* POST /{type}/{id}/review -- settle a new element written as proposed, one carrying
|
|
1631
|
-
* `x_review_proposed` (the queue's `new_element` row
|
|
1630
|
+
* `x_review_proposed` (the queue's `new_element` row). The owner's key or a
|
|
1632
1631
|
* co-builder's, with its PIN. `{ decision: 'accept' }` clears the mark (a write by you: a new
|
|
1633
1632
|
* change_seq, one /changes row) and answers `{ element }`; `{ decision: 'decline', reason? }`
|
|
1634
1633
|
* deletes the element (a tombstone, the links to it scrubbed, its open proposals dropped) and
|
|
@@ -1723,7 +1722,7 @@ var OwV2Client = class {
|
|
|
1723
1722
|
* `navigate: false`). `redirectUri` is the registered return address as a string, `https:`
|
|
1724
1723
|
* only, never built from `location.origin`: a tool's registration is read at
|
|
1725
1724
|
* `GET /api/v2/auth/clients`. `resume` is small JSON handed back by `completeSignIn`. No request
|
|
1726
|
-
* is sent; any client, keyless included.
|
|
1725
|
+
* is sent; any client, keyless included.
|
|
1727
1726
|
*/
|
|
1728
1727
|
async signInWithOnlyWorlds(opts) {
|
|
1729
1728
|
only("signInWithOnlyWorlds", opts, ["clientId", "redirectUri", "resume", "storage", "navigate"]);
|
|
@@ -1742,7 +1741,7 @@ var OwV2Client = class {
|
|
|
1742
1741
|
only("completeSignIn", opts, ["clientId", "storage", "url"]);
|
|
1743
1742
|
return completeSignIn(this.baseUrl, this.fetchImpl, opts);
|
|
1744
1743
|
}
|
|
1745
|
-
// -- Ask your world
|
|
1744
|
+
// -- Ask your world -------------------------------------------
|
|
1746
1745
|
/**
|
|
1747
1746
|
* POST /account/ask -- a question about a world the account owns or is in, answered by
|
|
1748
1747
|
* keel's AI proxy from `context` only (build it with buildAskContext from the elements
|
|
@@ -4781,7 +4780,7 @@ var TokenResource = class {
|
|
|
4781
4780
|
* Consume tokens for service usage
|
|
4782
4781
|
*
|
|
4783
4782
|
* @deprecated keel serves no consume route (404 on production since 2026-10;
|
|
4784
|
-
* no client decides what its act costs,
|
|
4783
|
+
* no client decides what its act costs, ruled 2026-10-14): spending
|
|
4785
4784
|
* happens server-side in the route that does the work. Removed in 5.0.
|
|
4786
4785
|
*
|
|
4787
4786
|
* Reports token consumption to track daily usage. Allows consumption even if
|