{"_id":"@abrum/web-runtime","_rev":"2-2aa8783db2577679c207904b3a571d9a","name":"@abrum/web-runtime","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@abrum/web-runtime","version":"0.1.0","_id":"@abrum/web-runtime@0.1.0","maintainers":[{"name":"robinhuse","email":"hello@abrum.ai"}],"homepage":"https://github.com/abrum-ai/xp0#readme","bugs":{"url":"https://github.com/abrum-ai/xp0/issues"},"dist":{"shasum":"6242b15297c453f20a1ec241d868b23a2ef92b98","tarball":"https://registry.npmjs.org/@abrum/web-runtime/-/web-runtime-0.1.0.tgz","fileCount":9,"integrity":"sha512-EIOy4/t7D0hN3NRWOh2Up3y9y+C6L7ghERTckAVJwAnmS6nh5gezL98Z2rSQSNHNpfWT+ZU5lSvr9OVclgj6fA==","signatures":[{"sig":"MEUCIQD0Kt+EXX8ks1o8bUvsWAhSC3ZrsVOegqBxshn4fAuBMQIgLzCD9KO/NW6dVzn2zZy7vSCJhmnYdNA1kSq4DDjJuhM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":264536},"main":"./src/index.ts","type":"module","types":"./src/index.ts","exports":{".":"./src/index.ts","./contracts":"./src/contracts.ts"},"gitHead":"c18af1cffb279e75781392e2b1e4900f253cb641","scripts":{"test":"node --import jiti/register --test src/*.test.ts","typecheck":"tsc --noEmit"},"_npmUser":{"name":"robinhuse","email":"hello@abrum.ai"},"repository":{"url":"git+https://github.com/abrum-ai/xp0.git","type":"git","directory":"packages/xp0-web-runtime"},"_npmVersion":"10.9.8","description":"Browser-facing xp0 runtime for typed, signed twins over a station.","directories":{},"_nodeVersion":"22.22.3","dependencies":{"@scure/bip39":"^1.6.0","@noble/curves":"^1.9.7","@noble/hashes":"^1.8.0","@noble/ciphers":"^1.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jiti":"^2.7.0","typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/web-runtime_0.1.0_1786036357872_0.07434484337139025","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@abrum/web-runtime","version":"0.1.1","repository":{"type":"git","url":"git+https://github.com/abrum-ai/abrum.git","directory":"packages/abrum-web-runtime"},"type":"module","main":"./src/index.ts","types":"./src/index.ts","exports":{".":"./src/index.ts","./contracts":"./src/contracts.ts"},"publishConfig":{"access":"public"},"scripts":{"typecheck":"tsc --noEmit","test":"node --import jiti/register --test src/*.test.ts"},"dependencies":{"@abrum/runtime":"0.1.1","@noble/ciphers":"^1.3.0","@noble/curves":"^1.9.7","@noble/hashes":"^1.8.0","@scure/bip39":"^1.6.0"},"devDependencies":{"jiti":"^2.7.0","typescript":"^5.9.3"},"gitHead":"3cedb87e86a7f09c45d913a9ca358ce0552acbf9","_id":"@abrum/web-runtime@0.1.1","description":"Browser-facing abrum runtime for typed, signed twins over a station.","bugs":{"url":"https://github.com/abrum-ai/abrum/issues"},"homepage":"https://github.com/abrum-ai/abrum#readme","_nodeVersion":"24.19.0","_npmVersion":"11.19.1","dist":{"integrity":"sha512-Bi/aoLiN3V+kEyaIqbRtpuCcqi+vmEO0B9t7XhMBuIKWsM9TFMxmQeGI25Y79jWrdBN41LnR1t3Woi8hrRuE2g==","shasum":"68b418c390a7fbb79d060e4ffd0653b6f8365299","tarball":"https://registry.npmjs.org/@abrum/web-runtime/-/web-runtime-0.1.1.tgz","fileCount":9,"unpackedSize":313684,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDX8lHA3XKFpNzQr4CCtXQU14Q/Iwrn+0Tba4Q3aPat6AIgSL9zESS3yf3wiulHma8Za8TiP6BsElBzEe4cBPmBhxY="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:cb5f942c-8610-4f17-95ac-4b45c0925ea7"}},"directories":{},"maintainers":[{"name":"robinhuse","email":"hello@abrum.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/web-runtime_0.1.1_1788439654427_0.49738475299684803"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-06T17:12:37.666Z","modified":"2026-09-03T12:47:34.749Z","0.1.0":"2026-08-06T17:12:38.008Z","0.1.1":"2026-09-03T12:47:34.561Z"},"bugs":{"url":"https://github.com/abrum-ai/abrum/issues"},"homepage":"https://github.com/abrum-ai/abrum#readme","repository":{"type":"git","url":"git+https://github.com/abrum-ai/abrum.git","directory":"packages/abrum-web-runtime"},"description":"Browser-facing abrum runtime for typed, signed twins over a station.","maintainers":[{"name":"robinhuse","email":"hello@abrum.ai"}],"readme":"# @abrum/web-runtime\n\nBrowser-facing abrum runtime for typed, signed twins over a station.\n\nThe runtime keeps the kernel model intact: data is still signed twins, schemas are\nschema twins, and Rooms remain the sync, storage, and access boundary. Physical\nmembership comes from the per-Room store; relations describe semantic graph edges.\nThe developer API hides the normal boilerplate so app code can work with typed\nlocal data.\n\n## Core Shape\n\n```ts\nimport { abrum } from \"@abrum/web-runtime\";\n\nexport const notesApp = abrum.app(\"notes\", {\n  note: abrum.entity({\n    text: abrum.string(),\n    createdAtMs: abrum.date().index(),\n    updatedAtMs: abrum.date(),\n  }).named(\"schema-note-v1\").type(\"note\").roomScoped(),\n});\n```\n\nThis compiles to:\n\n- a schema twin for `schema-note-v1`\n- object twins with `content.type === \"note\"`\n- JSON Schema metadata for required fields, indexes, unique fields, and abrum app identity\n\nNormal app code should not manually create schema or object twins. Create a\n`contains` relation only when the application models an actual hierarchy or a\nselectively shared subtree.\n\n## Field Builders\n\n```ts\nabrum.string()\nabrum.number()\nabrum.boolean()\nabrum.date()\nabrum.json()\nabrum.any()\n```\n\nModifiers:\n\n```ts\nabrum.string().optional()\nabrum.string().index()\nabrum.string().indexed()\nabrum.string().unique()\n```\n\nNotes:\n\n- Fields are required by default.\n- `abrum.date()` accepts a timestamp, ISO string, or `Date`; `Date` is stored as an ISO string.\n- `abrum.number()` currently accepts safe integers because canonical twin blocks require safe integers.\n- `.index()` and `.unique()` are schema metadata today; station-backed indexes are the next layer.\n\n## Runtime Usage\n\n```ts\nimport { AbrumRuntime } from \"@abrum/web-runtime\";\nimport { notesApp } from \"./notes.schema\";\n\nconst runtime = await AbrumRuntime.open({\n  station: \"http://127.0.0.1:8792\",\n  storageKey: \"abrum.notes.owner:http://127.0.0.1:8792\",\n});\n\nawait runtime.createUser(\"Robin\"); // local Device Key; no recovery phrase\nawait runtime.pair(\"Robin\");\n\nawait runtime.createEntity(notesApp, \"note\", {\n  text: \"hello\",\n  createdAtMs: Date.now(),\n  updatedAtMs: Date.now(),\n});\n```\n\n`createEntity` creates and pushes the schema twin, object twin, and space\ncontainment relation in one call.\n\n## Rust/WASM Core\n\nThe public TypeScript API is not meant to become a second protocol\nimplementation. Protocol-critical work should live in Rust:\n\n- identity derivation\n- canonical TwinBlock serialization\n- CID calculation\n- Ed25519 signing\n- signed HTTP request payloads\n- X25519 identity derivation\n- HKDF Room-key derivation\n- XChaCha20-Poly1305 seal/open, key wrap/unwrap, and conveyed secrets\n- schema/object/relation/user-principal twin constructors\n\n`crates/abrum-wasm` exposes those `abrum-core` functions as a small WASM ABI. The\nbrowser runtime accepts a protocol core, so app code does not change when the\ngenerated WASM package is loaded:\n\n```ts\nimport init, * as wasm from \"@abrum/wasm\";\nimport { AbrumRuntime, createAbrumWasmProtocolCore } from \"@abrum/web-runtime\";\n\nawait init();\n\nconst runtime = await AbrumRuntime.open({\n  station: \"http://127.0.0.1:8792\",\n  core: createAbrumWasmProtocolCore(wasm),\n});\n```\n\nUntil a generated WASM package is installed, the runtime keeps a TypeScript\nfallback with the same `AbrumProtocolCore` interface. That fallback is a\ndevelopment convenience, not the long-term source of truth.\n\n## React Usage\n\n`@abrum/react` builds on this package:\n\n```tsx\nimport { useAbrumDb } from \"@abrum/react\";\nimport { notesApp } from \"./notes.schema\";\n\nexport function Notes() {\n  const db = useAbrumDb(notesApp);\n  const notes = db.note.useMany({\n    order: [\"createdAtMs\", \"desc\"],\n  });\n\n  async function addNote(text: string) {\n    await db.note.create({\n      text,\n      createdAtMs: Date.now(),\n      updatedAtMs: Date.now(),\n    });\n  }\n\n  return notes.data.map((note) => (\n    <article key={note.$.cid}>\n      {note.text}\n    </article>\n  ));\n}\n```\n\nThe query is realtime by default. The runtime subscribes to station events and\nthe React layer incrementally pulls twin-log entries when the station reports a\nchange.\n\n## Query Options\n\n```ts\nconst recent = db.note.useMany({\n  where: {\n    text: { contains: \"hello\" },\n    createdAtMs: { gt: Date.now() - 86_400_000 },\n  },\n  order: [\"createdAtMs\", \"desc\"],\n  limit: 50,\n});\n```\n\nCurrent query evaluation is client-side over the readable twin log for the\nselected space. This is correct for the first web runtime, but large production\nspaces need station projections and indexes behind the same API.\n\n## Raw Escape Hatches\n\nThe high-level API is the default path. The raw API remains available for system\ncode, migrations, custom protocols, and debugging:\n\n```ts\nconst schema = await runtime.schemaTwin(\"custom-schema\", jsonSchema);\nconst [object] = await runtime.objectInRoomTwins(schema.cid, content);\nconst relation = await runtime.relationTwin({\n  source: object.cid,\n  target: otherCid,\n  relationType: \"references\",\n  inheritsAccess: false,\n});\n\nawait runtime.putTwins([schema, object, relation]);\nconst log = await runtime.pull();\n```\n\n## Identity And Spaces\n\nThe runtime owns the browser user identity for the current storage key:\n\n```ts\nconst { user } = await runtime.createUser(\"Robin\");\n\n// Product sessions are enrolled by another active ABRUM device and handed to\n// the app by its trusted host. `restoreUser(phrase)` remains only as a one-time\n// compatibility import for historical mnemonic-as-seed browser sessions.\n```\n\nPairing a user with a station creates the user's hosted space and stores the\nselected space:\n\n```ts\nawait runtime.pair(\"Robin\");\nawait runtime.loadSpaces();\nruntime.selectSpace(spaceId);\n```\n\nRooms are the default access and sync boundary. `roomScoped()` entities are\nstored in the selected Room and inherit its root authorization from physical\nRoom membership; no technical relation Twin is generated.\n\n## Production Direction\n\nThis package is intentionally small. The standard-worthy direction is:\n\n- app schemas as code\n- typed entity create/query/update/delete\n- realtime by default\n- raw twin escape hatches\n- station-backed indexes and projections behind the same query API\n- production schema lock so unknown app schemas cannot be created by arbitrary clients\n- relation and action DSLs built on the same app descriptor\n\nThe kernel should stay twin-native. Application code should stay data-native.\n","readmeFilename":"README.md"}