@zhin.js/plugin-rps 1.0.0

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.
Files changed (47) hide show
  1. package/lib/commands.d.ts +6 -0
  2. package/lib/commands.d.ts.map +1 -0
  3. package/lib/commands.js +86 -0
  4. package/lib/commands.js.map +1 -0
  5. package/lib/engine.d.ts +9 -0
  6. package/lib/engine.d.ts.map +1 -0
  7. package/lib/engine.js +38 -0
  8. package/lib/engine.js.map +1 -0
  9. package/lib/game-flow.d.ts +14 -0
  10. package/lib/game-flow.d.ts.map +1 -0
  11. package/lib/game-flow.js +92 -0
  12. package/lib/game-flow.js.map +1 -0
  13. package/lib/hub-register.d.ts +5 -0
  14. package/lib/hub-register.d.ts.map +1 -0
  15. package/lib/hub-register.js +26 -0
  16. package/lib/hub-register.js.map +1 -0
  17. package/lib/index.d.ts +2 -0
  18. package/lib/index.d.ts.map +1 -0
  19. package/lib/index.js +26 -0
  20. package/lib/index.js.map +1 -0
  21. package/lib/models.d.ts +26 -0
  22. package/lib/models.d.ts.map +1 -0
  23. package/lib/models.js +20 -0
  24. package/lib/models.js.map +1 -0
  25. package/lib/rps-command.d.ts +5 -0
  26. package/lib/rps-command.d.ts.map +1 -0
  27. package/lib/rps-command.js +37 -0
  28. package/lib/rps-command.js.map +1 -0
  29. package/lib/session-service.d.ts +17 -0
  30. package/lib/session-service.d.ts.map +1 -0
  31. package/lib/session-service.js +87 -0
  32. package/lib/session-service.js.map +1 -0
  33. package/lib/view.d.ts +9 -0
  34. package/lib/view.d.ts.map +1 -0
  35. package/lib/view.js +49 -0
  36. package/lib/view.js.map +1 -0
  37. package/package.json +37 -0
  38. package/plugin.yml +2 -0
  39. package/src/commands.ts +102 -0
  40. package/src/engine.ts +44 -0
  41. package/src/game-flow.ts +127 -0
  42. package/src/hub-register.ts +30 -0
  43. package/src/index.ts +36 -0
  44. package/src/models.ts +47 -0
  45. package/src/rps-command.ts +45 -0
  46. package/src/session-service.ts +92 -0
  47. package/src/view.ts +56 -0
@@ -0,0 +1,6 @@
1
+ import { type Plugin } from 'zhin.js';
2
+ import type { SessionService } from './session-service.js';
3
+ export declare function registerCommands(plugin: Plugin, getServices: () => SessionService | null): void;
4
+ export declare function registerInteractive(plugin: Plugin, getServices: () => SessionService | null): void;
5
+ export declare function registerTextFallback(plugin: Plugin, getServices: () => SessionService | null): void;
6
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiD,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AASrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAoB3D,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CAG/F;AA4BD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CAUlG;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CA4BnG"}
@@ -0,0 +1,86 @@
1
+ import { MessageCommand, getActionFromMessage } from 'zhin.js';
2
+ import { buildChoiceFallbackMap, channelKey, normalizeRpsAction, parseChoicePayload, } from '@zhin.js/game-shared';
3
+ import { handleChoice, RPS_PREFIX } from './game-flow.js';
4
+ import { runRpsCommand } from './rps-command.js';
5
+ function registerPattern(plugin, pattern, desc, getServices) {
6
+ plugin.addCommand(new MessageCommand(pattern)
7
+ .desc(desc)
8
+ .action(async (message, result) => {
9
+ const services = getServices();
10
+ if (!services)
11
+ return '猜拳需要启用 database 配置。';
12
+ const raw = result.params.action ?? '';
13
+ return runRpsCommand(plugin, services, message, normalizeRpsAction(raw));
14
+ }));
15
+ }
16
+ export function registerCommands(plugin, getServices) {
17
+ registerPattern(plugin, 'rps [action:word]', '猜拳(rps)', getServices);
18
+ registerPattern(plugin, '猜拳 [action:word]', '猜拳(中文)', getServices);
19
+ }
20
+ async function resolveChoice(message, services) {
21
+ const action = getActionFromMessage(message);
22
+ if (!action)
23
+ return null;
24
+ const parsed = parseChoicePayload(action.payload, RPS_PREFIX);
25
+ if (parsed)
26
+ return { sessionId: parsed.sessionId, choiceId: parsed.choiceId };
27
+ const choiceId = action.id || action.payload;
28
+ if (!choiceId)
29
+ return null;
30
+ const ch = channelKey(message);
31
+ const session = await services.getActiveForUser(ch, message.$sender.id)
32
+ ?? (action.sourceMessageId
33
+ ? await services.getActiveByBoardMessageId(action.sourceMessageId)
34
+ : null);
35
+ if (!session || session.channel_key !== ch)
36
+ return null;
37
+ const valid = ['rock', 'paper', 'scissors', 'restart'];
38
+ if (!valid.includes(choiceId))
39
+ return null;
40
+ return { sessionId: session.id, choiceId };
41
+ }
42
+ export function registerInteractive(plugin, getServices) {
43
+ plugin.registerInteractiveHandler(`${RPS_PREFIX}:`, async (message) => {
44
+ const services = getServices();
45
+ if (!services)
46
+ return false;
47
+ const choice = await resolveChoice(message, services);
48
+ if (!choice)
49
+ return false;
50
+ const err = await handleChoice(plugin, services, message, choice.sessionId, choice.choiceId);
51
+ if (err)
52
+ await message.$reply?.(err);
53
+ return true;
54
+ });
55
+ }
56
+ export function registerTextFallback(plugin, getServices) {
57
+ plugin.addMiddleware(async (message, next) => {
58
+ const services = getServices();
59
+ if (!services)
60
+ return next();
61
+ const action = getActionFromMessage(message);
62
+ if (action?.payload.startsWith(`${RPS_PREFIX}:`))
63
+ return next();
64
+ const ch = channelKey(message);
65
+ const session = await services.getActiveForUser(ch, message.$sender.id);
66
+ if (!session || session.status !== 'active')
67
+ return next();
68
+ const raw = message.$raw?.trim() ?? '';
69
+ const n = /^(\d+)$/.exec(raw);
70
+ if (!n)
71
+ return next();
72
+ const map = buildChoiceFallbackMap(RPS_PREFIX, session.id, [
73
+ { id: 'rock', label: '石头' },
74
+ { id: 'paper', label: '布' },
75
+ { id: 'scissors', label: '剪刀' },
76
+ ]);
77
+ const payload = map[n[1]];
78
+ const parsed = payload ? parseChoicePayload(payload, RPS_PREFIX) : null;
79
+ if (!parsed || parsed.sessionId !== session.id)
80
+ return next();
81
+ const err = await handleChoice(plugin, services, message, session.id, parsed.choiceId);
82
+ if (err)
83
+ await message.$reply?.(err);
84
+ });
85
+ }
86
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export declare const RPS_PREFIX = "rps";
2
+ export type RpsMove = 'rock' | 'paper' | 'scissors';
3
+ export declare const MOVE_LABELS: Record<RpsMove, string>;
4
+ export declare function randomBotMove(): RpsMove;
5
+ /** 1=玩家胜 2=机器人胜 0=平局 */
6
+ export declare function resolveRound(player: RpsMove, bot: RpsMove): 0 | 1 | 2;
7
+ export declare function parseMove(raw: string): RpsMove | null;
8
+ export declare const WIN_TARGET = 3;
9
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,QAAQ,CAAC;AAEhC,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC;AAEpD,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAI/C,CAAC;AAQF,wBAAgB,aAAa,IAAI,OAAO,CAGvC;AAED,wBAAwB;AACxB,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAGrE;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAcrD;AAED,eAAO,MAAM,UAAU,IAAI,CAAC"}
package/lib/engine.js ADDED
@@ -0,0 +1,38 @@
1
+ export const RPS_PREFIX = 'rps';
2
+ export const MOVE_LABELS = {
3
+ rock: '✊ 石头',
4
+ paper: '✋ 布',
5
+ scissors: '✌️ 剪刀',
6
+ };
7
+ const BEATS = {
8
+ rock: 'scissors',
9
+ paper: 'rock',
10
+ scissors: 'paper',
11
+ };
12
+ export function randomBotMove() {
13
+ const moves = ['rock', 'paper', 'scissors'];
14
+ return moves[Math.floor(Math.random() * moves.length)];
15
+ }
16
+ /** 1=玩家胜 2=机器人胜 0=平局 */
17
+ export function resolveRound(player, bot) {
18
+ if (player === bot)
19
+ return 0;
20
+ return BEATS[player] === bot ? 1 : 2;
21
+ }
22
+ export function parseMove(raw) {
23
+ const t = raw.trim().toLowerCase();
24
+ const map = {
25
+ rock: 'rock',
26
+ paper: 'paper',
27
+ scissors: 'scissors',
28
+ 石头: 'rock',
29
+ 布: 'paper',
30
+ 剪刀: 'scissors',
31
+ r: 'rock',
32
+ p: 'paper',
33
+ s: 'scissors',
34
+ };
35
+ return map[t] ?? null;
36
+ }
37
+ export const WIN_TARGET = 3;
38
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,CAAC;AAIhC,MAAM,CAAC,MAAM,WAAW,GAA4B;IAClD,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,KAAK;IACZ,QAAQ,EAAE,OAAO;CAClB,CAAC;AAEF,MAAM,KAAK,GAA6B;IACtC,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,MAAM;IACb,QAAQ,EAAE,OAAO;CAClB,CAAC;AAEF,MAAM,UAAU,aAAa;IAC3B,MAAM,KAAK,GAAc,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACvD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAE,CAAC;AAC1D,CAAC;AAED,wBAAwB;AACxB,MAAM,UAAU,YAAY,CAAC,MAAe,EAAE,GAAY;IACxD,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,CAAC,CAAC;IAC7B,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACnC,MAAM,GAAG,GAA4B;QACnC,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,OAAO;QACd,QAAQ,EAAE,UAAU;QACpB,EAAE,EAAE,MAAM;QACV,CAAC,EAAE,OAAO;QACV,EAAE,EAAE,UAAU;QACd,CAAC,EAAE,MAAM;QACT,CAAC,EAAE,OAAO;QACV,CAAC,EAAE,UAAU;KACd,CAAC;IACF,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { Message, Plugin } from 'zhin.js';
2
+ import type { RpsSessionRow } from './models.js';
3
+ import { RPS_PREFIX, type RpsMove } from './engine.js';
4
+ import type { SessionService } from './session-service.js';
5
+ export declare function sendOrEditView(plugin: Plugin, services: SessionService, message: Message<any>, session: RpsSessionRow, lastRound?: {
6
+ player: RpsMove;
7
+ bot: RpsMove;
8
+ result: 0 | 1 | 2;
9
+ }): Promise<void>;
10
+ export declare function startGame(plugin: Plugin, services: SessionService, message: Message<any>): Promise<string | undefined>;
11
+ export declare function handleChoice(plugin: Plugin, services: SessionService, message: Message<any>, sessionId: string, choiceId: string): Promise<string | null>;
12
+ export declare function continueGame(plugin: Plugin, services: SessionService, message: Message<any>): Promise<string>;
13
+ export { RPS_PREFIX };
14
+ //# sourceMappingURL=game-flow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"game-flow.d.ts","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EACL,UAAU,EAIV,KAAK,OAAO,EACb,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,OAAO,EAAE,aAAa,EACtB,SAAS,CAAC,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;CAAE,GAC/D,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,GACpB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAY7B;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6CxB;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,GACpB,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -0,0 +1,92 @@
1
+ import { RPS_PREFIX, WIN_TARGET, randomBotMove, resolveRound, } from './engine.js';
2
+ import { buildRpsView } from './view.js';
3
+ export async function sendOrEditView(plugin, services, message, session, lastRound) {
4
+ const content = buildRpsView(session, lastRound);
5
+ const adapter = plugin.root.inject(message.$adapter);
6
+ if (session.board_message_id) {
7
+ const msgId = await adapter.editMessage({
8
+ messageId: session.board_message_id,
9
+ context: String(message.$adapter),
10
+ endpoint: message.$endpoint,
11
+ id: message.$channel.id,
12
+ type: message.$channel.type,
13
+ content,
14
+ });
15
+ if (msgId !== session.board_message_id) {
16
+ await services.updateSession(session.id, { board_message_id: msgId });
17
+ }
18
+ return;
19
+ }
20
+ const msgId = await message.$reply?.(content);
21
+ if (msgId)
22
+ await services.updateSession(session.id, { board_message_id: msgId });
23
+ }
24
+ export async function startGame(plugin, services, message) {
25
+ const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
26
+ const active = await services.getActiveByChannel(ch);
27
+ if (active) {
28
+ if (active.player_id === message.$sender.id) {
29
+ return '你已有进行中的猜拳,发送「猜拳 继续」刷新,或「猜拳 放弃」。';
30
+ }
31
+ return `本频道 ${active.player_name} 正在猜拳对决中。`;
32
+ }
33
+ const session = await services.createSession(message);
34
+ await sendOrEditView(plugin, services, message, session);
35
+ return undefined;
36
+ }
37
+ export async function handleChoice(plugin, services, message, sessionId, choiceId) {
38
+ const session = await services.getById(sessionId);
39
+ if (!session)
40
+ return '对局不存在。';
41
+ if (session.status !== 'active' && choiceId !== 'restart') {
42
+ return '对局已结束,请点击再来一局。';
43
+ }
44
+ if (session.player_id !== message.$sender.id)
45
+ return '这是别人的对局。';
46
+ if (choiceId === 'restart') {
47
+ await services.updateSession(session.id, {
48
+ player_wins: 0,
49
+ bot_wins: 0,
50
+ round: 0,
51
+ status: 'active',
52
+ board_message_id: '',
53
+ });
54
+ const updated = (await services.getById(session.id));
55
+ await sendOrEditView(plugin, services, message, updated);
56
+ return null;
57
+ }
58
+ const player = choiceId;
59
+ if (!['rock', 'paper', 'scissors'].includes(player))
60
+ return '无效出拳。';
61
+ const bot = randomBotMove();
62
+ const result = resolveRound(player, bot);
63
+ let playerWins = session.player_wins;
64
+ let botWins = session.bot_wins;
65
+ if (result === 1)
66
+ playerWins++;
67
+ if (result === 2)
68
+ botWins++;
69
+ let status = 'active';
70
+ if (playerWins >= WIN_TARGET)
71
+ status = 'won';
72
+ else if (botWins >= WIN_TARGET)
73
+ status = 'lost';
74
+ await services.updateSession(session.id, {
75
+ player_wins: playerWins,
76
+ bot_wins: botWins,
77
+ round: session.round + 1,
78
+ status,
79
+ });
80
+ const updated = (await services.getById(session.id));
81
+ await sendOrEditView(plugin, services, message, updated, { player, bot, result });
82
+ return null;
83
+ }
84
+ export async function continueGame(plugin, services, message) {
85
+ const session = await services.getActiveForUser(`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`, message.$sender.id);
86
+ if (!session)
87
+ return '你没有进行中的猜拳,发送「猜拳 开始」。';
88
+ await sendOrEditView(plugin, services, message, session);
89
+ return '已刷新猜拳界面。';
90
+ }
91
+ export { RPS_PREFIX };
92
+ //# sourceMappingURL=game-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { RPS_HELP } from './rps-command.js';
2
+ import type { SessionService } from './session-service.js';
3
+ export declare function registerRpsHub(getServices: () => SessionService | null): () => void;
4
+ export { RPS_HELP };
5
+ //# sourceMappingURL=hub-register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hub-register.d.ts","sourceRoot":"","sources":["../src/hub-register.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,cAAc,GAAG,IAAI,GAAG,MAAM,IAAI,CAoBnF;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { registerGame } from '@zhin.js/game-shared';
2
+ import { runRpsCommand, RPS_HELP } from './rps-command.js';
3
+ export function registerRpsHub(getServices) {
4
+ return registerGame({
5
+ id: 'rps',
6
+ title: '猜拳对决',
7
+ icon: '✊',
8
+ description: '石头剪刀布,三局两胜',
9
+ commandPrefix: '猜拳',
10
+ quickStart: '开始',
11
+ aliases: ['rps'],
12
+ menus: [
13
+ { id: 'start', label: '🎮 开始对局', style: 'primary' },
14
+ { id: 'continue', label: '🔄 继续' },
15
+ { id: 'help', label: '📖 玩法说明' },
16
+ ],
17
+ runAction: async (actionId, ctx) => {
18
+ const services = getServices();
19
+ if (!services)
20
+ return '猜拳需要启用 database 配置。';
21
+ return runRpsCommand(ctx.plugin, services, ctx.message, actionId);
22
+ },
23
+ });
24
+ }
25
+ export { RPS_HELP };
26
+ //# sourceMappingURL=hub-register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hub-register.js","sourceRoot":"","sources":["../src/hub-register.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG3D,MAAM,UAAU,cAAc,CAAC,WAAwC;IACrE,OAAO,YAAY,CAAC;QAClB,EAAE,EAAE,KAAK;QACT,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,GAAG;QACT,WAAW,EAAE,YAAY;QACzB,aAAa,EAAE,IAAI;QACnB,UAAU,EAAE,IAAI;QAChB,OAAO,EAAE,CAAC,KAAK,CAAC;QAChB,KAAK,EAAE;YACL,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;YACnD,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE;YAClC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE;SACjC;QACD,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE;YACjC,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;YAC/B,IAAI,CAAC,QAAQ;gBAAE,OAAO,qBAAqB,CAAC;YAC5C,OAAO,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACpE,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/lib/index.js ADDED
@@ -0,0 +1,26 @@
1
+ import { Cron, formatCompact, usePlugin } from 'zhin.js';
2
+ import { registerModels } from './models.js';
3
+ import { createServices, resolveGameDatabase, } from './session-service.js';
4
+ import { registerCommands, registerInteractive, registerTextFallback } from './commands.js';
5
+ import { registerRpsHub } from './hub-register.js';
6
+ const plugin = usePlugin();
7
+ const { logger, useContext, addCron } = plugin;
8
+ registerModels(plugin);
9
+ let services = null;
10
+ useContext('database', (dbFeature) => {
11
+ services = createServices(resolveGameDatabase(dbFeature));
12
+ logger.info(formatCompact({ 模块: '猜拳', 数据模型: '已就绪' }));
13
+ });
14
+ registerRpsHub(() => services);
15
+ registerCommands(plugin, () => services);
16
+ registerInteractive(plugin, () => services);
17
+ registerTextFallback(plugin, () => services);
18
+ addCron(new Cron('0 */15 * * * *', async () => {
19
+ if (!services)
20
+ return;
21
+ const n = await services.abortStale(30 * 60 * 1000);
22
+ if (n > 0)
23
+ logger.debug(formatCompact({ 猜拳: '清理超时局', count: n }));
24
+ }));
25
+ logger.info(formatCompact({ 模块: '猜拳', 状态: '已加载' }));
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAwB,MAAM,SAAS,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,cAAc,EACd,mBAAmB,GAEpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC5F,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;AAC3B,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;AAE/C,cAAc,CAAC,MAAM,CAAC,CAAC;AAEvB,IAAI,QAAQ,GAA0B,IAAI,CAAC;AAE3C,UAAU,CAAC,UAAU,EAAE,CAAC,SAA0B,EAAE,EAAE;IACpD,QAAQ,GAAG,cAAc,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC,CAAC;IAC1D,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC;AAEH,cAAc,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC;AAC/B,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC;AACzC,mBAAmB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC;AAC5C,oBAAoB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC;AAE7C,OAAO,CACL,IAAI,IAAI,CAAC,gBAAgB,EAAE,KAAK,IAAI,EAAE;IACpC,IAAI,CAAC,QAAQ;QAAE,OAAO;IACtB,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC,GAAG,CAAC;QAAE,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACpE,CAAC,CAAC,CACH,CAAC;AAEF,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { Models, Plugin } from 'zhin.js';
2
+ export type RpsSessionStatus = 'active' | 'won' | 'lost' | 'aborted';
3
+ declare module 'zhin.js' {
4
+ interface Models {
5
+ rps_sessions: {
6
+ id: string;
7
+ adapter: string;
8
+ endpoint: string;
9
+ channel_type: string;
10
+ channel_id: string;
11
+ channel_key: string;
12
+ player_id: string;
13
+ player_name: string;
14
+ player_wins: number;
15
+ bot_wins: number;
16
+ round: number;
17
+ status: RpsSessionStatus;
18
+ board_message_id: string;
19
+ updated_at: number;
20
+ created_at: number;
21
+ };
22
+ }
23
+ }
24
+ export type RpsSessionRow = Models['rps_sessions'];
25
+ export declare function registerModels(plugin: Plugin): void;
26
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;AAErE,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,MAAM;QACd,YAAY,EAAE;YACZ,EAAE,EAAE,MAAM,CAAC;YACX,OAAO,EAAE,MAAM,CAAC;YAChB,QAAQ,EAAE,MAAM,CAAC;YACjB,YAAY,EAAE,MAAM,CAAC;YACrB,UAAU,EAAE,MAAM,CAAC;YACnB,WAAW,EAAE,MAAM,CAAC;YACpB,SAAS,EAAE,MAAM,CAAC;YAClB,WAAW,EAAE,MAAM,CAAC;YACpB,WAAW,EAAE,MAAM,CAAC;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,gBAAgB,CAAC;YACzB,gBAAgB,EAAE,MAAM,CAAC;YACzB,UAAU,EAAE,MAAM,CAAC;YACnB,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC;KACH;CACF;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;AAEnD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAkBnD"}
package/lib/models.js ADDED
@@ -0,0 +1,20 @@
1
+ export function registerModels(plugin) {
2
+ plugin.defineModel('rps_sessions', {
3
+ id: { type: 'text', primary: true },
4
+ adapter: { type: 'text', nullable: false },
5
+ endpoint: { type: 'text', nullable: false },
6
+ channel_type: { type: 'text', nullable: false },
7
+ channel_id: { type: 'text', nullable: false },
8
+ channel_key: { type: 'text', nullable: false },
9
+ player_id: { type: 'text', nullable: false },
10
+ player_name: { type: 'text', default: '' },
11
+ player_wins: { type: 'integer', default: 0 },
12
+ bot_wins: { type: 'integer', default: 0 },
13
+ round: { type: 'integer', default: 0 },
14
+ status: { type: 'text', default: 'active' },
15
+ board_message_id: { type: 'text', default: '' },
16
+ updated_at: { type: 'integer', default: 0 },
17
+ created_at: { type: 'integer', default: 0 },
18
+ });
19
+ }
20
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AA4BA,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,MAAM,CAAC,WAAW,CAAC,cAAc,EAAE;QACjC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACnC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC1C,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC3C,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC/C,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC7C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC9C,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC5C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QAC1C,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACzC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC3C,gBAAgB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QAC/C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC3C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;KAC5C,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Message, Plugin } from 'zhin.js';
2
+ import type { SessionService } from './session-service.js';
3
+ export declare const RPS_HELP: string;
4
+ export declare function runRpsCommand(plugin: Plugin, services: SessionService, message: Message<any>, action: string): Promise<string | undefined>;
5
+ //# sourceMappingURL=rps-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rps-command.d.ts","sourceRoot":"","sources":["../src/rps-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,eAAO,MAAM,QAAQ,QAMT,CAAC;AAEb,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA0B7B"}
@@ -0,0 +1,37 @@
1
+ import { channelKey } from '@zhin.js/game-shared';
2
+ import { continueGame, startGame } from './game-flow.js';
3
+ export const RPS_HELP = [
4
+ '✊✋✌️ 猜拳对决(三局两胜)',
5
+ '猜拳 / rps — 帮助',
6
+ '猜拳 开始 — 新对局',
7
+ '猜拳 继续 — 刷新界面',
8
+ '猜拳 放弃 — 结束对局',
9
+ ].join('\n');
10
+ export async function runRpsCommand(plugin, services, message, action) {
11
+ const ch = channelKey(message);
12
+ const userId = message.$sender.id;
13
+ if (!action || action === 'help') {
14
+ const active = await services.getActiveByChannel(ch);
15
+ const lines = [RPS_HELP, ''];
16
+ if (active) {
17
+ lines.push(`进行中:${active.player_name} · ${active.player_wins}:${active.bot_wins}`);
18
+ }
19
+ else {
20
+ lines.push('暂无对局,发送「猜拳 开始」或从游戏大厅进入。');
21
+ }
22
+ return lines.join('\n');
23
+ }
24
+ if (action === 'start')
25
+ return startGame(plugin, services, message);
26
+ if (action === 'continue')
27
+ return continueGame(plugin, services, message);
28
+ if (action === 'quit') {
29
+ const row = await services.getActiveForUser(ch, userId);
30
+ if (!row)
31
+ return '你没有进行中的猜拳。';
32
+ await services.updateSession(row.id, { status: 'aborted' });
33
+ return '已放弃猜拳对局。';
34
+ }
35
+ return `未知子命令:${action}\n\n${RPS_HELP}`;
36
+ }
37
+ //# sourceMappingURL=rps-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rps-command.js","sourceRoot":"","sources":["../src/rps-command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGzD,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,iBAAiB;IACjB,eAAe;IACf,aAAa;IACb,cAAc;IACd,cAAc;CACf,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,QAAwB,EACxB,OAAqB,EACrB,MAAc;IAEd,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;IAElC,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC7B,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,WAAW,MAAM,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrF,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,MAAM,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACpE,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAE1E,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACxD,IAAI,CAAC,GAAG;YAAE,OAAO,YAAY,CAAC;QAC9B,MAAM,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAC5D,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,OAAO,SAAS,MAAM,OAAO,QAAQ,EAAE,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { Database, DatabaseFeature, Message, Models } from 'zhin.js';
2
+ import type { RpsSessionRow } from './models.js';
3
+ export type RpsDatabase = Database<unknown, Models, string>;
4
+ export declare class SessionService {
5
+ private readonly db;
6
+ constructor(db: RpsDatabase);
7
+ getActiveByChannel(channel: string): Promise<RpsSessionRow | null>;
8
+ getActiveForUser(channel: string, userId: string): Promise<RpsSessionRow | null>;
9
+ getById(id: string): Promise<RpsSessionRow | null>;
10
+ getActiveByBoardMessageId(messageId: string): Promise<RpsSessionRow | null>;
11
+ createSession(message: Message<any>): Promise<RpsSessionRow>;
12
+ updateSession(id: string, patch: Partial<RpsSessionRow>): Promise<void>;
13
+ abortStale(idleMs: number): Promise<number>;
14
+ }
15
+ export declare function createServices(db: RpsDatabase): SessionService;
16
+ export declare function resolveGameDatabase(feature: DatabaseFeature): RpsDatabase;
17
+ //# sourceMappingURL=session-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-service.d.ts","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAgB,MAAM,SAAS,CAAC;AAExF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAQ5D,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,WAAW;IAEtC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAKlE,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAMhF,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAIlD,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAa3E,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC;IAuB5D,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvE,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAalD;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,WAAW,GAAG,cAAc,CAE9D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,WAAW,CAEzE"}
@@ -0,0 +1,87 @@
1
+ import { channelKey, generateSessionId } from '@zhin.js/game-shared';
2
+ function getModel(db) {
3
+ const model = db.models.get('rps_sessions');
4
+ if (!model)
5
+ throw new Error('rps_sessions not registered');
6
+ return model;
7
+ }
8
+ export class SessionService {
9
+ db;
10
+ constructor(db) {
11
+ this.db = db;
12
+ }
13
+ async getActiveByChannel(channel) {
14
+ const rows = await getModel(this.db).findAll({ channel_key: channel, status: 'active' });
15
+ return rows[0] ?? null;
16
+ }
17
+ async getActiveForUser(channel, userId) {
18
+ const row = await this.getActiveByChannel(channel);
19
+ if (!row || row.player_id !== userId)
20
+ return null;
21
+ return row;
22
+ }
23
+ async getById(id) {
24
+ return getModel(this.db).findOne({ id });
25
+ }
26
+ async getActiveByBoardMessageId(messageId) {
27
+ if (!messageId)
28
+ return null;
29
+ const rows = await getModel(this.db).findAll({ status: 'active' });
30
+ for (const row of rows) {
31
+ const stored = row.board_message_id;
32
+ if (!stored)
33
+ continue;
34
+ if (stored === messageId || stored.endsWith(`:${messageId}`))
35
+ return row;
36
+ const tail = stored.split(':').pop();
37
+ if (tail && messageId.endsWith(tail))
38
+ return row;
39
+ }
40
+ return null;
41
+ }
42
+ async createSession(message) {
43
+ const now = Date.now();
44
+ const row = {
45
+ id: generateSessionId(),
46
+ adapter: String(message.$adapter),
47
+ endpoint: message.$endpoint,
48
+ channel_type: message.$channel.type,
49
+ channel_id: message.$channel.id,
50
+ channel_key: channelKey(message),
51
+ player_id: message.$sender.id,
52
+ player_name: message.$sender.name?.trim() || message.$sender.id,
53
+ player_wins: 0,
54
+ bot_wins: 0,
55
+ round: 0,
56
+ status: 'active',
57
+ board_message_id: '',
58
+ updated_at: now,
59
+ created_at: now,
60
+ };
61
+ await getModel(this.db).create(row);
62
+ return row;
63
+ }
64
+ async updateSession(id, patch) {
65
+ await getModel(this.db).updateWhere({ id }, { ...patch, updated_at: Date.now() });
66
+ }
67
+ async abortStale(idleMs) {
68
+ const cutoff = Date.now() - idleMs;
69
+ const model = getModel(this.db);
70
+ const rows = await model.findAll({ status: 'active' });
71
+ let n = 0;
72
+ for (const row of rows) {
73
+ if (row.updated_at < cutoff) {
74
+ await model.updateWhere({ id: row.id }, { status: 'aborted', updated_at: Date.now() });
75
+ n++;
76
+ }
77
+ }
78
+ return n;
79
+ }
80
+ }
81
+ export function createServices(db) {
82
+ return new SessionService(db);
83
+ }
84
+ export function resolveGameDatabase(feature) {
85
+ return feature.db;
86
+ }
87
+ //# sourceMappingURL=session-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"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"}
package/lib/view.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type { SendContent } from 'zhin.js';
2
+ import type { RpsSessionRow } from './models.js';
3
+ import { type RpsMove } from './engine.js';
4
+ export declare function buildRpsView(session: RpsSessionRow, lastRound?: {
5
+ player: RpsMove;
6
+ bot: RpsMove;
7
+ result: 0 | 1 | 2;
8
+ }): SendContent;
9
+ //# sourceMappingURL=view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAuC,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAEhF,wBAAgB,YAAY,CAC1B,OAAO,EAAE,aAAa,EACtB,SAAS,CAAC,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;CAAE,GAC/D,WAAW,CA+Cb"}