@asterql/view-protocol
npm install @asterql/view-protocol
Registered view definitions, deterministic view ids, canonical params, and a
small handler shape for AsterQL.
This package is the bridge between "run this query locally" and "ship a
cacheable UI data endpoint." Production requests use manifest-backed ids, while
local tools can opt into raw query evaluation explicitly.
import {
createViewCacheHeaders,
createManifest,
createViewHandler,
createViewUrl,
defineView,
} from "@asterql/view-protocol";
const recentOrders = defineView({
service: "dashboard",
query: `*.orders[status == $status] | sort(-createdAt)[:10] {id, total}`,
});
const manifest = createManifest([recentOrders]);
const url = createViewUrl(recentOrders, { status: "paid" });
const cacheHeaders = createViewCacheHeaders(recentOrders, { status: "paid" });
const handle = createViewHandler({
views: [recentOrders],
async load({ params }) {
return loadDashboardData(params);
},
});
API
defineView(input): normalize a query and compute a deterministic view id.
getViewId(view): return the content hash id for a view.
createManifest(views): emit a stable manifest keyed by view id.
createViewETag(view, params?, options?): compute a weak ETag from the view
id, canonical params hash, and optional service data version.
createViewCacheHeaders(view, params?, options?): create Cache-Control
and ETag headers from the view cache policy.
encodeParams(params) / decodeParams(value): base64url canonical JSON.
createViewUrl(view, params?, options?): build /views/:viewId URLs.
createViewHandler(options): execute registered views against host data.
fetchView(view, params?, options?): tiny fetch helper for clients.
State sync primitives:
createEntityKey(kind, id) / parseEntityKey(key): stable normalized
entity ids in kind:id form.
createScopeKey(kind, id) / parseScopeKey(scope): stable scope ids such
as agent:agent_123.
hashRecordVersion(input) and hashServerEventId(input): deterministic
record/event ids over canonical JSON.
ServerEvent, ServerEventEnvelope, EntityRecord, EntityPatch, and
InvalidationClass: browser-safe wire and store contracts for normalized
state sync.
invalidationIntersects(a, b): match entity, entity-kind, scope, service,
and view invalidation classes.
parseEntityPath(path) / formatEntityPath(path): JSON Pointer helpers for
patch paths.
getEntityPathValue, setEntityPathValue, unsetEntityPathValue,
applyEntityPatch, and applyEntityPatches: immutable JSON patch helpers
for set, unset, merge, appendText, keyed insert, and removeKey.
canonicalJsonBytes(value), sha256Base64Url(bytes),
hashCanonicalJson(prefix, value), hashParams, hashSchema, and
hashViewDefinition: canonical hashing helpers matching the package's
existing view/schema/params ids.
createVersionedViewETag(input) / parseVersionedViewETag(etag): weak
ETags that embed the view id, canonical params hash, auth-scope hash, body
hash, and a sorted invalidation-class version map, so revalidation can
answer "did any class this view depends on advance?" from the ETag alone.
formatInvalidationClass(class), classVersionFromDate(value),
mergeClassVersions(...maps), advancedClassVersions(current, baseline, keys?), classVersionsFromETagPayload(payload), hashAuthScope(value),
and ifNoneMatchIncludes(header, etag): the class-version vocabulary used
by versioned ETags and invalidation-driven cache revalidation.
The handler only executes registered views by default. Registered view responses
include explicit cache headers: views with a cache policy use that policy, and
views without one are no-store. Raw dev _eval responses are always
no-store and exist only when allowEval: true is passed.