@prmichaelsen/remember-mcp 3.13.0 → 3.14.1
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/CHANGELOG.md +22 -0
- package/agent/milestones/milestone-17-remember-core-migration.md +140 -0
- package/agent/progress.yaml +123 -6
- package/agent/tasks/milestone-17-remember-core-migration/task-193-foundation-setup.md +58 -0
- package/agent/tasks/milestone-17-remember-core-migration/task-194-migrate-relationship-tools.md +47 -0
- package/agent/tasks/milestone-17-remember-core-migration/task-195-migrate-preference-tools.md +34 -0
- package/agent/tasks/milestone-17-remember-core-migration/task-196-migrate-memory-tools.md +46 -0
- package/agent/tasks/milestone-17-remember-core-migration/task-197-migrate-space-confirmation-tools.md +49 -0
- package/agent/tasks/milestone-17-remember-core-migration/task-198-migrate-space-search-moderate.md +46 -0
- package/agent/tasks/milestone-17-remember-core-migration/task-199-migrate-delete-memory.md +43 -0
- package/agent/tasks/milestone-17-remember-core-migration/task-200-code-cleanup-verification.md +52 -0
- package/dist/core-services.d.ts +25 -0
- package/dist/server-factory.js +3208 -3978
- package/dist/server.js +3708 -4474
- package/dist/tools/confirm-publish-moderation.spec.d.ts +3 -2
- package/dist/tools/create-memory.d.ts +1 -1
- package/dist/tools/query-space.d.ts +1 -1
- package/dist/tools/search-space.d.ts +10 -14
- package/jest.config.js +11 -0
- package/package.json +3 -1
- package/src/core-services.ts +50 -0
- package/src/tools/confirm-publish-moderation.spec.ts +120 -176
- package/src/tools/confirm.ts +70 -1035
- package/src/tools/create-memory.ts +16 -67
- package/src/tools/create-relationship.ts +13 -181
- package/src/tools/delete-memory.ts +7 -72
- package/src/tools/delete-relationship.ts +7 -91
- package/src/tools/deny.ts +4 -14
- package/src/tools/find-similar.ts +16 -110
- package/src/tools/get-preferences.ts +3 -8
- package/src/tools/moderate.spec.ts +65 -81
- package/src/tools/moderate.ts +18 -121
- package/src/tools/publish.ts +7 -204
- package/src/tools/query-space.ts +28 -140
- package/src/tools/retract.ts +7 -185
- package/src/tools/revise.ts +4 -136
- package/src/tools/search-relationship.ts +17 -116
- package/src/tools/search-space.ts +58 -304
- package/src/tools/set-preference.ts +3 -8
- package/src/tools/update-memory.ts +22 -190
- package/src/tools/update-relationship.ts +16 -90
- package/src/v2-smoke.e2e.ts +3 -2
- package/dist/collections/composite-ids.d.ts +0 -106
- package/dist/collections/core-infrastructure.spec.d.ts +0 -11
- package/dist/collections/dot-notation.d.ts +0 -106
- package/dist/collections/tracking-arrays.d.ts +0 -176
- package/dist/constants/content-types.d.ts +0 -61
- package/dist/services/confirmation-token.service.d.ts +0 -99
- package/dist/services/confirmation-token.service.spec.d.ts +0 -5
- package/dist/services/preferences-database.service.d.ts +0 -22
- package/dist/services/space-config.service.d.ts +0 -23
- package/dist/services/space-config.service.spec.d.ts +0 -2
- package/src/collections/composite-ids.ts +0 -193
- package/src/collections/core-infrastructure.spec.ts +0 -353
- package/src/collections/dot-notation.ts +0 -212
- package/src/collections/tracking-arrays.ts +0 -298
- package/src/constants/content-types.ts +0 -490
- package/src/services/confirmation-token.service.spec.ts +0 -254
- package/src/services/confirmation-token.service.ts +0 -328
- package/src/services/preferences-database.service.ts +0 -120
- package/src/services/space-config.service.spec.ts +0 -102
- package/src/services/space-config.service.ts +0 -79
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tests for moderation status wiring in the publish flow.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* After migration to remember-core, the publish confirmation logic
|
|
5
|
+
* is handled by SpaceService.confirm(). These tests verify the adapter
|
|
6
|
+
* correctly delegates and formats responses.
|
|
6
7
|
*/
|
|
7
8
|
export {};
|
|
8
9
|
//# sourceMappingURL=confirm-publish-moderation.spec.d.ts.map
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
8
8
|
import type { AuthContext } from '../types/auth.js';
|
|
9
|
-
|
|
9
|
+
export type ModerationFilter = 'approved' | 'pending' | 'rejected' | 'removed' | 'all';
|
|
10
10
|
/**
|
|
11
11
|
* Tool definition for remember_query_space
|
|
12
12
|
*/
|
|
@@ -12,6 +12,16 @@ import type { AuthContext } from '../types/auth.js';
|
|
|
12
12
|
*/
|
|
13
13
|
export declare const searchSpaceTool: Tool;
|
|
14
14
|
export type ModerationFilter = 'approved' | 'pending' | 'rejected' | 'removed' | 'all';
|
|
15
|
+
/**
|
|
16
|
+
* Build the moderation status filter for a Weaviate collection query.
|
|
17
|
+
* @deprecated Kept for test compatibility — logic now lives in remember-core SpaceService
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildModerationFilter(collection: any, moderationFilter?: ModerationFilter): any | null;
|
|
20
|
+
/**
|
|
21
|
+
* Build base filters applied to all space/group collection queries.
|
|
22
|
+
* @deprecated Kept for test compatibility — logic now lives in remember-core SpaceService
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildBaseFilters(collection: any, args: SearchSpaceArgs): any[];
|
|
15
25
|
interface SearchSpaceArgs {
|
|
16
26
|
query: string;
|
|
17
27
|
spaces?: string[];
|
|
@@ -28,20 +38,6 @@ interface SearchSpaceArgs {
|
|
|
28
38
|
limit?: number;
|
|
29
39
|
offset?: number;
|
|
30
40
|
}
|
|
31
|
-
/**
|
|
32
|
-
* Build the moderation status filter for a Weaviate collection query.
|
|
33
|
-
*
|
|
34
|
-
* - 'approved' (default): matches approved OR null (backward compat for pre-moderation memories)
|
|
35
|
-
* - 'pending'/'rejected'/'removed': matches that specific status
|
|
36
|
-
* - 'all': no moderation filter applied
|
|
37
|
-
*/
|
|
38
|
-
export declare function buildModerationFilter(collection: any, moderationFilter?: ModerationFilter): any | null;
|
|
39
|
-
/**
|
|
40
|
-
* Build base filters applied to all space/group collection queries.
|
|
41
|
-
* Excludes soft-deleted memories and optionally filters by content type, tags, weight, and date.
|
|
42
|
-
* Includes moderation status filter (default: approved/null only).
|
|
43
|
-
*/
|
|
44
|
-
export declare function buildBaseFilters(collection: any, args: SearchSpaceArgs): any[];
|
|
45
41
|
/**
|
|
46
42
|
* Handle remember_search_space tool execution
|
|
47
43
|
*/
|
package/jest.config.js
CHANGED
|
@@ -19,7 +19,12 @@ export default {
|
|
|
19
19
|
moduleNameMapper: {
|
|
20
20
|
'^@/(.*)$': '<rootDir>/src/$1',
|
|
21
21
|
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
22
|
+
'^@prmichaelsen/remember-core$': '<rootDir>/node_modules/@prmichaelsen/remember-core/dist/index.js',
|
|
23
|
+
'^@prmichaelsen/remember-core/(.*)$': '<rootDir>/node_modules/@prmichaelsen/remember-core/dist/$1/index.js',
|
|
22
24
|
},
|
|
25
|
+
transformIgnorePatterns: [
|
|
26
|
+
'node_modules/(?!(@prmichaelsen/remember-core)/)',
|
|
27
|
+
],
|
|
23
28
|
transform: {
|
|
24
29
|
'^.+\\.ts$': [
|
|
25
30
|
'ts-jest',
|
|
@@ -27,5 +32,11 @@ export default {
|
|
|
27
32
|
useESM: true,
|
|
28
33
|
},
|
|
29
34
|
],
|
|
35
|
+
'node_modules/@prmichaelsen/remember-core/.+\\.js$': [
|
|
36
|
+
'ts-jest',
|
|
37
|
+
{
|
|
38
|
+
useESM: true,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
30
41
|
},
|
|
31
42
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prmichaelsen/remember-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.14.1",
|
|
4
4
|
"description": "Multi-tenant memory system MCP server with vector search and relationships",
|
|
5
5
|
"main": "dist/server.js",
|
|
6
6
|
"type": "module",
|
|
@@ -50,8 +50,10 @@
|
|
|
50
50
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
51
51
|
"@prmichaelsen/firebase-admin-sdk-v8": "^2.2.0",
|
|
52
52
|
"@prmichaelsen/mcp-auth": "^7.0.4",
|
|
53
|
+
"@prmichaelsen/remember-core": "^0.16.0",
|
|
53
54
|
"@prmichaelsen/remember-mcp": "^2.7.3",
|
|
54
55
|
"dotenv": "^16.4.5",
|
|
56
|
+
"uuid": "^13.0.0",
|
|
55
57
|
"weaviate-client": "^3.2.0"
|
|
56
58
|
},
|
|
57
59
|
"devDependencies": {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge module: initializes remember-core services from remember-mcp infrastructure.
|
|
3
|
+
*
|
|
4
|
+
* Core services are scoped per-user (MemoryService, RelationshipService, SpaceService)
|
|
5
|
+
* except PreferencesDatabaseService and ConfirmationTokenService which are singletons.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
MemoryService,
|
|
10
|
+
RelationshipService,
|
|
11
|
+
SpaceService,
|
|
12
|
+
PreferencesDatabaseService,
|
|
13
|
+
ConfirmationTokenService,
|
|
14
|
+
createLogger,
|
|
15
|
+
} from '@prmichaelsen/remember-core';
|
|
16
|
+
import type { Logger } from '@prmichaelsen/remember-core';
|
|
17
|
+
import { getWeaviateClient } from './weaviate/client.js';
|
|
18
|
+
import { getMemoryCollection } from './weaviate/schema.js';
|
|
19
|
+
|
|
20
|
+
export interface CoreServices {
|
|
21
|
+
memory: MemoryService;
|
|
22
|
+
relationship: RelationshipService;
|
|
23
|
+
space: SpaceService;
|
|
24
|
+
preferences: PreferencesDatabaseService;
|
|
25
|
+
token: ConfirmationTokenService;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Singletons — shared across all user scopes
|
|
29
|
+
const coreLogger: Logger = createLogger('info');
|
|
30
|
+
const tokenService = new ConfirmationTokenService(coreLogger);
|
|
31
|
+
const preferencesService = new PreferencesDatabaseService(coreLogger);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create core services scoped to a specific user.
|
|
35
|
+
* Call after databases have been initialized (initWeaviateClient + initFirestore).
|
|
36
|
+
*/
|
|
37
|
+
export function createCoreServices(userId: string): CoreServices {
|
|
38
|
+
const collection = getMemoryCollection(userId);
|
|
39
|
+
const weaviateClient = getWeaviateClient();
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
memory: new MemoryService(collection, userId, coreLogger),
|
|
43
|
+
relationship: new RelationshipService(collection, userId, coreLogger),
|
|
44
|
+
space: new SpaceService(weaviateClient, collection, userId, tokenService, coreLogger),
|
|
45
|
+
preferences: preferencesService,
|
|
46
|
+
token: tokenService,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export { coreLogger, tokenService, preferencesService };
|
|
@@ -1,34 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tests for moderation status wiring in the publish flow.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* After migration to remember-core, the publish confirmation logic
|
|
5
|
+
* is handled by SpaceService.confirm(). These tests verify the adapter
|
|
6
|
+
* correctly delegates and formats responses.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
import { handleConfirm } from './confirm.js';
|
|
9
10
|
|
|
10
|
-
// ─── Mocks
|
|
11
|
+
// ─── Mocks ──────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
jest.mock('../core-services.js', () => ({
|
|
14
|
+
createCoreServices: jest.fn(),
|
|
15
|
+
}));
|
|
11
16
|
|
|
12
17
|
jest.mock('../weaviate/client.js', () => ({
|
|
13
18
|
getWeaviateClient: jest.fn(),
|
|
14
19
|
getMemoryCollectionName: jest.fn((userId: string) => `Memory_users_${userId}`),
|
|
15
|
-
fetchMemoryWithAllProperties: jest.fn(),
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
jest.mock('../weaviate/space-schema.js', () => ({
|
|
19
|
-
ensurePublicCollection: jest.fn(),
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
jest.mock('../services/confirmation-token.service.js', () => ({
|
|
23
|
-
confirmationTokenService: { confirmRequest: jest.fn() },
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
jest.mock('../services/space-config.service.js', () => ({
|
|
27
|
-
getSpaceConfig: jest.fn(),
|
|
28
|
-
}));
|
|
29
|
-
|
|
30
|
-
jest.mock('../utils/logger.js', () => ({
|
|
31
|
-
logger: { info: jest.fn(), debug: jest.fn(), warn: jest.fn(), error: jest.fn() },
|
|
32
20
|
}));
|
|
33
21
|
|
|
34
22
|
jest.mock('../utils/debug.js', () => ({
|
|
@@ -41,200 +29,156 @@ jest.mock('../utils/debug.js', () => ({
|
|
|
41
29
|
})),
|
|
42
30
|
}));
|
|
43
31
|
|
|
44
|
-
jest.mock('../collections/dot-notation.js', () => ({
|
|
45
|
-
CollectionType: { GROUPS: 'groups' },
|
|
46
|
-
getCollectionName: jest.fn((_: string, id: string) => `Memory_groups_${id}`),
|
|
47
|
-
}));
|
|
48
|
-
|
|
49
|
-
jest.mock('../collections/composite-ids.js', () => ({
|
|
50
|
-
generateCompositeId: jest.fn((u: string, m: string) => `${u}.${m}`),
|
|
51
|
-
parseCompositeId: jest.fn(),
|
|
52
|
-
}));
|
|
53
|
-
|
|
54
|
-
jest.mock('../collections/tracking-arrays.js', () => ({
|
|
55
|
-
addToSpaceIds: jest.fn(),
|
|
56
|
-
addToGroupIds: jest.fn(),
|
|
57
|
-
removeFromSpaceIds: jest.fn(),
|
|
58
|
-
removeFromGroupIds: jest.fn(),
|
|
59
|
-
getPublishedLocations: jest.fn(),
|
|
60
|
-
}));
|
|
61
|
-
|
|
62
32
|
jest.mock('../utils/error-handler.js', () => ({
|
|
63
33
|
handleToolError: jest.fn(),
|
|
64
34
|
}));
|
|
65
35
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const mockGetWeaviateClient = getWeaviateClient as jest.MockedFunction<any>;
|
|
74
|
-
const mockFetchMemory = fetchMemoryWithAllProperties as jest.MockedFunction<any>;
|
|
75
|
-
const mockEnsurePublicCollection = ensurePublicCollection as jest.MockedFunction<any>;
|
|
76
|
-
const mockConfirmRequest = confirmationTokenService.confirmRequest as jest.MockedFunction<any>;
|
|
77
|
-
const mockGetSpaceConfig = getSpaceConfig as jest.MockedFunction<any>;
|
|
78
|
-
|
|
79
|
-
// ─── Shared per-test mock state ──────────────────────────────
|
|
80
|
-
|
|
81
|
-
let spaceInsert: jest.Mock;
|
|
82
|
-
let spaceUpdate: jest.Mock;
|
|
83
|
-
let groupInsert: jest.Mock;
|
|
84
|
-
let groupUpdate: jest.Mock;
|
|
85
|
-
let userUpdate: jest.Mock;
|
|
86
|
-
|
|
87
|
-
const ORIGINAL_MEMORY = {
|
|
88
|
-
properties: {
|
|
89
|
-
user_id: 'user-1',
|
|
90
|
-
content: 'Test memory',
|
|
91
|
-
content_type: 'text',
|
|
92
|
-
tags: ['test'],
|
|
93
|
-
space_ids: [],
|
|
94
|
-
group_ids: [],
|
|
95
|
-
},
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
function makePublishRequest(overrides: Record<string, any> = {}) {
|
|
99
|
-
return {
|
|
100
|
-
request_id: 'req-1',
|
|
101
|
-
userId: 'user-1',
|
|
102
|
-
action: 'publish_memory' as const,
|
|
103
|
-
payload: { memory_id: 'mem-1', spaces: [], groups: [], ...overrides },
|
|
104
|
-
createdAt: Date.now(),
|
|
105
|
-
expiresAt: Date.now() + 300_000,
|
|
106
|
-
status: 'confirmed',
|
|
107
|
-
};
|
|
108
|
-
}
|
|
36
|
+
import { createCoreServices } from '../core-services.js';
|
|
37
|
+
const mockCreateCoreServices = createCoreServices as jest.MockedFunction<any>;
|
|
38
|
+
|
|
39
|
+
// ─── Shared mock state ──────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
let mockConfirm: jest.Mock;
|
|
42
|
+
let mockValidateToken: jest.Mock;
|
|
109
43
|
|
|
110
44
|
// ─── Tests ───────────────────────────────────────────────────
|
|
111
45
|
|
|
112
46
|
describe('publish moderation wiring', () => {
|
|
113
47
|
beforeEach(() => {
|
|
114
48
|
jest.clearAllMocks();
|
|
49
|
+
mockConfirm = jest.fn();
|
|
50
|
+
mockValidateToken = jest.fn();
|
|
115
51
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
groupInsert = jest.fn().mockResolvedValue(undefined);
|
|
120
|
-
groupUpdate = jest.fn().mockResolvedValue(undefined);
|
|
121
|
-
userUpdate = jest.fn().mockResolvedValue(undefined);
|
|
122
|
-
|
|
123
|
-
// Weaviate client: route collections by name
|
|
124
|
-
mockGetWeaviateClient.mockReturnValue({
|
|
125
|
-
collections: {
|
|
126
|
-
get: jest.fn().mockImplementation((name: string) => {
|
|
127
|
-
if (name.startsWith('Memory_groups_')) {
|
|
128
|
-
return { data: { insert: groupInsert, update: groupUpdate } };
|
|
129
|
-
}
|
|
130
|
-
// User collection
|
|
131
|
-
return { data: { insert: jest.fn(), update: userUpdate } };
|
|
132
|
-
}),
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
// Space collection via ensurePublicCollection
|
|
137
|
-
mockEnsurePublicCollection.mockResolvedValue({
|
|
138
|
-
data: { insert: spaceInsert, update: spaceUpdate },
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
// fetchMemoryWithAllProperties: 1st call = original, subsequent = null (not already published)
|
|
142
|
-
mockFetchMemory
|
|
143
|
-
.mockResolvedValueOnce(ORIGINAL_MEMORY)
|
|
144
|
-
.mockResolvedValue(null);
|
|
145
|
-
|
|
146
|
-
// Default: unmoderated
|
|
147
|
-
mockGetSpaceConfig.mockResolvedValue({
|
|
148
|
-
require_moderation: false,
|
|
149
|
-
default_write_mode: 'owner_only',
|
|
52
|
+
mockCreateCoreServices.mockReturnValue({
|
|
53
|
+
space: { confirm: mockConfirm },
|
|
54
|
+
token: { validateToken: mockValidateToken, confirmRequest: jest.fn() },
|
|
150
55
|
});
|
|
151
56
|
});
|
|
152
57
|
|
|
153
58
|
describe('spaces publication', () => {
|
|
154
59
|
it('sets moderation_status to approved for unmoderated space', async () => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
60
|
+
mockValidateToken.mockResolvedValue({ action: 'publish_memory' });
|
|
61
|
+
mockConfirm.mockResolvedValue({
|
|
62
|
+
action: 'publish_memory',
|
|
63
|
+
success: true,
|
|
64
|
+
composite_id: 'user-1.mem-1',
|
|
65
|
+
published_to: ['spaces: public'],
|
|
66
|
+
space_ids: ['public'],
|
|
67
|
+
group_ids: [],
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const result = JSON.parse(await handleConfirm({ token: 'tok-1' }, 'user-1'));
|
|
71
|
+
|
|
72
|
+
expect(result.success).toBe(true);
|
|
73
|
+
expect(result.published_to).toContain('spaces: public');
|
|
74
|
+
expect(mockConfirm).toHaveBeenCalledWith({ token: 'tok-1' });
|
|
162
75
|
});
|
|
163
76
|
|
|
164
77
|
it('sets moderation_status to pending for moderated space', async () => {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
78
|
+
mockValidateToken.mockResolvedValue({ action: 'publish_memory' });
|
|
79
|
+
mockConfirm.mockResolvedValue({
|
|
80
|
+
action: 'publish_memory',
|
|
81
|
+
success: true,
|
|
82
|
+
composite_id: 'user-1.mem-1',
|
|
83
|
+
published_to: ['spaces: moderated-space'],
|
|
84
|
+
space_ids: ['moderated-space'],
|
|
85
|
+
group_ids: [],
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const result = JSON.parse(await handleConfirm({ token: 'tok-2' }, 'user-1'));
|
|
89
|
+
|
|
90
|
+
expect(result.success).toBe(true);
|
|
91
|
+
expect(mockConfirm).toHaveBeenCalledWith({ token: 'tok-2' });
|
|
173
92
|
});
|
|
174
93
|
|
|
175
94
|
it('sets pending if any of multiple spaces requires moderation', async () => {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
95
|
+
mockValidateToken.mockResolvedValue({ action: 'publish_memory' });
|
|
96
|
+
mockConfirm.mockResolvedValue({
|
|
97
|
+
action: 'publish_memory',
|
|
98
|
+
success: true,
|
|
99
|
+
composite_id: 'user-1.mem-1',
|
|
100
|
+
published_to: ['spaces: open, strict'],
|
|
101
|
+
space_ids: ['open', 'strict'],
|
|
102
|
+
group_ids: [],
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const result = JSON.parse(await handleConfirm({ token: 'tok-3' }, 'user-1'));
|
|
106
|
+
|
|
107
|
+
expect(result.success).toBe(true);
|
|
108
|
+
expect(result.space_ids).toContain('open');
|
|
109
|
+
expect(result.space_ids).toContain('strict');
|
|
185
110
|
});
|
|
186
111
|
});
|
|
187
112
|
|
|
188
113
|
describe('groups publication', () => {
|
|
189
114
|
it('sets moderation_status to approved for unmoderated group', async () => {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
115
|
+
mockValidateToken.mockResolvedValue({ action: 'publish_memory' });
|
|
116
|
+
mockConfirm.mockResolvedValue({
|
|
117
|
+
action: 'publish_memory',
|
|
118
|
+
success: true,
|
|
119
|
+
composite_id: 'user-1.mem-1',
|
|
120
|
+
published_to: ['group: team-alpha'],
|
|
121
|
+
space_ids: [],
|
|
122
|
+
group_ids: ['team-alpha'],
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const result = JSON.parse(await handleConfirm({ token: 'tok-4' }, 'user-1'));
|
|
126
|
+
|
|
127
|
+
expect(result.success).toBe(true);
|
|
128
|
+
expect(result.group_ids).toContain('team-alpha');
|
|
197
129
|
});
|
|
198
130
|
|
|
199
131
|
it('sets moderation_status to pending for moderated group', async () => {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
132
|
+
mockValidateToken.mockResolvedValue({ action: 'publish_memory' });
|
|
133
|
+
mockConfirm.mockResolvedValue({
|
|
134
|
+
action: 'publish_memory',
|
|
135
|
+
success: true,
|
|
136
|
+
composite_id: 'user-1.mem-1',
|
|
137
|
+
published_to: ['group: strict-group'],
|
|
138
|
+
space_ids: [],
|
|
139
|
+
group_ids: ['strict-group'],
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const result = JSON.parse(await handleConfirm({ token: 'tok-5' }, 'user-1'));
|
|
143
|
+
|
|
144
|
+
expect(result.success).toBe(true);
|
|
145
|
+
expect(result.group_ids).toContain('strict-group');
|
|
208
146
|
});
|
|
209
147
|
|
|
210
148
|
it('sets independent moderation status per group', async () => {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
.
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
expect(
|
|
225
|
-
expect(groupInsert.mock.calls[0][0].properties.moderation_status).toBe('approved');
|
|
226
|
-
expect(groupInsert.mock.calls[1][0].properties.moderation_status).toBe('pending');
|
|
149
|
+
mockValidateToken.mockResolvedValue({ action: 'publish_memory' });
|
|
150
|
+
mockConfirm.mockResolvedValue({
|
|
151
|
+
action: 'publish_memory',
|
|
152
|
+
success: true,
|
|
153
|
+
composite_id: 'user-1.mem-1',
|
|
154
|
+
published_to: ['group: open-group', 'group: strict-group'],
|
|
155
|
+
space_ids: [],
|
|
156
|
+
group_ids: ['open-group', 'strict-group'],
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const result = JSON.parse(await handleConfirm({ token: 'tok-6' }, 'user-1'));
|
|
160
|
+
|
|
161
|
+
expect(result.success).toBe(true);
|
|
162
|
+
expect(result.group_ids).toEqual(['open-group', 'strict-group']);
|
|
227
163
|
});
|
|
228
164
|
});
|
|
229
165
|
|
|
230
166
|
describe('default behavior', () => {
|
|
231
167
|
it('defaults to approved when getSpaceConfig returns defaults', async () => {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
168
|
+
mockValidateToken.mockResolvedValue({ action: 'publish_memory' });
|
|
169
|
+
mockConfirm.mockResolvedValue({
|
|
170
|
+
action: 'publish_memory',
|
|
171
|
+
success: true,
|
|
172
|
+
composite_id: 'user-1.mem-1',
|
|
173
|
+
published_to: ['spaces: unknown-space'],
|
|
174
|
+
space_ids: ['unknown-space'],
|
|
175
|
+
group_ids: [],
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const result = JSON.parse(await handleConfirm({ token: 'tok-7' }, 'user-1'));
|
|
179
|
+
|
|
180
|
+
expect(result.success).toBe(true);
|
|
181
|
+
expect(result.published_to).toBeDefined();
|
|
238
182
|
});
|
|
239
183
|
});
|
|
240
184
|
});
|