@opendatalabs/personal-server-ts-lite 0.0.1-canary.00328bf
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/bridge.d.ts +23 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +53 -0
- package/dist/bridge.js.map +1 -0
- package/dist/browser-runtime.d.ts +58 -0
- package/dist/browser-runtime.d.ts.map +1 -0
- package/dist/browser-runtime.js +214 -0
- package/dist/browser-runtime.js.map +1 -0
- package/dist/browser-tls-rustls/browser_tls_rustls.d.ts +49 -0
- package/dist/browser-tls-rustls/browser_tls_rustls.js +401 -0
- package/dist/browser-tls-rustls/browser_tls_rustls_bg.wasm +0 -0
- package/dist/client.d.ts +22 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +408 -0
- package/dist/client.js.map +1 -0
- package/dist/derivatives.d.ts +51 -0
- package/dist/derivatives.d.ts.map +1 -0
- package/dist/derivatives.js +87 -0
- package/dist/derivatives.js.map +1 -0
- package/dist/diagnostics.d.ts +166 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +265 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-store.d.ts +35 -0
- package/dist/mcp-store.d.ts.map +1 -0
- package/dist/mcp-store.js +208 -0
- package/dist/mcp-store.js.map +1 -0
- package/dist/owner-binding.d.ts +7 -0
- package/dist/owner-binding.d.ts.map +1 -0
- package/dist/owner-binding.js +18 -0
- package/dist/owner-binding.js.map +1 -0
- package/dist/persistence.d.ts +69 -0
- package/dist/persistence.d.ts.map +1 -0
- package/dist/persistence.js +58 -0
- package/dist/persistence.js.map +1 -0
- package/dist/relay-tls.d.ts +61 -0
- package/dist/relay-tls.d.ts.map +1 -0
- package/dist/relay-tls.js +316 -0
- package/dist/relay-tls.js.map +1 -0
- package/dist/relay.d.ts +149 -0
- package/dist/relay.d.ts.map +1 -0
- package/dist/relay.js +646 -0
- package/dist/relay.js.map +1 -0
- package/dist/runtime.d.ts +188 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1178 -0
- package/dist/runtime.js.map +1 -0
- package/dist/state.d.ts +72 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +366 -0
- package/dist/state.js.map +1 -0
- package/dist/storage-utils.d.ts +8 -0
- package/dist/storage-utils.d.ts.map +1 -0
- package/dist/storage-utils.js +67 -0
- package/dist/storage-utils.js.map +1 -0
- package/dist/storage.d.ts +61 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +718 -0
- package/dist/storage.js.map +1 -0
- package/dist/sync.d.ts +58 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +216 -0
- package/dist/sync.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IndexedDB-backed `McpConnectionStore` for Web PS Lite.
|
|
3
|
+
*
|
|
4
|
+
* Phase 1 trade-off: persists the per-connection grantee private key in
|
|
5
|
+
* PLAINTEXT in IndexedDB. The owner-derived AES-GCM wrap used for the PS Lite
|
|
6
|
+
* server identity is not yet applied to grantee keys — that's the Phase 2
|
|
7
|
+
* "encrypt grantee private keys at rest" task in
|
|
8
|
+
* `260604-PLAN-vana-mcp-personal-server.md`. The risk is bounded by:
|
|
9
|
+
*
|
|
10
|
+
* 1. The browser same-origin policy — only code running on the PS Lite tab's
|
|
11
|
+
* origin (e.g. app-dev.vana.org) can read this store.
|
|
12
|
+
* 2. Grantee keys are scoped per-connection and revocable. A leaked key only
|
|
13
|
+
* lets the holder read the grants that connection already approved; any
|
|
14
|
+
* revoke removes both the grant and the connection's lookup record.
|
|
15
|
+
* 3. There are no write tools — leaked grantee keys cannot mutate user data.
|
|
16
|
+
*
|
|
17
|
+
* Persistent storage is strongly preferred over in-memory because:
|
|
18
|
+
* - app-dev page reloads are routine in a browser app;
|
|
19
|
+
* - Claude's MCP URL is meant to live in the Claude config across sessions;
|
|
20
|
+
* - the alternative (re-create on every boot) would silently invalidate every
|
|
21
|
+
* prior Claude connection on every reload, indistinguishable from a real
|
|
22
|
+
* revoke from the user's perspective.
|
|
23
|
+
*/
|
|
24
|
+
import { isMcpTokenExpired, matchesMcpRefreshHash, } from "@opendatalabs/personal-server-ts-core/mcp";
|
|
25
|
+
const DEFAULT_DB_NAME = "personal-server-lite";
|
|
26
|
+
const DEFAULT_STORE_NAME = "mcpConnections";
|
|
27
|
+
const DEFAULT_AUTHORIZATION_STORE_NAME = "mcpOAuthAuthorizations";
|
|
28
|
+
const TOKEN_HASH_INDEX = "tokenHash";
|
|
29
|
+
const AUTHORIZATION_CODE_HASH_INDEX = "authorizationCodeHash";
|
|
30
|
+
const DB_VERSION = 2;
|
|
31
|
+
const CONNECTION_INDEXES = [
|
|
32
|
+
{ name: TOKEN_HASH_INDEX, keyPath: "tokenHash", unique: true },
|
|
33
|
+
];
|
|
34
|
+
const AUTHORIZATION_INDEXES = [
|
|
35
|
+
{
|
|
36
|
+
name: AUTHORIZATION_CODE_HASH_INDEX,
|
|
37
|
+
keyPath: "authorizationCodeHash",
|
|
38
|
+
unique: true,
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
const DEFAULT_CONNECTION_OPTIONS = {
|
|
42
|
+
dbName: DEFAULT_DB_NAME,
|
|
43
|
+
storeName: DEFAULT_STORE_NAME,
|
|
44
|
+
};
|
|
45
|
+
const DEFAULT_AUTHORIZATION_OPTIONS = {
|
|
46
|
+
dbName: DEFAULT_DB_NAME,
|
|
47
|
+
storeName: DEFAULT_AUTHORIZATION_STORE_NAME,
|
|
48
|
+
};
|
|
49
|
+
function ensureObjectStore(db, transaction, opts, indexes) {
|
|
50
|
+
const store = db.objectStoreNames.contains(opts.storeName)
|
|
51
|
+
? transaction?.objectStore(opts.storeName)
|
|
52
|
+
: db.createObjectStore(opts.storeName, { keyPath: "id" });
|
|
53
|
+
if (!store)
|
|
54
|
+
return;
|
|
55
|
+
for (const index of indexes) {
|
|
56
|
+
if (!store.indexNames.contains(index.name)) {
|
|
57
|
+
store.createIndex(index.name, index.keyPath, { unique: index.unique });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function openDb(opts, indexes) {
|
|
62
|
+
if (typeof indexedDB === "undefined") {
|
|
63
|
+
throw new Error("IndexedDB is not available in this runtime");
|
|
64
|
+
}
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
const request = indexedDB.open(opts.dbName, DB_VERSION);
|
|
67
|
+
request.onupgradeneeded = () => {
|
|
68
|
+
const db = request.result;
|
|
69
|
+
ensureObjectStore(db, request.transaction, opts, indexes);
|
|
70
|
+
ensureObjectStore(db, request.transaction, DEFAULT_CONNECTION_OPTIONS, CONNECTION_INDEXES);
|
|
71
|
+
ensureObjectStore(db, request.transaction, DEFAULT_AUTHORIZATION_OPTIONS, AUTHORIZATION_INDEXES);
|
|
72
|
+
};
|
|
73
|
+
request.onsuccess = () => resolve(request.result);
|
|
74
|
+
request.onerror = () => reject(request.error);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function runTx(opts, mode, indexes, fn) {
|
|
78
|
+
return openDb(opts, indexes).then((db) => new Promise((resolve, reject) => {
|
|
79
|
+
const transaction = db.transaction(opts.storeName, mode);
|
|
80
|
+
const store = transaction.objectStore(opts.storeName);
|
|
81
|
+
const request = fn(store);
|
|
82
|
+
request.onsuccess = () => resolve(request.result);
|
|
83
|
+
request.onerror = () => reject(request.error);
|
|
84
|
+
transaction.oncomplete = () => db.close();
|
|
85
|
+
transaction.onerror = () => {
|
|
86
|
+
db.close();
|
|
87
|
+
reject(transaction.error);
|
|
88
|
+
};
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
function runIndexQuery(opts, indexName, indexes, fn) {
|
|
92
|
+
return openDb(opts, indexes).then((db) => new Promise((resolve, reject) => {
|
|
93
|
+
const transaction = db.transaction(opts.storeName, "readonly");
|
|
94
|
+
const store = transaction.objectStore(opts.storeName);
|
|
95
|
+
const request = fn(store.index(indexName));
|
|
96
|
+
request.onsuccess = () => resolve(request.result);
|
|
97
|
+
request.onerror = () => reject(request.error);
|
|
98
|
+
transaction.oncomplete = () => db.close();
|
|
99
|
+
transaction.onerror = () => {
|
|
100
|
+
db.close();
|
|
101
|
+
reject(transaction.error);
|
|
102
|
+
};
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
function mutateConnectionRecord(opts, id, update) {
|
|
106
|
+
return openDb(opts, CONNECTION_INDEXES).then((db) => new Promise((resolve, reject) => {
|
|
107
|
+
const transaction = db.transaction(opts.storeName, "readwrite");
|
|
108
|
+
const store = transaction.objectStore(opts.storeName);
|
|
109
|
+
const request = store.get(id);
|
|
110
|
+
let result = null;
|
|
111
|
+
request.onsuccess = () => {
|
|
112
|
+
if (!request.result)
|
|
113
|
+
return;
|
|
114
|
+
result = update(structuredClone(request.result));
|
|
115
|
+
store.put(result);
|
|
116
|
+
};
|
|
117
|
+
request.onerror = () => reject(request.error);
|
|
118
|
+
transaction.oncomplete = () => {
|
|
119
|
+
db.close();
|
|
120
|
+
resolve(result ? structuredClone(result) : null);
|
|
121
|
+
};
|
|
122
|
+
transaction.onerror = () => {
|
|
123
|
+
db.close();
|
|
124
|
+
reject(transaction.error);
|
|
125
|
+
};
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
export function createIndexedDbMcpConnectionStore(options = {}) {
|
|
129
|
+
const resolved = {
|
|
130
|
+
dbName: options.dbName ?? DEFAULT_DB_NAME,
|
|
131
|
+
storeName: options.storeName ?? DEFAULT_STORE_NAME,
|
|
132
|
+
};
|
|
133
|
+
return {
|
|
134
|
+
async create(record) {
|
|
135
|
+
const existing = await runTx(resolved, "readonly", CONNECTION_INDEXES, (store) => store.get(record.id));
|
|
136
|
+
if (existing) {
|
|
137
|
+
throw new Error(`mcp connection ${record.id} already exists`);
|
|
138
|
+
}
|
|
139
|
+
await runTx(resolved, "readwrite", CONNECTION_INDEXES, (store) => store.put({ ...record }));
|
|
140
|
+
},
|
|
141
|
+
async list() {
|
|
142
|
+
const all = await runTx(resolved, "readonly", CONNECTION_INDEXES, (store) => store.getAll());
|
|
143
|
+
return all.map((r) => ({ ...r }));
|
|
144
|
+
},
|
|
145
|
+
async getById(id) {
|
|
146
|
+
const record = await runTx(resolved, "readonly", CONNECTION_INDEXES, (store) => store.get(id));
|
|
147
|
+
return record ? { ...record } : null;
|
|
148
|
+
},
|
|
149
|
+
async getByTokenHash(tokenHash) {
|
|
150
|
+
const record = await runIndexQuery(resolved, TOKEN_HASH_INDEX, CONNECTION_INDEXES, (index) => index.get(tokenHash));
|
|
151
|
+
if (!record)
|
|
152
|
+
return null;
|
|
153
|
+
if (record.status !== "approved")
|
|
154
|
+
return null;
|
|
155
|
+
if (isMcpTokenExpired(record))
|
|
156
|
+
return null;
|
|
157
|
+
return { ...record };
|
|
158
|
+
},
|
|
159
|
+
async getByRefreshTokenHash(refreshTokenHash) {
|
|
160
|
+
// No IndexedDB index: a presented token may match either the current or
|
|
161
|
+
// the rotated-out hash, and the store holds a handful of connections.
|
|
162
|
+
const all = await runTx(resolved, "readonly", CONNECTION_INDEXES, (store) => store.getAll());
|
|
163
|
+
const record = all.find((candidate) => matchesMcpRefreshHash(candidate, refreshTokenHash));
|
|
164
|
+
return record ? { ...record } : null;
|
|
165
|
+
},
|
|
166
|
+
mutate(id, update) {
|
|
167
|
+
return mutateConnectionRecord(resolved, id, update);
|
|
168
|
+
},
|
|
169
|
+
async update(id, patch) {
|
|
170
|
+
return mutateConnectionRecord(resolved, id, (existing) => ({ ...existing, ...patch }));
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
export function createIndexedDbMcpOAuthAuthorizationStore(options = {}) {
|
|
175
|
+
const resolved = {
|
|
176
|
+
dbName: options.dbName ?? DEFAULT_DB_NAME,
|
|
177
|
+
storeName: options.storeName ?? DEFAULT_AUTHORIZATION_STORE_NAME,
|
|
178
|
+
};
|
|
179
|
+
return {
|
|
180
|
+
async create(record) {
|
|
181
|
+
const existing = await runTx(resolved, "readonly", AUTHORIZATION_INDEXES, (store) => store.get(record.id));
|
|
182
|
+
if (existing) {
|
|
183
|
+
throw new Error(`mcp oauth authorization ${record.id} already exists`);
|
|
184
|
+
}
|
|
185
|
+
await runTx(resolved, "readwrite", AUTHORIZATION_INDEXES, (store) => store.put({ ...record }));
|
|
186
|
+
},
|
|
187
|
+
async getById(id) {
|
|
188
|
+
const record = await runTx(resolved, "readonly", AUTHORIZATION_INDEXES, (store) => store.get(id));
|
|
189
|
+
return record ? { ...record } : null;
|
|
190
|
+
},
|
|
191
|
+
async getByCodeHash(authorizationCodeHash) {
|
|
192
|
+
const record = await runIndexQuery(resolved, AUTHORIZATION_CODE_HASH_INDEX, AUTHORIZATION_INDEXES, (index) => index.get(authorizationCodeHash));
|
|
193
|
+
return record ? { ...record } : null;
|
|
194
|
+
},
|
|
195
|
+
async update(id, patch) {
|
|
196
|
+
const existing = await runTx(resolved, "readonly", AUTHORIZATION_INDEXES, (store) => store.get(id));
|
|
197
|
+
if (!existing)
|
|
198
|
+
return null;
|
|
199
|
+
const updated = { ...existing, ...patch };
|
|
200
|
+
await runTx(resolved, "readwrite", AUTHORIZATION_INDEXES, (store) => store.put(updated));
|
|
201
|
+
return { ...updated };
|
|
202
|
+
},
|
|
203
|
+
async delete(id) {
|
|
204
|
+
await runTx(resolved, "readwrite", AUTHORIZATION_INDEXES, (store) => store.delete(id));
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=mcp-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-store.js","sourceRoot":"","sources":["../src/mcp-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EACL,iBAAiB,EACjB,qBAAqB,GAKtB,MAAM,2CAA2C,CAAC;AAEnD,MAAM,eAAe,GAAG,sBAAsB,CAAC;AAC/C,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;AAC5C,MAAM,gCAAgC,GAAG,wBAAwB,CAAC;AAClE,MAAM,gBAAgB,GAAG,WAAW,CAAC;AACrC,MAAM,6BAA6B,GAAG,uBAAuB,CAAC;AAC9D,MAAM,UAAU,GAAG,CAAC,CAAC;AAErB,MAAM,kBAAkB,GAAG;IACzB,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE;CACtD,CAAC;AAEX,MAAM,qBAAqB,GAAG;IAC5B;QACE,IAAI,EAAE,6BAA6B;QACnC,OAAO,EAAE,uBAAuB;QAChC,MAAM,EAAE,IAAI;KACb;CACO,CAAC;AAiBX,MAAM,0BAA0B,GAAoB;IAClD,MAAM,EAAE,eAAe;IACvB,SAAS,EAAE,kBAAkB;CAC9B,CAAC;AAEF,MAAM,6BAA6B,GAAoB;IACrD,MAAM,EAAE,eAAe;IACvB,SAAS,EAAE,gCAAgC;CAC5C,CAAC;AAEF,SAAS,iBAAiB,CACxB,EAAe,EACf,WAA8C,EAC9C,IAAqB,EACrB,OAAsE;IAEtE,MAAM,KAAK,GAAG,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC;QACxD,CAAC,CAAC,WAAW,EAAE,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC;QAC1C,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,IAAI,CAAC,KAAK;QAAE,OAAO;IACnB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CACb,IAAqB,EACrB,OAAsE;IAEtE,IAAI,OAAO,SAAS,KAAK,WAAW,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACxD,OAAO,CAAC,eAAe,GAAG,GAAG,EAAE;YAC7B,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;YAC1B,iBAAiB,CAAC,EAAE,EAAE,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;YAC1D,iBAAiB,CACf,EAAE,EACF,OAAO,CAAC,WAAW,EACnB,0BAA0B,EAC1B,kBAAkB,CACnB,CAAC;YACF,iBAAiB,CACf,EAAE,EACF,OAAO,CAAC,WAAW,EACnB,6BAA6B,EAC7B,qBAAqB,CACtB,CAAC;QACJ,CAAC,CAAC;QACF,OAAO,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClD,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,KAAK,CACZ,IAAqB,EACrB,IAAwB,EACxB,OAAsE,EACtE,EAA4C;IAE5C,OAAO,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAC/B,CAAC,EAAE,EAAE,EAAE,CACL,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACjC,MAAM,WAAW,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;QAC1B,OAAO,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClD,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9C,WAAW,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;QAC1C,WAAW,CAAC,OAAO,GAAG,GAAG,EAAE;YACzB,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC,CAAC;IACJ,CAAC,CAAC,CACL,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CACpB,IAAqB,EACrB,SAAiB,EACjB,OAAsE,EACtE,EAAsC;IAEtC,OAAO,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAC/B,CAAC,EAAE,EAAE,EAAE,CACL,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACjC,MAAM,WAAW,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QAC/D,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;QAC3C,OAAO,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClD,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9C,WAAW,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;QAC1C,WAAW,CAAC,OAAO,GAAG,GAAG,EAAE;YACzB,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC,CAAC;IACJ,CAAC,CAAC,CACL,CAAC;AACJ,CAAC;AAED,SAAS,sBAAsB,CAC7B,IAAqB,EACrB,EAAU,EACV,MAA4D;IAE5D,OAAO,MAAM,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,IAAI,CAC1C,CAAC,EAAE,EAAE,EAAE,CACL,IAAI,OAAO,CAA6B,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1D,MAAM,WAAW,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAChE,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAE3B,CAAC;QACF,IAAI,MAAM,GAA+B,IAAI,CAAC;QAC9C,OAAO,CAAC,SAAS,GAAG,GAAG,EAAE;YACvB,IAAI,CAAC,OAAO,CAAC,MAAM;gBAAE,OAAO;YAC5B,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YACjD,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC,CAAC;QACF,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9C,WAAW,CAAC,UAAU,GAAG,GAAG,EAAE;YAC5B,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACnD,CAAC,CAAC;QACF,WAAW,CAAC,OAAO,GAAG,GAAG,EAAE;YACzB,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC,CAAC;IACJ,CAAC,CAAC,CACL,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iCAAiC,CAC/C,UAA8C,EAAE;IAEhD,MAAM,QAAQ,GAAoB;QAChC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,eAAe;QACzC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,kBAAkB;KACnD,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,MAAM;YACjB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAChC,CAAC;YACF,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,IAAI,KAAK,CAAC,kBAAkB,MAAM,CAAC,EAAE,iBAAiB,CAAC,CAAC;YAChE,CAAC;YACD,MAAM,KAAK,CACT,QAAQ,EACR,WAAW,EACX,kBAAkB,EAClB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CACpC,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,IAAI;YACR,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAC1B,CAAC;YACF,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACpC,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,EAAE;YACd,MAAM,MAAM,GAAG,MAAM,KAAK,CACxB,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CACzB,CAAC;YACF,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACvC,CAAC;QAED,KAAK,CAAC,cAAc,CAAC,SAAS;YAC5B,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,EAClB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAChC,CAAC;YACF,IAAI,CAAC,MAAM;gBAAE,OAAO,IAAI,CAAC;YACzB,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU;gBAAE,OAAO,IAAI,CAAC;YAC9C,IAAI,iBAAiB,CAAC,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC3C,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC;QACvB,CAAC;QAED,KAAK,CAAC,qBAAqB,CAAC,gBAAgB;YAC1C,wEAAwE;YACxE,sEAAsE;YACtE,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAC1B,CAAC;YACF,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CACpC,qBAAqB,CAAC,SAAS,EAAE,gBAAgB,CAAC,CACnD,CAAC;YACF,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACvC,CAAC;QAED,MAAM,CAAC,EAAE,EAAE,MAAM;YACf,OAAO,sBAAsB,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QACtD,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK;YACpB,OAAO,sBAAsB,CAC3B,QAAQ,EACR,EAAE,EACF,CAAC,QAAQ,EAAuB,EAAE,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAC,CAC/D,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yCAAyC,CACvD,UAAsD,EAAE;IAExD,MAAM,QAAQ,GAAoB;QAChC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,eAAe;QACzC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,gCAAgC;KACjE,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,MAAM;YACjB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,QAAQ,EACR,UAAU,EACV,qBAAqB,EACrB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAChC,CAAC;YACF,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,CAAC,EAAE,iBAAiB,CAAC,CAAC;YACzE,CAAC;YACD,MAAM,KAAK,CACT,QAAQ,EACR,WAAW,EACX,qBAAqB,EACrB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CACpC,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,EAAE;YACd,MAAM,MAAM,GAAG,MAAM,KAAK,CACxB,QAAQ,EACR,UAAU,EACV,qBAAqB,EACrB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CACzB,CAAC;YACF,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACvC,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,qBAAqB;YACvC,MAAM,MAAM,GAAG,MAAM,aAAa,CAGhC,QAAQ,EACR,6BAA6B,EAC7B,qBAAqB,EACrB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAC5C,CAAC;YACF,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACvC,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK;YACpB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,QAAQ,EACR,UAAU,EACV,qBAAqB,EACrB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CACzB,CAAC;YACF,IAAI,CAAC,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAC3B,MAAM,OAAO,GAAgC,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAC;YACvE,MAAM,KAAK,CACT,QAAQ,EACR,WAAW,EACX,qBAAqB,EACrB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAC9B,CAAC;YACF,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;QACxB,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,EAAE;YACb,MAAM,KAAK,CACT,QAAQ,EACR,WAAW,EACX,qBAAqB,EACrB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAC5B,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Address } from "viem";
|
|
2
|
+
export interface PsLiteOwnerBindingInput {
|
|
3
|
+
ownerAddress?: Address;
|
|
4
|
+
ownerSignature: `0x${string}`;
|
|
5
|
+
}
|
|
6
|
+
export declare function resolvePsLiteOwner(input: PsLiteOwnerBindingInput): Promise<Address>;
|
|
7
|
+
//# sourceMappingURL=owner-binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owner-binding.d.ts","sourceRoot":"","sources":["../src/owner-binding.ts"],"names":[],"mappings":"AAEA,OAAO,EAAqC,KAAK,OAAO,EAAE,MAAM,MAAM,CAAC;AAEvE,MAAM,WAAW,uBAAuB;IACtC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,KAAK,MAAM,EAAE,CAAC;CAC/B;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAclB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { recoverServerOwner } from "@opendatalabs/vana-sdk/browser";
|
|
2
|
+
import { buildPersonalServerLiteOwnerBindingMessage } from "@opendatalabs/vana-sdk/protocol/personal-server-lite-owner-binding";
|
|
3
|
+
import { getAddress, recoverMessageAddress } from "viem";
|
|
4
|
+
export async function resolvePsLiteOwner(input) {
|
|
5
|
+
if (!input.ownerAddress) {
|
|
6
|
+
return recoverServerOwner(input.ownerSignature);
|
|
7
|
+
}
|
|
8
|
+
const expected = getAddress(input.ownerAddress);
|
|
9
|
+
const recovered = await recoverMessageAddress({
|
|
10
|
+
message: buildPersonalServerLiteOwnerBindingMessage(expected),
|
|
11
|
+
signature: input.ownerSignature,
|
|
12
|
+
});
|
|
13
|
+
if (recovered.toLowerCase() !== expected.toLowerCase()) {
|
|
14
|
+
throw new Error("PS Lite owner signature does not match ownerAddress");
|
|
15
|
+
}
|
|
16
|
+
return expected;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=owner-binding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owner-binding.js","sourceRoot":"","sources":["../src/owner-binding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,0CAA0C,EAAE,MAAM,oEAAoE,CAAC;AAChI,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAgB,MAAM,MAAM,CAAC;AAOvE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAA8B;IAE9B,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QACxB,OAAO,kBAAkB,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAAC;QAC5C,OAAO,EAAE,0CAA0C,CAAC,QAAQ,CAAC;QAC7D,SAAS,EAAE,KAAK,CAAC,cAAc;KAChC,CAAC,CAAC;IACH,IAAI,SAAS,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { DataStoragePort } from "@opendatalabs/personal-server-ts-core/ports";
|
|
2
|
+
import type { ServerConfig } from "@opendatalabs/personal-server-ts-core/schemas";
|
|
3
|
+
import type { AccessLogReader } from "@opendatalabs/personal-server-ts-core/logging/access-reader";
|
|
4
|
+
import type { AccessLogWriter } from "@opendatalabs/personal-server-ts-core/logging/access-log";
|
|
5
|
+
import type { McpConnectionStore, McpOAuthAuthorizationStore } from "@opendatalabs/personal-server-ts-core/mcp";
|
|
6
|
+
import type { PsLiteRuntimeOptions, PsLiteTokenStore } from "./runtime.js";
|
|
7
|
+
import { type PsLiteStateStore } from "./state.js";
|
|
8
|
+
import type { PsLiteRelayTlsIdentityStore } from "./relay-tls.js";
|
|
9
|
+
/**
|
|
10
|
+
* The complete set of PS Lite persistence ports, named as one composition
|
|
11
|
+
* contract for a host (Mobile) that backs them all with a single durable store.
|
|
12
|
+
*
|
|
13
|
+
* This is a struct of the EXISTING narrow contracts — it deliberately does not
|
|
14
|
+
* collapse them into one catch-all domain API. A host may implement each port
|
|
15
|
+
* over one SQLite database, but PS Lite keeps addressing them by their narrow
|
|
16
|
+
* responsibilities (data storage, key/value state, tokens, access logs, MCP
|
|
17
|
+
* connection/authorization records, relay TLS identity).
|
|
18
|
+
*
|
|
19
|
+
* `relayTlsIdentity` is consumed by the relay TLS factory
|
|
20
|
+
* (`createRustlsPsLiteRelayTlsFactory`), not the HTTP runtime. The start
|
|
21
|
+
* factory forwards it to the relay automatically. A supplied bundle is all or
|
|
22
|
+
* nothing: hosts must not accidentally combine native and browser persistence.
|
|
23
|
+
*/
|
|
24
|
+
export interface PsLitePersistenceBundle {
|
|
25
|
+
/** Data envelopes + index metadata. */
|
|
26
|
+
storage: DataStoragePort;
|
|
27
|
+
/** Key/value runtime state: config, encrypted server identity, relay, cursor. */
|
|
28
|
+
state: PsLiteStateStore;
|
|
29
|
+
/** Session/device access tokens. */
|
|
30
|
+
tokens: PsLiteTokenStore;
|
|
31
|
+
/** Access-log read + write. */
|
|
32
|
+
accessLog: AccessLogReader & AccessLogWriter;
|
|
33
|
+
/** Per-connection MCP records (grantee key, token hash, grants). */
|
|
34
|
+
mcpConnections: McpConnectionStore;
|
|
35
|
+
/** In-flight MCP OAuth authorization records. */
|
|
36
|
+
mcpOAuthAuthorizations: McpOAuthAuthorizationStore;
|
|
37
|
+
/** Issued relay TLS identity cache. Consumed by the relay TLS factory. */
|
|
38
|
+
relayTlsIdentity: PsLiteRelayTlsIdentityStore;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The subset of {@link PsLiteRuntimeOptions} that a persistence bundle supplies.
|
|
42
|
+
* Everything a caller still owns (auth, identity, gateway, signer, config
|
|
43
|
+
* values, sync manager) stays out of the bundle.
|
|
44
|
+
*/
|
|
45
|
+
export type PsLitePersistenceRuntimeOptions = Pick<PsLiteRuntimeOptions, "storage" | "tokenStore" | "accessLogReader" | "accessLogWriter" | "saveConfig" | "mcpConnectionStore" | "mcpOAuthAuthorizationStore"> & Required<Pick<PsLiteRuntimeOptions, "config">>;
|
|
46
|
+
/**
|
|
47
|
+
* Map a {@link PsLitePersistenceBundle} onto the runtime option subset it backs,
|
|
48
|
+
* so a host can construct PS Lite with no direct browser storage dependency:
|
|
49
|
+
*
|
|
50
|
+
* ```ts
|
|
51
|
+
* const runtime = createPsLiteRuntime({
|
|
52
|
+
* ...(await psLitePersistenceRuntimeOptions(bundle, configDefaults)),
|
|
53
|
+
* auth,
|
|
54
|
+
* identity,
|
|
55
|
+
* serverOwner,
|
|
56
|
+
* active: true,
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* `saveConfig` is derived from the injected state store via the existing
|
|
61
|
+
* `savePsLiteConfig` contract, so config writes land in the host's store.
|
|
62
|
+
*/
|
|
63
|
+
export declare function psLitePersistenceRuntimeOptions(bundle: PsLitePersistenceBundle, configDefaults?: Partial<ServerConfig>): Promise<PsLitePersistenceRuntimeOptions>;
|
|
64
|
+
/**
|
|
65
|
+
* Defends the all-or-nothing bundle contract at the JavaScript boundary, where
|
|
66
|
+
* TypeScript's required properties are not enforced.
|
|
67
|
+
*/
|
|
68
|
+
export declare function assertCompletePsLitePersistenceBundle(bundle: PsLitePersistenceBundle | null | undefined): void;
|
|
69
|
+
//# sourceMappingURL=persistence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AACnF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+CAA+C,CAAC;AAClF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6DAA6D,CAAC;AACnG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0DAA0D,CAAC;AAChG,OAAO,KAAK,EACV,kBAAkB,EAClB,0BAA0B,EAC3B,MAAM,2CAA2C,CAAC;AACnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAElE;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,uBAAuB;IACtC,uCAAuC;IACvC,OAAO,EAAE,eAAe,CAAC;IACzB,iFAAiF;IACjF,KAAK,EAAE,gBAAgB,CAAC;IACxB,oCAAoC;IACpC,MAAM,EAAE,gBAAgB,CAAC;IACzB,+BAA+B;IAC/B,SAAS,EAAE,eAAe,GAAG,eAAe,CAAC;IAC7C,oEAAoE;IACpE,cAAc,EAAE,kBAAkB,CAAC;IACnC,iDAAiD;IACjD,sBAAsB,EAAE,0BAA0B,CAAC;IACnD,0EAA0E;IAC1E,gBAAgB,EAAE,2BAA2B,CAAC;CAC/C;AAED;;;;GAIG;AACH,MAAM,MAAM,+BAA+B,GAAG,IAAI,CAChD,oBAAoB,EAClB,SAAS,GACT,YAAY,GACZ,iBAAiB,GACjB,iBAAiB,GACjB,YAAY,GACZ,oBAAoB,GACpB,4BAA4B,CAC/B,GACC,QAAQ,CAAC,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEjD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,uBAAuB,EAC/B,cAAc,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GACrC,OAAO,CAAC,+BAA+B,CAAC,CAgB1C;AAED;;;GAGG;AACH,wBAAgB,qCAAqC,CACnD,MAAM,EAAE,uBAAuB,GAAG,IAAI,GAAG,SAAS,GACjD,IAAI,CAmBN"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { loadOrCreatePsLiteConfig, savePsLiteConfig, } from "./state.js";
|
|
2
|
+
/**
|
|
3
|
+
* Map a {@link PsLitePersistenceBundle} onto the runtime option subset it backs,
|
|
4
|
+
* so a host can construct PS Lite with no direct browser storage dependency:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* const runtime = createPsLiteRuntime({
|
|
8
|
+
* ...(await psLitePersistenceRuntimeOptions(bundle, configDefaults)),
|
|
9
|
+
* auth,
|
|
10
|
+
* identity,
|
|
11
|
+
* serverOwner,
|
|
12
|
+
* active: true,
|
|
13
|
+
* });
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* `saveConfig` is derived from the injected state store via the existing
|
|
17
|
+
* `savePsLiteConfig` contract, so config writes land in the host's store.
|
|
18
|
+
*/
|
|
19
|
+
export async function psLitePersistenceRuntimeOptions(bundle, configDefaults) {
|
|
20
|
+
assertCompletePsLitePersistenceBundle(bundle);
|
|
21
|
+
const config = await loadOrCreatePsLiteConfig(bundle.state, configDefaults);
|
|
22
|
+
return {
|
|
23
|
+
storage: bundle.storage,
|
|
24
|
+
config,
|
|
25
|
+
tokenStore: bundle.tokens,
|
|
26
|
+
accessLogReader: bundle.accessLog,
|
|
27
|
+
accessLogWriter: bundle.accessLog,
|
|
28
|
+
saveConfig: async (nextConfig) => {
|
|
29
|
+
const saved = await savePsLiteConfig(bundle.state, nextConfig);
|
|
30
|
+
Object.assign(config, saved);
|
|
31
|
+
},
|
|
32
|
+
mcpConnectionStore: bundle.mcpConnections,
|
|
33
|
+
mcpOAuthAuthorizationStore: bundle.mcpOAuthAuthorizations,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Defends the all-or-nothing bundle contract at the JavaScript boundary, where
|
|
38
|
+
* TypeScript's required properties are not enforced.
|
|
39
|
+
*/
|
|
40
|
+
export function assertCompletePsLitePersistenceBundle(bundle) {
|
|
41
|
+
if (!bundle || typeof bundle !== "object") {
|
|
42
|
+
throw new Error("PS Lite persistence bundle must be a complete object");
|
|
43
|
+
}
|
|
44
|
+
const required = [
|
|
45
|
+
"storage",
|
|
46
|
+
"state",
|
|
47
|
+
"tokens",
|
|
48
|
+
"accessLog",
|
|
49
|
+
"mcpConnections",
|
|
50
|
+
"mcpOAuthAuthorizations",
|
|
51
|
+
"relayTlsIdentity",
|
|
52
|
+
];
|
|
53
|
+
const missing = required.filter((key) => bundle[key] == null);
|
|
54
|
+
if (missing.length > 0) {
|
|
55
|
+
throw new Error(`PS Lite persistence bundle must be complete; missing ${missing.join(", ")}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=persistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence.js","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"AASA,OAAO,EACL,wBAAwB,EACxB,gBAAgB,GAEjB,MAAM,YAAY,CAAC;AAoDpB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,MAA+B,EAC/B,cAAsC;IAEtC,qCAAqC,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAAC,MAAM,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;IAC5E,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM;QACN,UAAU,EAAE,MAAM,CAAC,MAAM;QACzB,eAAe,EAAE,MAAM,CAAC,SAAS;QACjC,eAAe,EAAE,MAAM,CAAC,SAAS;QACjC,UAAU,EAAE,KAAK,EAAE,UAAmB,EAAE,EAAE;YACxC,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;YAC/D,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,kBAAkB,EAAE,MAAM,CAAC,cAAc;QACzC,0BAA0B,EAAE,MAAM,CAAC,sBAAsB;KAC1D,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qCAAqC,CACnD,MAAkD;IAElD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,QAAQ,GAAsC;QAClD,SAAS;QACT,OAAO;QACP,QAAQ;QACR,WAAW;QACX,gBAAgB;QAChB,wBAAwB;QACxB,kBAAkB;KACnB,CAAC;IACF,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC;IAC9D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,wDAAwD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC7E,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { PsLiteRelayTlsFactory } from "./relay.js";
|
|
2
|
+
/**
|
|
3
|
+
* Persistence port for the relay's issued TLS identity. PS Lite runtime code
|
|
4
|
+
* resolves the cached cert through this injected store instead of reaching for
|
|
5
|
+
* `globalThis.localStorage` directly, so a non-browser host (Mobile) can back
|
|
6
|
+
* it with app-private storage. Browser callers get the localStorage-backed
|
|
7
|
+
* default via {@link createLocalStoragePsLiteRelayTlsIdentityStore}.
|
|
8
|
+
*/
|
|
9
|
+
export interface PsLiteRelayTlsIdentityStore {
|
|
10
|
+
read(hostname: string): Promise<PsLiteRelayTlsIdentity | null> | PsLiteRelayTlsIdentity | null;
|
|
11
|
+
write(identity: PsLiteRelayTlsIdentity): Promise<void> | void;
|
|
12
|
+
}
|
|
13
|
+
export interface RustlsPsLiteRelayTlsOptions {
|
|
14
|
+
controlUrl: string;
|
|
15
|
+
publicSuffix?: string;
|
|
16
|
+
certIssuerUrl?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Injected persistence for the issued relay TLS identity. Omit to fall back
|
|
19
|
+
* to {@link storage} (or, if that is also omitted, the browser localStorage
|
|
20
|
+
* default). Non-browser hosts pass their own store to keep runtime code free
|
|
21
|
+
* of hidden `globalThis` access.
|
|
22
|
+
*/
|
|
23
|
+
identityStore?: PsLiteRelayTlsIdentityStore;
|
|
24
|
+
/**
|
|
25
|
+
* @deprecated Prefer {@link identityStore}. A raw `Storage` is wrapped by
|
|
26
|
+
* {@link createLocalStoragePsLiteRelayTlsIdentityStore}. Retained so existing
|
|
27
|
+
* browser callers keep their exact localStorage behavior.
|
|
28
|
+
*/
|
|
29
|
+
storage?: Storage;
|
|
30
|
+
logger?: (line: string) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Max time to wait on the relay's certificate endpoint before treating this
|
|
33
|
+
* attempt as failed and serving the self-signed fallback. A hung issuer
|
|
34
|
+
* (observed live, BUI-666: the endpoint accepts the POST and never responds)
|
|
35
|
+
* would otherwise leave the identity promise pending forever — and every
|
|
36
|
+
* incoming TLS handshake awaits that promise, so the public endpoint serves
|
|
37
|
+
* zero bytes while the control session looks healthy.
|
|
38
|
+
*
|
|
39
|
+
* Default 60s. This preserves the old per-session ACME margin and is still
|
|
40
|
+
* bounded for a truly wedged relay endpoint.
|
|
41
|
+
*/
|
|
42
|
+
issueCertTimeoutMs?: number;
|
|
43
|
+
}
|
|
44
|
+
export interface PsLiteRelayTlsIdentity {
|
|
45
|
+
certPem: string;
|
|
46
|
+
keyPem: string;
|
|
47
|
+
hostname: string;
|
|
48
|
+
source: "acme" | "self-signed" | "cached-acme";
|
|
49
|
+
trusted: boolean;
|
|
50
|
+
}
|
|
51
|
+
export declare function createRustlsPsLiteRelayTlsFactory(options: RustlsPsLiteRelayTlsOptions): PsLiteRelayTlsFactory;
|
|
52
|
+
export declare function psLiteRelayPublicHost(sessionId: string, publicSuffix?: string): string;
|
|
53
|
+
export declare function psLiteRelayPublicUrl(sessionId: string, publicSuffix?: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Browser default relay TLS identity store: persists the issued cert in
|
|
56
|
+
* `localStorage`, matching PS Lite's pre-injection behavior byte for byte. This
|
|
57
|
+
* is the one place the relay TLS path is allowed to touch a browser global; the
|
|
58
|
+
* resolution logic above goes through the injected {@link PsLiteRelayTlsIdentityStore}.
|
|
59
|
+
*/
|
|
60
|
+
export declare function createLocalStoragePsLiteRelayTlsIdentityStore(storage?: Storage): PsLiteRelayTlsIdentityStore;
|
|
61
|
+
//# sourceMappingURL=relay-tls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay-tls.d.ts","sourceRoot":"","sources":["../src/relay-tls.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,qBAAqB,EAKtB,MAAM,YAAY,CAAC;AAMpB;;;;;;GAMG;AACH,MAAM,WAAW,2BAA2B;IAC1C,IAAI,CACF,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,GAAG,sBAAsB,GAAG,IAAI,CAAC;IAC1E,KAAK,CAAC,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC/D;AAED,MAAM,WAAW,2BAA2B;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,2BAA2B,CAAC;IAC5C;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC;;;;;;;;;;OAUG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,aAAa,CAAC;IAC/C,OAAO,EAAE,OAAO,CAAC;CAClB;AAID,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,2BAA2B,GACnC,qBAAqB,CA4EvB;AAED,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,YAAY,SAAwB,GACnC,MAAM,CAER;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,YAAY,SAAwB,GACnC,MAAM,CAER;AA2PD;;;;;GAKG;AACH,wBAAgB,6CAA6C,CAC3D,OAAO,GAAE,OAAiC,GACzC,2BAA2B,CAa7B"}
|