Keep SCUM data parsing plugin-owned
This commit is contained in:
@@ -4,7 +4,7 @@ import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import { migrateConfigurationRecord, migrateGiftGrantRecord, migratePlayerProfileRecord, migratePlayerRecord, migrateStatePatchRecord, migrateTrajectoryHistoryRecord, migrateTrajectoryRecord, migrationStatus } from "../examples/scum-server-plugin/features/migration.js";
|
||||
import { buildPlayerAttributeMutation, createGiftDelivery, deleteGiftDefinition, loadSCUMSurface, mergePlayerSnapshots, parseGiftCommands, parseGiftItems, playerAttributeDrafts, playerAttributeSqlPreview, projectSCUMLoginLogs, queueGiftDelivery, queuePlayerAttributePatch, resetGiftClaim, resetPendingGift, resolveMapBounds, saveEventProduce, saveGiftDefinition, saveMapSettings, scumCollections, startEvent, type RecordMap, type SCUMSurfaceData, type SCUMWorkspaceActions } from "../examples/scum-server-plugin/features/page-data.js";
|
||||
import { buildPlayerAttributeMutation, createGiftDelivery, deleteGiftDefinition, loadSCUMSurface, mergePlayerSnapshots, parseGiftCommands, parseGiftItems, playerAttributeDrafts, playerAttributeSqlPreview, queueGiftDelivery, queuePlayerAttributePatch, queueSCUMDatabaseRefresh, resetGiftClaim, resetPendingGift, resolveMapBounds, saveEventProduce, saveGiftDefinition, saveMapSettings, scumCollections, startEvent, type RecordMap, type SCUMSurfaceData, type SCUMWorkspaceActions } from "../examples/scum-server-plugin/features/page-data.js";
|
||||
import { collectMapPoints, mapPointStyle } from "../examples/scum-server-plugin/features/page.js";
|
||||
import { renderPluginPage } from "../examples/scum-server-plugin/page-bundle/index.js";
|
||||
import { configurationCatalog, validateConfigPatch, validateStatePatch, validateVehicleSpawn, vehicleSpawnCatalog } from "../examples/scum-server-plugin/features/schemas.js";
|
||||
@@ -103,25 +103,17 @@ describe("SCUM plugin feature module", () => {
|
||||
expect(dataClientSource).not.toContain("scum-client-manager");
|
||||
});
|
||||
|
||||
it("projects SCUM login log lines inside the plugin-owned page module", async () => {
|
||||
const pluginData = pluginDataActions({ list: async (collection, key) => {
|
||||
if (collection === scumCollections.players) return { items: [{ key: "76561198000000001", value: { steamId: "76561198000000001", displayName: "Old", normalBalance: 100 } }] };
|
||||
if (collection === scumCollections.logCursors && key) return { items: [{ key, value: { nextSeq: 1 } }] };
|
||||
return { items: [], count: 0 };
|
||||
} });
|
||||
const logs = {
|
||||
listStreams: vi.fn(async () => ({ items: [{ id: "stream-login", streamKey: "scum.login", latestSeq: 3 }], count: 1 })),
|
||||
query: vi.fn(async () => ({ logStreamId: "stream-login", entries: [
|
||||
{ seq: 2, timestamp: "2026-08-10T00:01:00Z", line: "Login: Player 'Mira' SteamID 76561198000000001 IP 203.0.113.7" },
|
||||
{ seq: 3, timestamp: "2026-08-10T00:04:00Z", line: "Logout: Player 'Mira' SteamID 76561198000000001 IP 203.0.113.7" }
|
||||
], nextSeq: 3, latestSeq: 3 }))
|
||||
};
|
||||
await expect(projectSCUMLoginLogs({ pluginData, logs })).resolves.toBe(2);
|
||||
expect(logs.query).toHaveBeenCalledWith({ logStreamId: "stream-login", afterSeq: 1, limit: 200 });
|
||||
expect(pluginData.transact).toHaveBeenCalledWith(scumCollections.players, [expect.objectContaining({ key: "76561198000000001", value: expect.objectContaining({ displayName: "Mira", online: false, status: "offline", normalBalance: 100, lastLoginIp: "203.0.113.7", lastLogoutObservedAt: "2026-08-10T00:04:00Z", source: "plugin.log.scum.login" }) })]);
|
||||
expect(pluginData.transact).toHaveBeenCalledWith(scumCollections.activityEvents, expect.arrayContaining([expect.objectContaining({ key: "stream-login:2", value: expect.objectContaining({ eventType: "login", rawLine: expect.stringContaining("Login:") }) }), expect.objectContaining({ key: "stream-login:3", value: expect.objectContaining({ eventType: "logout", rawLine: expect.stringContaining("Logout:") }) })]));
|
||||
expect(pluginData.put).toHaveBeenCalledWith(scumCollections.logCursors, "scum.login:stream-login", expect.objectContaining({ nextSeq: 3 }));
|
||||
expect(dataClientSource).toContain("projectSCUMLoginLogs");
|
||||
it("queues SCUM database reads through declared template keys instead of log parsing", async () => {
|
||||
const dispatch = vi.fn<NonNullable<SCUMWorkspaceActions["dispatch"]>>(async (envelope) => ({ status: "queued", result: { jobId: envelope.requestId } }));
|
||||
await expect(queueSCUMDatabaseRefresh({ dispatch }, "players", 5000)).resolves.toHaveLength(2);
|
||||
expect(dispatch.mock.calls.map(([envelope]) => envelope.payload?.["input.templateKey"])).toEqual(["scum.player.profile", "scum.positions"]);
|
||||
expect(dispatch.mock.calls.map(([envelope]) => envelope.payload)).toEqual(expect.arrayContaining([
|
||||
expect.objectContaining({ capability: "remote.run.db.sqlite.query", declarationKey: "scum-database", targetKey: "scum-database", "input.templateKey": "scum.player.profile", "input.activeWithinSeconds": "600" }),
|
||||
expect.objectContaining({ capability: "remote.run.db.sqlite.query", declarationKey: "scum-database", targetKey: "scum-database", "input.templateKey": "scum.positions", "input.activeWithinSeconds": "600" })
|
||||
]));
|
||||
expect(dispatch.mock.calls[0]?.[0].payload).not.toHaveProperty("input.sqlText");
|
||||
expect(dataClientSource).not.toContain("projectSCUMLoginLogs");
|
||||
expect(dataClientSource).not.toContain("logs.query");
|
||||
});
|
||||
|
||||
it("uses workflows as the manifest activity key and keeps activity as a compatibility alias", async () => {
|
||||
@@ -312,9 +304,11 @@ describe("SCUM plugin feature module", () => {
|
||||
for (const forbidden of ["listSCUM", "gameGift", "createSCUMOperation", "createSCUMWorkflow", "C:/", "/Users/", "hostPath", "sampleCoordinates", "samplePlayers"]) expect(source).not.toContain(forbidden);
|
||||
expect(source).toContain("pluginData");
|
||||
expect(source).toContain("remote.access.request");
|
||||
expect(source).not.toContain("input.templateKey");
|
||||
expect(source).toContain("input.templateKey");
|
||||
expect(source).not.toContain("projectSCUMLoginLogs");
|
||||
expect(source).not.toContain("logs.query");
|
||||
expect(source).not.toContain("requestSCUMPageQueries");
|
||||
expect(pageSource).toContain("setInterval(refresh, 3000)");
|
||||
expect(pageSource).toContain("setInterval(refresh, 5000)");
|
||||
expect(pageSource).toContain("clearInterval(interval)");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user