@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.
@@ -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 Error("Must specify at least one space or group to publish to");
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 Error(`Invalid space IDs: ${invalidSpaces.join(", ")}`);
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 Error("Group IDs cannot be empty or contain dots");
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 Error(`Memory not found: ${input.memory_id}`);
3309
+ throw new NotFoundError("Memory", input.memory_id);
3292
3310
  if (memory.properties.user_id !== this.userId)
3293
- throw new Error("Permission denied: not memory owner");
3311
+ throw new ForbiddenError("Permission denied: not memory owner");
3294
3312
  if (memory.properties.doc_type !== "memory")
3295
- throw new Error("Only memories can be published");
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 Error(`Space '${spaceId}' only accepts content_type '${requiredType}', got '${memoryContentType ?? "undefined"}'`);
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 Error("Must specify at least one space or group to retract from");
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 Error(`Group IDs cannot contain dots: ${invalidGroups.join(", ")}`);
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 Error(`Memory not found: ${input.memory_id}`);
3351
+ throw new NotFoundError("Memory", input.memory_id);
3334
3352
  if (memory.properties.user_id !== this.userId)
3335
- throw new Error("Permission denied: not memory owner");
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 Error(`Memory is not published to some destinations. Not in spaces: [${notPublishedSpaces.join(", ")}], Not in groups: [${notPublishedGroups.join(", ")}]`);
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 Error(`Memory not found: ${input.memory_id}`);
3380
+ throw new NotFoundError("Memory", input.memory_id);
3363
3381
  if (memory.properties.user_id !== this.userId)
3364
- throw new Error("Permission denied: not memory owner");
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 Error("Memory has no published copies to revise. Publish first with publish().");
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 Error("Invalid or expired confirmation token");
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 Error(`Unknown action type: ${request.action}`);
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 Error("Token not found or already used");
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 Error("Must specify either space_id or group_id");
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 Error(`Invalid action: ${input.action}. Must be approve, reject, or remove`);
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 Error(`Moderator access required for group ${input.group_id}`);
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 Error("Moderator access required to moderate memories in spaces");
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
- const location2 = input.group_id ? `group ${input.group_id}` : `space ${input.space_id}`;
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 Error(`Invalid space IDs: ${invalidSpaces.join(", ")}`);
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 Error("Group IDs cannot be empty or contain dots");
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 Error(`Moderator access required to view ${moderationFilter} memories in group ${groupId}`);
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 Error(`Moderator access required to view ${moderationFilter} memories in spaces`);
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 Error("Question cannot be empty");
3569
+ throw new ValidationError("Question cannot be empty");
3553
3570
  if (input.spaces.length === 0)
3554
- throw new Error("Must specify at least one space to query");
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 Error(`Invalid space IDs: ${invalidSpaces.join(", ")}`);
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 Error(`Moderator access required to view ${moderationFilterValue} memories in spaces`);
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 Error("No destinations in publish request");
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 Error(`Memory ${request.payload.memory_id} no longer exists`);
3633
+ throw new NotFoundError("Memory", request.payload.memory_id);
3617
3634
  if (originalMemory.properties.user_id !== this.userId)
3618
- throw new Error("Permission denied");
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 Error(`Source memory ${request.payload.memory_id} no longer exists`);
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 Error(`Source memory ${memory_id} no longer exists`);
3851
+ throw new NotFoundError("Memory", memory_id);
3835
3852
  if (sourceMemory.properties.user_id !== this.userId)
3836
- throw new Error("Permission denied");
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
- return { pass: false, reason: "Content moderation unavailable. Please try again later." };
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 text = data.content?.[0]?.text ?? "";
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
- return { pass: false, reason: "Content moderation unavailable. Please try again later." };
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 Error("Must specify at least one space or group to publish to");
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 Error(`Invalid space IDs: ${invalidSpaces.join(", ")}`);
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 Error("Group IDs cannot be empty or contain dots");
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 Error(`Memory not found: ${input.memory_id}`);
3313
+ throw new NotFoundError("Memory", input.memory_id);
3296
3314
  if (memory.properties.user_id !== this.userId)
3297
- throw new Error("Permission denied: not memory owner");
3315
+ throw new ForbiddenError("Permission denied: not memory owner");
3298
3316
  if (memory.properties.doc_type !== "memory")
3299
- throw new Error("Only memories can be published");
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 Error(`Space '${spaceId}' only accepts content_type '${requiredType}', got '${memoryContentType ?? "undefined"}'`);
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 Error("Must specify at least one space or group to retract from");
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 Error(`Group IDs cannot contain dots: ${invalidGroups.join(", ")}`);
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 Error(`Memory not found: ${input.memory_id}`);
3355
+ throw new NotFoundError("Memory", input.memory_id);
3338
3356
  if (memory.properties.user_id !== this.userId)
3339
- throw new Error("Permission denied: not memory owner");
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 Error(`Memory is not published to some destinations. Not in spaces: [${notPublishedSpaces.join(", ")}], Not in groups: [${notPublishedGroups.join(", ")}]`);
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 Error(`Memory not found: ${input.memory_id}`);
3384
+ throw new NotFoundError("Memory", input.memory_id);
3367
3385
  if (memory.properties.user_id !== this.userId)
3368
- throw new Error("Permission denied: not memory owner");
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 Error("Memory has no published copies to revise. Publish first with publish().");
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 Error("Invalid or expired confirmation token");
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 Error(`Unknown action type: ${request.action}`);
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 Error("Token not found or already used");
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 Error("Must specify either space_id or group_id");
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 Error(`Invalid action: ${input.action}. Must be approve, reject, or remove`);
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 Error(`Moderator access required for group ${input.group_id}`);
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 Error("Moderator access required to moderate memories in spaces");
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
- const location2 = input.group_id ? `group ${input.group_id}` : `space ${input.space_id}`;
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 Error(`Invalid space IDs: ${invalidSpaces.join(", ")}`);
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 Error("Group IDs cannot be empty or contain dots");
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 Error(`Moderator access required to view ${moderationFilter} memories in group ${groupId}`);
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 Error(`Moderator access required to view ${moderationFilter} memories in spaces`);
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 Error("Question cannot be empty");
3573
+ throw new ValidationError("Question cannot be empty");
3557
3574
  if (input.spaces.length === 0)
3558
- throw new Error("Must specify at least one space to query");
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 Error(`Invalid space IDs: ${invalidSpaces.join(", ")}`);
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 Error(`Moderator access required to view ${moderationFilterValue} memories in spaces`);
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 Error("No destinations in publish request");
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 Error(`Memory ${request.payload.memory_id} no longer exists`);
3637
+ throw new NotFoundError("Memory", request.payload.memory_id);
3621
3638
  if (originalMemory.properties.user_id !== this.userId)
3622
- throw new Error("Permission denied");
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 Error(`Source memory ${request.payload.memory_id} no longer exists`);
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 Error(`Source memory ${memory_id} no longer exists`);
3855
+ throw new NotFoundError("Memory", memory_id);
3839
3856
  if (sourceMemory.properties.user_id !== this.userId)
3840
- throw new Error("Permission denied");
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
- return { pass: false, reason: "Content moderation unavailable. Please try again later." };
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 text = data.content?.[0]?.text ?? "";
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
- return { pass: false, reason: "Content moderation unavailable. Please try again later." };
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.1",
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.33.3",
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"