@onlyworlds/sdk 4.62.0 → 4.64.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 +3 -1
- package/CHANGELOG.md +19 -0
- package/README.md +2 -0
- package/SCHEMA.md +1 -1
- package/dist/index.d.ts +39 -14
- package/dist/index.js +98 -14
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# For AI agents using @onlyworlds/sdk
|
|
2
2
|
|
|
3
|
-
**Current as of**: SDK **4.x** · schema-dist **v0.33.0-dist.
|
|
3
|
+
**Current as of**: SDK **4.x** · schema-dist **v0.33.0-dist.49** (canonical 00.33.00).
|
|
4
4
|
This line is asserted by `codegen:check` in CI — if the pin moves and this file is not
|
|
5
5
|
re-read against it, the check fails rather than letting this document rot quietly.
|
|
6
6
|
|
|
@@ -88,6 +88,8 @@ against live data). The v1 surface (`OnlyWorldsClient`, the `ElementType` enum)
|
|
|
88
88
|
§4.7 (`.owworld`): the reader checks the central directory before inflating
|
|
89
89
|
and ignores files beside the world's folder; the writer's output is byte-stable (marker
|
|
90
90
|
first, UTF-8 name order, 1980 stamps) and holds only `world.json` and the folder's parts.
|
|
91
|
+
Producers marked `"private": true` in `records/RECORDS.json` are left out whole unless
|
|
92
|
+
`writeWorldFile(files, topDir, { includePrivateRecords: true })` (since 4.63.0; OW-8).
|
|
91
93
|
- World calendars (since 4.20.0): `worldCalendars(elements)` finds the elements carrying
|
|
92
94
|
`atlas_calendar` (Atlas owns the field: read it, never write it); `resolveCalendarLens` picks
|
|
93
95
|
one; `formatStep(config, step)` names a point on the world's integer time line, `parseDate`
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ earlier history lives in git log only.
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [4.64.0] - 2026-10-23
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Every options object in the package now refuses an unknown key**, not only the client's typed methods (4.51.0 to 4.53.0): `readWorldFile`, `parseDate`, `resolveCalendarLens`, `lookupWorld`, `renderElement`, `planPhoto`, `preparePhoto`, the client's `request()` escape hatch, `listAll` (with its own keys: a `cursor` it was handed was overwritten unread), the deprecated `tokens.consume` and `new OwSignInError`'s third argument throw a `TypeError` naming the function, the key and the keys it takes, before anything is read, decoded, parsed or sent. A dropped key was never harmless: `readWorldFile(bytes, { maxbytes: 1e6 })` read with the 2 GiB budget, `parseDate(cfg, input, { Now: 12 })` parsed as if the world had no now, and W11's `list('character', { name__icontains })` read every Character and a cleanup script deleted 99 of them (2026-10-22). A plain-JavaScript caller passing a misspelt key will now see a `TypeError` where the call used to run with the default; TypeScript callers were already refused at compile time. `writeWorldFile` and `typeWord` keep their refusals on the same shared check; `typeWord`'s message now reads like the others (`typeWord: unknown option 'plural'. The keys are supertype, many.`).
|
|
13
|
+
- Tests: one test calls every options parameter of the exported surface with `{ __unknown__: 1 }` and asserts a `TypeError` naming the key, nothing sent; a second reads `src/index.ts` with the TypeScript checker and fails on any exported object parameter that is neither in that list nor named as data (a calendar config, a world index, an element), so a new options object cannot ship unfenced. Watched failing on mutants of the `readWorldFile`, `parseDate`, `preparePhoto` and `request()` fences, and on an exported options function added without one.
|
|
14
|
+
|
|
15
|
+
## [4.63.0] - 2026-10-23
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **`writeWorldFile(files, topDir, { includePrivateRecords })`**, OW-8's private clause (folder format spec v0.3.15, §4.5 rule 11 and §4.7). By default the writer now leaves out, whole, every `records/<producer>/` directory whose entry in `records/RECORDS.json` says `"private": true`, so a tool's own notes do not travel the first time a world is shared. `RECORDS.json` itself travels byte-exact, its private entries kept, so a reader can see a producer was left out. Only the boolean `true` marks a directory private (`"true"`, a string, does not). A producer's name matches its directory by the archive's one fold (NFC, then simple case folding), so a manifest's `Fold` leaves out `records/fold/` on a disk that ignores case. With `includePrivateRecords: true` every record travels as before and the manifest is not read. No manifest, nothing is private. Type `OwWriteWorldFileOptions`.
|
|
20
|
+
- **A manifest the writer cannot read is refused, not guessed at**: a `RECORDS.json` that is not JSON, not an array, holds an entry that is not an object, or marks an entry private without a producer name throws a `TypeError` naming the file and the option, having written nothing, unless `includePrivateRecords: true` is passed. A world whose manifest is in an older shape now needs the option to be written. The options object refuses an unknown key, and an `includePrivateRecords` that is not a boolean, with a `TypeError`, before anything else.
|
|
21
|
+
- Tests: the conformance set's four private cases, written from its `sources.private` world (each source file checked by its sha256): the default side equals `pass-OW-8-private-left-out` and the asked side `pass-OW-8-private-asked`, entry for entry, and neither is `fail-OW-8-private-partial` or `fail-OW-8-private-manifest-rewritten`. Also the string `"true"`, a producer whose name is a prefix of another's, no manifest, each unreadable manifest refused and carried when asked, and the options. Each behaviour watched failing on its own mutant.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- **Schema repinned to schema-dist `v0.33.0-dist.49`** (same canonical 00.33.00; no schema file moved, no generated type changed, `ONLYWORLDS_VERSION` still `'00.33.00'`). The `.owworld` conformance set grows to 85 zips with the four OW-8 private-records writer cases on `sources.private`; none of the earlier 81 moved.
|
|
26
|
+
|
|
8
27
|
## [4.62.0] - 2026-10-22
|
|
9
28
|
|
|
10
29
|
### Added
|
package/README.md
CHANGED
|
@@ -285,6 +285,8 @@ Files beside the world's folder and archive junk (`__MACOSX`, `.DS_Store`) are i
|
|
|
285
285
|
|
|
286
286
|
The writer gives the same bytes for the same files: the `mimetype` marker first, then every entry in the UTF-8 order of its name, stamped 1980-01-01 00:00. It writes `world.json`, `elements/`, `spatial/`, `media/` and `records/`, and leaves any other file out. A tool's dot-folder you hand it travels too, which makes the file a private copy rather than a portable `.owworld`.
|
|
287
287
|
|
|
288
|
+
`records/` travels byte for byte, except a producer's directory that `records/RECORDS.json` marks `"private": true`: that one is left out whole, and `RECORDS.json` itself travels unchanged, so the reader can see a producer was left out. Pass `writeWorldFile(files, topDir, { includePrivateRecords: true })` to carry private records too. A `RECORDS.json` that is not a JSON array of objects is refused with a `TypeError` unless you pass that option, since the writer cannot tell which records are private.
|
|
289
|
+
|
|
288
290
|
## World calendars
|
|
289
291
|
|
|
290
292
|
A world's time is an integer line (`time_range_current` is a point on it, and so is an Event's `start_date`). A calendar names its points: months, days, eras. Atlas keeps a calendar on an element (a Construct by convention) in its `atlas_calendar` field, and the SDK reads it with Atlas's own calendar code (since 4.20.0). Atlas owns that field and is its only writer; read it, never write it.
|
package/SCHEMA.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OnlyWorlds Schema Reference
|
|
2
2
|
|
|
3
|
-
**Source**: https://github.com/OnlyWorlds/schema-dist @ **v0.33.0-dist.
|
|
3
|
+
**Source**: https://github.com/OnlyWorlds/schema-dist @ **v0.33.0-dist.49** — canonical schema **00.33.00**, published 2026-10-22.
|
|
4
4
|
|
|
5
5
|
GENERATED from the canonical schema YAML — do not hand-edit (regenerate: `python codegen/generate_types.py`).
|
|
6
6
|
Written for both humans and AI agents reading this package locally.
|
package/dist/index.d.ts
CHANGED
|
@@ -4324,7 +4324,9 @@ declare function typeWord(world: object | null | undefined, type: string, opts?:
|
|
|
4324
4324
|
* THE WRITER emits a portable copy (OW-7, OW-12, OW-13): the `mimetype` marker
|
|
4325
4325
|
* first and stored, then only the folder's parts, every entry stamped
|
|
4326
4326
|
* 1980-01-01 00:00, in the UTF-8 byte order of its name, JSON deflated and
|
|
4327
|
-
* everything else stored.
|
|
4327
|
+
* everything else stored. `records/` travels whole and byte-exact, except the
|
|
4328
|
+
* producers `records/RECORDS.json` marks private, left out whole unless the
|
|
4329
|
+
* caller asks (OW-8, §4.5 rule 11).
|
|
4328
4330
|
*
|
|
4329
4331
|
* A tool's own `.<tool>/` folder is the tool's (spec §4): the reader returns
|
|
4330
4332
|
* it like any file (a caller leaves files out with `skip`), and the writer
|
|
@@ -4369,9 +4371,17 @@ interface OwReadWorldFileOptions {
|
|
|
4369
4371
|
declare function simpleCaseFold(text: string): string;
|
|
4370
4372
|
/**
|
|
4371
4373
|
* Read a world file. Throws `OwWorldFileError` saying why, having returned
|
|
4372
|
-
* nothing; the caller writes only what this returns.
|
|
4374
|
+
* nothing; the caller writes only what this returns. An unknown option is a
|
|
4375
|
+
* `TypeError` before the bytes are looked at.
|
|
4373
4376
|
*/
|
|
4374
4377
|
declare function readWorldFile(bytes: Uint8Array, opts?: OwReadWorldFileOptions): OwReadWorldFile;
|
|
4378
|
+
interface OwWriteWorldFileOptions {
|
|
4379
|
+
/**
|
|
4380
|
+
* Carry the producers marked private in `records/RECORDS.json` (spec §4.5
|
|
4381
|
+
* rule 11, OW-8). Left out or false, their directories are left out whole.
|
|
4382
|
+
*/
|
|
4383
|
+
includePrivateRecords?: boolean;
|
|
4384
|
+
}
|
|
4375
4385
|
/**
|
|
4376
4386
|
* Write a world file under one top-level folder `topDir`: the `mimetype`
|
|
4377
4387
|
* marker first and stored, then `world.json` (without `api`) and the folder's
|
|
@@ -4379,12 +4389,26 @@ declare function readWorldFile(bytes: Uint8Array, opts?: OwReadWorldFileOptions)
|
|
|
4379
4389
|
* deflated and everything else stored (spec §4.7, OW-6, OW-7, OW-12, OW-13).
|
|
4380
4390
|
* Any other file is left out. A tool's dot-folder in `files` travels, and
|
|
4381
4391
|
* makes the result a private copy, not a portable `.owworld` (OW-7): leave it
|
|
4382
|
-
* out of `files` for a portable one.
|
|
4383
|
-
*
|
|
4384
|
-
*
|
|
4385
|
-
*
|
|
4392
|
+
* out of `files` for a portable one.
|
|
4393
|
+
*
|
|
4394
|
+
* `records/` travels byte-exact, except private records (OW-8, spec §4.5 rule
|
|
4395
|
+
* 11): every `records/<producer>/` whose entry in `records/RECORDS.json` says
|
|
4396
|
+
* `"private": true` (the boolean; `"true"` is not private; the name matched by
|
|
4397
|
+
* OW-18's fold, so `Fold` names `records/fold/`) is left out whole,
|
|
4398
|
+
* and `RECORDS.json` itself travels byte-exact, its private entries kept, so a
|
|
4399
|
+
* reader learns a producer was left out. Pass `{ includePrivateRecords: true }`
|
|
4400
|
+
* to carry them; then the manifest is not read and every record travels. No
|
|
4401
|
+
* manifest, nothing is private.
|
|
4402
|
+
*
|
|
4403
|
+
* Throws a `TypeError`, having written nothing, for an unknown option, an
|
|
4404
|
+
* `includePrivateRecords` that is not a boolean, and (unless private records
|
|
4405
|
+
* are asked for) a `RECORDS.json` that is not a JSON array of objects or that
|
|
4406
|
+
* marks an entry private without a producer name. Refuses (`OwWorldFileError`)
|
|
4407
|
+
* an unsafe path or `topDir`, a duplicate path, a name some disk cannot hold,
|
|
4408
|
+
* two names that fold to one, and a world.json that is missing, will not parse
|
|
4409
|
+
* (it may hold a key, so it is never zipped raw) or has no `id`.
|
|
4386
4410
|
*/
|
|
4387
|
-
declare function writeWorldFile(files: OwWorldFileEntry[], topDir: string): Uint8Array;
|
|
4411
|
+
declare function writeWorldFile(files: OwWorldFileEntry[], topDir: string, opts?: OwWriteWorldFileOptions): Uint8Array;
|
|
4388
4412
|
|
|
4389
4413
|
/**
|
|
4390
4414
|
* World lookup: find the elements a plain-language question is about, in a
|
|
@@ -4512,13 +4536,13 @@ declare function buildWorldIndex<T extends OwLookupElement>(elements: Iterable<T
|
|
|
4512
4536
|
* elements whose other text holds the question's words. An empty question
|
|
4513
4537
|
* returns no hits.
|
|
4514
4538
|
*/
|
|
4515
|
-
declare function lookupWorld<T extends OwLookupElement>(index: OwWorldIndex<T>, question: string,
|
|
4539
|
+
declare function lookupWorld<T extends OwLookupElement>(index: OwWorldIndex<T>, question: string, opts?: OwLookupOptions): OwLookupHit<T>[];
|
|
4516
4540
|
/**
|
|
4517
4541
|
* A compact text card for one element, for a person or a model: name, type,
|
|
4518
4542
|
* kind, description, its fields, its links by name (or how many point outside
|
|
4519
4543
|
* the data), and what links to it.
|
|
4520
4544
|
*/
|
|
4521
|
-
declare function renderElement<T extends OwLookupElement>(element: T, index: OwWorldIndex<T>,
|
|
4545
|
+
declare function renderElement<T extends OwLookupElement>(element: T, index: OwWorldIndex<T>, opts?: OwRenderOptions): string;
|
|
4522
4546
|
|
|
4523
4547
|
/**
|
|
4524
4548
|
* Context for keel's AI proxy (POST /api/v2/account/ask, Keel #159): the elements a
|
|
@@ -4618,9 +4642,9 @@ declare function planPhoto(source: {
|
|
|
4618
4642
|
type: string;
|
|
4619
4643
|
}, opts?: OwPhotoOptions): OwPhotoPlan;
|
|
4620
4644
|
/**
|
|
4621
|
-
* Shrink and convert a picture for upload. Throws `TypeError`
|
|
4622
|
-
*
|
|
4623
|
-
* over `maxBytes`.
|
|
4645
|
+
* Shrink and convert a picture for upload. Throws `TypeError` for an unknown
|
|
4646
|
+
* option (before anything is decoded), outside a browser, for a file the
|
|
4647
|
+
* browser cannot decode, or when the result is still over `maxBytes`.
|
|
4624
4648
|
*/
|
|
4625
4649
|
declare function preparePhoto(input: Blob, opts?: OwPhotoOptions): Promise<OwPreparedPhoto>;
|
|
4626
4650
|
|
|
@@ -4885,7 +4909,8 @@ declare function worldCalendars(elements: Iterable<OwCalendarElement>): WorldCal
|
|
|
4885
4909
|
*
|
|
4886
4910
|
* `fallbackToOnly`: when no calendar was ever chosen (`activeId` is `undefined`, not
|
|
4887
4911
|
* `null`) and the world holds exactly one, use it. `null` is an explicit "no calendar" and
|
|
4888
|
-
* stays null. With several calendars and no choice, nothing is guessed.
|
|
4912
|
+
* stays null. With several calendars and no choice, nothing is guessed. An unknown option is a
|
|
4913
|
+
* TypeError (the caller's bug, not the world's data).
|
|
4889
4914
|
*/
|
|
4890
4915
|
declare function resolveCalendarLens(elements: Iterable<OwCalendarElement>, activeId: string | null | undefined, opts?: {
|
|
4891
4916
|
fallbackToOnly?: boolean;
|
|
@@ -5195,4 +5220,4 @@ declare class TokenResource {
|
|
|
5195
5220
|
getEncryptionInfo(): Promise<EncryptionInfo>;
|
|
5196
5221
|
}
|
|
5197
5222
|
|
|
5198
|
-
export { AGENT_DOORS, ASK_LIMITS, type AccessKeyResponse, CALENDAR_FIELD, CALENDAR_SUPERTYPE, type CalendarConfig, type CalendarEra, type CalendarIntercalary, type CalendarMonths, type CalendarWeek, ELEMENT_FAMILIES, ELEMENT_ICONS, ELEMENT_LABELS, ELEMENT_SECTIONS, ELEMENT_TYPES, type ElementFamily, type ElementType, type EncryptionInfo, type EraDomain, FAMILY_COLORS, FAMILY_ORDER, FIELD_ACRONYMS, FIELD_SCHEMA, FILE_EXTENSIONS, type FieldInfo, type FieldType, GameTier, type ListParams, ONLYWORLDS_VERSION, type OwAccountWorld, type OwAgentJoined, type OwAllowance, OwApiError, type OwAskAnswer, type OwAskContext, type OwAuthErrorCode, type OwBulkItem, type OwBulkItemResult, type OwBulkResponse, type OwCalendarElement, type OwChange, type OwChangeDelete, type OwChangeUpsert, type OwChangesPage, type OwClientConfig, type OwCreatedWorldLink, type OwDeleteReason, type OwDraught, type OwDraughtComponent, type OwDraughtItem, type OwDraughtPolicy, type OwElement, type OwElementBase, type OwErrorBody, type OwFileAddedBy, type OwFileDownload, type OwFileKind, type OwFileRow, type OwFileTicket, type OwFrontDoor, type OwHiddenRow, type OwJoinPreview, type OwJoined, type OwJoinedMembership, type OwKeyKind, type OwLinkEdit, type OwLookupElement, type OwLookupHit, type OwLookupLink, type OwLookupOptions, type OwLookupReason, type OwMe, type OwMediaTicket, type OwMember, type OwMemberRole, type OwMintedKey, type OwNamesMap, OwNetworkError, type OwPage, type OwPhotoOptions, type OwPhotoPlan, type OwPlayerJoined, OwPreconditionFailedError, type OwPreparedPhoto, type OwProposal, type OwProposalAccepted, type OwProposalConflict, type OwProposalList, type OwProposalQuery, type OwProposalState, type OwProposeInput, type OwProposed, OwProposedError, type OwReadWorldFile, type OwReadWorldFileOptions, type OwRemovalTicket, type OwRemovedImage, type OwRenderOptions, type OwResyncReason, type OwSeat, type OwSeatCreated, type OwSignInBegin, type OwSignInBegun, type OwSignInComplete, OwSignInError, type OwSignInReason, type OwSignInResult, type OwSignInStorage, type OwSignedIn, type OwSortAddToRow, type OwSortAnswer, type OwSortAskRow, type OwSortLinkRow, type OwSortMakeRow, type OwSortNote, type OwSortRef, type OwSortRow, OwStaleProposalError, type OwUploadedFile, type OwUploadedImage, OwV2Client, type OwWordPair, type OwWorldFileEntry, OwWorldFileError, type OwWorldFileReason, type OwWorldFileRow, type OwWorldFiles, type OwWorldIndex, type OwWorldLink, type OwWorldMeta, type OwWorldProposalQuery, type OwWorldPublicPage, type OwWriteDoor, PHOTO_MAX_BYTES, PHOTO_TYPES, PUBLIC_FIELDS, type ParseError, type ParseOptions, type ParseResult, ROOM_PAIRS, type RevokeAllSessionsResponse, type RevokeSessionResponse, SPATIAL_TYPES, type SectionInfo, type StepBreakdown, type TokenConsumeParams, type TokenConsumeResponse, TokenResource, type TokenStatus, type TokenTransport, WORLD_FILE_MAX_BYTES, WORLD_FILE_MAX_ENTRIES, WORLD_FILE_MEDIA_TYPE, type WorldCalendar, absYearForEraYear, absoluteYear, approxYearLength, base64url, breakdownStep, buildAskContext, buildWorldIndex, detectKeyKind, displayYear, elementColor, eraForStep, errorFromResponse, familyOf, fieldLabel, fileKindOf, floorDiv, floorMod, formatDuration, formatMidLabel, formatStep, formatYearLabel, getElementIcon, getElementLabel, isAgentDoor, isDemoKey, isKnownOf, isLeapYear, isParseError, isRoomElement, kindCanWrite, lookupWorld, monthStartSteps, parseDate, parseErrorEnvelope, pinExpectation, pkceChallenge, planPhoto, preparePhoto, readCalendarConfig, readCalendarValue, readWorldFile, renderElement, resolveCalendarLens, resolveEraDomains, simpleCaseFold, typeWord, validateCalendarConfig, weekdayForStep, worldCalendars, writeWorldFile, yearLength, yearStartStep };
|
|
5223
|
+
export { AGENT_DOORS, ASK_LIMITS, type AccessKeyResponse, CALENDAR_FIELD, CALENDAR_SUPERTYPE, type CalendarConfig, type CalendarEra, type CalendarIntercalary, type CalendarMonths, type CalendarWeek, ELEMENT_FAMILIES, ELEMENT_ICONS, ELEMENT_LABELS, ELEMENT_SECTIONS, ELEMENT_TYPES, type ElementFamily, type ElementType, type EncryptionInfo, type EraDomain, FAMILY_COLORS, FAMILY_ORDER, FIELD_ACRONYMS, FIELD_SCHEMA, FILE_EXTENSIONS, type FieldInfo, type FieldType, GameTier, type ListParams, ONLYWORLDS_VERSION, type OwAccountWorld, type OwAgentJoined, type OwAllowance, OwApiError, type OwAskAnswer, type OwAskContext, type OwAuthErrorCode, type OwBulkItem, type OwBulkItemResult, type OwBulkResponse, type OwCalendarElement, type OwChange, type OwChangeDelete, type OwChangeUpsert, type OwChangesPage, type OwClientConfig, type OwCreatedWorldLink, type OwDeleteReason, type OwDraught, type OwDraughtComponent, type OwDraughtItem, type OwDraughtPolicy, type OwElement, type OwElementBase, type OwErrorBody, type OwFileAddedBy, type OwFileDownload, type OwFileKind, type OwFileRow, type OwFileTicket, type OwFrontDoor, type OwHiddenRow, type OwJoinPreview, type OwJoined, type OwJoinedMembership, type OwKeyKind, type OwLinkEdit, type OwLookupElement, type OwLookupHit, type OwLookupLink, type OwLookupOptions, type OwLookupReason, type OwMe, type OwMediaTicket, type OwMember, type OwMemberRole, type OwMintedKey, type OwNamesMap, OwNetworkError, type OwPage, type OwPhotoOptions, type OwPhotoPlan, type OwPlayerJoined, OwPreconditionFailedError, type OwPreparedPhoto, type OwProposal, type OwProposalAccepted, type OwProposalConflict, type OwProposalList, type OwProposalQuery, type OwProposalState, type OwProposeInput, type OwProposed, OwProposedError, type OwReadWorldFile, type OwReadWorldFileOptions, type OwRemovalTicket, type OwRemovedImage, type OwRenderOptions, type OwResyncReason, type OwSeat, type OwSeatCreated, type OwSignInBegin, type OwSignInBegun, type OwSignInComplete, OwSignInError, type OwSignInReason, type OwSignInResult, type OwSignInStorage, type OwSignedIn, type OwSortAddToRow, type OwSortAnswer, type OwSortAskRow, type OwSortLinkRow, type OwSortMakeRow, type OwSortNote, type OwSortRef, type OwSortRow, OwStaleProposalError, type OwUploadedFile, type OwUploadedImage, OwV2Client, type OwWordPair, type OwWorldFileEntry, OwWorldFileError, type OwWorldFileReason, type OwWorldFileRow, type OwWorldFiles, type OwWorldIndex, type OwWorldLink, type OwWorldMeta, type OwWorldProposalQuery, type OwWorldPublicPage, type OwWriteDoor, type OwWriteWorldFileOptions, PHOTO_MAX_BYTES, PHOTO_TYPES, PUBLIC_FIELDS, type ParseError, type ParseOptions, type ParseResult, ROOM_PAIRS, type RevokeAllSessionsResponse, type RevokeSessionResponse, SPATIAL_TYPES, type SectionInfo, type StepBreakdown, type TokenConsumeParams, type TokenConsumeResponse, TokenResource, type TokenStatus, type TokenTransport, WORLD_FILE_MAX_BYTES, WORLD_FILE_MAX_ENTRIES, WORLD_FILE_MEDIA_TYPE, type WorldCalendar, absYearForEraYear, absoluteYear, approxYearLength, base64url, breakdownStep, buildAskContext, buildWorldIndex, detectKeyKind, displayYear, elementColor, eraForStep, errorFromResponse, familyOf, fieldLabel, fileKindOf, floorDiv, floorMod, formatDuration, formatMidLabel, formatStep, formatYearLabel, getElementIcon, getElementLabel, isAgentDoor, isDemoKey, isKnownOf, isLeapYear, isParseError, isRoomElement, kindCanWrite, lookupWorld, monthStartSteps, parseDate, parseErrorEnvelope, pinExpectation, pkceChallenge, planPhoto, preparePhoto, readCalendarConfig, readCalendarValue, readWorldFile, renderElement, resolveCalendarLens, resolveEraDomains, simpleCaseFold, typeWord, validateCalendarConfig, weekdayForStep, worldCalendars, writeWorldFile, yearLength, yearStartStep };
|
package/dist/index.js
CHANGED
|
@@ -56,6 +56,19 @@ function keyedId(idempotencyKey, index) {
|
|
|
56
56
|
${index}`);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
// src/options.ts
|
|
60
|
+
function unknownKey(opts, keys) {
|
|
61
|
+
if (!opts || typeof opts !== "object") return void 0;
|
|
62
|
+
for (const k of Object.keys(opts)) if (!keys.includes(k)) return k;
|
|
63
|
+
return void 0;
|
|
64
|
+
}
|
|
65
|
+
function refuseUnknownOptions(fn, opts, keys, after = "") {
|
|
66
|
+
const k = unknownKey(opts, keys);
|
|
67
|
+
if (k !== void 0) {
|
|
68
|
+
throw new TypeError(`${fn}: unknown option '${k}'. The keys are ${keys.join(", ")}.${after ? ` ${after}` : ""}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
59
72
|
// src/v2/errors.ts
|
|
60
73
|
var OwApiError = class extends Error {
|
|
61
74
|
constructor(status, code, message, docUrl, detail, type = null, param = null, retryAfter = null) {
|
|
@@ -342,6 +355,7 @@ var OwNetworkError = class extends Error {
|
|
|
342
355
|
};
|
|
343
356
|
var OwSignInError = class extends Error {
|
|
344
357
|
constructor(reason, message, opts = {}) {
|
|
358
|
+
refuseUnknownOptions("OwSignInError", opts, ["status", "code", "retryAfter"]);
|
|
345
359
|
super(message);
|
|
346
360
|
this.name = "OwSignInError";
|
|
347
361
|
this.reason = reason;
|
|
@@ -652,7 +666,7 @@ var OwV2Client = class {
|
|
|
652
666
|
// -- Element CRUD --------------------------------------------------------
|
|
653
667
|
/** GET /{type}/ -- one cursor page. */
|
|
654
668
|
async list(type, params = {}) {
|
|
655
|
-
only("list", params, LIST_PARAM_KEYS,
|
|
669
|
+
only("list", params, LIST_PARAM_KEYS, LIST_FILTER_HINT);
|
|
656
670
|
const query = buildQuery({
|
|
657
671
|
limit: params.limit ?? this.pageSize,
|
|
658
672
|
cursor: params.cursor,
|
|
@@ -691,6 +705,7 @@ var OwV2Client = class {
|
|
|
691
705
|
}
|
|
692
706
|
/** Cursor-walk every page of a type. Politeness: uses config pageSize. */
|
|
693
707
|
async *listAll(type, params = {}) {
|
|
708
|
+
only("listAll", params, LIST_ALL_PARAM_KEYS, LIST_FILTER_HINT);
|
|
694
709
|
let cursor;
|
|
695
710
|
do {
|
|
696
711
|
const page = await this.list(type, { ...params, cursor });
|
|
@@ -1718,6 +1733,7 @@ var OwV2Client = class {
|
|
|
1718
1733
|
* sanitizePayload — callers own their body shape.
|
|
1719
1734
|
*/
|
|
1720
1735
|
async request(method, path, opts = {}) {
|
|
1736
|
+
only("request", opts, REQUEST_OPTION_KEYS);
|
|
1721
1737
|
if (opts.ifMatch !== void 0 && !(Number.isInteger(opts.ifMatch) && opts.ifMatch >= 0)) {
|
|
1722
1738
|
throw new TypeError(`ifMatch must be a whole number (an element's change_seq), got ${String(opts.ifMatch)}`);
|
|
1723
1739
|
}
|
|
@@ -1930,12 +1946,26 @@ function objectKey(keyOrUrl) {
|
|
|
1930
1946
|
return decodeURIComponent(new URL(keyOrUrl).pathname.replace(/^\/+/, ""));
|
|
1931
1947
|
}
|
|
1932
1948
|
var LIST_PARAM_KEYS = ["limit", "cursor", "ids", "createdBy", "expand", "fields", "filter", "viewAs"];
|
|
1949
|
+
var LIST_ALL_PARAM_KEYS = LIST_PARAM_KEYS.filter((k) => k !== "cursor");
|
|
1950
|
+
var LIST_FILTER_HINT = "A wire filter (name, name__icontains, supertype, subtype, characters) goes under filter: { ... }.";
|
|
1951
|
+
var REQUEST_OPTION_KEYS = [
|
|
1952
|
+
"query",
|
|
1953
|
+
"body",
|
|
1954
|
+
"idempotencyKey",
|
|
1955
|
+
"auth",
|
|
1956
|
+
"allowEmpty",
|
|
1957
|
+
"replayAware",
|
|
1958
|
+
"write",
|
|
1959
|
+
"elementWrite",
|
|
1960
|
+
"proposable",
|
|
1961
|
+
"ifMatch",
|
|
1962
|
+
"ifNoneMatch",
|
|
1963
|
+
"onEtag"
|
|
1964
|
+
];
|
|
1933
1965
|
function only(method, obj, keys, hint = "") {
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
throw new TypeError(`${method}: unknown parameter '${k}'. ${hint ? hint + " " : ""}The keys are ${keys.join(", ")}. Nothing was sent.`);
|
|
1938
|
-
}
|
|
1966
|
+
const k = unknownKey(obj, keys);
|
|
1967
|
+
if (k !== void 0) {
|
|
1968
|
+
throw new TypeError(`${method}: unknown parameter '${k}'. ${hint ? hint + " " : ""}The keys are ${keys.join(", ")}. Nothing was sent.`);
|
|
1939
1969
|
}
|
|
1940
1970
|
}
|
|
1941
1971
|
var CLIENT_CONFIG_KEYS = ["apiKey", "apiPin", "baseUrl", "pageSize", "changesPageSize", "fetch", "agent", "client"];
|
|
@@ -2884,6 +2914,7 @@ var OwWorldFileError = class extends Error {
|
|
|
2884
2914
|
this.reason = reason;
|
|
2885
2915
|
}
|
|
2886
2916
|
};
|
|
2917
|
+
var READ_OPTION_KEYS = ["maxBytes", "maxEntries", "skip"];
|
|
2887
2918
|
var refuse = (reason, message) => {
|
|
2888
2919
|
throw new OwWorldFileError(reason, message);
|
|
2889
2920
|
};
|
|
@@ -3163,6 +3194,7 @@ function checkFileAndFolder(files) {
|
|
|
3163
3194
|
}
|
|
3164
3195
|
}
|
|
3165
3196
|
function readWorldFile(bytes, opts = {}) {
|
|
3197
|
+
refuseUnknownOptions("readWorldFile", opts, READ_OPTION_KEYS, "Nothing was read.");
|
|
3166
3198
|
const maxBytes = opts.maxBytes ?? WORLD_FILE_MAX_BYTES;
|
|
3167
3199
|
const maxEntries = opts.maxEntries ?? WORLD_FILE_MAX_ENTRIES;
|
|
3168
3200
|
const entries = centralDirectory(bytes);
|
|
@@ -3249,7 +3281,43 @@ function carried(path) {
|
|
|
3249
3281
|
return !segs.some((s) => s.startsWith(".")) && !path.endsWith(".meta");
|
|
3250
3282
|
}
|
|
3251
3283
|
var STAMP = new Date(1980, 0, 1, 0, 0, 0);
|
|
3252
|
-
|
|
3284
|
+
var WRITE_OPTION_KEYS = ["includePrivateRecords"];
|
|
3285
|
+
var RECORDS_MANIFEST = "records/RECORDS.json";
|
|
3286
|
+
function asksPrivate(opts) {
|
|
3287
|
+
if (opts === void 0 || opts === null) return false;
|
|
3288
|
+
if (typeof opts !== "object") throw new TypeError(`writeWorldFile: options must be an object, such as { includePrivateRecords: true }. Nothing was written.`);
|
|
3289
|
+
refuseUnknownOptions("writeWorldFile", opts, WRITE_OPTION_KEYS, "Nothing was written.");
|
|
3290
|
+
const asked = opts.includePrivateRecords;
|
|
3291
|
+
if (asked !== void 0 && typeof asked !== "boolean") {
|
|
3292
|
+
throw new TypeError(`writeWorldFile: includePrivateRecords must be true or false; got ${JSON.stringify(asked) ?? String(asked)}. Nothing was written.`);
|
|
3293
|
+
}
|
|
3294
|
+
return asked === true;
|
|
3295
|
+
}
|
|
3296
|
+
function privateProducers(files) {
|
|
3297
|
+
const manifest = files.find((f) => f.path === RECORDS_MANIFEST);
|
|
3298
|
+
if (!manifest) return [];
|
|
3299
|
+
const unreadable = (why) => {
|
|
3300
|
+
throw new TypeError(`writeWorldFile: ${RECORDS_MANIFEST} ${why}, so which records are private cannot be read and none is left out by guess (spec \xA74.7, OW-8). Fix the manifest, or pass { includePrivateRecords: true } to carry every record. Nothing was written.`);
|
|
3301
|
+
};
|
|
3302
|
+
let doc;
|
|
3303
|
+
try {
|
|
3304
|
+
doc = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(manifest.data));
|
|
3305
|
+
} catch {
|
|
3306
|
+
unreadable("is not JSON");
|
|
3307
|
+
}
|
|
3308
|
+
if (!Array.isArray(doc)) unreadable("is not a JSON array of entries");
|
|
3309
|
+
const out = [];
|
|
3310
|
+
for (const entry of doc) {
|
|
3311
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) unreadable("holds an entry that is not an object");
|
|
3312
|
+
const { producer, private: isPrivate } = entry;
|
|
3313
|
+
if (isPrivate !== true) continue;
|
|
3314
|
+
if (typeof producer !== "string" || producer === "") unreadable("marks an entry private without a producer name");
|
|
3315
|
+
out.push(producer);
|
|
3316
|
+
}
|
|
3317
|
+
return out;
|
|
3318
|
+
}
|
|
3319
|
+
function writeWorldFile(files, topDir, opts = {}) {
|
|
3320
|
+
const includePrivate = asksPrivate(opts);
|
|
3253
3321
|
if (pathFault(topDir) || topDir.includes("/")) throw new OwWorldFileError("unsafe_path");
|
|
3254
3322
|
const seen = /* @__PURE__ */ new Set();
|
|
3255
3323
|
for (const f of files) {
|
|
@@ -3257,7 +3325,12 @@ function writeWorldFile(files, topDir) {
|
|
|
3257
3325
|
if (seen.has(f.path)) throw new OwWorldFileError("unsafe_path", `The path ${f.path} is listed twice.`);
|
|
3258
3326
|
seen.add(f.path);
|
|
3259
3327
|
}
|
|
3260
|
-
const
|
|
3328
|
+
const left = new Set(includePrivate ? [] : privateProducers(files).map(foldName));
|
|
3329
|
+
const inPrivate = (path) => {
|
|
3330
|
+
const segs = path.split("/");
|
|
3331
|
+
return segs.length > 2 && segs[0] === "records" && left.has(foldName(segs[1]));
|
|
3332
|
+
};
|
|
3333
|
+
const kept = files.filter((f) => carried(f.path) && !inPrivate(f.path));
|
|
3261
3334
|
if (!kept.some((f) => f.path === WORLD_FILE)) throw new OwWorldFileError("not_a_world");
|
|
3262
3335
|
const keys = kept.map((f) => `${topDir}/${f.path}`);
|
|
3263
3336
|
for (const key of keys) {
|
|
@@ -3324,7 +3397,7 @@ function isRoomElement(el) {
|
|
|
3324
3397
|
|
|
3325
3398
|
// src/names.ts
|
|
3326
3399
|
var SLUGS = new Set(ELEMENT_TYPES);
|
|
3327
|
-
var OPTION_KEYS =
|
|
3400
|
+
var OPTION_KEYS = ["supertype", "many"];
|
|
3328
3401
|
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3329
3402
|
function word(pair, many) {
|
|
3330
3403
|
if (!isObject(pair) || typeof pair.one !== "string") return null;
|
|
@@ -3335,9 +3408,7 @@ function word(pair, many) {
|
|
|
3335
3408
|
return plural === "" ? one : plural;
|
|
3336
3409
|
}
|
|
3337
3410
|
function typeWord(world, type, opts = {}) {
|
|
3338
|
-
|
|
3339
|
-
if (!OPTION_KEYS.has(key)) throw new TypeError(`typeWord: unknown option "${key}" (known: supertype, many)`);
|
|
3340
|
-
}
|
|
3411
|
+
refuseUnknownOptions("typeWord", opts, OPTION_KEYS);
|
|
3341
3412
|
const map = world?.x_names;
|
|
3342
3413
|
if (!isObject(map) || map.version !== 1) return null;
|
|
3343
3414
|
const { types, supertypes } = map;
|
|
@@ -3360,6 +3431,8 @@ function typeWord(world, type, opts = {}) {
|
|
|
3360
3431
|
}
|
|
3361
3432
|
|
|
3362
3433
|
// src/lookup.ts
|
|
3434
|
+
var LOOKUP_OPTION_KEYS = ["limit"];
|
|
3435
|
+
var RENDER_OPTION_KEYS = ["descMax", "linkMax", "incomingMax"];
|
|
3363
3436
|
var STOP = /* @__PURE__ */ new Set([
|
|
3364
3437
|
"a",
|
|
3365
3438
|
"an",
|
|
@@ -3663,7 +3736,9 @@ function similarWords(w, vocab) {
|
|
|
3663
3736
|
}
|
|
3664
3737
|
return res;
|
|
3665
3738
|
}
|
|
3666
|
-
function lookupWorld(index, question,
|
|
3739
|
+
function lookupWorld(index, question, opts = {}) {
|
|
3740
|
+
refuseUnknownOptions("lookupWorld", opts, LOOKUP_OPTION_KEYS);
|
|
3741
|
+
const { limit = 8 } = opts;
|
|
3667
3742
|
const seeds = 12;
|
|
3668
3743
|
const q = words(normalize(question));
|
|
3669
3744
|
const qSet = new Set(q);
|
|
@@ -3780,7 +3855,9 @@ function lookupWorld(index, question, { limit = 8 } = {}) {
|
|
|
3780
3855
|
for (const [id, c] of cand) if (SPATIAL.has(index.byId.get(id).type)) c.score *= 0.85;
|
|
3781
3856
|
return [...cand.entries()].map(([id, c]) => ({ element: index.byId.get(id), score: Math.round(c.score * 10) / 10, reasons: c.reasons })).sort((a, b) => b.score - a.score || String(a.element.name).length - String(b.element.name).length || (a.element.id < b.element.id ? -1 : 1)).slice(0, limit);
|
|
3782
3857
|
}
|
|
3783
|
-
function renderElement(element, index,
|
|
3858
|
+
function renderElement(element, index, opts = {}) {
|
|
3859
|
+
refuseUnknownOptions("renderElement", opts, RENDER_OPTION_KEYS);
|
|
3860
|
+
const { descMax = 500, linkMax = 12, incomingMax = 10 } = opts;
|
|
3784
3861
|
const el = element;
|
|
3785
3862
|
const name = (id) => index.byId.get(id)?.name ?? "?";
|
|
3786
3863
|
const kind = [el.supertype, el.subtype].filter((x) => x && x !== "undefined").join(" / ");
|
|
@@ -3864,7 +3941,9 @@ function buildAskContext(items, index) {
|
|
|
3864
3941
|
// src/photo.ts
|
|
3865
3942
|
var PHOTO_TYPES = ["image/webp", "image/png", "image/jpeg", "image/avif"];
|
|
3866
3943
|
var PHOTO_MAX_BYTES = 15 * 1024 * 1024;
|
|
3944
|
+
var PHOTO_OPTION_KEYS = ["maxSide", "quality", "maxBytes"];
|
|
3867
3945
|
function planPhoto(source, opts = {}) {
|
|
3946
|
+
refuseUnknownOptions("planPhoto", opts, PHOTO_OPTION_KEYS);
|
|
3868
3947
|
const maxSide = opts.maxSide ?? 2048;
|
|
3869
3948
|
if (!(maxSide > 0)) throw new TypeError("preparePhoto: maxSide must be a positive number");
|
|
3870
3949
|
if (!(source.width > 0 && source.height > 0)) throw new TypeError("preparePhoto: the picture has no size");
|
|
@@ -3889,6 +3968,7 @@ function makeCanvas(width, height) {
|
|
|
3889
3968
|
throw new TypeError("preparePhoto needs a browser: no canvas here");
|
|
3890
3969
|
}
|
|
3891
3970
|
async function preparePhoto(input, opts = {}) {
|
|
3971
|
+
refuseUnknownOptions("preparePhoto", opts, PHOTO_OPTION_KEYS);
|
|
3892
3972
|
const quality = opts.quality ?? 0.82;
|
|
3893
3973
|
const maxBytes = opts.maxBytes ?? PHOTO_MAX_BYTES;
|
|
3894
3974
|
const decode = globalThis.createImageBitmap;
|
|
@@ -4227,6 +4307,7 @@ function formatMidLabel(cfg, step) {
|
|
|
4227
4307
|
if (b.monthName != null && b.day != null) return `${b.day} ${b.monthName} ${b.year}`;
|
|
4228
4308
|
return formatYearLabel(cfg, step);
|
|
4229
4309
|
}
|
|
4310
|
+
var PARSE_OPTION_KEYS = ["now"];
|
|
4230
4311
|
function absYearForEraYear(cfg, era, Y) {
|
|
4231
4312
|
if (era.restart === false) return Y;
|
|
4232
4313
|
const base = era.year_base ?? 1;
|
|
@@ -4245,6 +4326,7 @@ function defaultEra(cfg, now) {
|
|
|
4245
4326
|
return [...pool].sort((a, b) => b.start - a.start)[0];
|
|
4246
4327
|
}
|
|
4247
4328
|
function parseDate(cfg, input, opts = {}) {
|
|
4329
|
+
refuseUnknownOptions("parseDate", opts, PARSE_OPTION_KEYS);
|
|
4248
4330
|
const raw = input.trim();
|
|
4249
4331
|
if (raw === "") return { error: "empty date" };
|
|
4250
4332
|
if (/^-?\d+$/.test(raw)) return { step: parseInt(raw, 10) };
|
|
@@ -4375,6 +4457,7 @@ function worldCalendars(elements) {
|
|
|
4375
4457
|
return out;
|
|
4376
4458
|
}
|
|
4377
4459
|
function resolveCalendarLens(elements, activeId, opts) {
|
|
4460
|
+
refuseUnknownOptions("resolveCalendarLens", opts, ["fallbackToOnly"]);
|
|
4378
4461
|
if (activeId === void 0 && opts?.fallbackToOnly) {
|
|
4379
4462
|
const all = worldCalendars(elements);
|
|
4380
4463
|
return all.length === 1 ? all[0] : null;
|
|
@@ -4454,6 +4537,7 @@ var TokenResource = class {
|
|
|
4454
4537
|
* ```
|
|
4455
4538
|
*/
|
|
4456
4539
|
async consume(params) {
|
|
4540
|
+
refuseUnknownOptions("consume", params, ["amount", "service", "sessionId", "metadata"], "Nothing was sent.");
|
|
4457
4541
|
return this.req("POST", "/tokens/consume/", {
|
|
4458
4542
|
body: {
|
|
4459
4543
|
amount: params.amount,
|