@prismer/sdk 1.7.3 → 1.7.4
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 +119 -6
- package/dist/cli.js +556 -17
- package/dist/index.d.mts +72 -2
- package/dist/index.d.ts +72 -2
- package/dist/index.js +137 -14
- package/dist/index.mjs +149 -13
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1207,6 +1207,28 @@ var ENVIRONMENTS = {
|
|
|
1207
1207
|
production: "https://prismer.cloud"
|
|
1208
1208
|
};
|
|
1209
1209
|
|
|
1210
|
+
// src/aip.ts
|
|
1211
|
+
import {
|
|
1212
|
+
AIPIdentity
|
|
1213
|
+
} from "@prismer/aip-sdk";
|
|
1214
|
+
import {
|
|
1215
|
+
publicKeyToDIDKey,
|
|
1216
|
+
didKeyToPublicKey,
|
|
1217
|
+
validateDIDKey
|
|
1218
|
+
} from "@prismer/aip-sdk";
|
|
1219
|
+
import {
|
|
1220
|
+
buildCredential,
|
|
1221
|
+
buildPresentation,
|
|
1222
|
+
verifyCredential,
|
|
1223
|
+
verifyPresentation
|
|
1224
|
+
} from "@prismer/aip-sdk";
|
|
1225
|
+
import {
|
|
1226
|
+
buildDelegation,
|
|
1227
|
+
buildEphemeralDelegation,
|
|
1228
|
+
verifyDelegation,
|
|
1229
|
+
verifyEphemeralDelegation
|
|
1230
|
+
} from "@prismer/aip-sdk";
|
|
1231
|
+
|
|
1210
1232
|
// src/storage.ts
|
|
1211
1233
|
var MemoryStorage = class {
|
|
1212
1234
|
constructor() {
|
|
@@ -2091,20 +2113,27 @@ var PBKDF2_ITERATIONS = 1e5;
|
|
|
2091
2113
|
var SALT_LENGTH = 16;
|
|
2092
2114
|
var IV_LENGTH = 12;
|
|
2093
2115
|
var KEY_LENGTH = 256;
|
|
2094
|
-
var
|
|
2116
|
+
var _E2EEncryption = class _E2EEncryption {
|
|
2095
2117
|
constructor() {
|
|
2096
2118
|
this.masterKey = null;
|
|
2097
2119
|
this.keyPair = null;
|
|
2098
2120
|
this.sessionKeys = /* @__PURE__ */ new Map();
|
|
2099
2121
|
// conversationId → AES key
|
|
2100
2122
|
this.salt = null;
|
|
2123
|
+
// ─── Pipeline Functions ──────────────────────────────────
|
|
2124
|
+
this.messageCount = 0;
|
|
2125
|
+
this.lastRotation = Date.now();
|
|
2101
2126
|
}
|
|
2102
2127
|
/**
|
|
2103
2128
|
* Initialize encryption with user passphrase.
|
|
2104
2129
|
* Derives a master key via PBKDF2 and generates an ECDH key pair.
|
|
2130
|
+
*
|
|
2131
|
+
* @param passphrase - User passphrase for master key derivation
|
|
2132
|
+
* @param salt - Optional Base64-encoded salt. If omitted, a random 16-byte salt is generated.
|
|
2133
|
+
* Store the salt (via exportSalt()) so you can re-derive the same master key later.
|
|
2105
2134
|
*/
|
|
2106
|
-
async init(passphrase) {
|
|
2107
|
-
this.salt = getRandomValues(new Uint8Array(SALT_LENGTH));
|
|
2135
|
+
async init(passphrase, salt) {
|
|
2136
|
+
this.salt = salt ? new Uint8Array(base64ToArrayBuffer(salt)) : getRandomValues(new Uint8Array(SALT_LENGTH));
|
|
2108
2137
|
const passphraseKey = await subtle().importKey(
|
|
2109
2138
|
"raw",
|
|
2110
2139
|
new TextEncoder().encode(passphrase),
|
|
@@ -2115,7 +2144,7 @@ var E2EEncryption = class {
|
|
|
2115
2144
|
this.masterKey = await subtle().deriveKey(
|
|
2116
2145
|
{
|
|
2117
2146
|
name: "PBKDF2",
|
|
2118
|
-
salt: this.salt,
|
|
2147
|
+
salt: new Uint8Array(this.salt.buffer, this.salt.byteOffset, this.salt.byteLength).buffer,
|
|
2119
2148
|
iterations: PBKDF2_ITERATIONS,
|
|
2120
2149
|
hash: "SHA-256"
|
|
2121
2150
|
},
|
|
@@ -2130,6 +2159,14 @@ var E2EEncryption = class {
|
|
|
2130
2159
|
["deriveKey"]
|
|
2131
2160
|
);
|
|
2132
2161
|
}
|
|
2162
|
+
/**
|
|
2163
|
+
* Export the salt as Base64 string for persistent storage.
|
|
2164
|
+
* You must store this and pass it back to init() to re-derive the same master key.
|
|
2165
|
+
*/
|
|
2166
|
+
exportSalt() {
|
|
2167
|
+
if (!this.salt) throw new Error("E2E not initialized. Call init() first.");
|
|
2168
|
+
return arrayBufferToBase64(this.salt.buffer);
|
|
2169
|
+
}
|
|
2133
2170
|
/**
|
|
2134
2171
|
* Export public key for sharing with conversation peers.
|
|
2135
2172
|
*/
|
|
@@ -2242,8 +2279,93 @@ var E2EEncryption = class {
|
|
|
2242
2279
|
this.keyPair = null;
|
|
2243
2280
|
this.sessionKeys.clear();
|
|
2244
2281
|
this.salt = null;
|
|
2282
|
+
this.messageCount = 0;
|
|
2283
|
+
}
|
|
2284
|
+
/**
|
|
2285
|
+
* High-level encrypt-for-send pipeline.
|
|
2286
|
+
* Encrypts content, builds metadata, and handles key rotation.
|
|
2287
|
+
*
|
|
2288
|
+
* Returns { encryptedContent, metadata } ready to send.
|
|
2289
|
+
*/
|
|
2290
|
+
async encryptForSend(conversationId, content) {
|
|
2291
|
+
if (!this.hasSessionKey(conversationId)) {
|
|
2292
|
+
throw new Error("No session key for this conversation. Call deriveSessionKey() first.");
|
|
2293
|
+
}
|
|
2294
|
+
const needsRotation = this.shouldRotateKey();
|
|
2295
|
+
const encryptedContent = await this.encrypt(conversationId, content);
|
|
2296
|
+
this.messageCount++;
|
|
2297
|
+
return {
|
|
2298
|
+
encryptedContent,
|
|
2299
|
+
metadata: {
|
|
2300
|
+
encrypted: true,
|
|
2301
|
+
encryptionVersion: 1,
|
|
2302
|
+
...needsRotation && { keyRotationRequested: true }
|
|
2303
|
+
}
|
|
2304
|
+
};
|
|
2305
|
+
}
|
|
2306
|
+
/**
|
|
2307
|
+
* High-level decrypt-on-receive pipeline.
|
|
2308
|
+
* Decrypts content and validates metadata.
|
|
2309
|
+
*/
|
|
2310
|
+
async decryptOnReceive(conversationId, encryptedContent, metadata) {
|
|
2311
|
+
if (!this.hasSessionKey(conversationId)) {
|
|
2312
|
+
throw new Error("No session key for this conversation. Call deriveSessionKey() first.");
|
|
2313
|
+
}
|
|
2314
|
+
return this.decrypt(conversationId, encryptedContent);
|
|
2315
|
+
}
|
|
2316
|
+
/**
|
|
2317
|
+
* High-level file encryption pipeline.
|
|
2318
|
+
*/
|
|
2319
|
+
async encryptFile(conversationId, fileData) {
|
|
2320
|
+
const base64Data = arrayBufferToBase64(fileData);
|
|
2321
|
+
const encryptedData = await this.encrypt(conversationId, base64Data);
|
|
2322
|
+
return {
|
|
2323
|
+
encryptedData,
|
|
2324
|
+
metadata: {
|
|
2325
|
+
encrypted: true,
|
|
2326
|
+
encryptionVersion: 1,
|
|
2327
|
+
fileEncrypted: true
|
|
2328
|
+
}
|
|
2329
|
+
};
|
|
2330
|
+
}
|
|
2331
|
+
/**
|
|
2332
|
+
* High-level file decryption pipeline.
|
|
2333
|
+
*/
|
|
2334
|
+
async decryptFile(conversationId, encryptedData) {
|
|
2335
|
+
const base64Data = await this.decrypt(conversationId, encryptedData);
|
|
2336
|
+
return base64ToArrayBuffer(base64Data);
|
|
2337
|
+
}
|
|
2338
|
+
/**
|
|
2339
|
+
* Check if key rotation is needed (1000 messages or 24 hours).
|
|
2340
|
+
*/
|
|
2341
|
+
shouldRotateKey() {
|
|
2342
|
+
if (this.messageCount >= _E2EEncryption.KEY_ROTATION_THRESHOLD) {
|
|
2343
|
+
return true;
|
|
2344
|
+
}
|
|
2345
|
+
if (Date.now() - this.lastRotation >= _E2EEncryption.KEY_ROTATION_INTERVAL_MS) {
|
|
2346
|
+
return true;
|
|
2347
|
+
}
|
|
2348
|
+
return false;
|
|
2349
|
+
}
|
|
2350
|
+
/**
|
|
2351
|
+
* Perform key rotation: generate new ECDH keypair and reset counters.
|
|
2352
|
+
* The caller is responsible for re-exchanging keys with peers.
|
|
2353
|
+
*/
|
|
2354
|
+
async rotateKeys() {
|
|
2355
|
+
this.keyPair = await subtle().generateKey(
|
|
2356
|
+
{ name: "ECDH", namedCurve: "P-256" },
|
|
2357
|
+
false,
|
|
2358
|
+
["deriveKey"]
|
|
2359
|
+
);
|
|
2360
|
+
this.messageCount = 0;
|
|
2361
|
+
this.lastRotation = Date.now();
|
|
2362
|
+
this.sessionKeys.clear();
|
|
2363
|
+
return this.exportPublicKey();
|
|
2245
2364
|
}
|
|
2246
2365
|
};
|
|
2366
|
+
_E2EEncryption.KEY_ROTATION_THRESHOLD = 1e3;
|
|
2367
|
+
_E2EEncryption.KEY_ROTATION_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
2368
|
+
var E2EEncryption = _E2EEncryption;
|
|
2247
2369
|
function arrayBufferToBase64(buffer) {
|
|
2248
2370
|
if (typeof btoa !== "undefined") {
|
|
2249
2371
|
const bytes = new Uint8Array(buffer);
|
|
@@ -3292,11 +3414,11 @@ var EvolutionClient = class {
|
|
|
3292
3414
|
}
|
|
3293
3415
|
/** Delete a gene */
|
|
3294
3416
|
async deleteGene(geneId) {
|
|
3295
|
-
return this._r("DELETE", `/api/im/evolution/genes/${geneId}`);
|
|
3417
|
+
return this._r("DELETE", `/api/im/evolution/genes/${encodeURIComponent(geneId)}`);
|
|
3296
3418
|
}
|
|
3297
3419
|
/** Publish a gene. Pass skipCanary=true to bypass canary validation (MVP/admin). */
|
|
3298
3420
|
async publishGene(geneId, options) {
|
|
3299
|
-
return this._r("POST", `/api/im/evolution/genes/${geneId}/publish`, options?.skipCanary ? { skipCanary: true } : void 0);
|
|
3421
|
+
return this._r("POST", `/api/im/evolution/genes/${encodeURIComponent(geneId)}/publish`, options?.skipCanary ? { skipCanary: true } : void 0);
|
|
3300
3422
|
}
|
|
3301
3423
|
/** Import a published gene */
|
|
3302
3424
|
async importGene(geneId) {
|
|
@@ -3382,6 +3504,14 @@ var EvolutionClient = class {
|
|
|
3382
3504
|
async getSkillContent(slugOrId) {
|
|
3383
3505
|
return this._r("GET", `/api/im/skills/${encodeURIComponent(slugOrId)}/content`);
|
|
3384
3506
|
}
|
|
3507
|
+
/** Create/submit a community skill */
|
|
3508
|
+
async createSkill(input) {
|
|
3509
|
+
return this._r("POST", "/api/im/skills", input);
|
|
3510
|
+
}
|
|
3511
|
+
/** Star a skill (increment community rating) */
|
|
3512
|
+
async starSkill(skillId) {
|
|
3513
|
+
return this._r("POST", `/api/im/skills/${encodeURIComponent(skillId)}/star`);
|
|
3514
|
+
}
|
|
3385
3515
|
/**
|
|
3386
3516
|
* Install a skill and write SKILL.md to local filesystem.
|
|
3387
3517
|
* Combines cloud install + local file sync for Claude Code / OpenClaw / OpenCode.
|
|
@@ -3444,8 +3574,8 @@ var EvolutionClient = class {
|
|
|
3444
3574
|
async uninstallSkillLocal(slugOrId) {
|
|
3445
3575
|
const result = await this.uninstallSkill(slugOrId);
|
|
3446
3576
|
const removedPaths = [];
|
|
3447
|
-
const
|
|
3448
|
-
if (!
|
|
3577
|
+
const slug = safeSlug(slugOrId);
|
|
3578
|
+
if (!slug) return { ...result, data: { uninstalled: result.data?.uninstalled ?? false, removedPaths } };
|
|
3449
3579
|
try {
|
|
3450
3580
|
const fs = await import("fs");
|
|
3451
3581
|
const path = await import("path");
|
|
@@ -3453,10 +3583,10 @@ var EvolutionClient = class {
|
|
|
3453
3583
|
const home = os.homedir();
|
|
3454
3584
|
const pluginBase = process.env.PRISMER_PLUGIN_DIR || path.join(home, ".claude", "plugins", "prismer");
|
|
3455
3585
|
const dirs = [
|
|
3456
|
-
path.join(home, ".claude", "skills",
|
|
3457
|
-
path.join(home, ".openclaw", "skills",
|
|
3458
|
-
path.join(home, ".config", "opencode", "skills",
|
|
3459
|
-
path.join(pluginBase, "skills",
|
|
3586
|
+
path.join(home, ".claude", "skills", slug),
|
|
3587
|
+
path.join(home, ".openclaw", "skills", slug),
|
|
3588
|
+
path.join(home, ".config", "opencode", "skills", slug),
|
|
3589
|
+
path.join(pluginBase, "skills", slug)
|
|
3460
3590
|
];
|
|
3461
3591
|
for (const dir of dirs) {
|
|
3462
3592
|
try {
|
|
@@ -3566,6 +3696,9 @@ var EvolutionClient = class {
|
|
|
3566
3696
|
return this._r("POST", "/api/im/evolution/sync", body);
|
|
3567
3697
|
}
|
|
3568
3698
|
};
|
|
3699
|
+
function safeSlug(input) {
|
|
3700
|
+
return input.replace(/[\/\\]/g, "").replace(/\.\./g, "").replace(/\0/g, "");
|
|
3701
|
+
}
|
|
3569
3702
|
function guessMimeType(fileName) {
|
|
3570
3703
|
const ext = fileName.split(".").pop()?.toLowerCase() || "";
|
|
3571
3704
|
const map = {
|
|
@@ -3982,6 +4115,7 @@ function createClient(config) {
|
|
|
3982
4115
|
return new PrismerClient(config);
|
|
3983
4116
|
}
|
|
3984
4117
|
export {
|
|
4118
|
+
AIPIdentity,
|
|
3985
4119
|
AccountClient,
|
|
3986
4120
|
AttachmentQueue,
|
|
3987
4121
|
BindingsClient,
|
|
@@ -4022,5 +4156,7 @@ export {
|
|
|
4022
4156
|
encryptContext,
|
|
4023
4157
|
encryptFile,
|
|
4024
4158
|
encryptForSend,
|
|
4025
|
-
extractSignals
|
|
4159
|
+
extractSignals,
|
|
4160
|
+
guessMimeType,
|
|
4161
|
+
safeSlug
|
|
4026
4162
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prismer/sdk",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.4",
|
|
4
4
|
"description": "Official TypeScript SDK for Prismer Cloud API",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@iarna/toml": "^2.2.5",
|
|
37
|
+
"@prismer/aip-sdk": "file:../../aip/typescript",
|
|
37
38
|
"commander": "^12.1.0"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|