Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bc8acfc
chore(deps): bump vana sdk preview
Kahtaf Sep 4, 2026
7e7bbbc
feat(vana): allow direct endpoint overrides
Kahtaf Sep 4, 2026
9b49858
feat(vana): read approved data through enclave jobs
Kahtaf Sep 4, 2026
3c0fab2
docs(vana): add enclave read preview tooling
Kahtaf Sep 4, 2026
bfe6e4a
fix(vana): address enclave read review findings
Kahtaf Sep 4, 2026
77f3e6f
chore(repo): ignore review handoff files
Kahtaf Sep 4, 2026
c7a001b
fix(vana): bound enclave read polling
Kahtaf Sep 4, 2026
2c63543
fix(vana): require secure gateway origins
Kahtaf Sep 4, 2026
5ba81c4
fix(vana): clarify missing enclave identity
Kahtaf Sep 4, 2026
9e8adf3
test(vana): cover injected enclave reads
Kahtaf Sep 4, 2026
7d47f47
chore(deps): pin vana-sdk pr-207 build bde799e
Kahtaf Sep 4, 2026
63fcf5e
fix(vana): honor server default network
Kahtaf Sep 4, 2026
4393616
fix(vana): honor server default environment
Kahtaf Sep 4, 2026
da3e5a4
fix(vana): restore missing job error mapping
Kahtaf Sep 4, 2026
423cd71
chore(deps): pin vana-sdk 3.23.0
Kahtaf Sep 4, 2026
9768c1c
chore: pin vana sdk result contract
Kahtaf Sep 4, 2026
b7ff584
fix: distinguish lorebook read failures
Kahtaf Sep 4, 2026
033764f
fix: reuse approved grant on read retry
Kahtaf Sep 4, 2026
5373b62
chore(deps): re-pin vana sdk build
Kahtaf Sep 4, 2026
97eac01
fix: consume raw enclave result bytes
Kahtaf Sep 4, 2026
3b9199f
fix(read): resume the same enclave job across requests
Kahtaf Sep 4, 2026
2589731
fix(read): honour endpoint overrides in acknowledgeRead
Kahtaf Sep 4, 2026
a07d070
fix(read): report a still-running job instead of timing out
Kahtaf Sep 5, 2026
9a89dd2
chore(deps): pin vana-sdk 3.23.0-pr.211.341f55d
Kahtaf Sep 5, 2026
ff49c73
chore(deps): pin vana-sdk 3.23.0-pr.211.fa01520
Kahtaf Sep 5, 2026
bb2b8d9
fix: accept enclave grants on consent return
Kahtaf Sep 8, 2026
74bb48b
chore(deps): pin verified Moksha SDK release
Kahtaf Sep 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ VANA_PRIVATE_KEY=0x...
# in .env.local with the exact LAN-reachable dev-server URL (for example, http://192.168.x.x:3010).
APP_URL=http://localhost:3010

# Optional preview-only Direct endpoint overrides. Leave unset to keep the
# SDK's production/dev service-plane defaults.
VANA_ACCESS_REQUEST_BASE_URL=
VANA_APPROVAL_APP_BASE_URL=

# Optional preview enclave read path. Leave VANA_READ_MODE unset (or anything
# other than "enclave") to keep direct Personal Server reads + escrow.
VANA_READ_MODE=
# Server-side service-plane fallback when the URL has no vana_env query parameter.
# Must be dev or production; explicit query parameters still take precedence.
VANA_DEFAULT_ENV=production
# Server-side network fallback when the URL has no network query parameter.
# Must be mainnet or moksha; explicit query parameters still take precedence.
VANA_DEFAULT_NETWORK=mainnet
# Must be a bare origin with no path, query, or fragment when enclave mode is on.
VANA_GATEWAY_URL=

# Optional shared delivery store. Without it the mobile foreground-delivery
# capability lives in process memory, which is correct only when one process
# serves every request — on a serverless host the phone's callback can land on a
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ next-env.d.ts
.gstack/
.idea/
.vercel
HANDOFF-*.md
REVIEW-*.md
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,44 @@ authorization it needs to poll status and read for the whole request lifetime.

Lorebook stores no browser pending request. The originating tab owns create and poll.

## Enclave read mode (preview)

The preview jobs path is opt-in. With `VANA_READ_MODE=enclave`, Lorebook keeps the existing Direct
DCR creation and status polling, then submits each approved scope to the Node-only SDK jobs client.
The server resolves the grant owner from the status when available or from the Gateway's public
grant endpoint, decrypts the jobs result, and feeds the decoded JSON through the existing Lorebook
rendering. Enclave mode does not use escrow; after a successful read it sends the same consumer
acknowledgement as the direct path so Vana Web can complete the request. With the flag unset, the
production direct-read behavior is unchanged.

Configure the preview locally without committing real endpoints or keys:

```dotenv
VANA_READ_MODE=enclave
VANA_DEFAULT_ENV=dev
VANA_DEFAULT_NETWORK=moksha
VANA_GATEWAY_URL=https://gateway-preview.example
VANA_ACCESS_REQUEST_BASE_URL=http://approval-preview.example
VANA_APPROVAL_APP_BASE_URL=http://approval-preview.example
```

`VANA_DEFAULT_ENV` and `VANA_DEFAULT_NETWORK` are the server-side fallbacks when the request URL
omits `vana_env` or `network`. They accept `dev`/`production` and `moksha`/`mainnet`, defaulting to
`production` and `mainnet`; explicit query parameters still win. Startup fails with a clear
configuration error when the network default is `mainnet` but the Gateway host contains `moksha`.
`VANA_GATEWAY_URL` must be a bare HTTPS origin (or loopback HTTP origin). To inspect an
already-approved scope without the UI, use the CLI; it defaults to Moksha (`VANA_NETWORK=moksha`)
and prints only the decrypted result:

```bash
GRANT_ID=0x... \
SCOPE=spotify.profile \
VANA_GATEWAY_URL=https://gateway-preview.example \
VANA_PRIVATE_KEY=0x... \
VANA_NETWORK=moksha \
pnpm enclave:read
```

## Verification

```bash
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"enclave:read": "tsx scripts/enclave-read.ts",
"test": "tsx --test test/*.test.ts",
"typecheck": "next typegen && tsc --noEmit"
},
"dependencies": {
"@opendatalabs/vana-sdk": "3.15.0",
"@opendatalabs/vana-sdk": "3.23.0-pr.211.36da1d8",
"next": "16.2.10",
"react": "19.2.4",
"react-dom": "19.2.4",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions scripts/enclave-read.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { readEnclaveScopes } from "../src/lib/vana/enclave";
import { chainIdForNetwork, type VanaRuntime } from "../src/lib/vana/runtime";

function requiredEnv(name: string): string {
const value = process.env[name]?.trim();
if (!value) throw new Error(`Missing ${name}.`);
return value;
}

async function main(): Promise<void> {
const network = (process.env.VANA_NETWORK?.trim() || "moksha") as VanaRuntime["network"];
if (network !== "mainnet" && network !== "moksha") {
throw new Error("VANA_NETWORK must be mainnet or moksha.");
}
const scope = requiredEnv("SCOPE");
const results = await readEnclaveScopes({
gatewayUrl: requiredEnv("VANA_GATEWAY_URL"),
chainId: chainIdForNetwork(network),
builderPrivateKey: requiredEnv("VANA_PRIVATE_KEY"),
grantId: requiredEnv("GRANT_ID"),
scopes: [scope],
});
console.log(JSON.stringify(results[scope], null, 2));
}

main().catch((error: unknown) => {
console.error(error instanceof Error ? error.message : String(error));
process.exitCode = 1;
});
2 changes: 2 additions & 0 deletions src/app/api/vana/delivery/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
} from "@/lib/vana/server";
import { NextRequest } from "next/server";

export const maxDuration = 60;

type DeliveryBody = {
requestId: string;
personalServerUrl: string;
Expand Down
13 changes: 11 additions & 2 deletions src/app/api/vana/read/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { getDeliveredResult } from "@/lib/vana/foreground-delivery";
import { readApprovedScopes } from "@/lib/vana/server";
import { NextRequest } from "next/server";

export const maxDuration = 60;

export async function GET(request: NextRequest) {
const requestId = requestIdFromUrl(request.url);
if (!requestId) {
Expand Down Expand Up @@ -34,14 +36,21 @@ export async function GET(request: NextRequest) {
bound.binding.runtime,
bound.app,
bound.config,
requestId,
bound.binding,
);
if ("state" in result) {
return jsonNoStore(result, { status: 202 });
}
return jsonNoStore({ scope: result.scope, data: result.data });
} catch (error) {
const clientError = mapClientError(error);
console.error(`[vana/read] Read failed for ${requestId}`, error);
return jsonNoStore(
{ kind: clientError.kind, error: clientError.error },
{
kind: clientError.kind,
error: clientError.error,
...(clientError.detail ? { detail: clientError.detail } : {}),
},
{ status: clientError.status },
);
}
Expand Down
11 changes: 10 additions & 1 deletion src/app/api/vana/request/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,23 @@ import { jsonNoStore, noStore } from "@/lib/vana/response";
import {
resolveFixtureJourney,
resolveLaunchRuntime,
resolveVanaDefaultEnv,
resolveVanaDefaultNetwork,
type VanaRuntime,
} from "@/lib/vana/runtime";
import { getVanaController, getVanaServerConfig } from "@/lib/vana/server";
import { NextRequest, NextResponse } from "next/server";

const DEFAULT_NETWORK = resolveVanaDefaultNetwork(process.env);
const DEFAULT_ENV = resolveVanaDefaultEnv(process.env);

export async function POST(request: NextRequest) {
try {
const runtime = resolveLaunchRuntime(new URL(request.url).searchParams);
const runtime = resolveLaunchRuntime(
new URL(request.url).searchParams,
DEFAULT_NETWORK,
DEFAULT_ENV,
);
const config = getVanaServerConfig();
const journey = journeyFromUrl(request.url, runtime);
const app = appForJourney(journey);
Expand Down
5 changes: 4 additions & 1 deletion src/app/api/vana/status/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { assertGrantReadReady } from "@/lib/vana/capability";
import { getBoundVanaRequest, requestIdFromUrl } from "@/lib/vana/request";
import { jsonNoStore } from "@/lib/vana/response";
import { getDeliveredResult } from "@/lib/vana/foreground-delivery";
import { shouldUseEnclaveRead } from "@/lib/vana/enclave";
import { NextRequest } from "next/server";

export async function GET(request: NextRequest) {
Expand All @@ -29,7 +30,9 @@ export async function GET(request: NextRequest) {

const status = await bound.controller.getAccessRequestStatus(requestId);
if (status.status === "approved" || status.status === "ready_for_read") {
assertGrantReadReady(status);
assertGrantReadReady(status, {
requirePersonalServerUrl: !shouldUseEnclaveRead(status),
});
}
return jsonNoStore({ status: status.status });
} catch (error) {
Expand Down
9 changes: 8 additions & 1 deletion src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { LorebookApp } from "@/components/LorebookApp";
import {
resolveVanaDefaultEnv,
resolveVanaDefaultNetwork,
} from "@/lib/vana/runtime";

export default function Home() {
return (
<LorebookApp />
<LorebookApp
defaultEnv={resolveVanaDefaultEnv(process.env)}
defaultNetwork={resolveVanaDefaultNetwork(process.env)}
/>
);
}
Loading