chore(仓库对齐): 文档库结构治理 + IM/插件线落地
build / build-and-scan (push) Waiting to run

文档库:目录改为编号制(01-规范/02-架构设计/03-数据库/04-调整方案/
05-交接单/06-ops/07-scripts/08-skills/09-archive),顶层散文件归入 01-规范/;
INDEX.md 与 docs-manifest.json 重刷(档案 146 篇);旧目录名引用全量对齐。

IM 线:src/im/**(SDK / hub / store / presence / ws / gateway-token)、
src/web/routes/im.ts、src/db/plugin-data/**、src/supervisor/plugin-assembly.ts
及对应 test/**。

插件线:poc/{im-agent-bridge,im-connection-gateway,im-conversation-tabs,
business-plugins-im,carbon-mcp-probe}、src/web/routes/{sessions,overlay-device}.ts、
src/net/relay/{device-grant,instance-credential}.ts。

仓库卫生:清出 40 个历史误入库 / 已改名文件(34 个交接单归档 + 6 个旧结构,
本地均有副本);dsh-server-docs/.gitignore 补 tmp/;交接单不入库(政策)。
This commit is contained in:
admin committed 2026-09-24 07:25:16 +08:00
1 parent 3d8f50e366
commit e6207aa691
239 files changed
+34477 -14633

No files matched your search

+100
View File
@@ -302,6 +302,106 @@ function register(backend, makeAdapter) {
await db.close()
}
})
// ── v12 · 设备台账(序㊻ 步骤 6 / S3)────────────────────────────────────────
test(`${backend}: upsertOverlayDevice —— 首签 = 1、续签 = +1(同一行)、租约被刷新`, async () => {
const db = await makeAdapter()
try {
await db.createUser(user('u1', 'u1'))
const t0 = 1_700_000_000_000
const base = { network: 'u:u1', hostId: 'd-u1-abcdef12', userId: 'u1', nodeKey: 'ab'.repeat(32) }
const first = await db.upsertOverlayDevice({ ...base, leaseExpiresAt: t0 + 1000, at: t0 })
assert.equal(first.grantRenewals, 1, '首次插入 = 1')
assert.equal(first.status, 'active', '首次插入 = active')
assert.equal(first.createdAt, t0)
assert.equal(first.grantIssuedAt, t0)
const second = await db.upsertOverlayDevice({ ...base, leaseExpiresAt: t0 + 2000, at: t0 + 500 })
assert.equal(second.grantRenewals, 2, '续签 = 旧值 + 1(⛔ 不是恒为 1,也不是 2 卡住)')
assert.equal(second.leaseExpiresAt, t0 + 2000, '租约必须被刷新')
assert.equal(second.createdAt, t0, 'created_at 不被续签改动')
const third = await db.upsertOverlayDevice({ ...base, leaseExpiresAt: t0 + 3000, at: t0 + 900 })
assert.equal(third.grantRenewals, 3, '第三次 = 3(计数真的在累加)')
assert.equal((await db.listOverlayDevices('u:u1')).length, 1, '续签 = 同一行,⛔ 不是插新行')
// 按网过滤 / 按 userId 归属
await db.createUser(user('u2', 'u2'))
await db.upsertOverlayDevice({
network: 'u:u2',
hostId: 'd-u2-11111111',
userId: 'u2',
nodeKey: 'cd'.repeat(32),
leaseExpiresAt: t0 + 1000,
at: t0,
})
assert.equal((await db.listOverlayDevices()).length, 2, '不带过滤 = 全部')
assert.equal((await db.listOverlayDevices('u:u2')).length, 1, '按网过滤')
assert.equal((await db.findOverlayDevice('u:u2', 'd-u2-11111111')).userId, 'u2')
assert.equal(await db.findOverlayDevice('u:u2', 'd-u2-22222222'), undefined, '不存在 ⇒ undefined(⛔ 不抛)')
} finally {
await db.close()
}
})
test(`${backend}: setOverlayDeviceStatus —— 停发是**黏性**的(续签不复活)+ 不存在的行 = false`, async () => {
const db = await makeAdapter()
try {
await db.createUser(user('u3', 'u3'))
const row = {
network: 'u:u3',
hostId: 'd-u3-abcdef12',
userId: 'u3',
nodeKey: 'ef'.repeat(32),
leaseExpiresAt: Date.now() + 1000,
}
await db.upsertOverlayDevice(row)
assert.equal(await db.setOverlayDeviceStatus('u:u3', 'd-u3-abcdef12', 'revoked'), true)
assert.equal((await db.findOverlayDevice('u:u3', 'd-u3-abcdef12')).status, 'revoked')
// 🔴 关键:续签**不许**把它复活(SQL 层的 DO UPDATE SET 里没有 status 这一列)
const renewed = await db.upsertOverlayDevice({ ...row, leaseExpiresAt: Date.now() + 9999 })
assert.equal(renewed.status, 'revoked', '⚠️ 续签不得让被停发的设备自动复活')
assert.equal(renewed.grantRenewals, 2, '但它确实是一次续签(计数照常累加)')
// 恢复只能显式来
assert.equal(await db.setOverlayDeviceStatus('u:u3', 'd-u3-abcdef12', 'active'), true)
assert.equal((await db.findOverlayDevice('u:u3', 'd-u3-abcdef12')).status, 'active')
// 不存在的行 ⇒ false(路由据此回 404)
assert.equal(await db.setOverlayDeviceStatus('u:u3', 'd-u3-00000000', 'revoked'), false)
} finally {
await db.close()
}
})
test(`${backend}: overlay_devices 归属 user(删除用户即级联清理台账)`, async () => {
const db = await makeAdapter()
try {
await db.createUser(user('u4', 'u4'))
await db.upsertOverlayDevice({
network: 'u:u4',
hostId: 'd-u4-abcdef12',
userId: 'u4',
nodeKey: 'aa'.repeat(32),
leaseExpiresAt: Date.now() + 1000,
})
assert.equal((await db.listOverlayDevices()).length, 1)
await db.deleteUser('u4')
assert.equal((await db.listOverlayDevices()).length, 0, '删用户应当把台账一起带走(ON DELETE CASCADE)')
// 未知用户 ⇒ 外键违例(与其它表同一口径)
await assert.rejects(
() =>
db.upsertOverlayDevice({
network: 'u:ghost',
hostId: 'd-ghost-abcdef12',
userId: 'missing',
nodeKey: 'bb'.repeat(32),
leaseExpiresAt: Date.now(),
}),
ForeignKeyViolationError,
)
} finally {
await db.close()
}
})
}
register('sqlite', () => new SqliteAdapter(':memory:', 100000))