@zhin.js/plugin-dungeon-expedition 1.1.18 → 1.1.20

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.
@@ -1,16 +1,18 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { replyGameOperation, gamePlayerFromInput } from '@zhin.js/game-kit';
2
3
  import { defineCommand } from 'zhin.js/command';
3
- import { messageFromCommandInput } from '@zhin.js/game-kit';
4
4
  import { getDungeonHelp, normalizeDungeonAction, runDungeonCommand, } from "../../../lib/dungeon-command.js";
5
5
  import { resolveGameServices } from "../../../lib/runtime-store.js";
6
6
  export default defineCommand({
7
7
  description: 'Multiplayer dungeon expedition',
8
8
  params: { action: { type: 'string', default: '' } },
9
- async execute({ params, input, use, locale, formatCommand }) {
9
+ async execute({ params, input, use, locale, formatCommand, session }) {
10
10
  const rawAction = String(params.action ?? '');
11
11
  if (normalizeDungeonAction(rawAction) === 'help')
12
12
  return getDungeonHelp({ locale, formatCommand });
13
13
  const service = resolveGameServices({ use });
14
- return runDungeonCommand(service, messageFromCommandInput(input, { locale, formatCommand }), rawAction);
14
+ const player = gamePlayerFromInput(input, { locale, formatCommand });
15
+ await replyGameOperation({ session: service, player, reply: session?.reply,
16
+ run: () => runDungeonCommand(service, player, rawAction) });
15
17
  },
16
18
  });
@@ -1,5 +1,5 @@
1
+ import { replyGameOperation, gamePlayerFromInput } from '@zhin.js/game-kit';
1
2
  import { defineCommand } from 'zhin.js/command';
2
- import { messageFromCommandInput } from '@zhin.js/game-kit';
3
3
  import {
4
4
  getDungeonHelp,
5
5
  normalizeDungeonAction,
@@ -10,14 +10,12 @@ import { resolveGameServices } from '../../../src/runtime-store.js';
10
10
  export default defineCommand({
11
11
  description: 'Multiplayer dungeon expedition',
12
12
  params: { action: { type: 'string', default: '' } },
13
- async execute({ params, input, use, locale, formatCommand }) {
13
+ async execute({ params, input, use, locale, formatCommand, session }) {
14
14
  const rawAction = String(params.action ?? '');
15
15
  if (normalizeDungeonAction(rawAction) === 'help') return getDungeonHelp({ locale, formatCommand });
16
16
  const service = resolveGameServices({ use });
17
- return runDungeonCommand(
18
- service,
19
- messageFromCommandInput(input, { locale, formatCommand }),
20
- rawAction,
21
- );
17
+ const player = gamePlayerFromInput(input, { locale, formatCommand });
18
+ await replyGameOperation({ session: service, player, reply: session?.reply,
19
+ run: () => runDungeonCommand(service, player, rawAction) });
22
20
  },
23
21
  });
@@ -1,6 +1,6 @@
1
- import { type GameMessageLike, type GameReply } from '@zhin.js/game-kit';
1
+ import { type GamePlayer, type GameReply } from '@zhin.js/game-kit';
2
2
  import type { SessionService } from './session-service.js';
3
- export declare function getDungeonHelp(message?: Pick<GameMessageLike, 'locale' | 'formatCommand'>): string;
3
+ export declare function getDungeonHelp(message?: Pick<GamePlayer, 'locale' | 'formatCommand'>): string;
4
4
  export declare const DUNGEON_HELP: string;
5
5
  export declare function normalizeDungeonAction(action: string): string | null;
6
- export declare function runDungeonCommand(service: SessionService, message: GameMessageLike, rawAction: string): Promise<GameReply>;
6
+ export declare function runDungeonCommand(service: SessionService, message: GamePlayer, rawAction: string): Promise<GameReply>;
@@ -55,16 +55,18 @@ export function normalizeDungeonAction(action) {
55
55
  return ACTION_ALIASES[action.trim().toLowerCase()] ?? null;
56
56
  }
57
57
  export async function runDungeonCommand(service, message, rawAction) {
58
- const action = normalizeDungeonAction(rawAction);
59
- if (!action || action === 'help')
60
- return getDungeonHelp(message);
61
- if (action === 'create')
62
- return startDungeon(service, message);
63
- if (action === 'status')
64
- return continueDungeon(service, message);
65
- const session = await service.getActiveByChannel(channelKey(message));
66
- if (!session)
67
- return messages(message.locale, 'empty') + gameCommandHint(message, 'dungeon');
68
- return handleDungeonChoice(service, message, dungeonSessionToken(session), action);
58
+ return service.runInScope({ scope: channelKey(message), run: async () => {
59
+ const action = normalizeDungeonAction(rawAction);
60
+ if (!action || action === 'help')
61
+ return getDungeonHelp(message);
62
+ if (action === 'create')
63
+ return startDungeon(service, message);
64
+ if (action === 'status')
65
+ return continueDungeon(service, message);
66
+ const session = await service.getActiveByChannel(channelKey(message));
67
+ if (!session)
68
+ return messages(message.locale, 'empty') + gameCommandHint(message, 'dungeon');
69
+ return handleDungeonChoice(service, message, dungeonSessionToken(session), action);
70
+ } });
69
71
  }
70
72
  //# sourceMappingURL=dungeon-command.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dungeon-command.js","sourceRoot":"","sources":["../src/dungeon-command.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dungeon-command.js","sourceRoot":"","sources":["../src/dungeon-command.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
- import { type GameMessageLike, type GameReply } from '@zhin.js/game-kit';
1
+ import { type GamePlayer, type GameReply } from '@zhin.js/game-kit';
2
2
  import type { DungeonSessionRow } from './models.js';
3
3
  import { type SessionService } from './session-service.js';
4
- export declare function startDungeon(service: SessionService, message: GameMessageLike): Promise<GameReply>;
5
- export declare function continueDungeon(service: SessionService, message: GameMessageLike): Promise<GameReply>;
6
- export declare function handleDungeonChoice(service: SessionService, message: GameMessageLike, sessionToken: string, choiceId: string): Promise<GameReply>;
4
+ export declare function startDungeon(service: SessionService, message: GamePlayer): Promise<GameReply>;
5
+ export declare function continueDungeon(service: SessionService, message: GamePlayer): Promise<GameReply>;
6
+ export declare function handleDungeonChoice(service: SessionService, message: GamePlayer, sessionToken: string, choiceId: string): Promise<GameReply>;
7
7
  export declare function commandActionId(session: DungeonSessionRow, actorId: string, choiceId: string): string;
package/lib/game-flow.js CHANGED
@@ -4,73 +4,79 @@ import { DungeonRuleError, } from './engine.js';
4
4
  import { stateFromSession, } from './session-service.js';
5
5
  import { buildDungeonView, parseDungeonSessionToken, } from './view.js';
6
6
  export async function startDungeon(service, message) {
7
- const active = await service.getActiveByChannel(channelKey(message));
8
- if (active)
9
- return buildDungeonView(active, stateFromSession(active), message.$channel.type);
10
- try {
11
- const session = await service.createSession(message);
12
- return buildDungeonView(session, stateFromSession(session), message.$channel.type);
13
- }
14
- catch (error) {
15
- if (error instanceof GameSessionConflictError)
16
- return error.format(message.locale);
17
- throw error;
18
- }
7
+ return service.runInScope({ scope: channelKey(message), run: async () => {
8
+ const active = await service.getActiveByChannel(channelKey(message));
9
+ if (active)
10
+ return buildDungeonView(active, stateFromSession(active), message.target.kind);
11
+ try {
12
+ const session = await service.createSession(message);
13
+ return buildDungeonView(session, stateFromSession(session), message.target.kind);
14
+ }
15
+ catch (error) {
16
+ if (error instanceof GameSessionConflictError)
17
+ return error.format(message.locale);
18
+ throw error;
19
+ }
20
+ } });
19
21
  }
20
22
  export async function continueDungeon(service, message) {
21
- const locale = resolveLocale(message.locale);
22
- const session = await service.getActiveByChannel(channelKey(message));
23
- if (!session)
24
- return messages(locale, 'text1');
25
- return buildDungeonView(session, stateFromSession(session), message.$channel.type);
23
+ return service.runInScope({ scope: channelKey(message), run: async () => {
24
+ const locale = resolveLocale(message.locale);
25
+ const session = await service.getActiveByChannel(channelKey(message));
26
+ if (!session)
27
+ return messages(locale, 'text1');
28
+ return buildDungeonView(session, stateFromSession(session), message.target.kind);
29
+ } });
26
30
  }
27
31
  export async function handleDungeonChoice(service, message, sessionToken, choiceId) {
28
- let locale = resolveLocale(message.locale);
29
- const token = parseDungeonSessionToken(sessionToken);
30
- if (!token)
31
- return messages(locale, 'text2');
32
- const session = await service.getById(token.sessionId);
33
- if (!session || session.channel_key !== channelKey(message)) {
34
- return messages(locale, 'text3');
35
- }
36
- locale = resolveLocale(session.locale);
37
- if (choiceId === 'restart') {
38
- if (session.status === 'active')
39
- return messages(locale, 'text4');
40
- if (session.owner_id !== message.$sender.id)
41
- return messages(locale, 'text5');
42
- return startDungeon(service, message);
43
- }
44
- const action = actionFromChoice(choiceId, message);
45
- if (!action)
46
- return messages(locale, 'text6');
47
- try {
48
- const result = await service.performAction({
49
- sessionId: session.id,
50
- actorId: message.$sender.id,
51
- actorName: message.$sender.name?.trim() || message.$sender.id,
52
- action,
53
- expectedRevision: token.revision,
54
- actionId: `${session.id}:${token.revision}:${message.$sender.id}:${choiceId}`,
55
- });
56
- return buildDungeonView(result.session, stateFromSession(result.session), message.$channel.type);
57
- }
58
- catch (error) {
59
- if (error instanceof DungeonRuleError)
60
- return error.message;
61
- if (error instanceof GameSessionConflictError)
62
- return error.format(locale);
63
- if (error instanceof SessionRevisionConflictError) {
64
- const latest = await service.getById(session.id);
65
- if (!latest)
66
- return messages(locale, 'text7');
67
- const view = buildDungeonView(latest, stateFromSession(latest), message.$channel.type);
68
- return Array.isArray(view)
69
- ? [messages(locale, 'text8'), ...view]
70
- : [messages(locale, 'text8'), view];
71
- }
72
- throw error;
73
- }
32
+ return service.runInScope({ scope: channelKey(message), run: async () => {
33
+ let locale = resolveLocale(message.locale);
34
+ const token = parseDungeonSessionToken(sessionToken);
35
+ if (!token)
36
+ return messages(locale, 'text2');
37
+ const session = await service.getById(token.sessionId);
38
+ if (!session || session.channel_key !== channelKey(message)) {
39
+ return messages(locale, 'text3');
40
+ }
41
+ locale = resolveLocale(session.locale);
42
+ if (choiceId === 'restart') {
43
+ if (session.status === 'active')
44
+ return messages(locale, 'text4');
45
+ if (session.owner_id !== message.sender.id)
46
+ return messages(locale, 'text5');
47
+ return startDungeon(service, message);
48
+ }
49
+ const action = actionFromChoice(choiceId, message);
50
+ if (!action)
51
+ return messages(locale, 'text6');
52
+ try {
53
+ const result = await service.performAction({
54
+ sessionId: session.id,
55
+ actorId: message.sender.id,
56
+ actorName: message.sender.name?.trim() || message.sender.id,
57
+ action,
58
+ expectedRevision: token.revision,
59
+ actionId: `${session.id}:${token.revision}:${message.sender.id}:${choiceId}`,
60
+ });
61
+ return buildDungeonView(result.session, stateFromSession(result.session), message.target.kind);
62
+ }
63
+ catch (error) {
64
+ if (error instanceof DungeonRuleError)
65
+ return error.message;
66
+ if (error instanceof GameSessionConflictError)
67
+ return error.format(locale);
68
+ if (error instanceof SessionRevisionConflictError) {
69
+ const latest = await service.getById(session.id);
70
+ if (!latest)
71
+ return messages(locale, 'text7');
72
+ const view = buildDungeonView(latest, stateFromSession(latest), message.target.kind);
73
+ return Array.isArray(view)
74
+ ? [messages(locale, 'text8'), ...view]
75
+ : [messages(locale, 'text8'), view];
76
+ }
77
+ throw error;
78
+ }
79
+ } });
74
80
  }
75
81
  export function commandActionId(session, actorId, choiceId) {
76
82
  return `${session.id}:${session.revision}:${actorId}:${choiceId}`;
@@ -79,7 +85,7 @@ function actionFromChoice(choiceId, message) {
79
85
  if (choiceId === 'join') {
80
86
  return {
81
87
  type: 'join',
82
- name: message.$sender.name?.trim() || message.$sender.id,
88
+ name: message.sender.name?.trim() || message.sender.id,
83
89
  };
84
90
  }
85
91
  if (choiceId === 'ready')
@@ -1 +1 @@
1
- {"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { Database, Models } from '@zhin.js/core';
2
- import { VersionedSessionService, type GameMessageLike, type SessionMutationResult } from '@zhin.js/game-kit';
2
+ import { VersionedSessionService, type GamePlayer, type SessionMutationResult } from '@zhin.js/game-kit';
3
3
  import { type DungeonAction, type DungeonState } from './engine.js';
4
4
  import type { DungeonSessionRow } from './models.js';
5
5
  export type DungeonDatabase = Database<unknown, Models, string>;
@@ -13,7 +13,7 @@ export interface PerformDungeonActionOptions {
13
13
  }
14
14
  export declare class SessionService extends VersionedSessionService<DungeonSessionRow> {
15
15
  constructor(database: DungeonDatabase);
16
- createSession(message: GameMessageLike, seed?: string | number): Promise<DungeonSessionRow>;
16
+ createSession(message: GamePlayer, seed?: string | number): Promise<DungeonSessionRow>;
17
17
  getActiveForUser(channelKeyValue: string, userId: string): Promise<DungeonSessionRow | null>;
18
18
  performAction(options: PerformDungeonActionOptions): Promise<SessionMutationResult<DungeonSessionRow>>;
19
19
  }
@@ -1,4 +1,4 @@
1
- import { DeterministicRandom, VersionedSessionService, channelKey, generateCompactId, } from '@zhin.js/game-kit';
1
+ import { DeterministicRandom, VersionedSessionService, generateCompactId, } from '@zhin.js/game-kit';
2
2
  import { activePlayer, applyDungeonAction, createDungeonState, decodeDungeonState, } from './engine.js';
3
3
  export class SessionService extends VersionedSessionService {
4
4
  constructor(database) {
@@ -12,30 +12,28 @@ export class SessionService extends VersionedSessionService {
12
12
  async createSession(message, seed) {
13
13
  const now = Date.now();
14
14
  const id = generateCompactId('dng_');
15
- const ownerName = message.$sender.name?.trim() || message.$sender.id;
16
- const state = createDungeonState(message.$sender.id, ownerName, message.locale);
15
+ const ownerName = message.sender.name?.trim() || message.sender.id;
16
+ const state = createDungeonState(message.sender.id, ownerName, message.locale);
17
17
  const random = DeterministicRandom.fromSeed(seed ?? id);
18
18
  return this.createRow({
19
- id,
20
- locale: message.locale ?? 'zh-CN',
21
- adapter: String(message.$adapter),
22
- endpoint: message.$endpoint,
23
- channel_type: message.$channel.type,
24
- channel_id: message.$channel.id,
25
- channel_key: channelKey(message),
26
- owner_id: message.$sender.id,
27
- owner_name: ownerName,
28
- state_json: JSON.stringify(state),
29
- phase: state.phase,
30
- turn: activePlayer(state)?.id ?? '',
31
- rng_state: random.state,
32
- schema_version: state.schemaVersion,
33
- revision: 0,
34
- processed_actions: '[]',
35
- deadline_at: now + 5 * 60_000,
36
- status: 'active',
37
- updated_at: now,
38
- created_at: now,
19
+ target: message.target,
20
+ fields: {
21
+ id,
22
+ locale: message.locale ?? 'zh-CN',
23
+ owner_id: message.sender.id,
24
+ owner_name: ownerName,
25
+ state_json: JSON.stringify(state),
26
+ phase: state.phase,
27
+ turn: activePlayer(state)?.id ?? '',
28
+ rng_state: random.state,
29
+ schema_version: state.schemaVersion,
30
+ revision: 0,
31
+ processed_actions: '[]',
32
+ deadline_at: now + 5 * 60_000,
33
+ status: 'active',
34
+ updated_at: now,
35
+ created_at: now,
36
+ },
39
37
  });
40
38
  }
41
39
  async getActiveForUser(channelKeyValue, userId) {
@@ -1 +1 @@
1
- {"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,EACV,iBAAiB,GAKlB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,GAGnB,MAAM,aAAa,CAAC;AAcrB,MAAM,OAAO,cAAe,SAAQ,uBAA0C;IAC5E,YAAY,QAAyB;QACnC,KAAK,CAAC,QAA6D,EAAE;YACnE,MAAM,EAAE,SAAS;YACjB,KAAK,EAAE,kBAAkB;YACzB,UAAU,EAAE,CAAC,UAAU,CAAC;YACxB,eAAe,EAAE,sBAAsB;SACxC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,OAAwB,EACxB,IAAsB;QAEtB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACrE,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAChF,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,SAAS,CAAC;YACpB,EAAE;YACF,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,OAAO;YACjC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;YACjC,QAAQ,EAAE,OAAO,CAAC,SAAS;YAC3B,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI;YACnC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;YAC/B,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC;YAChC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE;YAC5B,UAAU,EAAE,SAAS;YACrB,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;YACjC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE;YACnC,SAAS,EAAE,MAAM,CAAC,KAAK;YACvB,cAAc,EAAE,KAAK,CAAC,aAAa;YACnC,QAAQ,EAAE,CAAC;YACX,iBAAiB,EAAE,IAAI;YACvB,WAAW,EAAE,GAAG,GAAG,CAAC,GAAG,MAAM;YAC7B,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,GAAG;SAChB,CAAC,CAAC;IACL,CAAC;IAEQ,KAAK,CAAC,gBAAgB,CAC7B,eAAuB,EACvB,MAAc;QAEd,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;YACpC,WAAW,EAAE,eAAe;YAC5B,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CACvB,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI,CAC7C,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,MAAM,CACjC,CAAC,IAAI,IAAI,CAAC;IACf,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,OAAoC;QAEpC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,EAAE;gBAC3C,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,KAAK,EAAE,EAAE;aACV,CAAC,CAAC;QACL,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACnC,MAAM,IAAI,CAAC,sBAAsB,CAC/B,QAAQ,CAAC,WAAW,EACpB,CAAC,OAAO,CAAC,OAAO,CAAC,CAClB,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,EAAE;YAC3C,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;YAC1C,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE;gBACjB,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;gBACrD,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBAChE,MAAM,IAAI,GAAG,kBAAkB,CAC7B,KAAK,EACL,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,MAAM,EACd,MAAM,EACN,OAAO,CAAC,MAAM,IAAI,SAAS,CAC5B,CAAC;gBACF,OAAO;oBACL,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;oBAChC,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE;oBAClC,SAAS,EAAE,MAAM,CAAC,KAAK;oBACvB,cAAc,EAAE,IAAI,CAAC,aAAa;oBAClC,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,MAAM;oBACpC,MAAM,EAAE,IAAI,CAAC,KAAK,KAAK,WAAW;wBAChC,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW;wBACrD,CAAC,CAAC,QAAQ;iBACb,CAAC;YACJ,CAAC;SACF,CAAC,CAAC;IACL,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,QAAyB;IACtD,OAAO,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAA0B;IACzD,OAAO,kBAAkB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,sBAAsB,CAC7B,OAAoC;IAEpC,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACrD,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,EAAE,MAAM,CAAC,EAAE;QACjB,QAAQ,EAAE,MAAM,CAAC,IAAI;QACrB,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAChE,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS;gBAC5B,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM;gBAChC,CAAC,CAAC,MAAM;QACV,KAAK,EAAE,KAAK,CAAC,YAAY,GAAG,EAAE,GAAG,MAAM,CAAC,IAAI;KAC7C,CAAC,CAAC,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,21 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { defineGameCommandAliasMiddleware, messageFromCommandInput, } from '@zhin.js/game-kit';
3
- import { normalizeDungeonAction, runDungeonCommand, } from "../../lib/dungeon-command.js";
2
+ import { replyGameOperation, defineGameCommandAliasMiddleware, gamePlayerFromInput } from '@zhin.js/game-kit';
3
+ import { normalizeDungeonAction, getDungeonHelp, runDungeonCommand, } from "../../lib/dungeon-command.js";
4
4
  import { resolveGameServices } from "../../lib/runtime-store.js";
5
5
  export default defineGameCommandAliasMiddleware({
6
6
  aliases: ['地牢', 'dungeon'],
7
7
  async run(action, input, context) {
8
- if (normalizeDungeonAction(action) === null)
9
- return null;
10
- return runDungeonCommand(resolveGameServices(context), messageFromCommandInput(input), action);
8
+ const normalized = normalizeDungeonAction(action);
9
+ if (normalized === null)
10
+ return false;
11
+ if (normalized === 'help') {
12
+ await context.input.$reply(getDungeonHelp({ locale: context.input.locale,
13
+ formatCommand: path => context.input.formatCommand?.(path, context.owner.id) }));
14
+ return true;
15
+ }
16
+ const services = resolveGameServices(context), player = gamePlayerFromInput(input);
17
+ await replyGameOperation({ session: services, player, reply: content => context.input.$reply(content),
18
+ run: () => runDungeonCommand(services, player, action) });
19
+ return true;
11
20
  },
12
21
  });
@@ -1,9 +1,7 @@
1
- import {
2
- defineGameCommandAliasMiddleware,
3
- messageFromCommandInput,
4
- } from '@zhin.js/game-kit';
1
+ import { replyGameOperation, defineGameCommandAliasMiddleware, gamePlayerFromInput } from '@zhin.js/game-kit';
5
2
  import {
6
3
  normalizeDungeonAction,
4
+ getDungeonHelp,
7
5
  runDungeonCommand,
8
6
  } from '../../src/dungeon-command.js';
9
7
  import { resolveGameServices } from '../../src/runtime-store.js';
@@ -11,11 +9,16 @@ import { resolveGameServices } from '../../src/runtime-store.js';
11
9
  export default defineGameCommandAliasMiddleware({
12
10
  aliases: ['地牢', 'dungeon'],
13
11
  async run(action, input, context) {
14
- if (normalizeDungeonAction(action) === null) return null;
15
- return runDungeonCommand(
16
- resolveGameServices(context),
17
- messageFromCommandInput(input),
18
- action,
19
- );
12
+ const normalized = normalizeDungeonAction(action);
13
+ if (normalized === null) return false;
14
+ if (normalized === 'help') {
15
+ await context.input.$reply(getDungeonHelp({ locale: context.input.locale,
16
+ formatCommand: path => context.input.formatCommand?.(path, context.owner.id) }));
17
+ return true;
18
+ }
19
+ const services = resolveGameServices(context), player = gamePlayerFromInput(input);
20
+ await replyGameOperation({ session: services, player, reply: content => context.input.$reply(content),
21
+ run: () => runDungeonCommand(services, player, action) });
22
+ return true;
20
23
  },
21
24
  });
@@ -1,6 +1,6 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { replyGameOperation, buildChoiceFallbackMap, channelKey, gamePlayerFromInput, parseChoicePayload, resolveGameTextPayload, } from '@zhin.js/game-kit';
2
3
  import { defineMiddleware } from 'zhin.js/middleware';
3
- import { buildChoiceFallbackMap, channelKey, messageFromCommandInput, parseChoicePayload, resolveGameTextPayload, } from '@zhin.js/game-kit';
4
4
  import { handleDungeonChoice } from "../../lib/game-flow.js";
5
5
  import { resolveGameServices } from "../../lib/runtime-store.js";
6
6
  import { stateFromSession } from "../../lib/session-service.js";
@@ -8,19 +8,23 @@ import { DUNGEON_PREFIX, choicesForState, dungeonSessionToken, } from "../../lib
8
8
  export default defineMiddleware({
9
9
  target: 'inbound',
10
10
  async handle(context, next) {
11
+ if (!context.input.sender?.id) {
12
+ await next();
13
+ return;
14
+ }
11
15
  const raw = context.input.content?.trim() ?? '';
12
16
  if (!raw) {
13
17
  await next();
14
18
  return;
15
19
  }
16
20
  const service = resolveGameServices(context);
17
- const message = messageFromCommandInput(context.input);
21
+ const message = gamePlayerFromInput(context.input);
18
22
  const payloadFromText = resolveGameTextPayload(raw);
19
23
  if (payloadFromText?.startsWith(`${DUNGEON_PREFIX}:`)) {
20
24
  const parsed = parseChoicePayload(payloadFromText, DUNGEON_PREFIX);
21
25
  if (parsed) {
22
- const reply = await handleDungeonChoice(service, message, parsed.sessionId, parsed.choiceId);
23
- await context.input.$reply(reply);
26
+ await replyGameOperation({ session: service, player: message, reply: content => context.input.$reply(content),
27
+ run: () => handleDungeonChoice(service, message, parsed.sessionId, parsed.choiceId) });
24
28
  return;
25
29
  }
26
30
  await next();
@@ -39,7 +43,7 @@ export default defineMiddleware({
39
43
  await next();
40
44
  return;
41
45
  }
42
- const reply = await handleDungeonChoice(service, message, parsed.sessionId, parsed.choiceId);
43
- await context.input.$reply(reply);
46
+ await replyGameOperation({ session: service, player: message, reply: content => context.input.$reply(content),
47
+ run: () => handleDungeonChoice(service, message, parsed.sessionId, parsed.choiceId) });
44
48
  },
45
49
  });
@@ -1,12 +1,13 @@
1
- import type { Message } from '@zhin.js/core/runtime';
2
- import { defineMiddleware } from 'zhin.js/middleware';
3
1
  import {
2
+ replyGameOperation,
4
3
  buildChoiceFallbackMap,
5
4
  channelKey,
6
- messageFromCommandInput,
5
+ gamePlayerFromInput,
7
6
  parseChoicePayload,
8
7
  resolveGameTextPayload,
9
8
  } from '@zhin.js/game-kit';
9
+ import type { Message } from '@zhin.js/core/runtime';
10
+ import { defineMiddleware } from 'zhin.js/middleware';
10
11
  import { handleDungeonChoice } from '../../src/game-flow.js';
11
12
  import { resolveGameServices } from '../../src/runtime-store.js';
12
13
  import { stateFromSession } from '../../src/session-service.js';
@@ -19,24 +20,25 @@ import {
19
20
  export default defineMiddleware<Message>({
20
21
  target: 'inbound',
21
22
  async handle(context, next) {
23
+ if (!context.input.sender?.id) { await next(); return; }
22
24
  const raw = context.input.content?.trim() ?? '';
23
25
  if (!raw) {
24
26
  await next();
25
27
  return;
26
28
  }
27
29
  const service = resolveGameServices(context);
28
- const message = messageFromCommandInput(context.input);
30
+ const message = gamePlayerFromInput(context.input);
29
31
  const payloadFromText = resolveGameTextPayload(raw);
30
32
  if (payloadFromText?.startsWith(`${DUNGEON_PREFIX}:`)) {
31
33
  const parsed = parseChoicePayload(payloadFromText, DUNGEON_PREFIX);
32
34
  if (parsed) {
33
- const reply = await handleDungeonChoice(
35
+ await replyGameOperation({ session: service, player: message, reply: content => context.input.$reply(content),
36
+ run: () => handleDungeonChoice(
34
37
  service,
35
38
  message,
36
39
  parsed.sessionId,
37
40
  parsed.choiceId,
38
- );
39
- await context.input.$reply(reply);
41
+ ) });
40
42
  return;
41
43
  }
42
44
  await next();
@@ -60,12 +62,12 @@ export default defineMiddleware<Message>({
60
62
  await next();
61
63
  return;
62
64
  }
63
- const reply = await handleDungeonChoice(
65
+ await replyGameOperation({ session: service, player: message, reply: content => context.input.$reply(content),
66
+ run: () => handleDungeonChoice(
64
67
  service,
65
68
  message,
66
69
  parsed.sessionId,
67
70
  parsed.choiceId,
68
- );
69
- await context.input.$reply(reply);
71
+ ) });
70
72
  },
71
73
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/plugin-dungeon-expedition",
3
- "version": "1.1.18",
3
+ "version": "1.1.20",
4
4
  "description": "Zhin.js multiplayer deterministic dungeon expedition",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -23,13 +23,13 @@
23
23
  ],
24
24
  "license": "MIT",
25
25
  "dependencies": {
26
- "@zhin.js/core": "1.1.53",
27
- "@zhin.js/game-kit": "1.1.18"
26
+ "@zhin.js/core": "1.1.55",
27
+ "@zhin.js/game-kit": "1.1.20"
28
28
  },
29
29
  "devDependencies": {
30
30
  "typescript": "^6.0.3",
31
31
  "vitest": "^4.1.10",
32
- "zhin.js": "1.1.18"
32
+ "zhin.js": "1.1.20"
33
33
  },
34
34
  "repository": {
35
35
  "type": "git",
@@ -66,9 +66,9 @@
66
66
  "plugins": []
67
67
  },
68
68
  "peerDependencies": {
69
- "@zhin.js/command": "^1.1.11",
70
- "@zhin.js/middleware": "^1.1.10",
71
- "zhin.js": "^1.1.18"
69
+ "@zhin.js/command": "^1.1.13",
70
+ "@zhin.js/middleware": "^1.1.12",
71
+ "zhin.js": "^1.1.20"
72
72
  },
73
73
  "peerDependenciesMeta": {
74
74
  "@zhin.js/command": {
@@ -1,5 +1,5 @@
1
1
  import { createMessages } from 'zhin.js/i18n';
2
- import { gameCommandHint, channelKey, type GameMessageLike, type GameReply } from '@zhin.js/game-kit';
2
+ import { gameCommandHint, channelKey, type GamePlayer, type GameReply } from '@zhin.js/game-kit';
3
3
  import {
4
4
  continueDungeon,
5
5
  handleDungeonChoice,
@@ -20,7 +20,7 @@ const messages = createMessages({
20
20
  abort: { 'zh-CN': '队长结束远征', en: 'Leader ends the expedition' },
21
21
  empty: { 'zh-CN': '当前频道没有远征队。', en: 'This channel has no expedition party.' },
22
22
  });
23
- export function getDungeonHelp(message: Pick<GameMessageLike, 'locale' | 'formatCommand'> = {}): string {
23
+ export function getDungeonHelp(message: Pick<GamePlayer, 'locale' | 'formatCommand'> = {}): string {
24
24
  const command = message.formatCommand?.('dungeon');
25
25
  const actions = ['start', 'join', 'ready', 'go', 'explore', 'attack', 'defend', 'potion', 'status', 'abort'] as const;
26
26
  return [messages(message.locale, 'title'), ...(command === undefined ? [] : actions.map(action => `${command} ${action} — ${messages(message.locale, action)}`))].join('\n');
@@ -65,20 +65,22 @@ export function normalizeDungeonAction(action: string): string | null {
65
65
 
66
66
  export async function runDungeonCommand(
67
67
  service: SessionService,
68
- message: GameMessageLike,
68
+ message: GamePlayer,
69
69
  rawAction: string,
70
70
  ): Promise<GameReply> {
71
- const action = normalizeDungeonAction(rawAction);
72
- if (!action || action === 'help') return getDungeonHelp(message);
73
- if (action === 'create') return startDungeon(service, message);
74
- if (action === 'status') return continueDungeon(service, message);
71
+ return service.runInScope({ scope: channelKey(message), run: async () => {
72
+ const action = normalizeDungeonAction(rawAction);
73
+ if (!action || action === 'help') return getDungeonHelp(message);
74
+ if (action === 'create') return startDungeon(service, message);
75
+ if (action === 'status') return continueDungeon(service, message);
75
76
 
76
- const session = await service.getActiveByChannel(channelKey(message));
77
- if (!session) return messages(message.locale, 'empty') + gameCommandHint(message, 'dungeon');
78
- return handleDungeonChoice(
79
- service,
80
- message,
81
- dungeonSessionToken(session),
82
- action,
83
- );
77
+ const session = await service.getActiveByChannel(channelKey(message));
78
+ if (!session) return messages(message.locale, 'empty') + gameCommandHint(message, 'dungeon');
79
+ return handleDungeonChoice(
80
+ service,
81
+ message,
82
+ dungeonSessionToken(session),
83
+ action,
84
+ );
85
+ } });
84
86
  }
package/src/game-flow.ts CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  GameSessionConflictError,
4
4
  SessionRevisionConflictError,
5
5
  channelKey,
6
- type GameMessageLike,
6
+ type GamePlayer,
7
7
  type GameReply,
8
8
  } from '@zhin.js/game-kit';
9
9
  import {
@@ -22,81 +22,87 @@ import {
22
22
 
23
23
  export async function startDungeon(
24
24
  service: SessionService,
25
- message: GameMessageLike,
25
+ message: GamePlayer,
26
26
  ): Promise<GameReply> {
27
- const active = await service.getActiveByChannel(channelKey(message));
28
- if (active) return buildDungeonView(active, stateFromSession(active), message.$channel.type);
29
- try {
30
- const session = await service.createSession(message);
31
- return buildDungeonView(session, stateFromSession(session), message.$channel.type);
32
- } catch (error) {
33
- if (error instanceof GameSessionConflictError) return error.format(message.locale);
34
- throw error;
35
- }
27
+ return service.runInScope({ scope: channelKey(message), run: async () => {
28
+ const active = await service.getActiveByChannel(channelKey(message));
29
+ if (active) return buildDungeonView(active, stateFromSession(active), message.target.kind);
30
+ try {
31
+ const session = await service.createSession(message);
32
+ return buildDungeonView(session, stateFromSession(session), message.target.kind);
33
+ } catch (error) {
34
+ if (error instanceof GameSessionConflictError) return error.format(message.locale);
35
+ throw error;
36
+ }
37
+ } });
36
38
  }
37
39
 
38
40
  export async function continueDungeon(
39
41
  service: SessionService,
40
- message: GameMessageLike,
42
+ message: GamePlayer,
41
43
  ): Promise<GameReply> {
42
- const locale = resolveLocale(message.locale);
43
- const session = await service.getActiveByChannel(channelKey(message));
44
- if (!session) return messages(locale, 'text1');
45
- return buildDungeonView(session, stateFromSession(session), message.$channel.type);
44
+ return service.runInScope({ scope: channelKey(message), run: async () => {
45
+ const locale = resolveLocale(message.locale);
46
+ const session = await service.getActiveByChannel(channelKey(message));
47
+ if (!session) return messages(locale, 'text1');
48
+ return buildDungeonView(session, stateFromSession(session), message.target.kind);
49
+ } });
46
50
  }
47
51
 
48
52
  export async function handleDungeonChoice(
49
53
  service: SessionService,
50
- message: GameMessageLike,
54
+ message: GamePlayer,
51
55
  sessionToken: string,
52
56
  choiceId: string,
53
57
  ): Promise<GameReply> {
54
- let locale = resolveLocale(message.locale);
55
- const token = parseDungeonSessionToken(sessionToken);
56
- if (!token) return messages(locale, 'text2');
57
- const session = await service.getById(token.sessionId);
58
- if (!session || session.channel_key !== channelKey(message)) {
59
- return messages(locale, 'text3');
60
- }
61
- locale = resolveLocale(session.locale);
62
- if (choiceId === 'restart') {
63
- if (session.status === 'active') return messages(locale, 'text4');
64
- if (session.owner_id !== message.$sender.id) return messages(locale, 'text5');
65
- return startDungeon(service, message);
66
- }
67
- const action = actionFromChoice(choiceId, message);
68
- if (!action) return messages(locale, 'text6');
69
- try {
70
- const result = await service.performAction({
71
- sessionId: session.id,
72
- actorId: message.$sender.id,
73
- actorName: message.$sender.name?.trim() || message.$sender.id,
74
- action,
75
- expectedRevision: token.revision,
76
- actionId: `${session.id}:${token.revision}:${message.$sender.id}:${choiceId}`,
77
- });
78
- return buildDungeonView(
79
- result.session,
80
- stateFromSession(result.session),
81
- message.$channel.type,
82
- );
83
- } catch (error) {
84
- if (error instanceof DungeonRuleError) return error.message;
85
- if (error instanceof GameSessionConflictError) return error.format(locale);
86
- if (error instanceof SessionRevisionConflictError) {
87
- const latest = await service.getById(session.id);
88
- if (!latest) return messages(locale, 'text7');
89
- const view = buildDungeonView(
90
- latest,
91
- stateFromSession(latest),
92
- message.$channel.type,
58
+ return service.runInScope({ scope: channelKey(message), run: async () => {
59
+ let locale = resolveLocale(message.locale);
60
+ const token = parseDungeonSessionToken(sessionToken);
61
+ if (!token) return messages(locale, 'text2');
62
+ const session = await service.getById(token.sessionId);
63
+ if (!session || session.channel_key !== channelKey(message)) {
64
+ return messages(locale, 'text3');
65
+ }
66
+ locale = resolveLocale(session.locale);
67
+ if (choiceId === 'restart') {
68
+ if (session.status === 'active') return messages(locale, 'text4');
69
+ if (session.owner_id !== message.sender.id) return messages(locale, 'text5');
70
+ return startDungeon(service, message);
71
+ }
72
+ const action = actionFromChoice(choiceId, message);
73
+ if (!action) return messages(locale, 'text6');
74
+ try {
75
+ const result = await service.performAction({
76
+ sessionId: session.id,
77
+ actorId: message.sender.id,
78
+ actorName: message.sender.name?.trim() || message.sender.id,
79
+ action,
80
+ expectedRevision: token.revision,
81
+ actionId: `${session.id}:${token.revision}:${message.sender.id}:${choiceId}`,
82
+ });
83
+ return buildDungeonView(
84
+ result.session,
85
+ stateFromSession(result.session),
86
+ message.target.kind,
93
87
  );
94
- return Array.isArray(view)
95
- ? [messages(locale, 'text8'), ...view]
96
- : [messages(locale, 'text8'), view];
88
+ } catch (error) {
89
+ if (error instanceof DungeonRuleError) return error.message;
90
+ if (error instanceof GameSessionConflictError) return error.format(locale);
91
+ if (error instanceof SessionRevisionConflictError) {
92
+ const latest = await service.getById(session.id);
93
+ if (!latest) return messages(locale, 'text7');
94
+ const view = buildDungeonView(
95
+ latest,
96
+ stateFromSession(latest),
97
+ message.target.kind,
98
+ );
99
+ return Array.isArray(view)
100
+ ? [messages(locale, 'text8'), ...view]
101
+ : [messages(locale, 'text8'), view];
102
+ }
103
+ throw error;
97
104
  }
98
- throw error;
99
- }
105
+ } });
100
106
  }
101
107
 
102
108
  export function commandActionId(
@@ -109,12 +115,12 @@ export function commandActionId(
109
115
 
110
116
  function actionFromChoice(
111
117
  choiceId: string,
112
- message: GameMessageLike,
118
+ message: GamePlayer,
113
119
  ): DungeonAction | null {
114
120
  if (choiceId === 'join') {
115
121
  return {
116
122
  type: 'join',
117
- name: message.$sender.name?.trim() || message.$sender.id,
123
+ name: message.sender.name?.trim() || message.sender.id,
118
124
  };
119
125
  }
120
126
  if (choiceId === 'ready') return { type: 'ready' };
@@ -2,9 +2,8 @@ import type { Database, Models } from '@zhin.js/core';
2
2
  import {
3
3
  DeterministicRandom,
4
4
  VersionedSessionService,
5
- channelKey,
6
5
  generateCompactId,
7
- type GameMessageLike,
6
+ type GamePlayer,
8
7
  type GameOutcome,
9
8
  type GameSessionDatabase,
10
9
  type SessionMutationResult,
@@ -41,35 +40,33 @@ export class SessionService extends VersionedSessionService<DungeonSessionRow> {
41
40
  }
42
41
 
43
42
  async createSession(
44
- message: GameMessageLike,
43
+ message: GamePlayer,
45
44
  seed?: string | number,
46
45
  ): Promise<DungeonSessionRow> {
47
46
  const now = Date.now();
48
47
  const id = generateCompactId('dng_');
49
- const ownerName = message.$sender.name?.trim() || message.$sender.id;
50
- const state = createDungeonState(message.$sender.id, ownerName, message.locale);
48
+ const ownerName = message.sender.name?.trim() || message.sender.id;
49
+ const state = createDungeonState(message.sender.id, ownerName, message.locale);
51
50
  const random = DeterministicRandom.fromSeed(seed ?? id);
52
51
  return this.createRow({
53
- id,
54
- locale: message.locale ?? 'zh-CN',
55
- adapter: String(message.$adapter),
56
- endpoint: message.$endpoint,
57
- channel_type: message.$channel.type,
58
- channel_id: message.$channel.id,
59
- channel_key: channelKey(message),
60
- owner_id: message.$sender.id,
61
- owner_name: ownerName,
62
- state_json: JSON.stringify(state),
63
- phase: state.phase,
64
- turn: activePlayer(state)?.id ?? '',
65
- rng_state: random.state,
66
- schema_version: state.schemaVersion,
67
- revision: 0,
68
- processed_actions: '[]',
69
- deadline_at: now + 5 * 60_000,
70
- status: 'active',
71
- updated_at: now,
72
- created_at: now,
52
+ target: message.target,
53
+ fields: {
54
+ id,
55
+ locale: message.locale ?? 'zh-CN',
56
+ owner_id: message.sender.id,
57
+ owner_name: ownerName,
58
+ state_json: JSON.stringify(state),
59
+ phase: state.phase,
60
+ turn: activePlayer(state)?.id ?? '',
61
+ rng_state: random.state,
62
+ schema_version: state.schemaVersion,
63
+ revision: 0,
64
+ processed_actions: '[]',
65
+ deadline_at: now + 5 * 60_000,
66
+ status: 'active',
67
+ updated_at: now,
68
+ created_at: now,
69
+ },
73
70
  });
74
71
  }
75
72