import assert from 'node:assert/strict'; import test from 'node:test'; import { createMindSpaceService, DEFAULT_SPACE_QUOTA_BYTES, ensureDefaultSpaces, initializeDefaultSpace, SYSTEM_CATEGORIES, } from './mindspace.mjs'; test('initializeDefaultSpace creates one space and all system categories', async () => { const queries = []; let id = 0; const db = { async query(sql, params) { queries.push({ sql, params }); if (sql.includes('SELECT id FROM h5_user_spaces')) { return [[{ id: 'space-1' }]]; } return [[]]; }, }; const spaceId = await initializeDefaultSpace(db, 'user-1', { now: 123, idFactory: () => `id-${++id}`, }); assert.equal(spaceId, 'space-1'); assert.equal(queries.length, SYSTEM_CATEGORIES.length + 2); assert.equal(queries[0].params[3], DEFAULT_SPACE_QUOTA_BYTES); assert.deepEqual( queries .filter(({ sql }) => sql.includes('INSERT INTO h5_space_categories')) .map(({ params }) => params[3]), ['oa', 'private', 'public', 'draft', 'archive'], ); }); test('ensureDefaultSpaces backfills only users without a space', async () => { let selectedMissingUsers = false; const createdFor = []; const pool = { async query(sql, params) { if (sql.includes('LEFT JOIN h5_user_spaces')) { selectedMissingUsers = true; return [[{ id: 'user-a' }, { id: 'user-b' }]]; } if (sql.includes('INSERT INTO h5_user_spaces')) { createdFor.push(params[1]); return [[]]; } if (sql.includes('SELECT id FROM h5_user_spaces')) { return [[{ id: `space-${params[0]}` }]]; } return [[]]; }, }; const count = await ensureDefaultSpaces(pool, { idFactory: () => 'generated-id', }); assert.equal(selectedMissingUsers, true); assert.equal(count, 2); assert.deepEqual(createdFor, ['user-a', 'user-b']); }); test('getSpace scopes space and categories to the authenticated user', async () => { const calls = []; const pool = { async query(sql, params) { calls.push({ sql, params }); if (sql.includes('FROM h5_user_spaces')) { return [[{ id: 'space-1', user_id: 'user-1', space_name: '我的空间', quota_bytes: 5 * 1024 * 1024, used_bytes: 1024, reserved_bytes: 2048, status: 'active', created_at: 10, updated_at: 20, }]]; } return [[{ id: 'category-1', category_code: 'private', category_name: '私人区', visibility_policy: 'private', ai_access_policy: 'explicit_asset_grant', publish_policy: 'desensitized_copy_only', is_system: 1, sort_order: 20, item_count: 0, }]]; }, }; const service = createMindSpaceService(pool); const space = await service.getSpace('user-1'); assert.equal(space.userId, 'user-1'); assert.equal(space.quota.availableBytes, 5 * 1024 * 1024 - 3072); assert.equal(space.categories[0].code, 'private'); assert.deepEqual(calls[0].params, ['user-1']); assert.deepEqual(calls[1].params, ['user-1', 'space-1']); }); test('getSpace returns null when the user has no space', async () => { const service = createMindSpaceService({ async query() { return [[]]; }, }); assert.equal(await service.getSpace('missing-user'), null); assert.equal(await service.getQuota('missing-user'), null); assert.equal(await service.listCategories('missing-user'), null); });