@opendatalabs/personal-server-ts-core 1.10.1 → 1.11.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.
- package/dist/api/index.d.ts +23 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js.map +1 -1
- package/dist/derivatives/api.d.ts +7 -1
- package/dist/derivatives/api.d.ts.map +1 -1
- package/dist/derivatives/api.js +45 -8
- package/dist/derivatives/api.js.map +1 -1
- package/dist/errors/catalog.d.ts +3 -0
- package/dist/errors/catalog.d.ts.map +1 -1
- package/dist/errors/catalog.js +5 -0
- package/dist/errors/catalog.js.map +1 -1
- package/dist/test-utils/wallet.d.ts +6 -0
- package/dist/test-utils/wallet.d.ts.map +1 -1
- package/dist/test-utils/wallet.js +46 -0
- package/dist/test-utils/wallet.js.map +1 -1
- package/dist/write/attribution.d.ts +23 -5
- package/dist/write/attribution.d.ts.map +1 -1
- package/dist/write/attribution.js +137 -12
- package/dist/write/attribution.js.map +1 -1
- package/dist/write/authorize.d.ts +77 -0
- package/dist/write/authorize.d.ts.map +1 -0
- package/dist/write/authorize.js +109 -0
- package/dist/write/authorize.js.map +1 -0
- package/dist/write/index.d.ts +2 -0
- package/dist/write/index.d.ts.map +1 -1
- package/dist/write/index.js +2 -0
- package/dist/write/index.js.map +1 -1
- package/dist/write/route.d.ts +61 -0
- package/dist/write/route.d.ts.map +1 -0
- package/dist/write/route.js +132 -0
- package/dist/write/route.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The write-session handshake, as a runtime-agnostic request handler.
|
|
3
|
+
*
|
|
4
|
+
* `POST /v1/write/session`: a registered builder proves control of its key and
|
|
5
|
+
* of a write-grant with a Web3Signed proof (the same handshake shape as the
|
|
6
|
+
* self-signing MCP session) and gets a short-lived bearer token. That token
|
|
7
|
+
* then gates delegated writes on the EXISTING ingest endpoint
|
|
8
|
+
* (`POST /v1/data/:scope`) and the derivative question routes. The Personal
|
|
9
|
+
* Server keeps signing AddData as the owner; the builder never holds the owner
|
|
10
|
+
* key.
|
|
11
|
+
*
|
|
12
|
+
* This lived in the Node server as a Hono route (packages/server/src/routes/
|
|
13
|
+
* write-session.ts) and reached for `node:crypto` for two things: a sha-256 of
|
|
14
|
+
* the proof header, and 32 random bytes for the token. Both have Web Crypto
|
|
15
|
+
* equivalents, so the handshake is expressed here over plain `Request` /
|
|
16
|
+
* `Response` and BOTH builds mount the same handler — the Node route is a Hono
|
|
17
|
+
* wrapper around it, and the browser runtime dispatches to it directly. There
|
|
18
|
+
* is one implementation of who may open a write session.
|
|
19
|
+
*/
|
|
20
|
+
import { authenticateRequest } from "../auth/index.js";
|
|
21
|
+
import { ProtocolError } from "../errors/catalog.js";
|
|
22
|
+
import { hashConnectionToken } from "../mcp/connection-api.js";
|
|
23
|
+
import { createWriteSession, } from "./session.js";
|
|
24
|
+
function jsonError(status, errorCode, message) {
|
|
25
|
+
return { error: { code: status, errorCode, message } };
|
|
26
|
+
}
|
|
27
|
+
function jsonResponse(body, status) {
|
|
28
|
+
return new Response(JSON.stringify(body), {
|
|
29
|
+
status,
|
|
30
|
+
headers: { "Content-Type": "application/json" },
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Only ProtocolErrors are client-facing. Anything else (gateway, store,
|
|
35
|
+
* runtime failures) is logged with its cause and answered generically so
|
|
36
|
+
* internal details never reach the caller. Same mapping as the core data
|
|
37
|
+
* handler.
|
|
38
|
+
*/
|
|
39
|
+
function internalError(logger, err, stage) {
|
|
40
|
+
logger?.error?.({ err, stage }, "Write session handshake failed with an unexpected error");
|
|
41
|
+
return jsonResponse(jsonError(500, "INTERNAL_ERROR", "Internal server error"), 500);
|
|
42
|
+
}
|
|
43
|
+
function defaultRandomToken() {
|
|
44
|
+
const bytes = new Uint8Array(32);
|
|
45
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
46
|
+
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
47
|
+
return `vana_write_${hex}`;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Handle one `POST /v1/write/session` request. The caller has already matched
|
|
51
|
+
* the method and path; anything reaching here is treated as the handshake.
|
|
52
|
+
*/
|
|
53
|
+
export async function handleWriteSessionRequest(request, deps) {
|
|
54
|
+
// Fail closed: minting a session requires this server's owner to bind the
|
|
55
|
+
// grant to (createWriteSession rejects wrong-owner grants).
|
|
56
|
+
if (!deps.serverOwner) {
|
|
57
|
+
return jsonResponse(jsonError(500, "SERVER_NOT_CONFIGURED", "Server owner is not configured"), 500);
|
|
58
|
+
}
|
|
59
|
+
let authResult;
|
|
60
|
+
try {
|
|
61
|
+
authResult = await authenticateRequest({
|
|
62
|
+
request,
|
|
63
|
+
serverOrigin: deps.serverOrigin,
|
|
64
|
+
devToken: deps.devToken,
|
|
65
|
+
accessToken: deps.accessToken,
|
|
66
|
+
sessionTokenVerifier: deps.tokenStore,
|
|
67
|
+
serverOwner: deps.serverOwner,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
if (!(err instanceof ProtocolError)) {
|
|
72
|
+
return internalError(deps.logger, err, "authenticate");
|
|
73
|
+
}
|
|
74
|
+
return jsonResponse(jsonError(401, "WRITE_SESSION_AUTH_FAILED", err.message), 401);
|
|
75
|
+
}
|
|
76
|
+
// A bearer credential (dev token, control-plane token, CLI session) proves
|
|
77
|
+
// nothing about the builder's key, so it can never open a write session.
|
|
78
|
+
if (authResult.mechanism !== "web3-signed") {
|
|
79
|
+
return jsonResponse(jsonError(401, "WRITE_SESSION_PROOF_REQUIRED", "POST /v1/write/session requires a Web3Signed proof signed by the builder key"), 401);
|
|
80
|
+
}
|
|
81
|
+
const grantId = authResult.auth.payload.grantId;
|
|
82
|
+
if (!grantId) {
|
|
83
|
+
return jsonResponse(jsonError(400, "GRANT_ID_REQUIRED", "The Web3Signed proof must carry a grantId (the write-grant issued to the builder)"), 400);
|
|
84
|
+
}
|
|
85
|
+
// Replay guard: bind to a digest of the exact proof header, remembered
|
|
86
|
+
// until the proof's own expiry (a replay only matters while still valid).
|
|
87
|
+
const proofHeader = request.headers.get("authorization") ?? "";
|
|
88
|
+
const proofId = await hashConnectionToken(proofHeader);
|
|
89
|
+
const expSec = authResult.auth.payload.exp;
|
|
90
|
+
const expiresAtMs = (typeof expSec === "number"
|
|
91
|
+
? expSec
|
|
92
|
+
: Math.floor(Date.now() / 1000) + 300) * 1000;
|
|
93
|
+
try {
|
|
94
|
+
const session = await createWriteSession({
|
|
95
|
+
builderAddress: authResult.auth.signer,
|
|
96
|
+
grantId,
|
|
97
|
+
proof: { id: proofId, expiresAtMs },
|
|
98
|
+
}, {
|
|
99
|
+
store: deps.sessionStore,
|
|
100
|
+
authSessionVerifier: deps.authSessionVerifier,
|
|
101
|
+
grantVerifier: deps.grantVerifier,
|
|
102
|
+
serverOwner: deps.serverOwner,
|
|
103
|
+
randomToken: deps.randomToken ?? defaultRandomToken,
|
|
104
|
+
...(deps.ttlMs === undefined ? {} : { ttlMs: deps.ttlMs }),
|
|
105
|
+
...(deps.now === undefined ? {} : { now: deps.now }),
|
|
106
|
+
...(deps.replayStore === undefined
|
|
107
|
+
? {}
|
|
108
|
+
: { replayStore: deps.replayStore }),
|
|
109
|
+
});
|
|
110
|
+
deps.logger?.info?.({
|
|
111
|
+
builder: authResult.auth.signer,
|
|
112
|
+
grantId: session.grantId,
|
|
113
|
+
writeScopes: session.writeScopes,
|
|
114
|
+
}, "Write session minted");
|
|
115
|
+
const body = {
|
|
116
|
+
access_token: session.accessToken,
|
|
117
|
+
token_type: "Bearer",
|
|
118
|
+
expires_in: session.expiresInSeconds,
|
|
119
|
+
// Write patterns, prefix stripped — what POST /v1/data/:scope will
|
|
120
|
+
// accept under this token.
|
|
121
|
+
scope: session.writeScopes.join(" "),
|
|
122
|
+
};
|
|
123
|
+
return jsonResponse(body, 200);
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
if (err instanceof ProtocolError) {
|
|
127
|
+
return jsonResponse(err.toJSON(), err.code);
|
|
128
|
+
}
|
|
129
|
+
return internalError(deps.logger, err, "create-session");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/write/route.ts"],"names":[],"mappings":"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"}
|