Reference
Single-page view · as markdown
wispist.json reference
Wispist / Reference
wispist.json is an optional file at the site archive root. It declares the collections exposed to browser code by that release.
The parser is strict:
- The file must be UTF-8 JSON no larger than 64 KiB.
- Duplicate object members and unknown fields are errors.
versionmust be1.collectionsis required and may contain at most 32 entries.- Collection limits may lower, but never raise, host defaults.
- Missing
wispist.jsonmeans zero declared collections.
An invalid declaration rejects the complete upload. It never falls back to a permissive policy.
Top-level object #
| Member | Type | Required | Meaning |
|---|---|---|---|
version | integer | yes | Protocol declaration version; exactly 1. |
collections | object | yes | Collection name to collection declaration. |
Collection names #
Names match:
[a-z][a-z0-9_-]{0,47}
They are ASCII, case-sensitive, and compared byte-for-byte.
Collection declaration #
| Member | Type | Required | Meaning |
|---|---|---|---|
access | string or object | yes | A built-in profile or all six operation policies. |
limits | object | no | Lower document count and byte limits. |
Shared profile #
shared expands to anyone for list, read, create, update, delete, and subscribe. Every visitor can read and change the collection.
Expanded access #
Every operation must appear exactly once:
| Operation | Controls |
|---|---|
list | Listing collection documents. |
read | Reading one document and receiving its body in a subscription. |
create | Generated-ID POST and selected-ID create. |
update | Replacing an existing document. |
delete | Deleting an existing document. |
subscribe | Opening a change stream for the collection. |
Each value is one of:
| Value | Meaning |
|---|---|
anyone | Permit every principal. |
authenticated | Require an authenticated principal asserted by the host. |
nobody | Deny the operation. |
Wispdeck initially supplies anonymous principals to ordinary hosted-site and preview JavaScript. Preview authorisation grants access to the preview, not authenticated Wispist authority.
read and list are intentionally independent, as are read and subscribe.
Collection limits #
| Member | Type | Range | Default |
|---|---|---|---|
maxDocuments | integer | 1 to host maximum | 1,000 |
maxDocumentBytes | integer | 2 to host maximum | 32 KiB |
These limits apply to that collection. The namespace also has a total live or draft byte limit.
See also #
- Limits and abuse controls — the installation defaults these declarations may lower.
- Documents and collections — what a declared collection contains.
- Forbidden — what a denied operation returns.
Browser API reference
Wispist / Reference
Wispdeck defines one non-enumerable, non-writable global before site-authored elements run:
wispist.version
wispist.mode
wispist.readOnly
wispist.collection(name)
There is no connect method. The client makes no request during evaluation.
Environment fields #
| Field | Type | Meaning |
|---|---|---|
version | number | Client protocol major; 1. |
mode | string | live, draft, or live-preview. |
readOnly | boolean | Whether the host has forced mutations off. |
mode and readOnly are synchronous presentation metadata. The server enforces the real binding independently.
Collection handle #
const = ;
collection(name) validates the collection-name grammar locally and returns a frozen handle. The server still requires the active release to declare it.
list(options?) #
Returns a promise for every document in creation order. options.limit selects the page size from 1 to 250; the client follows pagination automatically.
const = await ;
get(id) #
Returns one complete document envelope or rejects with not_found.
const = await ;
add(data) #
Creates a generated-ID document and returns it. data must be a non-null object and not an array. The client generates the required idempotency key.
const = await ;
create(id, data) #
Creates exactly the selected ID and returns it. It uses create-only semantics and rejects with revision_conflict if that ID exists.
replace(document, data) #
Conditionally replaces the observed document with data and returns the new envelope. A concurrent change rejects with revision_conflict.
update(document, changes) #
Shallow-merges changes into document.data locally, then performs replace.
const = await ;
An undefined change is omitted by JSON serialisation but does not delete the old property from the local merge. To remove properties or make nested changes, construct the complete new object and call replace.
delete(document) #
Conditionally deletes the observed document. The promise resolves with no value.
Subscribe #
const = ;
The callback runs once with event.type === "initial" and after each applied change. Documents remain in creation order, with ID as the deterministic tie-breaker.
The client reconnects after recoverable EventSource failures with bounded exponential backoff and jitter. A server reset causes a fresh list. onError receives initial or terminal errors; ordinary reconnects do not create unhandled promise rejections.
subscribe returns the unsubscribe function immediately.
WispistError #
Rejected operations use an Error subclass with:
| Field | Meaning |
|---|---|
name | Always WispistError. |
type | RFC 9457 problem type URI, when an HTTP problem was returned. |
code | Ergonomic code mapped from a known problem type. |
title | Stable problem title. |
detail | Safe occurrence-specific explanation. |
status | HTTP status, when available. |
instance | Problem occurrence URI, when available. |
requestId | X-Request-ID value, when available. |
problem | Complete decoded Problem Details object. |
The wire protocol does not contain a separate code. type is the stable machine identifier; code is client convenience. Network failures use network_error without a type or HTTP status. An invalid non-problem response uses invalid_response.
Known codes are listed in Problem Details.
Browser dependencies and side effects #
The client uses fetch, EventSource, and Web Crypto. It has no package dependency, local-storage use, service worker, analytics, or telemetry. Requests are same-origin, use same-origin credentials, and disable browser caching.
See also #
- HTTP API reference — the routes these methods call.
- Problem Details — every
codeaWispistErrorcan carry. - Live updates — how
subscribebehaves across disconnects and resets.
HTTP API reference
Wispist / Reference
Wispist v1 is served from the hosted site's own origin under /_wispist/:
GET /_wispist/client/v1.js
GET /_wispist/v1
GET /_wispist/v1/collections/{collection}/documents
POST /_wispist/v1/collections/{collection}/documents
GET /_wispist/v1/collections/{collection}/documents/{document}
PUT /_wispist/v1/collections/{collection}/documents/{document}
DELETE /_wispist/v1/collections/{collection}/documents/{document}
GET /_wispist/v1/changes
Use the browser client unless direct HTTP control is necessary.
General rules #
- API responses use
Cache-Control: no-storeandX-Content-Type-Options: nosniff. - JSON responses use
application/json; charset=utf-8. - JSON request bodies require
Content-Type: application/json. - Every response includes
X-Request-ID. A caller-provided UUID may be retained. - Errors use RFC 9457
application/problem+json. - Unsupported methods on known resources return
405withAllow. - Paths and identifiers must be decoded, canonical, and free of encoded separators or dot segments.
- No CORS permission is emitted.
Unsafe requests require one exact same-origin Origin header. If Sec-Fetch-Site is present, it must be same-origin.
Service description #
List documents #
?limit defaults to 100 and may be 1 to 250. after is an opaque pagination cursor.
The changes cursor is captured by the first page and repeated by later pages. List all pages, then consume changes after it to reconcile concurrent mutations.
Create a generated ID #
The key is required and contains 16 to 128 visible ASCII characters. The same namespace, key, and request fingerprint returns the original 201 Created response for at least 24 hours. Reusing the key for a different request returns idempotency conflict.
The response includes Location, the document ETag, and the complete envelope.
Read #
The ETag is the quoted opaque revision. If-None-Match supports wildcard, lists, and weak comparison for GET/HEAD and may return 304 Not Modified.
Create or replace a selected ID #
Create only:
Replace:
Exactly one precondition is required. Create returns 201; replacement returns 200. Both return a new document and ETag.
Delete #
Success is 204 No Content. The deletion appends a change containing ID and deleted revision but no document body.
Change stream #
?collections is repeatable with 1 to 8 distinct declared values. Every collection must permit subscribe and read.
id: opaque-change-cursor
event: change
data: {"collection":"before-you-go","operation":"update","document":{...}}
A deletion supplies id and revision instead of document. A reset event means the client must list again. If after is absent, the stream begins after the current high-water mark and does not replay the collection.
The server sends heartbeat comments while otherwise idle. Delivery is at least once; de-duplicate by cursor.
See also #
- Browser API reference — the supported client over these routes.
- Problem Details — the error shape every route uses.
- Limits and abuse controls — body, pagination, stream, and rate bounds.
Limits and abuse controls
Wispist / Reference
Wispist applies hard resource limits and bounded rate buckets before expensive work. A release may lower collection limits but cannot raise installation policy.
Resource defaults #
| Resource | Default |
|---|---|
| Collections per release | 32 |
| Documents per collection | 1,000 |
| Document JSON | 32 KiB |
| Live document data per site | 10 MiB |
| Draft document data per site | 5 MiB |
| List page | 100; maximum 250 |
| Collections per SSE stream | 8 |
| SSE streams per site and client | 6 |
| SSE streams per site | 100 |
| Pending events per stream | 128 |
| Request envelope allowance | document limit plus 4 KiB |
| Live idempotency records per namespace | 10,000 |
| Retained changes per namespace | 10,000 |
| Change age | 7 days |
| Idempotency retention | at least 24 hours |
The document-data quota counts compact document JSON, not release files. Change and idempotency tables are separately bounded.
Initial Wispdeck rate buckets #
| Bucket | Sustained | Burst |
|---|---|---|
| Reads per site and client | 600/minute | 100 |
| Mutations per site and client | 60/minute | 20 |
| Mutations across one site | 300/minute | 60 |
| Generated-ID creates across one site | 10,000/day | 100 |
| All Wispist requests | 6,000/minute | 1,000 |
Client keys come from Wispdeck's trusted-proxy-aware address resolution. Untrusted forwarding headers are ignored.
Buckets use bounded memory and expire after inactivity. Concurrent streams use counters rather than token rates. A rejected request returns rate limited with Retry-After.
Rate limits are availability controls, not authorisation. A public shared collection remains publicly writable below the rate allowance.
See also #
- wispist.json reference — how a release lowers collection limits.
- Quota exceeded, Request too large, Rate limited — the problems these bounds produce.