@mnemosyne_os/sdk 1.0.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/README.md +233 -0
- package/dist/index.cjs +530 -0
- package/dist/index.d.cts +443 -0
- package/dist/index.d.ts +443 -0
- package/dist/index.js +479 -0
- package/package.json +51 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
import WebSocket from "ws";
|
|
3
|
+
|
|
4
|
+
// src/manifest.ts
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { readFileSync } from "fs";
|
|
7
|
+
import { resolve } from "path";
|
|
8
|
+
var VALID_SCOPES = [
|
|
9
|
+
"vault:read:DEV",
|
|
10
|
+
"vault:write:DEV",
|
|
11
|
+
"vault:read:SOCIAL",
|
|
12
|
+
"vault:write:SOCIAL",
|
|
13
|
+
"vault:read:PERSONAL",
|
|
14
|
+
"vault:write:PERSONAL",
|
|
15
|
+
"vault:read:FINANCE",
|
|
16
|
+
"vault:write:FINANCE",
|
|
17
|
+
"vault:read:COOK",
|
|
18
|
+
"vault:write:COOK",
|
|
19
|
+
"share:request",
|
|
20
|
+
"share:grant"
|
|
21
|
+
];
|
|
22
|
+
var VALID_INTENTS = ["INGEST", "QUERY", "CORRELATE", "FORGET"];
|
|
23
|
+
var VALID_VAULTS = ["DEV", "SOCIAL", "PERSONAL", "FINANCE", "COOK"];
|
|
24
|
+
var SEMVER_RE = /^\d+\.\d+\.\d+/;
|
|
25
|
+
var APP_ID_RE = /^[a-z0-9][a-z0-9_-]{1,63}$/;
|
|
26
|
+
var AppManifestSchema = z.object({
|
|
27
|
+
id: z.string().regex(APP_ID_RE, {
|
|
28
|
+
message: "id must be lowercase alphanumeric with hyphens/underscores, 2-64 chars"
|
|
29
|
+
}),
|
|
30
|
+
name: z.string().min(2).max(64),
|
|
31
|
+
version: z.string().regex(SEMVER_RE, { message: "version must be SemVer (e.g. 1.0.0)" }),
|
|
32
|
+
author: z.string().max(64).optional(),
|
|
33
|
+
mnemosyne_sdk: z.string().regex(/^\^?\d+\.\d+\.\d+/, {
|
|
34
|
+
message: "mnemosyne_sdk must be a SemVer range (e.g. ^1.0.0)"
|
|
35
|
+
}),
|
|
36
|
+
scopes: z.array(z.enum(VALID_SCOPES)).min(1, {
|
|
37
|
+
message: "At least one scope required \u2014 apps with no scopes have no access"
|
|
38
|
+
}),
|
|
39
|
+
vaults: z.array(z.enum(VALID_VAULTS)).min(1),
|
|
40
|
+
intents: z.array(z.enum(VALID_INTENTS)).min(1),
|
|
41
|
+
max_chronicle_size_kb: z.number().int().min(1).max(1024).optional().default(64),
|
|
42
|
+
requires_consent: z.boolean().optional().default(false),
|
|
43
|
+
description: z.string().max(256).optional()
|
|
44
|
+
}).strict();
|
|
45
|
+
function loadManifest(pathOrManifest) {
|
|
46
|
+
if (typeof pathOrManifest === "string") {
|
|
47
|
+
const absPath = resolve(pathOrManifest);
|
|
48
|
+
let raw;
|
|
49
|
+
try {
|
|
50
|
+
raw = JSON.parse(readFileSync(absPath, "utf-8"));
|
|
51
|
+
} catch {
|
|
52
|
+
throw new Error(`[MnemoSDK] Cannot read manifest at: ${absPath}`);
|
|
53
|
+
}
|
|
54
|
+
return parseManifest(raw);
|
|
55
|
+
}
|
|
56
|
+
return parseManifest(pathOrManifest);
|
|
57
|
+
}
|
|
58
|
+
function parseManifest(raw) {
|
|
59
|
+
const result = AppManifestSchema.safeParse(raw);
|
|
60
|
+
if (!result.success) {
|
|
61
|
+
const issues = result.error.issues.map((i) => ` \u2022 ${i.path.join(".")}: ${i.message}`).join("\n");
|
|
62
|
+
throw new Error(`[MnemoSDK] Invalid app.manifest.json:
|
|
63
|
+
${issues}`);
|
|
64
|
+
}
|
|
65
|
+
return result.data;
|
|
66
|
+
}
|
|
67
|
+
function assertScope(manifest, scope) {
|
|
68
|
+
if (!manifest.scopes.includes(scope)) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`[MnemoSDK] Scope "${scope}" not declared in manifest for app "${manifest.id}". Add it to manifest.scopes to request this permission.`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function assertVault(manifest, vault) {
|
|
75
|
+
if (!manifest.vaults.includes(vault)) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`[MnemoSDK] Vault "${vault}" not in manifest.vaults for app "${manifest.id}".`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/jwt.ts
|
|
83
|
+
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
84
|
+
function b64url(input) {
|
|
85
|
+
const buf = typeof input === "string" ? Buffer.from(input, "utf8") : input;
|
|
86
|
+
return buf.toString("base64url");
|
|
87
|
+
}
|
|
88
|
+
function parseB64url(input) {
|
|
89
|
+
return Buffer.from(input, "base64url").toString("utf8");
|
|
90
|
+
}
|
|
91
|
+
var HEADER = b64url(JSON.stringify({ alg: "HS256", typ: "JWT" }));
|
|
92
|
+
function signToken(payload, secret) {
|
|
93
|
+
const payloadB64 = b64url(JSON.stringify(payload));
|
|
94
|
+
const data = `${HEADER}.${payloadB64}`;
|
|
95
|
+
const sig = createHmac("sha256", secret).update(data).digest();
|
|
96
|
+
return `${data}.${b64url(sig)}`;
|
|
97
|
+
}
|
|
98
|
+
function verifyToken(token, secret) {
|
|
99
|
+
const parts = token.split(".");
|
|
100
|
+
if (parts.length !== 3) {
|
|
101
|
+
return { valid: false, reason: "MALFORMED_TOKEN" };
|
|
102
|
+
}
|
|
103
|
+
const [headerB64, payloadB64, sigB64] = parts;
|
|
104
|
+
const data = `${headerB64}.${payloadB64}`;
|
|
105
|
+
const expectedSig = createHmac("sha256", secret).update(data).digest();
|
|
106
|
+
const actualSig = Buffer.from(sigB64, "base64url");
|
|
107
|
+
if (expectedSig.length !== actualSig.length || !timingSafeEqual(expectedSig, actualSig)) {
|
|
108
|
+
return { valid: false, reason: "INVALID_SIGNATURE" };
|
|
109
|
+
}
|
|
110
|
+
let payload;
|
|
111
|
+
try {
|
|
112
|
+
payload = JSON.parse(parseB64url(payloadB64));
|
|
113
|
+
} catch {
|
|
114
|
+
return { valid: false, reason: "MALFORMED_PAYLOAD" };
|
|
115
|
+
}
|
|
116
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
117
|
+
if (payload.exp < now) {
|
|
118
|
+
return { valid: false, reason: "TOKEN_EXPIRED" };
|
|
119
|
+
}
|
|
120
|
+
return { valid: true, payload };
|
|
121
|
+
}
|
|
122
|
+
function generateAppToken(appId, scopes, secret, ttlMs = 24 * 60 * 60 * 1e3) {
|
|
123
|
+
const iat = Math.floor(Date.now() / 1e3);
|
|
124
|
+
const exp = Math.floor((Date.now() + ttlMs) / 1e3);
|
|
125
|
+
const payload = {
|
|
126
|
+
sub: appId,
|
|
127
|
+
iat,
|
|
128
|
+
exp,
|
|
129
|
+
scopes,
|
|
130
|
+
jti: randomBytes(16).toString("hex")
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
token: signToken(payload, secret),
|
|
134
|
+
expiresAt: exp * 1e3
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function generateSecret() {
|
|
138
|
+
return randomBytes(32).toString("hex");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/client.ts
|
|
142
|
+
var MnemoClient = class _MnemoClient {
|
|
143
|
+
manifest;
|
|
144
|
+
options;
|
|
145
|
+
ws = null;
|
|
146
|
+
token = null;
|
|
147
|
+
connected = false;
|
|
148
|
+
pending = /* @__PURE__ */ new Map();
|
|
149
|
+
handlers = /* @__PURE__ */ new Map();
|
|
150
|
+
// ── Static factory ──────────────────────────────────────────────────────────
|
|
151
|
+
/**
|
|
152
|
+
* Crée et connecte un client Mnemosyne.
|
|
153
|
+
* @throws si le manifest est invalide ou la connexion échoue
|
|
154
|
+
*/
|
|
155
|
+
static async connect(options) {
|
|
156
|
+
const client = new _MnemoClient(options);
|
|
157
|
+
await client._connect();
|
|
158
|
+
return client;
|
|
159
|
+
}
|
|
160
|
+
constructor(options) {
|
|
161
|
+
this.manifest = loadManifest(options.manifest);
|
|
162
|
+
this.options = {
|
|
163
|
+
appId: options.appId,
|
|
164
|
+
manifest: options.manifest,
|
|
165
|
+
transport: options.transport ?? "auto",
|
|
166
|
+
wsPort: options.wsPort ?? 7799,
|
|
167
|
+
token: options.token ?? "",
|
|
168
|
+
timeoutMs: options.timeoutMs ?? 3e4
|
|
169
|
+
};
|
|
170
|
+
if (this.options.appId !== this.manifest.id) {
|
|
171
|
+
throw new Error(
|
|
172
|
+
`[MnemoSDK] appId "${this.options.appId}" does not match manifest.id "${this.manifest.id}"`
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// ── Connection ──────────────────────────────────────────────────────────────
|
|
177
|
+
async _connect() {
|
|
178
|
+
const transport = this._resolveTransport();
|
|
179
|
+
if (transport === "ws") {
|
|
180
|
+
await this._connectWs();
|
|
181
|
+
} else {
|
|
182
|
+
this._connectIpc();
|
|
183
|
+
}
|
|
184
|
+
if (!this.options.token) {
|
|
185
|
+
const reg = await this._register();
|
|
186
|
+
this.token = reg.token;
|
|
187
|
+
} else {
|
|
188
|
+
this.token = this.options.token;
|
|
189
|
+
}
|
|
190
|
+
this.connected = true;
|
|
191
|
+
this._emit("connected", { appId: this.manifest.id });
|
|
192
|
+
console.log(`[MnemoSDK] \u2713 Connected as "${this.manifest.id}" via ${transport}`);
|
|
193
|
+
}
|
|
194
|
+
_resolveTransport() {
|
|
195
|
+
if (this.options.transport === "ipc") return "ipc";
|
|
196
|
+
if (this.options.transport === "ws") return "ws";
|
|
197
|
+
const hasIpc = typeof globalThis !== "undefined" && typeof globalThis["window"] !== "undefined" && typeof globalThis["window"]["mnemosyne"] !== "undefined";
|
|
198
|
+
return hasIpc ? "ipc" : "ws";
|
|
199
|
+
}
|
|
200
|
+
_connectWs() {
|
|
201
|
+
return new Promise((resolve2, reject) => {
|
|
202
|
+
const url = `ws://localhost:${this.options.wsPort}`;
|
|
203
|
+
this.ws = new WebSocket(url);
|
|
204
|
+
const timeout = setTimeout(() => {
|
|
205
|
+
this.ws?.terminate();
|
|
206
|
+
reject(new Error(`[MnemoSDK] Connection timeout to ${url}`));
|
|
207
|
+
}, this.options.timeoutMs);
|
|
208
|
+
this.ws.on("open", () => {
|
|
209
|
+
clearTimeout(timeout);
|
|
210
|
+
resolve2();
|
|
211
|
+
});
|
|
212
|
+
this.ws.on("message", (raw) => {
|
|
213
|
+
try {
|
|
214
|
+
const msg = JSON.parse(raw.toString());
|
|
215
|
+
if ("id" in msg) {
|
|
216
|
+
this._handleRpcResponse(msg);
|
|
217
|
+
} else if ("type" in msg) {
|
|
218
|
+
this._handleEvent(msg);
|
|
219
|
+
}
|
|
220
|
+
} catch {
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
this.ws.on("error", (err) => {
|
|
224
|
+
this._emit("error", { message: err.message });
|
|
225
|
+
});
|
|
226
|
+
this.ws.on("close", () => {
|
|
227
|
+
this.connected = false;
|
|
228
|
+
this._emit("disconnected", {});
|
|
229
|
+
for (const [, p] of this.pending) {
|
|
230
|
+
clearTimeout(p.timer);
|
|
231
|
+
p.reject(new Error("[MnemoSDK] WebSocket disconnected"));
|
|
232
|
+
}
|
|
233
|
+
this.pending.clear();
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
_connectIpc() {
|
|
238
|
+
this.connected = true;
|
|
239
|
+
}
|
|
240
|
+
// ── RPC layer ───────────────────────────────────────────────────────────────
|
|
241
|
+
async _rpc(method, params) {
|
|
242
|
+
if (!this.connected && method !== "sdk.register") {
|
|
243
|
+
throw new Error("[MnemoSDK] Client not connected. Call MnemoClient.connect() first.");
|
|
244
|
+
}
|
|
245
|
+
if (this._resolveTransport() === "ipc") {
|
|
246
|
+
return this._rpcIpc(method, params);
|
|
247
|
+
}
|
|
248
|
+
return this._rpcWs(method, params);
|
|
249
|
+
}
|
|
250
|
+
_rpcWs(method, params) {
|
|
251
|
+
return new Promise((resolve2, reject) => {
|
|
252
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
253
|
+
return reject(new Error("[MnemoSDK] WebSocket not open"));
|
|
254
|
+
}
|
|
255
|
+
const id = Math.random().toString(36).slice(2);
|
|
256
|
+
const req = { id, method, params, ...this.token ? { token: this.token } : {} };
|
|
257
|
+
const timer = setTimeout(() => {
|
|
258
|
+
this.pending.delete(id);
|
|
259
|
+
reject(new Error(`[MnemoSDK] RPC timeout: ${method}`));
|
|
260
|
+
}, this.options.timeoutMs);
|
|
261
|
+
this.pending.set(id, {
|
|
262
|
+
resolve: (v) => resolve2(v),
|
|
263
|
+
reject,
|
|
264
|
+
timer
|
|
265
|
+
});
|
|
266
|
+
this.ws.send(JSON.stringify(req));
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
async _rpcIpc(method, params) {
|
|
270
|
+
const mnemo = globalThis["window"];
|
|
271
|
+
if (!mnemo?.mnemosyne) {
|
|
272
|
+
throw new Error("[MnemoSDK] IPC transport: window.mnemosyne not available");
|
|
273
|
+
}
|
|
274
|
+
const ipcMap = {
|
|
275
|
+
"sdk.register": "registerApp",
|
|
276
|
+
"sdk.ingest": "sendPulse",
|
|
277
|
+
"sdk.query": "sendPulse",
|
|
278
|
+
"sdk.correlate": "sendPulse",
|
|
279
|
+
"sdk.share": "requestCrossAppShare",
|
|
280
|
+
"sdk.nft.validate": "validateNFTLicense",
|
|
281
|
+
"sdk.graph.query": "queryNeuralGraph"
|
|
282
|
+
};
|
|
283
|
+
const ipcMethod = ipcMap[method];
|
|
284
|
+
if (!ipcMethod || !mnemo.mnemosyne[ipcMethod]) {
|
|
285
|
+
throw new Error(`[MnemoSDK] IPC method not found for: ${method}`);
|
|
286
|
+
}
|
|
287
|
+
return mnemo.mnemosyne[ipcMethod](params);
|
|
288
|
+
}
|
|
289
|
+
_handleRpcResponse(msg) {
|
|
290
|
+
const p = this.pending.get(msg.id);
|
|
291
|
+
if (!p) return;
|
|
292
|
+
clearTimeout(p.timer);
|
|
293
|
+
this.pending.delete(msg.id);
|
|
294
|
+
if (msg.error) {
|
|
295
|
+
p.reject(new Error(msg.error));
|
|
296
|
+
} else {
|
|
297
|
+
p.resolve(msg.result);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
_handleEvent(event) {
|
|
301
|
+
this._emit(event.type, event.data);
|
|
302
|
+
}
|
|
303
|
+
// ── Auth ────────────────────────────────────────────────────────────────────
|
|
304
|
+
async _register() {
|
|
305
|
+
return this._rpc("sdk.register", {
|
|
306
|
+
manifest: this.manifest
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Renouvelle le token JWT avant expiration.
|
|
311
|
+
* Appelé automatiquement si le token expire dans moins de 5 minutes.
|
|
312
|
+
*/
|
|
313
|
+
async renewToken() {
|
|
314
|
+
const reg = await this._register();
|
|
315
|
+
this.token = reg.token;
|
|
316
|
+
console.log(`[MnemoSDK] Token renewed for "${this.manifest.id}", expires: ${new Date(reg.expiresAt).toISOString()}`);
|
|
317
|
+
}
|
|
318
|
+
// ── Public API ──────────────────────────────────────────────────────────────
|
|
319
|
+
/**
|
|
320
|
+
* Ingère du contenu dans le vault Mnemosyne.
|
|
321
|
+
* Isolé par source_app_id — seule ton app peut lire ce qu'elle écrit.
|
|
322
|
+
*/
|
|
323
|
+
async ingest(payload) {
|
|
324
|
+
assertScope(this.manifest, `vault:write:${payload.vault}`);
|
|
325
|
+
assertVault(this.manifest, payload.vault);
|
|
326
|
+
if (!this.manifest.intents.includes("INGEST")) {
|
|
327
|
+
throw new Error('[MnemoSDK] Intent "INGEST" not declared in manifest');
|
|
328
|
+
}
|
|
329
|
+
const maxBytes = (this.manifest.max_chronicle_size_kb ?? 64) * 1024;
|
|
330
|
+
if (new TextEncoder().encode(payload.content).length > maxBytes) {
|
|
331
|
+
throw new Error(`[MnemoSDK] Content exceeds max_chronicle_size_kb (${this.manifest.max_chronicle_size_kb}KB)`);
|
|
332
|
+
}
|
|
333
|
+
return this._rpc("sdk.ingest", {
|
|
334
|
+
appId: this.manifest.id,
|
|
335
|
+
...payload
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Requête sémantique — retourne uniquement les chronicles de ton app (source_app_id isolation).
|
|
340
|
+
*/
|
|
341
|
+
async query(text, options = {}) {
|
|
342
|
+
const vault = options.vault ?? this.manifest.vaults[0];
|
|
343
|
+
assertScope(this.manifest, `vault:read:${vault}`);
|
|
344
|
+
if (!this.manifest.intents.includes("QUERY")) {
|
|
345
|
+
throw new Error('[MnemoSDK] Intent "QUERY" not declared in manifest');
|
|
346
|
+
}
|
|
347
|
+
return this._rpc("sdk.query", {
|
|
348
|
+
appId: this.manifest.id,
|
|
349
|
+
text,
|
|
350
|
+
vault,
|
|
351
|
+
limit: options.limit ?? 10,
|
|
352
|
+
threshold: options.threshold ?? 0
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Demande un accès aux chronicles d'une autre app.
|
|
357
|
+
* Déclenche un popup de consentement utilisateur dans Mnemosyne OS.
|
|
358
|
+
* Timeout : 60s par défaut (configurable).
|
|
359
|
+
*/
|
|
360
|
+
async requestShare(request) {
|
|
361
|
+
assertScope(this.manifest, "share:request");
|
|
362
|
+
return this._rpc("sdk.share", {
|
|
363
|
+
requestingAppId: this.manifest.id,
|
|
364
|
+
fromAppId: request.fromAppId,
|
|
365
|
+
reason: request.reason,
|
|
366
|
+
timeoutMs: request.timeoutMs ?? 6e4
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
// ── Events ──────────────────────────────────────────────────────────────────
|
|
370
|
+
on(type, handler) {
|
|
371
|
+
if (!this.handlers.has(type)) {
|
|
372
|
+
this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
373
|
+
}
|
|
374
|
+
this.handlers.get(type).add(handler);
|
|
375
|
+
return () => this.handlers.get(type)?.delete(handler);
|
|
376
|
+
}
|
|
377
|
+
_emit(type, data) {
|
|
378
|
+
const set = this.handlers.get(type);
|
|
379
|
+
if (!set) return;
|
|
380
|
+
const event = { type, data, timestamp: Date.now() };
|
|
381
|
+
for (const h of set) h(event);
|
|
382
|
+
}
|
|
383
|
+
// ── Lifecycle ───────────────────────────────────────────────────────────────
|
|
384
|
+
/**
|
|
385
|
+
* Ferme proprement la connexion.
|
|
386
|
+
* Attend la résolution de tous les RPC en cours.
|
|
387
|
+
*/
|
|
388
|
+
async disconnect() {
|
|
389
|
+
this.connected = false;
|
|
390
|
+
if (this.ws) {
|
|
391
|
+
this.ws.close(1e3, "Client disconnect");
|
|
392
|
+
this.ws = null;
|
|
393
|
+
}
|
|
394
|
+
for (const [, p] of this.pending) {
|
|
395
|
+
clearTimeout(p.timer);
|
|
396
|
+
p.reject(new Error("[MnemoSDK] Client disconnected"));
|
|
397
|
+
}
|
|
398
|
+
this.pending.clear();
|
|
399
|
+
console.log(`[MnemoSDK] Disconnected: "${this.manifest.id}"`);
|
|
400
|
+
}
|
|
401
|
+
get isConnected() {
|
|
402
|
+
return this.connected;
|
|
403
|
+
}
|
|
404
|
+
get appId() {
|
|
405
|
+
return this.manifest.id;
|
|
406
|
+
}
|
|
407
|
+
get appManifest() {
|
|
408
|
+
return { ...this.manifest };
|
|
409
|
+
}
|
|
410
|
+
/** Inspecte le token actuel (décodé, sans vérification) */
|
|
411
|
+
get tokenInfo() {
|
|
412
|
+
if (!this.token) return null;
|
|
413
|
+
try {
|
|
414
|
+
const [, payloadB64] = this.token.split(".");
|
|
415
|
+
if (!payloadB64) return null;
|
|
416
|
+
return JSON.parse(Buffer.from(payloadB64, "base64url").toString("utf8"));
|
|
417
|
+
} catch {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
// src/constants.ts
|
|
424
|
+
var MNEMOSYNE_METHODS = {
|
|
425
|
+
// ── Auth ──────────────────────────────────────────────────────────────────
|
|
426
|
+
/** Enregistre l'app, valide le manifest, retourne un JWT 24h */
|
|
427
|
+
REGISTER: "sdk.register",
|
|
428
|
+
// ── Vault ─────────────────────────────────────────────────────────────────
|
|
429
|
+
/** Ingère du contenu dans le vault (vectorisation incluse) */
|
|
430
|
+
INGEST: "sdk.ingest",
|
|
431
|
+
/** Requête sémantique — résultats filtrés par source_app_id */
|
|
432
|
+
QUERY: "sdk.query",
|
|
433
|
+
/** Trouve les connexions causales entre deux contenus */
|
|
434
|
+
CORRELATE: "sdk.correlate",
|
|
435
|
+
/** Supprime un chronicle par ID (scope vault:write requis) */
|
|
436
|
+
FORGET: "sdk.forget",
|
|
437
|
+
// ── Cross-App ─────────────────────────────────────────────────────────────
|
|
438
|
+
/** Demande d'accès aux chronicles d'une autre app (popup consentement) */
|
|
439
|
+
SHARE: "sdk.share",
|
|
440
|
+
// ── NFT Licence ───────────────────────────────────────────────────────────
|
|
441
|
+
/**
|
|
442
|
+
* Vérifie qu'un wallet possède le NFT de licence de cette app.
|
|
443
|
+
* Requiert le scope `nft:validate` dans le manifest.
|
|
444
|
+
* Cache TTL 5 min côté OS pour ne pas spam la blockchain.
|
|
445
|
+
*/
|
|
446
|
+
NFT_VALIDATE: "sdk.nft.validate",
|
|
447
|
+
// ── NeuralGraph ───────────────────────────────────────────────────────────
|
|
448
|
+
/**
|
|
449
|
+
* Requête le NeuralGraph — retourne les nœuds et arêtes proches du texte.
|
|
450
|
+
* Requiert le scope `neural:graph:read` dans le manifest.
|
|
451
|
+
*/
|
|
452
|
+
GRAPH_QUERY: "sdk.graph.query"
|
|
453
|
+
};
|
|
454
|
+
var MNEMOSYNE_WS_PORT = 7799;
|
|
455
|
+
var MNEMOSYNE_WS_HOST = "127.0.0.1";
|
|
456
|
+
var MNEMOSYNE_TOKEN_TTL_S = 24 * 60 * 60;
|
|
457
|
+
var MNEMOSYNE_NFT_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
458
|
+
var MNEMOSYNE_CHAINS = {
|
|
459
|
+
BASE: { id: 8453, name: "Base", rpc: "https://mainnet.base.org" },
|
|
460
|
+
POLYGON: { id: 137, name: "Polygon", rpc: "https://polygon-rpc.com" },
|
|
461
|
+
BASE_SEPOLIA: { id: 84532, name: "Base Sepolia (testnet)", rpc: "https://sepolia.base.org" }
|
|
462
|
+
};
|
|
463
|
+
export {
|
|
464
|
+
AppManifestSchema,
|
|
465
|
+
MNEMOSYNE_CHAINS,
|
|
466
|
+
MNEMOSYNE_METHODS,
|
|
467
|
+
MNEMOSYNE_NFT_CACHE_TTL_MS,
|
|
468
|
+
MNEMOSYNE_TOKEN_TTL_S,
|
|
469
|
+
MNEMOSYNE_WS_HOST,
|
|
470
|
+
MNEMOSYNE_WS_PORT,
|
|
471
|
+
MnemoClient,
|
|
472
|
+
assertScope,
|
|
473
|
+
assertVault,
|
|
474
|
+
generateAppToken,
|
|
475
|
+
generateSecret,
|
|
476
|
+
loadManifest,
|
|
477
|
+
parseManifest,
|
|
478
|
+
verifyToken
|
|
479
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mnemosyne_os/sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official SDK for building Layer 2 apps on Mnemosyne OS — connects to the local AI memory runtime via WebSocket or Electron IPC.",
|
|
5
|
+
"keywords": ["mnemosyne", "ai", "memory", "vector", "sdk", "sovereign", "layer2", "local-ai", "electron"],
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Tony Trochet",
|
|
8
|
+
"email": "tony@xpacegems.com",
|
|
9
|
+
"url": "https://www.linkedin.com/in/tony-t-19544650/"
|
|
10
|
+
},
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"homepage": "https://github.com/yaka0007/Mnemosyne-Neural-OS",
|
|
13
|
+
"repository": { "type": "git", "url": "https://github.com/yaka0007/Mnemosyne-Neural-OS.git" },
|
|
14
|
+
"bugs": { "url": "https://github.com/yaka0007/Mnemosyne-Neural-OS/issues" },
|
|
15
|
+
"publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" },
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/index.cjs",
|
|
18
|
+
"module": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
|
+
"require": "./dist/index.cjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": ["dist", "README.md"],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsup src/index.ts --format esm,cjs --dts --clean",
|
|
30
|
+
"dev": "tsup src/index.ts --format esm,cjs --dts --watch",
|
|
31
|
+
"typecheck": "tsc --noEmit",
|
|
32
|
+
"release": "npm run typecheck && npm run build && npm publish --access public",
|
|
33
|
+
"release:patch": "npm run typecheck && npm run build && npm version patch --no-git-tag-version && npm publish --access public",
|
|
34
|
+
"release:minor": "npm run typecheck && npm run build && npm version minor --no-git-tag-version && npm publish --access public",
|
|
35
|
+
"release:major": "npm run typecheck && npm run build && npm version major --no-git-tag-version && npm publish --access public"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"zod": "^3.22.4",
|
|
39
|
+
"ws": "^8.16.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^20.0.0",
|
|
43
|
+
"@types/ws": "^8.5.10",
|
|
44
|
+
"tsup": "^8.0.0",
|
|
45
|
+
"typescript": "^5.3.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=18.0.0"
|
|
50
|
+
}
|
|
51
|
+
}
|