@prmichaelsen/remember-mcp 3.15.1 → 3.15.3
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/server-factory.js +65 -42
- package/dist/server.js +65 -42
- package/package.json +4 -2
package/dist/server-factory.js
CHANGED
|
@@ -1397,6 +1397,24 @@ var ValidationError = class extends AppError {
|
|
|
1397
1397
|
this.fields = fields;
|
|
1398
1398
|
}
|
|
1399
1399
|
};
|
|
1400
|
+
var NotFoundError = class extends AppError {
|
|
1401
|
+
resource;
|
|
1402
|
+
id;
|
|
1403
|
+
kind = "not_found";
|
|
1404
|
+
constructor(resource, id) {
|
|
1405
|
+
super(`${resource} not found: ${id}`, { resource, id });
|
|
1406
|
+
this.resource = resource;
|
|
1407
|
+
this.id = id;
|
|
1408
|
+
}
|
|
1409
|
+
};
|
|
1410
|
+
var ForbiddenError = class extends AppError {
|
|
1411
|
+
requiredRole;
|
|
1412
|
+
kind = "forbidden";
|
|
1413
|
+
constructor(message = "Access denied", requiredRole) {
|
|
1414
|
+
super(message, { requiredRole });
|
|
1415
|
+
this.requiredRole = requiredRole;
|
|
1416
|
+
}
|
|
1417
|
+
};
|
|
1400
1418
|
|
|
1401
1419
|
// node_modules/@prmichaelsen/remember-core/node_modules/uuid/dist/esm/regex.js
|
|
1402
1420
|
var regex_default = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;
|
|
@@ -3272,32 +3290,32 @@ var SpaceService = class {
|
|
|
3272
3290
|
const spaces = input.spaces || [];
|
|
3273
3291
|
const groups = input.groups || [];
|
|
3274
3292
|
if (spaces.length === 0 && groups.length === 0) {
|
|
3275
|
-
throw new
|
|
3293
|
+
throw new ValidationError("Must specify at least one space or group to publish to");
|
|
3276
3294
|
}
|
|
3277
3295
|
if (spaces.length > 0) {
|
|
3278
3296
|
const invalidSpaces = spaces.filter((s) => !isValidSpaceId(s));
|
|
3279
3297
|
if (invalidSpaces.length > 0) {
|
|
3280
|
-
throw new
|
|
3298
|
+
throw new ValidationError(`Invalid space IDs: ${invalidSpaces.join(", ")}`, { spaces: invalidSpaces });
|
|
3281
3299
|
}
|
|
3282
3300
|
}
|
|
3283
3301
|
if (groups.length > 0) {
|
|
3284
3302
|
const invalidGroups = groups.filter((g) => !g || g.includes(".") || g.trim() === "");
|
|
3285
3303
|
if (invalidGroups.length > 0) {
|
|
3286
|
-
throw new
|
|
3304
|
+
throw new ValidationError("Group IDs cannot be empty or contain dots");
|
|
3287
3305
|
}
|
|
3288
3306
|
}
|
|
3289
3307
|
const memory = await fetchMemoryWithAllProperties(this.userCollection, input.memory_id);
|
|
3290
3308
|
if (!memory)
|
|
3291
|
-
throw new
|
|
3309
|
+
throw new NotFoundError("Memory", input.memory_id);
|
|
3292
3310
|
if (memory.properties.user_id !== this.userId)
|
|
3293
|
-
throw new
|
|
3311
|
+
throw new ForbiddenError("Permission denied: not memory owner");
|
|
3294
3312
|
if (memory.properties.doc_type !== "memory")
|
|
3295
|
-
throw new
|
|
3313
|
+
throw new ValidationError("Only memories can be published");
|
|
3296
3314
|
const memoryContentType = memory.properties.content_type;
|
|
3297
3315
|
for (const spaceId of spaces) {
|
|
3298
3316
|
const requiredType = SPACE_CONTENT_TYPE_RESTRICTIONS[spaceId];
|
|
3299
3317
|
if (requiredType && memoryContentType !== requiredType) {
|
|
3300
|
-
throw new
|
|
3318
|
+
throw new ValidationError(`Space '${spaceId}' only accepts content_type '${requiredType}', got '${memoryContentType ?? "undefined"}'`);
|
|
3301
3319
|
}
|
|
3302
3320
|
}
|
|
3303
3321
|
await this.checkModeration(memory.properties.content);
|
|
@@ -3320,25 +3338,25 @@ var SpaceService = class {
|
|
|
3320
3338
|
const spaces = input.spaces || [];
|
|
3321
3339
|
const groups = input.groups || [];
|
|
3322
3340
|
if (spaces.length === 0 && groups.length === 0) {
|
|
3323
|
-
throw new
|
|
3341
|
+
throw new ValidationError("Must specify at least one space or group to retract from");
|
|
3324
3342
|
}
|
|
3325
3343
|
if (groups.length > 0) {
|
|
3326
3344
|
const invalidGroups = groups.filter((g) => g.includes("."));
|
|
3327
3345
|
if (invalidGroups.length > 0) {
|
|
3328
|
-
throw new
|
|
3346
|
+
throw new ValidationError(`Group IDs cannot contain dots: ${invalidGroups.join(", ")}`);
|
|
3329
3347
|
}
|
|
3330
3348
|
}
|
|
3331
3349
|
const memory = await fetchMemoryWithAllProperties(this.userCollection, input.memory_id);
|
|
3332
3350
|
if (!memory)
|
|
3333
|
-
throw new
|
|
3351
|
+
throw new NotFoundError("Memory", input.memory_id);
|
|
3334
3352
|
if (memory.properties.user_id !== this.userId)
|
|
3335
|
-
throw new
|
|
3353
|
+
throw new ForbiddenError("Permission denied: not memory owner");
|
|
3336
3354
|
const currentSpaceIds = Array.isArray(memory.properties.space_ids) ? memory.properties.space_ids : [];
|
|
3337
3355
|
const currentGroupIds = Array.isArray(memory.properties.group_ids) ? memory.properties.group_ids : [];
|
|
3338
3356
|
const notPublishedSpaces = spaces.filter((s) => !currentSpaceIds.includes(s));
|
|
3339
3357
|
const notPublishedGroups = groups.filter((g) => !currentGroupIds.includes(g));
|
|
3340
3358
|
if (notPublishedSpaces.length > 0 || notPublishedGroups.length > 0) {
|
|
3341
|
-
throw new
|
|
3359
|
+
throw new ValidationError(`Memory is not published to some destinations. Not in spaces: [${notPublishedSpaces.join(", ")}], Not in groups: [${notPublishedGroups.join(", ")}]`);
|
|
3342
3360
|
}
|
|
3343
3361
|
const { token } = await this.confirmationTokenService.createRequest(this.userId, "retract_memory", {
|
|
3344
3362
|
memory_id: input.memory_id,
|
|
@@ -3359,13 +3377,13 @@ var SpaceService = class {
|
|
|
3359
3377
|
async revise(input) {
|
|
3360
3378
|
const memory = await fetchMemoryWithAllProperties(this.userCollection, input.memory_id);
|
|
3361
3379
|
if (!memory)
|
|
3362
|
-
throw new
|
|
3380
|
+
throw new NotFoundError("Memory", input.memory_id);
|
|
3363
3381
|
if (memory.properties.user_id !== this.userId)
|
|
3364
|
-
throw new
|
|
3382
|
+
throw new ForbiddenError("Permission denied: not memory owner");
|
|
3365
3383
|
const spaceIds = Array.isArray(memory.properties.space_ids) ? memory.properties.space_ids : [];
|
|
3366
3384
|
const groupIds = Array.isArray(memory.properties.group_ids) ? memory.properties.group_ids : [];
|
|
3367
3385
|
if (spaceIds.length === 0 && groupIds.length === 0) {
|
|
3368
|
-
throw new
|
|
3386
|
+
throw new ValidationError("Memory has no published copies to revise. Publish first with publish().");
|
|
3369
3387
|
}
|
|
3370
3388
|
await this.checkModeration(memory.properties.content);
|
|
3371
3389
|
const { token } = await this.confirmationTokenService.createRequest(this.userId, "revise_memory", {
|
|
@@ -3385,7 +3403,7 @@ var SpaceService = class {
|
|
|
3385
3403
|
async confirm(input) {
|
|
3386
3404
|
const request = await this.confirmationTokenService.confirmRequest(this.userId, input.token);
|
|
3387
3405
|
if (!request) {
|
|
3388
|
-
throw new
|
|
3406
|
+
throw new ValidationError("Invalid or expired confirmation token");
|
|
3389
3407
|
}
|
|
3390
3408
|
if (request.action === "publish_memory") {
|
|
3391
3409
|
return this.executePublish(request);
|
|
@@ -3396,31 +3414,31 @@ var SpaceService = class {
|
|
|
3396
3414
|
if (request.action === "revise_memory") {
|
|
3397
3415
|
return this.executeRevise(request);
|
|
3398
3416
|
}
|
|
3399
|
-
throw new
|
|
3417
|
+
throw new ValidationError(`Unknown action type: ${request.action}`);
|
|
3400
3418
|
}
|
|
3401
3419
|
// ── Deny ────────────────────────────────────────────────────────────
|
|
3402
3420
|
async deny(input) {
|
|
3403
3421
|
const success = await this.confirmationTokenService.denyRequest(this.userId, input.token);
|
|
3404
3422
|
if (!success) {
|
|
3405
|
-
throw new
|
|
3423
|
+
throw new NotFoundError("Token", input.token);
|
|
3406
3424
|
}
|
|
3407
3425
|
return { success: true };
|
|
3408
3426
|
}
|
|
3409
3427
|
// ── Moderate ────────────────────────────────────────────────────────
|
|
3410
3428
|
async moderate(input, authContext) {
|
|
3411
3429
|
if (!input.space_id && !input.group_id) {
|
|
3412
|
-
throw new
|
|
3430
|
+
throw new ValidationError("Must specify either space_id or group_id");
|
|
3413
3431
|
}
|
|
3414
3432
|
if (!ACTION_TO_STATUS[input.action]) {
|
|
3415
|
-
throw new
|
|
3433
|
+
throw new ValidationError(`Invalid action: ${input.action}. Must be approve, reject, or remove`);
|
|
3416
3434
|
}
|
|
3417
3435
|
if (input.group_id) {
|
|
3418
3436
|
if (!canModerate(authContext, input.group_id)) {
|
|
3419
|
-
throw new
|
|
3437
|
+
throw new ForbiddenError(`Moderator access required for group ${input.group_id}`);
|
|
3420
3438
|
}
|
|
3421
3439
|
} else if (input.space_id) {
|
|
3422
3440
|
if (!canModerateAny(authContext)) {
|
|
3423
|
-
throw new
|
|
3441
|
+
throw new ForbiddenError("Moderator access required to moderate memories in spaces");
|
|
3424
3442
|
}
|
|
3425
3443
|
}
|
|
3426
3444
|
let collection;
|
|
@@ -3432,8 +3450,7 @@ var SpaceService = class {
|
|
|
3432
3450
|
}
|
|
3433
3451
|
const memory = await fetchMemoryWithAllProperties(collection, input.memory_id);
|
|
3434
3452
|
if (!memory) {
|
|
3435
|
-
|
|
3436
|
-
throw new Error(`Published memory ${input.memory_id} not found in ${location2}`);
|
|
3453
|
+
throw new NotFoundError("Published memory", input.memory_id);
|
|
3437
3454
|
}
|
|
3438
3455
|
const newStatus = ACTION_TO_STATUS[input.action];
|
|
3439
3456
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -3472,24 +3489,24 @@ var SpaceService = class {
|
|
|
3472
3489
|
if (spaces.length > 0) {
|
|
3473
3490
|
const invalidSpaces = spaces.filter((s) => !isValidSpaceId(s));
|
|
3474
3491
|
if (invalidSpaces.length > 0) {
|
|
3475
|
-
throw new
|
|
3492
|
+
throw new ValidationError(`Invalid space IDs: ${invalidSpaces.join(", ")}`, { spaces: invalidSpaces });
|
|
3476
3493
|
}
|
|
3477
3494
|
}
|
|
3478
3495
|
if (groups.length > 0) {
|
|
3479
3496
|
const invalidGroups = groups.filter((g) => !g || g.includes(".") || g.trim() === "");
|
|
3480
3497
|
if (invalidGroups.length > 0) {
|
|
3481
|
-
throw new
|
|
3498
|
+
throw new ValidationError("Group IDs cannot be empty or contain dots");
|
|
3482
3499
|
}
|
|
3483
3500
|
}
|
|
3484
3501
|
const moderationFilter = input.moderation_filter || "approved";
|
|
3485
3502
|
if (moderationFilter !== "approved") {
|
|
3486
3503
|
for (const groupId of groups) {
|
|
3487
3504
|
if (!canModerate(authContext, groupId)) {
|
|
3488
|
-
throw new
|
|
3505
|
+
throw new ForbiddenError(`Moderator access required to view ${moderationFilter} memories in group ${groupId}`);
|
|
3489
3506
|
}
|
|
3490
3507
|
}
|
|
3491
3508
|
if ((spaces.length > 0 || groups.length === 0) && !canModerateAny(authContext)) {
|
|
3492
|
-
throw new
|
|
3509
|
+
throw new ForbiddenError(`Moderator access required to view ${moderationFilter} memories in spaces`);
|
|
3493
3510
|
}
|
|
3494
3511
|
}
|
|
3495
3512
|
const fetchLimit = (limit + offset) * Math.max(1, groups.length + (spaces.length > 0 || groups.length === 0 ? 1 : 0));
|
|
@@ -3549,16 +3566,16 @@ var SpaceService = class {
|
|
|
3549
3566
|
// ── Query Space ─────────────────────────────────────────────────────
|
|
3550
3567
|
async query(input, authContext) {
|
|
3551
3568
|
if (!input.question?.trim())
|
|
3552
|
-
throw new
|
|
3569
|
+
throw new ValidationError("Question cannot be empty");
|
|
3553
3570
|
if (input.spaces.length === 0)
|
|
3554
|
-
throw new
|
|
3571
|
+
throw new ValidationError("Must specify at least one space to query");
|
|
3555
3572
|
const invalidSpaces = input.spaces.filter((s) => !isValidSpaceId(s));
|
|
3556
3573
|
if (invalidSpaces.length > 0) {
|
|
3557
|
-
throw new
|
|
3574
|
+
throw new ValidationError(`Invalid space IDs: ${invalidSpaces.join(", ")}`, { spaces: invalidSpaces });
|
|
3558
3575
|
}
|
|
3559
3576
|
const moderationFilterValue = input.moderation_filter || "approved";
|
|
3560
3577
|
if (moderationFilterValue !== "approved" && !canModerateAny(authContext)) {
|
|
3561
|
-
throw new
|
|
3578
|
+
throw new ForbiddenError(`Moderator access required to view ${moderationFilterValue} memories in spaces`);
|
|
3562
3579
|
}
|
|
3563
3580
|
const publicCollection = await ensurePublicCollection(this.weaviateClient);
|
|
3564
3581
|
const filterList = [];
|
|
@@ -3609,13 +3626,13 @@ var SpaceService = class {
|
|
|
3609
3626
|
const spaces = request.payload.spaces || [];
|
|
3610
3627
|
const groups = request.payload.groups || [];
|
|
3611
3628
|
if (spaces.length === 0 && groups.length === 0) {
|
|
3612
|
-
throw new
|
|
3629
|
+
throw new ValidationError("No destinations in publish request");
|
|
3613
3630
|
}
|
|
3614
3631
|
const originalMemory = await fetchMemoryWithAllProperties(this.userCollection, request.payload.memory_id);
|
|
3615
3632
|
if (!originalMemory)
|
|
3616
|
-
throw new
|
|
3633
|
+
throw new NotFoundError("Memory", request.payload.memory_id);
|
|
3617
3634
|
if (originalMemory.properties.user_id !== this.userId)
|
|
3618
|
-
throw new
|
|
3635
|
+
throw new ForbiddenError("Permission denied");
|
|
3619
3636
|
const compositeId = generateCompositeId(this.userId, request.payload.memory_id);
|
|
3620
3637
|
const weaviateId = compositeIdToUuid(compositeId);
|
|
3621
3638
|
const existingSpaceIds = Array.isArray(originalMemory.properties.space_ids) ? originalMemory.properties.space_ids : [];
|
|
@@ -3751,7 +3768,7 @@ var SpaceService = class {
|
|
|
3751
3768
|
const groups = request.payload.groups || [];
|
|
3752
3769
|
const sourceMemory = await fetchMemoryWithAllProperties(this.userCollection, request.payload.memory_id);
|
|
3753
3770
|
if (!sourceMemory)
|
|
3754
|
-
throw new
|
|
3771
|
+
throw new NotFoundError("Memory", request.payload.memory_id);
|
|
3755
3772
|
const currentSpaceIds = Array.isArray(sourceMemory.properties.space_ids) ? sourceMemory.properties.space_ids : [];
|
|
3756
3773
|
const currentGroupIds = Array.isArray(sourceMemory.properties.group_ids) ? sourceMemory.properties.group_ids : [];
|
|
3757
3774
|
const compositeId = generateCompositeId(this.userId, request.payload.memory_id);
|
|
@@ -3831,9 +3848,9 @@ var SpaceService = class {
|
|
|
3831
3848
|
const { memory_id, space_ids = [], group_ids = [] } = request.payload;
|
|
3832
3849
|
const sourceMemory = await fetchMemoryWithAllProperties(this.userCollection, memory_id);
|
|
3833
3850
|
if (!sourceMemory)
|
|
3834
|
-
throw new
|
|
3851
|
+
throw new NotFoundError("Memory", memory_id);
|
|
3835
3852
|
if (sourceMemory.properties.user_id !== this.userId)
|
|
3836
|
-
throw new
|
|
3853
|
+
throw new ForbiddenError("Permission denied");
|
|
3837
3854
|
const newContent = String(sourceMemory.properties.content ?? "");
|
|
3838
3855
|
const revisedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3839
3856
|
const compositeId = generateCompositeId(this.userId, memory_id);
|
|
@@ -4064,10 +4081,14 @@ function createModerationClient(options) {
|
|
|
4064
4081
|
})
|
|
4065
4082
|
});
|
|
4066
4083
|
if (!response.ok) {
|
|
4067
|
-
|
|
4084
|
+
const errorBody = await response.text().catch(() => "");
|
|
4085
|
+
const msg = `[moderation] Anthropic API error: ${response.status} ${response.statusText} ${errorBody}`;
|
|
4086
|
+
console.error(msg);
|
|
4087
|
+
return { pass: false, reason: msg };
|
|
4068
4088
|
}
|
|
4069
4089
|
const data = await response.json();
|
|
4070
|
-
const
|
|
4090
|
+
const rawText = data.content?.[0]?.text ?? "";
|
|
4091
|
+
const text = rawText.replace(/^```(?:json)?\s*\n?/i, "").replace(/\n?```\s*$/i, "").trim();
|
|
4071
4092
|
const parsed = JSON.parse(text);
|
|
4072
4093
|
const result = {
|
|
4073
4094
|
pass: parsed.pass === true,
|
|
@@ -4080,8 +4101,10 @@ function createModerationClient(options) {
|
|
|
4080
4101
|
}
|
|
4081
4102
|
cache.set(hash, result);
|
|
4082
4103
|
return result;
|
|
4083
|
-
} catch {
|
|
4084
|
-
|
|
4104
|
+
} catch (err2) {
|
|
4105
|
+
const msg = `[moderation] Unexpected error: ${err2 instanceof Error ? err2.message : String(err2)}`;
|
|
4106
|
+
console.error(msg, err2);
|
|
4107
|
+
return { pass: false, reason: msg };
|
|
4085
4108
|
}
|
|
4086
4109
|
}
|
|
4087
4110
|
};
|
package/dist/server.js
CHANGED
|
@@ -1401,6 +1401,24 @@ var ValidationError = class extends AppError {
|
|
|
1401
1401
|
this.fields = fields;
|
|
1402
1402
|
}
|
|
1403
1403
|
};
|
|
1404
|
+
var NotFoundError = class extends AppError {
|
|
1405
|
+
resource;
|
|
1406
|
+
id;
|
|
1407
|
+
kind = "not_found";
|
|
1408
|
+
constructor(resource, id) {
|
|
1409
|
+
super(`${resource} not found: ${id}`, { resource, id });
|
|
1410
|
+
this.resource = resource;
|
|
1411
|
+
this.id = id;
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
var ForbiddenError = class extends AppError {
|
|
1415
|
+
requiredRole;
|
|
1416
|
+
kind = "forbidden";
|
|
1417
|
+
constructor(message = "Access denied", requiredRole) {
|
|
1418
|
+
super(message, { requiredRole });
|
|
1419
|
+
this.requiredRole = requiredRole;
|
|
1420
|
+
}
|
|
1421
|
+
};
|
|
1404
1422
|
|
|
1405
1423
|
// node_modules/@prmichaelsen/remember-core/node_modules/uuid/dist/esm/regex.js
|
|
1406
1424
|
var regex_default = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;
|
|
@@ -3276,32 +3294,32 @@ var SpaceService = class {
|
|
|
3276
3294
|
const spaces = input.spaces || [];
|
|
3277
3295
|
const groups = input.groups || [];
|
|
3278
3296
|
if (spaces.length === 0 && groups.length === 0) {
|
|
3279
|
-
throw new
|
|
3297
|
+
throw new ValidationError("Must specify at least one space or group to publish to");
|
|
3280
3298
|
}
|
|
3281
3299
|
if (spaces.length > 0) {
|
|
3282
3300
|
const invalidSpaces = spaces.filter((s) => !isValidSpaceId(s));
|
|
3283
3301
|
if (invalidSpaces.length > 0) {
|
|
3284
|
-
throw new
|
|
3302
|
+
throw new ValidationError(`Invalid space IDs: ${invalidSpaces.join(", ")}`, { spaces: invalidSpaces });
|
|
3285
3303
|
}
|
|
3286
3304
|
}
|
|
3287
3305
|
if (groups.length > 0) {
|
|
3288
3306
|
const invalidGroups = groups.filter((g) => !g || g.includes(".") || g.trim() === "");
|
|
3289
3307
|
if (invalidGroups.length > 0) {
|
|
3290
|
-
throw new
|
|
3308
|
+
throw new ValidationError("Group IDs cannot be empty or contain dots");
|
|
3291
3309
|
}
|
|
3292
3310
|
}
|
|
3293
3311
|
const memory = await fetchMemoryWithAllProperties(this.userCollection, input.memory_id);
|
|
3294
3312
|
if (!memory)
|
|
3295
|
-
throw new
|
|
3313
|
+
throw new NotFoundError("Memory", input.memory_id);
|
|
3296
3314
|
if (memory.properties.user_id !== this.userId)
|
|
3297
|
-
throw new
|
|
3315
|
+
throw new ForbiddenError("Permission denied: not memory owner");
|
|
3298
3316
|
if (memory.properties.doc_type !== "memory")
|
|
3299
|
-
throw new
|
|
3317
|
+
throw new ValidationError("Only memories can be published");
|
|
3300
3318
|
const memoryContentType = memory.properties.content_type;
|
|
3301
3319
|
for (const spaceId of spaces) {
|
|
3302
3320
|
const requiredType = SPACE_CONTENT_TYPE_RESTRICTIONS[spaceId];
|
|
3303
3321
|
if (requiredType && memoryContentType !== requiredType) {
|
|
3304
|
-
throw new
|
|
3322
|
+
throw new ValidationError(`Space '${spaceId}' only accepts content_type '${requiredType}', got '${memoryContentType ?? "undefined"}'`);
|
|
3305
3323
|
}
|
|
3306
3324
|
}
|
|
3307
3325
|
await this.checkModeration(memory.properties.content);
|
|
@@ -3324,25 +3342,25 @@ var SpaceService = class {
|
|
|
3324
3342
|
const spaces = input.spaces || [];
|
|
3325
3343
|
const groups = input.groups || [];
|
|
3326
3344
|
if (spaces.length === 0 && groups.length === 0) {
|
|
3327
|
-
throw new
|
|
3345
|
+
throw new ValidationError("Must specify at least one space or group to retract from");
|
|
3328
3346
|
}
|
|
3329
3347
|
if (groups.length > 0) {
|
|
3330
3348
|
const invalidGroups = groups.filter((g) => g.includes("."));
|
|
3331
3349
|
if (invalidGroups.length > 0) {
|
|
3332
|
-
throw new
|
|
3350
|
+
throw new ValidationError(`Group IDs cannot contain dots: ${invalidGroups.join(", ")}`);
|
|
3333
3351
|
}
|
|
3334
3352
|
}
|
|
3335
3353
|
const memory = await fetchMemoryWithAllProperties(this.userCollection, input.memory_id);
|
|
3336
3354
|
if (!memory)
|
|
3337
|
-
throw new
|
|
3355
|
+
throw new NotFoundError("Memory", input.memory_id);
|
|
3338
3356
|
if (memory.properties.user_id !== this.userId)
|
|
3339
|
-
throw new
|
|
3357
|
+
throw new ForbiddenError("Permission denied: not memory owner");
|
|
3340
3358
|
const currentSpaceIds = Array.isArray(memory.properties.space_ids) ? memory.properties.space_ids : [];
|
|
3341
3359
|
const currentGroupIds = Array.isArray(memory.properties.group_ids) ? memory.properties.group_ids : [];
|
|
3342
3360
|
const notPublishedSpaces = spaces.filter((s) => !currentSpaceIds.includes(s));
|
|
3343
3361
|
const notPublishedGroups = groups.filter((g) => !currentGroupIds.includes(g));
|
|
3344
3362
|
if (notPublishedSpaces.length > 0 || notPublishedGroups.length > 0) {
|
|
3345
|
-
throw new
|
|
3363
|
+
throw new ValidationError(`Memory is not published to some destinations. Not in spaces: [${notPublishedSpaces.join(", ")}], Not in groups: [${notPublishedGroups.join(", ")}]`);
|
|
3346
3364
|
}
|
|
3347
3365
|
const { token } = await this.confirmationTokenService.createRequest(this.userId, "retract_memory", {
|
|
3348
3366
|
memory_id: input.memory_id,
|
|
@@ -3363,13 +3381,13 @@ var SpaceService = class {
|
|
|
3363
3381
|
async revise(input) {
|
|
3364
3382
|
const memory = await fetchMemoryWithAllProperties(this.userCollection, input.memory_id);
|
|
3365
3383
|
if (!memory)
|
|
3366
|
-
throw new
|
|
3384
|
+
throw new NotFoundError("Memory", input.memory_id);
|
|
3367
3385
|
if (memory.properties.user_id !== this.userId)
|
|
3368
|
-
throw new
|
|
3386
|
+
throw new ForbiddenError("Permission denied: not memory owner");
|
|
3369
3387
|
const spaceIds = Array.isArray(memory.properties.space_ids) ? memory.properties.space_ids : [];
|
|
3370
3388
|
const groupIds = Array.isArray(memory.properties.group_ids) ? memory.properties.group_ids : [];
|
|
3371
3389
|
if (spaceIds.length === 0 && groupIds.length === 0) {
|
|
3372
|
-
throw new
|
|
3390
|
+
throw new ValidationError("Memory has no published copies to revise. Publish first with publish().");
|
|
3373
3391
|
}
|
|
3374
3392
|
await this.checkModeration(memory.properties.content);
|
|
3375
3393
|
const { token } = await this.confirmationTokenService.createRequest(this.userId, "revise_memory", {
|
|
@@ -3389,7 +3407,7 @@ var SpaceService = class {
|
|
|
3389
3407
|
async confirm(input) {
|
|
3390
3408
|
const request = await this.confirmationTokenService.confirmRequest(this.userId, input.token);
|
|
3391
3409
|
if (!request) {
|
|
3392
|
-
throw new
|
|
3410
|
+
throw new ValidationError("Invalid or expired confirmation token");
|
|
3393
3411
|
}
|
|
3394
3412
|
if (request.action === "publish_memory") {
|
|
3395
3413
|
return this.executePublish(request);
|
|
@@ -3400,31 +3418,31 @@ var SpaceService = class {
|
|
|
3400
3418
|
if (request.action === "revise_memory") {
|
|
3401
3419
|
return this.executeRevise(request);
|
|
3402
3420
|
}
|
|
3403
|
-
throw new
|
|
3421
|
+
throw new ValidationError(`Unknown action type: ${request.action}`);
|
|
3404
3422
|
}
|
|
3405
3423
|
// ── Deny ────────────────────────────────────────────────────────────
|
|
3406
3424
|
async deny(input) {
|
|
3407
3425
|
const success = await this.confirmationTokenService.denyRequest(this.userId, input.token);
|
|
3408
3426
|
if (!success) {
|
|
3409
|
-
throw new
|
|
3427
|
+
throw new NotFoundError("Token", input.token);
|
|
3410
3428
|
}
|
|
3411
3429
|
return { success: true };
|
|
3412
3430
|
}
|
|
3413
3431
|
// ── Moderate ────────────────────────────────────────────────────────
|
|
3414
3432
|
async moderate(input, authContext) {
|
|
3415
3433
|
if (!input.space_id && !input.group_id) {
|
|
3416
|
-
throw new
|
|
3434
|
+
throw new ValidationError("Must specify either space_id or group_id");
|
|
3417
3435
|
}
|
|
3418
3436
|
if (!ACTION_TO_STATUS[input.action]) {
|
|
3419
|
-
throw new
|
|
3437
|
+
throw new ValidationError(`Invalid action: ${input.action}. Must be approve, reject, or remove`);
|
|
3420
3438
|
}
|
|
3421
3439
|
if (input.group_id) {
|
|
3422
3440
|
if (!canModerate(authContext, input.group_id)) {
|
|
3423
|
-
throw new
|
|
3441
|
+
throw new ForbiddenError(`Moderator access required for group ${input.group_id}`);
|
|
3424
3442
|
}
|
|
3425
3443
|
} else if (input.space_id) {
|
|
3426
3444
|
if (!canModerateAny(authContext)) {
|
|
3427
|
-
throw new
|
|
3445
|
+
throw new ForbiddenError("Moderator access required to moderate memories in spaces");
|
|
3428
3446
|
}
|
|
3429
3447
|
}
|
|
3430
3448
|
let collection;
|
|
@@ -3436,8 +3454,7 @@ var SpaceService = class {
|
|
|
3436
3454
|
}
|
|
3437
3455
|
const memory = await fetchMemoryWithAllProperties(collection, input.memory_id);
|
|
3438
3456
|
if (!memory) {
|
|
3439
|
-
|
|
3440
|
-
throw new Error(`Published memory ${input.memory_id} not found in ${location2}`);
|
|
3457
|
+
throw new NotFoundError("Published memory", input.memory_id);
|
|
3441
3458
|
}
|
|
3442
3459
|
const newStatus = ACTION_TO_STATUS[input.action];
|
|
3443
3460
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -3476,24 +3493,24 @@ var SpaceService = class {
|
|
|
3476
3493
|
if (spaces.length > 0) {
|
|
3477
3494
|
const invalidSpaces = spaces.filter((s) => !isValidSpaceId(s));
|
|
3478
3495
|
if (invalidSpaces.length > 0) {
|
|
3479
|
-
throw new
|
|
3496
|
+
throw new ValidationError(`Invalid space IDs: ${invalidSpaces.join(", ")}`, { spaces: invalidSpaces });
|
|
3480
3497
|
}
|
|
3481
3498
|
}
|
|
3482
3499
|
if (groups.length > 0) {
|
|
3483
3500
|
const invalidGroups = groups.filter((g) => !g || g.includes(".") || g.trim() === "");
|
|
3484
3501
|
if (invalidGroups.length > 0) {
|
|
3485
|
-
throw new
|
|
3502
|
+
throw new ValidationError("Group IDs cannot be empty or contain dots");
|
|
3486
3503
|
}
|
|
3487
3504
|
}
|
|
3488
3505
|
const moderationFilter = input.moderation_filter || "approved";
|
|
3489
3506
|
if (moderationFilter !== "approved") {
|
|
3490
3507
|
for (const groupId of groups) {
|
|
3491
3508
|
if (!canModerate(authContext, groupId)) {
|
|
3492
|
-
throw new
|
|
3509
|
+
throw new ForbiddenError(`Moderator access required to view ${moderationFilter} memories in group ${groupId}`);
|
|
3493
3510
|
}
|
|
3494
3511
|
}
|
|
3495
3512
|
if ((spaces.length > 0 || groups.length === 0) && !canModerateAny(authContext)) {
|
|
3496
|
-
throw new
|
|
3513
|
+
throw new ForbiddenError(`Moderator access required to view ${moderationFilter} memories in spaces`);
|
|
3497
3514
|
}
|
|
3498
3515
|
}
|
|
3499
3516
|
const fetchLimit = (limit + offset) * Math.max(1, groups.length + (spaces.length > 0 || groups.length === 0 ? 1 : 0));
|
|
@@ -3553,16 +3570,16 @@ var SpaceService = class {
|
|
|
3553
3570
|
// ── Query Space ─────────────────────────────────────────────────────
|
|
3554
3571
|
async query(input, authContext) {
|
|
3555
3572
|
if (!input.question?.trim())
|
|
3556
|
-
throw new
|
|
3573
|
+
throw new ValidationError("Question cannot be empty");
|
|
3557
3574
|
if (input.spaces.length === 0)
|
|
3558
|
-
throw new
|
|
3575
|
+
throw new ValidationError("Must specify at least one space to query");
|
|
3559
3576
|
const invalidSpaces = input.spaces.filter((s) => !isValidSpaceId(s));
|
|
3560
3577
|
if (invalidSpaces.length > 0) {
|
|
3561
|
-
throw new
|
|
3578
|
+
throw new ValidationError(`Invalid space IDs: ${invalidSpaces.join(", ")}`, { spaces: invalidSpaces });
|
|
3562
3579
|
}
|
|
3563
3580
|
const moderationFilterValue = input.moderation_filter || "approved";
|
|
3564
3581
|
if (moderationFilterValue !== "approved" && !canModerateAny(authContext)) {
|
|
3565
|
-
throw new
|
|
3582
|
+
throw new ForbiddenError(`Moderator access required to view ${moderationFilterValue} memories in spaces`);
|
|
3566
3583
|
}
|
|
3567
3584
|
const publicCollection = await ensurePublicCollection(this.weaviateClient);
|
|
3568
3585
|
const filterList = [];
|
|
@@ -3613,13 +3630,13 @@ var SpaceService = class {
|
|
|
3613
3630
|
const spaces = request.payload.spaces || [];
|
|
3614
3631
|
const groups = request.payload.groups || [];
|
|
3615
3632
|
if (spaces.length === 0 && groups.length === 0) {
|
|
3616
|
-
throw new
|
|
3633
|
+
throw new ValidationError("No destinations in publish request");
|
|
3617
3634
|
}
|
|
3618
3635
|
const originalMemory = await fetchMemoryWithAllProperties(this.userCollection, request.payload.memory_id);
|
|
3619
3636
|
if (!originalMemory)
|
|
3620
|
-
throw new
|
|
3637
|
+
throw new NotFoundError("Memory", request.payload.memory_id);
|
|
3621
3638
|
if (originalMemory.properties.user_id !== this.userId)
|
|
3622
|
-
throw new
|
|
3639
|
+
throw new ForbiddenError("Permission denied");
|
|
3623
3640
|
const compositeId = generateCompositeId(this.userId, request.payload.memory_id);
|
|
3624
3641
|
const weaviateId = compositeIdToUuid(compositeId);
|
|
3625
3642
|
const existingSpaceIds = Array.isArray(originalMemory.properties.space_ids) ? originalMemory.properties.space_ids : [];
|
|
@@ -3755,7 +3772,7 @@ var SpaceService = class {
|
|
|
3755
3772
|
const groups = request.payload.groups || [];
|
|
3756
3773
|
const sourceMemory = await fetchMemoryWithAllProperties(this.userCollection, request.payload.memory_id);
|
|
3757
3774
|
if (!sourceMemory)
|
|
3758
|
-
throw new
|
|
3775
|
+
throw new NotFoundError("Memory", request.payload.memory_id);
|
|
3759
3776
|
const currentSpaceIds = Array.isArray(sourceMemory.properties.space_ids) ? sourceMemory.properties.space_ids : [];
|
|
3760
3777
|
const currentGroupIds = Array.isArray(sourceMemory.properties.group_ids) ? sourceMemory.properties.group_ids : [];
|
|
3761
3778
|
const compositeId = generateCompositeId(this.userId, request.payload.memory_id);
|
|
@@ -3835,9 +3852,9 @@ var SpaceService = class {
|
|
|
3835
3852
|
const { memory_id, space_ids = [], group_ids = [] } = request.payload;
|
|
3836
3853
|
const sourceMemory = await fetchMemoryWithAllProperties(this.userCollection, memory_id);
|
|
3837
3854
|
if (!sourceMemory)
|
|
3838
|
-
throw new
|
|
3855
|
+
throw new NotFoundError("Memory", memory_id);
|
|
3839
3856
|
if (sourceMemory.properties.user_id !== this.userId)
|
|
3840
|
-
throw new
|
|
3857
|
+
throw new ForbiddenError("Permission denied");
|
|
3841
3858
|
const newContent = String(sourceMemory.properties.content ?? "");
|
|
3842
3859
|
const revisedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3843
3860
|
const compositeId = generateCompositeId(this.userId, memory_id);
|
|
@@ -4068,10 +4085,14 @@ function createModerationClient(options) {
|
|
|
4068
4085
|
})
|
|
4069
4086
|
});
|
|
4070
4087
|
if (!response.ok) {
|
|
4071
|
-
|
|
4088
|
+
const errorBody = await response.text().catch(() => "");
|
|
4089
|
+
const msg = `[moderation] Anthropic API error: ${response.status} ${response.statusText} ${errorBody}`;
|
|
4090
|
+
console.error(msg);
|
|
4091
|
+
return { pass: false, reason: msg };
|
|
4072
4092
|
}
|
|
4073
4093
|
const data = await response.json();
|
|
4074
|
-
const
|
|
4094
|
+
const rawText = data.content?.[0]?.text ?? "";
|
|
4095
|
+
const text = rawText.replace(/^```(?:json)?\s*\n?/i, "").replace(/\n?```\s*$/i, "").trim();
|
|
4075
4096
|
const parsed = JSON.parse(text);
|
|
4076
4097
|
const result = {
|
|
4077
4098
|
pass: parsed.pass === true,
|
|
@@ -4084,8 +4105,10 @@ function createModerationClient(options) {
|
|
|
4084
4105
|
}
|
|
4085
4106
|
cache.set(hash, result);
|
|
4086
4107
|
return result;
|
|
4087
|
-
} catch {
|
|
4088
|
-
|
|
4108
|
+
} catch (err2) {
|
|
4109
|
+
const msg = `[moderation] Unexpected error: ${err2 instanceof Error ? err2.message : String(err2)}`;
|
|
4110
|
+
console.error(msg, err2);
|
|
4111
|
+
return { pass: false, reason: msg };
|
|
4089
4112
|
}
|
|
4090
4113
|
}
|
|
4091
4114
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prmichaelsen/remember-mcp",
|
|
3
|
-
"version": "3.15.
|
|
3
|
+
"version": "3.15.3",
|
|
4
4
|
"description": "Multi-tenant memory system MCP server with vector search and relationships",
|
|
5
5
|
"main": "dist/server.js",
|
|
6
6
|
"type": "module",
|
|
@@ -47,10 +47,12 @@
|
|
|
47
47
|
"author": "Patrick Michaelsen",
|
|
48
48
|
"license": "MIT",
|
|
49
49
|
"dependencies": {
|
|
50
|
+
"@google-cloud/documentai": "^9.5.0",
|
|
51
|
+
"@google-cloud/vision": "^5.3.4",
|
|
50
52
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
51
53
|
"@prmichaelsen/firebase-admin-sdk-v8": "^2.2.0",
|
|
52
54
|
"@prmichaelsen/mcp-auth": "^7.0.4",
|
|
53
|
-
"@prmichaelsen/remember-core": "^0.
|
|
55
|
+
"@prmichaelsen/remember-core": "^0.34.14",
|
|
54
56
|
"dotenv": "^16.4.5",
|
|
55
57
|
"uuid": "^13.0.0",
|
|
56
58
|
"weaviate-client": "^3.2.0"
|