Varendo

Products example

Browse a visual catalog, inspect details, compare products, and open a schema-backed form.

The Products example proves one resource can drive cards, detail, comparison, and a form — with no generated markup.

Run it

  1. 1

    Open the scenario

    Open Products in the playground. You should see the catalog as cards — the resource prefers them for browsing.

  2. 2

    Run the scenario steps

    Choose Compare products, Open desk lamp, then Create product. You should see a side-by-side comparison, a detail view, and a form built from the registered schema.

  3. 3

    Inspect the run

    Choose Inspect. You should see the validated request, the result, and the reason that view was picked.

  4. 4

    Shrink the region

    Make the region narrower. You should see the view adapt without losing the filter or comparison selection.

  5. 5

    Run it locally

    Choose More → Export project, unzip the download, then run pnpm install and pnpm dev. You should see a local browse view and the status renderer-ready.

What it exercises

  • Browse as cards on wide containers, an equivalent view on narrow ones.
  • Open detail through stable product identity.
  • Compare two products without dropping attributes.
  • Render a create form from the registered schema. Submit produces a preview, never a silent write.
  • Keep filters and selection across a valid view swap.

Make it yours

  • Swap the synthetic records for your data adapter.
  • Read permissions from your real app state.
  • Keep product identity and price units explicit.
  • Dispose the app when the host removes the surface.

When it fails

An unknown field or view returns a diagnostic and keeps the last permitted view. A denied permission read returns no data. Fix the contract or the trusted policy, then send the request again.

Local browse starter source

The exported project renders one browse view. The additional Playground steps above require their resource meanings, forms/actions, or custom registrations; they are not bundled in this minimal starter. Follow Connect your data to add those contracts.

package.json · compiled export source
{
  "name": "aeliqo-products-example",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc --noEmit && vite build"
  },
  "dependencies": {
    "@varendo/core": "0.1.0",
    "@varendo/runtime": "0.1.0",
    "@varendo/web": "0.1.0",
    "zod": "4.5.4"
  },
  "devDependencies": {
    "typescript": "7.0.2",
    "vite": "8.2.2"
  }
}
tsconfig.json · compiled export source
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "lib": [
      "ES2022",
      "DOM"
    ],
    "types": [
      "vite/client"
    ],
    "strict": true,
    "noEmit": true
  },
  "include": [
    "src/**/*.ts"
  ]
}
index.html · compiled export source
<!doctype html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Products · Varendo</title></head><body><main><h1>Products</h1><p id="status" role="status">Loading…</p><div id="app"></div></main><script type="module" src="/src/main.ts"></script></body></html>
src/main.ts · compiled export source
import {defineResource} from '@varendo/core';
import {createQueryFunctionRegistry} from '@varendo/core/expressions';
import {createLocalDataService} from '@varendo/runtime/data';
import {createAeliqoApp} from '@varendo/web/app';
import {z} from 'zod';
import './style.css';

const resource = defineResource({
  id: 'products', revision: 'products-1', label: 'Products', identity: ['id'],
  schema: z.object({id: z.string(), name: z.string(), category: z.string(), price: z.number(), stock: z.number().int()}),
  fields: {name: {label: 'Name'}, category: {label: 'Category', role: 'dimension'}, price: {label: 'Price', role: 'measure'}, stock: {label: 'Stock'}},
  presentation: {allowedViews: ["table","cards"]},
});

const functions = createQueryFunctionRegistry({version: '2'});
if (!functions.ok) throw new Error(functions.diagnostics[0].message);
const data = createLocalDataService({
  snapshot: {catalog: resource.catalog, sourceRevision: 'synthetic-1', records: {products: [
  {
    "id": "pr-1",
    "name": "Field notebook",
    "category": "Stationery",
    "price": 12,
    "stock": 18
  },
  {
    "id": "pr-2",
    "name": "Desk lamp",
    "category": "Workspace",
    "price": 48,
    "stock": 7
  }
]}},
  functionRegistry: functions.value,
  sourceLimits: {rows: 1_000, bytes: 1_000_000},
  authorize: () => ({ok: true, value: {scopeDigest: 'local-demo', policyRevision: 'policy-1'}}),
});

const app = createAeliqoApp({
  resources: [{resource, data}],
  authority: {read: () => ({ok: true, value: {
    principalKey: 'local-user', scopeDigest: 'local-demo', policyRevision: 'policy-1',
    experienceRevision: 'web-1', grants: ['task.evaluate', 'result.inspect', 'experience.commit'],
    readContext: {principal: 'local-user'},
  }})},
});

const target = document.querySelector<HTMLElement>('#app');
if (target === null) throw new Error('The app target is missing.');
const mounted = app.mount({target, regionId: 'main', resourceId: resource.id});
if (!mounted.ok) throw new Error(mounted.diagnostics[0].message);
const receipt = await app.render({regionId: 'main', intent: {
  version: '1', id: 'products-browse', kind: 'browse', resource: resource.id,
  fields: ["name","category","price","stock"],
}});
document.querySelector('#status')!.textContent = receipt.status;
window.addEventListener('pagehide', () => app.dispose(), {once: true});
src/style.css · compiled export source
:root{font-family:Inter,ui-sans-serif,system-ui;color:#202033;background:#f7f7fb}body{margin:0}main{inline-size:min(72rem,calc(100% - 2rem));margin:3rem auto}#app{container-type:inline-size;min-block-size:20rem}
README.md · compiled export source
# Products · Varendo 0.1.0

Synthetic source project exported from the Varendo playground. Install requires the pinned 0.1.0 packages to be published to npm.

```sh
pnpm install
pnpm dev
```

The application works without an AI provider. Replace the local snapshot and authority adapter with application-owned implementations before using real data.