@opendatalabs/personal-server-ts-server 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Write API session route — POST /v1/write/session.
3
+ *
4
+ * The builder proves control of its key + write-grant with a Web3Signed proof
5
+ * (same handshake shape as the self-signing MCP session, routes/mcp.ts) and
6
+ * gets a short-lived bearer token. The token then gates delegated writes on
7
+ * the EXISTING ingest endpoint (POST /v1/data/:scope) — see api-auth.ts
8
+ * authorizeWrite. The PS keeps signing AddData as the owner; the builder
9
+ * never holds the owner key.
10
+ */
11
+ import { Hono } from "hono";
12
+ import type { Logger } from "pino";
13
+ import type { GatewayClient } from "@opendatalabs/vana-sdk/node";
14
+ import { type WriteProofReplayStore, type WriteSessionStore } from "@opendatalabs/personal-server-ts-core/write";
15
+ import type { TokenStore } from "../token-store.js";
16
+ export interface WriteSessionRouteDeps {
17
+ logger: Logger;
18
+ serverOrigin: string | (() => string);
19
+ serverOwner?: `0x${string}`;
20
+ gateway: GatewayClient;
21
+ devToken?: string;
22
+ accessToken?: string;
23
+ tokenStore?: TokenStore;
24
+ /**
25
+ * Session store shared with the data routes (api-auth authorizeWrite reads
26
+ * the tokens this route mints). The caller wires ONE store into both.
27
+ */
28
+ sessionStore: WriteSessionStore;
29
+ /** Defaults to a per-route in-memory replay guard. */
30
+ proofReplayStore?: WriteProofReplayStore;
31
+ }
32
+ export declare function writeSessionRoutes(deps: WriteSessionRouteDeps): Hono;
33
+ //# sourceMappingURL=write-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-session.d.ts","sourceRoot":"","sources":["../../src/routes/write-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACvB,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACtC,WAAW,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IAC5B,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;OAGG;IACH,YAAY,EAAE,iBAAiB,CAAC;IAChC,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,qBAAqB,CAAC;CAC1C;AAsBD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,qBAAqB,GAAG,IAAI,CA4GpE"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Write API session route — POST /v1/write/session.
3
+ *
4
+ * The builder proves control of its key + write-grant with a Web3Signed proof
5
+ * (same handshake shape as the self-signing MCP session, routes/mcp.ts) and
6
+ * gets a short-lived bearer token. The token then gates delegated writes on
7
+ * the EXISTING ingest endpoint (POST /v1/data/:scope) — see api-auth.ts
8
+ * authorizeWrite. The PS keeps signing AddData as the owner; the builder
9
+ * never holds the owner key.
10
+ */
11
+ import { createHash, randomBytes } from "node:crypto";
12
+ import { Hono } from "hono";
13
+ import { authenticateRequest } from "@opendatalabs/personal-server-ts-core/auth";
14
+ import { ProtocolError } from "@opendatalabs/personal-server-ts-core/errors";
15
+ import { createInMemoryWriteProofReplayStore, createWriteSession, } from "@opendatalabs/personal-server-ts-core/write";
16
+ function jsonError(status, errorCode, message) {
17
+ return {
18
+ error: { code: status, errorCode, message },
19
+ };
20
+ }
21
+ /**
22
+ * Only ProtocolErrors are client-facing. Anything else (gateway, store,
23
+ * runtime failures) is logged with its cause and answered generically so
24
+ * internal details never reach the caller. Same mapping as the core data
25
+ * handler.
26
+ */
27
+ function internalError(logger, err, stage) {
28
+ logger.error({ err, stage }, "Write session handshake failed with an unexpected error");
29
+ return jsonError(500, "INTERNAL_ERROR", "Internal server error");
30
+ }
31
+ export function writeSessionRoutes(deps) {
32
+ const app = new Hono();
33
+ const proofReplayStore = deps.proofReplayStore ?? createInMemoryWriteProofReplayStore();
34
+ app.post("/session", async (c) => {
35
+ // Fail closed: minting a session requires this server's owner to bind
36
+ // the grant to (createWriteSession rejects wrong-owner grants).
37
+ if (!deps.serverOwner) {
38
+ return c.json(jsonError(500, "SERVER_NOT_CONFIGURED", "Server owner is not configured"), 500);
39
+ }
40
+ let authResult;
41
+ try {
42
+ authResult = await authenticateRequest({
43
+ request: c.req.raw,
44
+ serverOrigin: deps.serverOrigin,
45
+ devToken: deps.devToken,
46
+ accessToken: deps.accessToken,
47
+ sessionTokenVerifier: deps.tokenStore,
48
+ serverOwner: deps.serverOwner,
49
+ });
50
+ }
51
+ catch (err) {
52
+ if (!(err instanceof ProtocolError)) {
53
+ return c.json(internalError(deps.logger, err, "authenticate"), 500);
54
+ }
55
+ return c.json(jsonError(401, "WRITE_SESSION_AUTH_FAILED", err.message), 401);
56
+ }
57
+ if (authResult.mechanism !== "web3-signed") {
58
+ return c.json(jsonError(401, "WRITE_SESSION_PROOF_REQUIRED", "POST /v1/write/session requires a Web3Signed proof signed by the builder key"), 401);
59
+ }
60
+ const grantId = authResult.auth.payload.grantId;
61
+ if (!grantId) {
62
+ return c.json(jsonError(400, "GRANT_ID_REQUIRED", "The Web3Signed proof must carry a grantId (the write-grant issued to the builder)"), 400);
63
+ }
64
+ // Replay guard: bind to a digest of the exact proof header, remembered
65
+ // until the proof's own expiry (a replay only matters while still valid).
66
+ const proofHeader = c.req.raw.headers.get("authorization") ?? "";
67
+ const proofId = createHash("sha256").update(proofHeader).digest("hex");
68
+ const expSec = authResult.auth.payload.exp;
69
+ const expiresAtMs = (typeof expSec === "number"
70
+ ? expSec
71
+ : Math.floor(Date.now() / 1000) + 300) * 1000;
72
+ try {
73
+ const session = await createWriteSession({
74
+ builderAddress: authResult.auth.signer,
75
+ grantId,
76
+ proof: { id: proofId, expiresAtMs },
77
+ }, {
78
+ store: deps.sessionStore,
79
+ authSessionVerifier: deps.gateway,
80
+ grantVerifier: deps.gateway,
81
+ serverOwner: deps.serverOwner,
82
+ randomToken: () => `vana_write_${randomBytes(32).toString("hex")}`,
83
+ replayStore: proofReplayStore,
84
+ });
85
+ deps.logger.info({
86
+ builder: authResult.auth.signer,
87
+ grantId: session.grantId,
88
+ writeScopes: session.writeScopes,
89
+ }, "Write session minted");
90
+ return c.json({
91
+ access_token: session.accessToken,
92
+ token_type: "Bearer",
93
+ expires_in: session.expiresInSeconds,
94
+ // Write patterns, prefix stripped — what POST /v1/data/:scope will
95
+ // accept under this token.
96
+ scope: session.writeScopes.join(" "),
97
+ });
98
+ }
99
+ catch (err) {
100
+ if (err instanceof ProtocolError) {
101
+ return c.json(err.toJSON(), err.code);
102
+ }
103
+ return c.json(internalError(deps.logger, err, "create-session"), 500);
104
+ }
105
+ });
106
+ return app;
107
+ }
108
+ //# sourceMappingURL=write-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-session.js","sourceRoot":"","sources":["../../src/routes/write-session.ts"],"names":[],"mappings":"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"}