@zhin.js/plugin-text-adventure 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 (98) hide show
  1. package/README.md +92 -0
  2. package/lib/achievements.d.ts +24 -0
  3. package/lib/achievements.d.ts.map +1 -0
  4. package/lib/achievements.js +62 -0
  5. package/lib/achievements.js.map +1 -0
  6. package/lib/adv-command.d.ts +5 -0
  7. package/lib/adv-command.d.ts.map +1 -0
  8. package/lib/adv-command.js +55 -0
  9. package/lib/adv-command.js.map +1 -0
  10. package/lib/commands.d.ts +6 -0
  11. package/lib/commands.d.ts.map +1 -0
  12. package/lib/commands.js +96 -0
  13. package/lib/commands.js.map +1 -0
  14. package/lib/game-flow.d.ts +9 -0
  15. package/lib/game-flow.d.ts.map +1 -0
  16. package/lib/game-flow.js +134 -0
  17. package/lib/game-flow.js.map +1 -0
  18. package/lib/hub-register.d.ts +5 -0
  19. package/lib/hub-register.d.ts.map +1 -0
  20. package/lib/hub-register.js +25 -0
  21. package/lib/hub-register.js.map +1 -0
  22. package/lib/index.d.ts +2 -0
  23. package/lib/index.d.ts.map +1 -0
  24. package/lib/index.js +37 -0
  25. package/lib/index.js.map +1 -0
  26. package/lib/models.d.ts +45 -0
  27. package/lib/models.d.ts.map +1 -0
  28. package/lib/models.js +37 -0
  29. package/lib/models.js.map +1 -0
  30. package/lib/profile-format.d.ts +6 -0
  31. package/lib/profile-format.d.ts.map +1 -0
  32. package/lib/profile-format.js +64 -0
  33. package/lib/profile-format.js.map +1 -0
  34. package/lib/profile-parse.d.ts +4 -0
  35. package/lib/profile-parse.d.ts.map +1 -0
  36. package/lib/profile-parse.js +21 -0
  37. package/lib/profile-parse.js.map +1 -0
  38. package/lib/profile-service.d.ts +17 -0
  39. package/lib/profile-service.d.ts.map +1 -0
  40. package/lib/profile-service.js +124 -0
  41. package/lib/profile-service.js.map +1 -0
  42. package/lib/scene-view.d.ts +4 -0
  43. package/lib/scene-view.d.ts.map +1 -0
  44. package/lib/scene-view.js +32 -0
  45. package/lib/scene-view.js.map +1 -0
  46. package/lib/session-service.d.ts +22 -0
  47. package/lib/session-service.d.ts.map +1 -0
  48. package/lib/session-service.js +100 -0
  49. package/lib/session-service.js.map +1 -0
  50. package/lib/story-catalog.d.ts +13 -0
  51. package/lib/story-catalog.d.ts.map +1 -0
  52. package/lib/story-catalog.js +104 -0
  53. package/lib/story-catalog.js.map +1 -0
  54. package/lib/story-items.d.ts +5 -0
  55. package/lib/story-items.d.ts.map +1 -0
  56. package/lib/story-items.js +23 -0
  57. package/lib/story-items.js.map +1 -0
  58. package/lib/story-path.d.ts +3 -0
  59. package/lib/story-path.d.ts.map +1 -0
  60. package/lib/story-path.js +66 -0
  61. package/lib/story-path.js.map +1 -0
  62. package/lib/story-scenes.d.ts +9 -0
  63. package/lib/story-scenes.d.ts.map +1 -0
  64. package/lib/story-scenes.js +478 -0
  65. package/lib/story-scenes.js.map +1 -0
  66. package/lib/story-transitions.d.ts +3 -0
  67. package/lib/story-transitions.d.ts.map +1 -0
  68. package/lib/story-transitions.js +193 -0
  69. package/lib/story-transitions.js.map +1 -0
  70. package/lib/story-types.d.ts +30 -0
  71. package/lib/story-types.d.ts.map +1 -0
  72. package/lib/story-types.js +3 -0
  73. package/lib/story-types.js.map +1 -0
  74. package/lib/story.d.ts +21 -0
  75. package/lib/story.d.ts.map +1 -0
  76. package/lib/story.js +91 -0
  77. package/lib/story.js.map +1 -0
  78. package/package.json +54 -0
  79. package/plugin.yml +2 -0
  80. package/src/achievements.ts +90 -0
  81. package/src/adv-command.ts +72 -0
  82. package/src/commands.ts +133 -0
  83. package/src/game-flow.ts +196 -0
  84. package/src/hub-register.ts +32 -0
  85. package/src/index.ts +47 -0
  86. package/src/models.ts +84 -0
  87. package/src/profile-format.ts +76 -0
  88. package/src/profile-parse.ts +19 -0
  89. package/src/profile-service.ts +151 -0
  90. package/src/scene-view.ts +46 -0
  91. package/src/session-service.ts +113 -0
  92. package/src/story-catalog.ts +110 -0
  93. package/src/story-items.ts +24 -0
  94. package/src/story-path.ts +75 -0
  95. package/src/story-scenes.ts +508 -0
  96. package/src/story-transitions.ts +198 -0
  97. package/src/story-types.ts +33 -0
  98. package/src/story.ts +104 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,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,GAAwB,IAAI,CAAC;AAEzC,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,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAC1D,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,QAAQ,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC7D,IAAI,CAAC,GAAG,CAAC;QAAE,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACtE,CAAC,CAAC,CACH,CAAC;AAEF,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,45 @@
1
+ import type { Models, Plugin } from 'zhin.js';
2
+ export type AdvSessionStatus = 'active' | 'completed' | 'aborted';
3
+ declare module 'zhin.js' {
4
+ interface Models {
5
+ adv_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
+ scene_id: string;
15
+ hp: number;
16
+ inventory: string;
17
+ flags: string;
18
+ ending_id: string;
19
+ status: AdvSessionStatus;
20
+ board_message_id: string;
21
+ step_count: number;
22
+ updated_at: number;
23
+ created_at: number;
24
+ };
25
+ adv_profiles: {
26
+ player_id: string;
27
+ player_name: string;
28
+ visited_scenes: string;
29
+ endings_seen: string;
30
+ items_found: string;
31
+ achievements: string;
32
+ runs_started: number;
33
+ runs_completed: number;
34
+ total_steps: number;
35
+ best_step_count: number;
36
+ updated_at: number;
37
+ created_at: number;
38
+ };
39
+ }
40
+ }
41
+ export type AdvSessionRow = Models['adv_sessions'];
42
+ export type AdvProfileRow = Models['adv_profiles'];
43
+ export type AdvModelName = 'adv_sessions' | 'adv_profiles';
44
+ export declare function registerModels(plugin: Plugin): void;
45
+ //# 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,WAAW,GAAG,SAAS,CAAC;AAElE,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,QAAQ,EAAE,MAAM,CAAC;YACjB,EAAE,EAAE,MAAM,CAAC;YACX,SAAS,EAAE,MAAM,CAAC;YAClB,KAAK,EAAE,MAAM,CAAC;YACd,SAAS,EAAE,MAAM,CAAC;YAClB,MAAM,EAAE,gBAAgB,CAAC;YACzB,gBAAgB,EAAE,MAAM,CAAC;YACzB,UAAU,EAAE,MAAM,CAAC;YACnB,UAAU,EAAE,MAAM,CAAC;YACnB,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC;QACF,YAAY,EAAE;YACZ,SAAS,EAAE,MAAM,CAAC;YAClB,WAAW,EAAE,MAAM,CAAC;YACpB,cAAc,EAAE,MAAM,CAAC;YACvB,YAAY,EAAE,MAAM,CAAC;YACrB,WAAW,EAAE,MAAM,CAAC;YACpB,YAAY,EAAE,MAAM,CAAC;YACrB,YAAY,EAAE,MAAM,CAAC;YACrB,cAAc,EAAE,MAAM,CAAC;YACvB,WAAW,EAAE,MAAM,CAAC;YACpB,eAAe,EAAE,MAAM,CAAC;YACxB,UAAU,EAAE,MAAM,CAAC;YACnB,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC;KACH;CACF;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;AACnD,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;AACnD,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,cAAc,CAAC;AAE3D,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAoCnD"}
package/lib/models.js ADDED
@@ -0,0 +1,37 @@
1
+ export function registerModels(plugin) {
2
+ plugin.defineModel('adv_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
+ scene_id: { type: 'text', default: 'start' },
12
+ hp: { type: 'integer', default: 100 },
13
+ inventory: { type: 'text', default: '[]' },
14
+ flags: { type: 'text', default: '{}' },
15
+ ending_id: { type: 'text', default: '' },
16
+ status: { type: 'text', default: 'active' },
17
+ board_message_id: { type: 'text', default: '' },
18
+ step_count: { type: 'integer', default: 0 },
19
+ updated_at: { type: 'integer', default: 0 },
20
+ created_at: { type: 'integer', default: 0 },
21
+ });
22
+ plugin.defineModel('adv_profiles', {
23
+ player_id: { type: 'text', primary: true },
24
+ player_name: { type: 'text', default: '' },
25
+ visited_scenes: { type: 'text', default: '[]' },
26
+ endings_seen: { type: 'text', default: '[]' },
27
+ items_found: { type: 'text', default: '[]' },
28
+ achievements: { type: 'text', default: '[]' },
29
+ runs_started: { type: 'integer', default: 0 },
30
+ runs_completed: { type: 'integer', default: 0 },
31
+ total_steps: { type: 'integer', default: 0 },
32
+ best_step_count: { type: 'integer', default: 0 },
33
+ updated_at: { type: 'integer', default: 0 },
34
+ created_at: { type: 'integer', default: 0 },
35
+ });
36
+ }
37
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AA+CA,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,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE;QAC5C,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE;QACrC,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QAC1C,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACtC,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QACxC,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;QAC3C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;KAC5C,CAAC,CAAC;IAEH,MAAM,CAAC,WAAW,CAAC,cAAc,EAAE;QACjC,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QAC1C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QAC1C,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QAC/C,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QAC7C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QAC5C,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QAC7C,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC7C,cAAc,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC/C,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,eAAe,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAChD,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,6 @@
1
+ import type { AdvProfileRow } from './models.js';
2
+ export declare function formatProgressCompact(profile: AdvProfileRow): string;
3
+ export declare function formatMapProgress(profile: AdvProfileRow): string;
4
+ export declare function formatAchievements(profile: AdvProfileRow, showHidden?: boolean): string;
5
+ export declare function formatNewAchievements(ids: string[]): string;
6
+ //# sourceMappingURL=profile-format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-format.d.ts","sourceRoot":"","sources":["../src/profile-format.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAOpE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CA4BhE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,EAAE,UAAU,UAAQ,GAAG,MAAM,CAerF;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,CAQ3D"}
@@ -0,0 +1,64 @@
1
+ import { achievementById, ACHIEVEMENTS, totalAchievements } from './achievements.js';
2
+ import { endingIds, endingLabel, MAP_ZONES, playableSceneIds, regionLabel, } from './story-catalog.js';
3
+ import { parseStringSet } from './profile-parse.js';
4
+ export function formatProgressCompact(profile) {
5
+ const visited = parseStringSet(profile.visited_scenes).size;
6
+ const endings = parseStringSet(profile.endings_seen).size;
7
+ const achievements = parseStringSet(profile.achievements).size;
8
+ const totalRegions = playableSceneIds().length;
9
+ const totalEndings = endingIds().length;
10
+ return `🗺️ ${visited}/${totalRegions} · 🎬 ${endings}/${totalEndings} · 🏅 ${achievements}/${totalAchievements()}`;
11
+ }
12
+ export function formatMapProgress(profile) {
13
+ const visited = parseStringSet(profile.visited_scenes);
14
+ const total = playableSceneIds().length;
15
+ const pct = total ? Math.round((visited.size / total) * 100) : 0;
16
+ const lines = [
17
+ `🗺️ **探索进度** ${visited.size}/${total}(${pct}%)`,
18
+ '',
19
+ ];
20
+ for (const zone of MAP_ZONES) {
21
+ const parts = zone.sceneIds.map((id) => {
22
+ const mark = visited.has(id) ? '✅' : '⬜';
23
+ return `${mark} ${regionLabel(id)}`;
24
+ });
25
+ lines.push(`**${zone.name}**`);
26
+ lines.push(parts.join(' '));
27
+ lines.push('');
28
+ }
29
+ const endings = parseStringSet(profile.endings_seen);
30
+ const allEndings = endingIds();
31
+ lines.push(`**结局图鉴** ${endings.size}/${allEndings.length}`);
32
+ lines.push(allEndings
33
+ .map((id) => `${endings.has(id) ? '✅' : '⬜'} ${endingLabel(id)}`)
34
+ .join(' '));
35
+ return lines.join('\n').trimEnd();
36
+ }
37
+ export function formatAchievements(profile, showHidden = false) {
38
+ const unlocked = parseStringSet(profile.achievements);
39
+ const lines = [
40
+ `🏅 **成就** ${unlocked.size}/${totalAchievements()}`,
41
+ `完成局数:${profile.runs_completed} · 生涯步数:${profile.total_steps}`,
42
+ '',
43
+ ];
44
+ for (const def of ACHIEVEMENTS) {
45
+ const got = unlocked.has(def.id);
46
+ if (def.hidden && !got && !showHidden)
47
+ continue;
48
+ const mark = got ? '✅' : '⬜';
49
+ lines.push(`${mark} ${def.icon} **${def.title}** — ${def.description}`);
50
+ }
51
+ return lines.join('\n');
52
+ }
53
+ export function formatNewAchievements(ids) {
54
+ if (!ids.length)
55
+ return '';
56
+ const lines = ['', '🏅 **新成就解锁!**'];
57
+ for (const id of ids) {
58
+ const def = achievementById(id);
59
+ if (def)
60
+ lines.push(`${def.icon} ${def.title} — ${def.description}`);
61
+ }
62
+ return lines.join('\n');
63
+ }
64
+ //# sourceMappingURL=profile-format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-format.js","sourceRoot":"","sources":["../src/profile-format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /** 解析 DB 中的 JSON 字符串集合(兼容 SQLite 已自动 parse 的数组) */
2
+ export declare function parseStringSet(value: string | string[] | unknown): Set<string>;
3
+ export declare function serializeStringSet(set: Set<string>): string;
4
+ //# sourceMappingURL=profile-parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-parse.d.ts","sourceRoot":"","sources":["../src/profile-parse.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAa9E;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAE3D"}
@@ -0,0 +1,21 @@
1
+ /** 解析 DB 中的 JSON 字符串集合(兼容 SQLite 已自动 parse 的数组) */
2
+ export function parseStringSet(value) {
3
+ if (Array.isArray(value)) {
4
+ return new Set(value.filter((x) => typeof x === 'string'));
5
+ }
6
+ if (typeof value !== 'string' || !value)
7
+ return new Set();
8
+ try {
9
+ const v = JSON.parse(value);
10
+ return Array.isArray(v)
11
+ ? new Set(v.filter((x) => typeof x === 'string'))
12
+ : new Set();
13
+ }
14
+ catch {
15
+ return new Set();
16
+ }
17
+ }
18
+ export function serializeStringSet(set) {
19
+ return JSON.stringify([...set].sort());
20
+ }
21
+ //# sourceMappingURL=profile-parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-parse.js","sourceRoot":"","sources":["../src/profile-parse.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,MAAM,UAAU,cAAc,CAAC,KAAkC;IAC/D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,GAAG,EAAE,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YACrB,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;YAC9D,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,GAAG,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAgB;IACjD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { AdvProfileRow } from './models.js';
2
+ import type { AdvDatabase } from './session-service.js';
3
+ export declare class ProfileService {
4
+ private readonly db;
5
+ constructor(db: AdvDatabase);
6
+ get(playerId: string): Promise<AdvProfileRow | null>;
7
+ getOrCreate(playerId: string, playerName: string): Promise<AdvProfileRow>;
8
+ patch(playerId: string, patch: Partial<AdvProfileRow>): Promise<void>;
9
+ onRunStarted(playerId: string, playerName: string): Promise<AdvProfileRow>;
10
+ /** 记录进入场景、步数、背包变化;返回新解锁成就 ID */
11
+ onStep(playerId: string, playerName: string, sceneId: string, inventory: string[]): Promise<string[]>;
12
+ /** 局终:记录结局、完成数、最佳步数 */
13
+ onRunCompleted(playerId: string, playerName: string, endingId: string, stepCount: number, inventory: string[]): Promise<string[]>;
14
+ private unlockPending;
15
+ }
16
+ export declare function createProfileService(db: AdvDatabase): ProfileService;
17
+ //# sourceMappingURL=profile-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-service.d.ts","sourceRoot":"","sources":["../src/profile-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,aAAa,CAAC;AAG/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAYxD,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,WAAW;IAEtC,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAIpD,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IA4BzE,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAOrE,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAMhF,gCAAgC;IAC1B,MAAM,CACV,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,MAAM,EAAE,CAAC;IA2BpB,uBAAuB;IACjB,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,MAAM,EAAE,CAAC;YAkBN,aAAa;CAuB5B;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,WAAW,GAAG,cAAc,CAEpE"}
@@ -0,0 +1,124 @@
1
+ import { evaluateAchievements } from './achievements.js';
2
+ import { parseStringSet, serializeStringSet } from './profile-parse.js';
3
+ import { playableSceneIds } from './story-catalog.js';
4
+ const PLAYABLE = new Set(playableSceneIds());
5
+ function getModel(db, name) {
6
+ const model = db.models.get(name);
7
+ if (!model)
8
+ throw new Error(`Model ${name} is not registered`);
9
+ return model;
10
+ }
11
+ export class ProfileService {
12
+ db;
13
+ constructor(db) {
14
+ this.db = db;
15
+ }
16
+ async get(playerId) {
17
+ return getModel(this.db, 'adv_profiles').findOne({ player_id: playerId });
18
+ }
19
+ async getOrCreate(playerId, playerName) {
20
+ const existing = await this.get(playerId);
21
+ if (existing) {
22
+ if (playerName && existing.player_name !== playerName) {
23
+ await this.patch(playerId, { player_name: playerName });
24
+ return (await this.get(playerId));
25
+ }
26
+ return existing;
27
+ }
28
+ const now = Date.now();
29
+ const row = {
30
+ player_id: playerId,
31
+ player_name: playerName || playerId,
32
+ visited_scenes: '[]',
33
+ endings_seen: '[]',
34
+ items_found: '[]',
35
+ achievements: '[]',
36
+ runs_started: 0,
37
+ runs_completed: 0,
38
+ total_steps: 0,
39
+ best_step_count: 0,
40
+ updated_at: now,
41
+ created_at: now,
42
+ };
43
+ await getModel(this.db, 'adv_profiles').create(row);
44
+ return row;
45
+ }
46
+ async patch(playerId, patch) {
47
+ await getModel(this.db, 'adv_profiles').updateWhere({ player_id: playerId }, { ...patch, updated_at: Date.now() });
48
+ }
49
+ async onRunStarted(playerId, playerName) {
50
+ const profile = await this.getOrCreate(playerId, playerName);
51
+ await this.patch(playerId, { runs_started: profile.runs_started + 1 });
52
+ return (await this.get(playerId));
53
+ }
54
+ /** 记录进入场景、步数、背包变化;返回新解锁成就 ID */
55
+ async onStep(playerId, playerName, sceneId, inventory) {
56
+ const profile = await this.getOrCreate(playerId, playerName);
57
+ const visited = parseStringSet(profile.visited_scenes);
58
+ const items = parseStringSet(profile.items_found);
59
+ let changed = false;
60
+ if (PLAYABLE.has(sceneId) && !visited.has(sceneId)) {
61
+ visited.add(sceneId);
62
+ changed = true;
63
+ }
64
+ for (const item of inventory) {
65
+ if (!items.has(item)) {
66
+ items.add(item);
67
+ changed = true;
68
+ }
69
+ }
70
+ const patch = {
71
+ total_steps: profile.total_steps + 1,
72
+ };
73
+ if (changed) {
74
+ patch.visited_scenes = serializeStringSet(visited);
75
+ patch.items_found = serializeStringSet(items);
76
+ }
77
+ await this.patch(playerId, patch);
78
+ const updated = (await this.get(playerId));
79
+ return this.unlockPending(updated);
80
+ }
81
+ /** 局终:记录结局、完成数、最佳步数 */
82
+ async onRunCompleted(playerId, playerName, endingId, stepCount, inventory) {
83
+ const profile = await this.getOrCreate(playerId, playerName);
84
+ const endings = parseStringSet(profile.endings_seen);
85
+ const items = parseStringSet(profile.items_found);
86
+ if (endingId)
87
+ endings.add(endingId);
88
+ for (const item of inventory)
89
+ items.add(item);
90
+ await this.patch(playerId, {
91
+ endings_seen: serializeStringSet(endings),
92
+ items_found: serializeStringSet(items),
93
+ runs_completed: profile.runs_completed + 1,
94
+ best_step_count: Math.max(profile.best_step_count, stepCount),
95
+ });
96
+ const updated = (await this.get(playerId));
97
+ return this.unlockPending(updated, { stepCount, inventory, endingId });
98
+ }
99
+ async unlockPending(profile, lastRun) {
100
+ const ctx = {
101
+ visited: parseStringSet(profile.visited_scenes),
102
+ endings: parseStringSet(profile.endings_seen),
103
+ itemsFound: parseStringSet(profile.items_found),
104
+ runsCompleted: profile.runs_completed,
105
+ bestStepCount: profile.best_step_count,
106
+ lastRun,
107
+ };
108
+ const current = [...parseStringSet(profile.achievements)];
109
+ const newly = evaluateAchievements(current, ctx);
110
+ if (!newly.length)
111
+ return [];
112
+ const merged = new Set(current);
113
+ for (const id of newly)
114
+ merged.add(id);
115
+ await this.patch(profile.player_id, {
116
+ achievements: serializeStringSet(merged),
117
+ });
118
+ return newly;
119
+ }
120
+ }
121
+ export function createProfileService(db) {
122
+ return new ProfileService(db);
123
+ }
124
+ //# sourceMappingURL=profile-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-service.js","sourceRoot":"","sources":["../src/profile-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { SendContent } from 'zhin.js';
2
+ import type { AdvProfileRow, AdvSessionRow } from './models.js';
3
+ export declare function buildSceneInteractive(session: AdvSessionRow, extraNarrative?: string, profile?: AdvProfileRow): SendContent | null;
4
+ //# sourceMappingURL=scene-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene-view.d.ts","sourceRoot":"","sources":["../src/scene-view.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAUhE,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,aAAa,EACtB,cAAc,SAAK,EACnB,OAAO,CAAC,EAAE,aAAa,GACtB,WAAW,GAAG,IAAI,CA6BpB"}
@@ -0,0 +1,32 @@
1
+ import { buildChoiceKeyboard } from '@zhin.js/game-shared';
2
+ import { formatProgressCompact } from './profile-format.js';
3
+ import { ADV_PREFIX, getScene, sceneNarrative, stateFromSession, visibleChoices, } from './story.js';
4
+ export function buildSceneInteractive(session, extraNarrative = '', profile) {
5
+ const scene = getScene(session.scene_id);
6
+ if (!scene)
7
+ return null;
8
+ const state = stateFromSession(session);
9
+ const choices = visibleChoices(scene, state);
10
+ const terminal = scene.terminal || session.status !== 'active';
11
+ let narrative = sceneNarrative(scene, state);
12
+ if (profile && !terminal) {
13
+ narrative = `${formatProgressCompact(profile)}\n\n${narrative}`;
14
+ }
15
+ if (extraNarrative) {
16
+ narrative += extraNarrative;
17
+ }
18
+ return buildChoiceKeyboard({
19
+ gamePrefix: ADV_PREFIX,
20
+ sessionId: session.id,
21
+ narrative,
22
+ choices: choices.map((c) => ({
23
+ id: c.id,
24
+ label: c.label,
25
+ style: c.style,
26
+ })),
27
+ terminal,
28
+ buttonsPerRow: 2,
29
+ fallbackHint: '回复数字选择(仅编号)',
30
+ });
31
+ }
32
+ //# sourceMappingURL=scene-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene-view.js","sourceRoot":"","sources":["../src/scene-view.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EACL,UAAU,EACV,QAAQ,EACR,cAAc,EACd,gBAAgB,EAChB,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,MAAM,UAAU,qBAAqB,CACnC,OAAsB,EACtB,cAAc,GAAG,EAAE,EACnB,OAAuB;IAEvB,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC;IAE/D,IAAI,SAAS,GAAG,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC7C,IAAI,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;QACzB,SAAS,GAAG,GAAG,qBAAqB,CAAC,OAAO,CAAC,OAAO,SAAS,EAAE,CAAC;IAClE,CAAC;IACD,IAAI,cAAc,EAAE,CAAC;QACnB,SAAS,IAAI,cAAc,CAAC;IAC9B,CAAC;IAED,OAAO,mBAAmB,CAAC;QACzB,UAAU,EAAE,UAAU;QACtB,SAAS,EAAE,OAAO,CAAC,EAAE;QACrB,SAAS;QACT,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3B,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,KAAK,EAAE,CAAC,CAAC,KAAK;SACf,CAAC,CAAC;QACH,QAAQ;QACR,aAAa,EAAE,CAAC;QAChB,YAAY,EAAE,aAAa;KAC5B,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { Database, DatabaseFeature, Message, Models } from 'zhin.js';
2
+ import type { AdvSessionRow } from './models.js';
3
+ import { ProfileService } from './profile-service.js';
4
+ export type AdvDatabase = Database<unknown, Models, string>;
5
+ export interface GameServices {
6
+ sessions: SessionService;
7
+ profiles: ProfileService;
8
+ }
9
+ export declare class SessionService {
10
+ private readonly db;
11
+ constructor(db: AdvDatabase);
12
+ getActiveByChannel(channel: string): Promise<AdvSessionRow | null>;
13
+ getActiveForUser(channel: string, userId: string): Promise<AdvSessionRow | null>;
14
+ getById(id: string): Promise<AdvSessionRow | null>;
15
+ getActiveByBoardMessageId(messageId: string): Promise<AdvSessionRow | null>;
16
+ createSession(message: Message<any>): Promise<AdvSessionRow>;
17
+ updateSession(id: string, patch: Partial<AdvSessionRow>): Promise<void>;
18
+ abortStale(idleMs: number): Promise<number>;
19
+ }
20
+ export declare function createServices(db: AdvDatabase): GameServices;
21
+ export declare function resolveGameDatabase(feature: DatabaseFeature): AdvDatabase;
22
+ //# 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,EAAgB,aAAa,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAwB,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE5E,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAS5D,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,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;IAQlE,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;IAc3E,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC;IA2B5D,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvE,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAalD;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,WAAW,GAAG,YAAY,CAK5D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,WAAW,CAEzE"}
@@ -0,0 +1,100 @@
1
+ import { channelKey, generateSessionId } from '@zhin.js/game-shared';
2
+ import { createProfileService } from './profile-service.js';
3
+ function getModel(db, name) {
4
+ const model = db.models.get(name);
5
+ if (!model)
6
+ throw new Error(`Model ${name} is not registered`);
7
+ return model;
8
+ }
9
+ export class SessionService {
10
+ db;
11
+ constructor(db) {
12
+ this.db = db;
13
+ }
14
+ async getActiveByChannel(channel) {
15
+ const rows = await getModel(this.db, 'adv_sessions').findAll({
16
+ channel_key: channel,
17
+ status: 'active',
18
+ });
19
+ return rows[0] ?? null;
20
+ }
21
+ async getActiveForUser(channel, userId) {
22
+ const row = await this.getActiveByChannel(channel);
23
+ if (!row || row.player_id !== userId)
24
+ return null;
25
+ return row;
26
+ }
27
+ async getById(id) {
28
+ return getModel(this.db, 'adv_sessions').findOne({ id });
29
+ }
30
+ async getActiveByBoardMessageId(messageId) {
31
+ if (!messageId)
32
+ return null;
33
+ const rows = await getModel(this.db, 'adv_sessions').findAll({ status: 'active' });
34
+ for (const row of rows) {
35
+ const stored = row.board_message_id;
36
+ if (!stored)
37
+ continue;
38
+ if (stored === messageId)
39
+ return row;
40
+ if (stored.endsWith(`:${messageId}`))
41
+ return row;
42
+ const tail = stored.split(':').pop();
43
+ if (tail && messageId.endsWith(tail))
44
+ return row;
45
+ }
46
+ return null;
47
+ }
48
+ async createSession(message) {
49
+ const now = Date.now();
50
+ const id = generateSessionId();
51
+ const row = {
52
+ id,
53
+ adapter: String(message.$adapter),
54
+ endpoint: message.$endpoint,
55
+ channel_type: message.$channel.type,
56
+ channel_id: message.$channel.id,
57
+ channel_key: channelKey(message),
58
+ player_id: message.$sender.id,
59
+ player_name: message.$sender.name?.trim() || message.$sender.id,
60
+ scene_id: 'start',
61
+ hp: 100,
62
+ inventory: '[]',
63
+ flags: '{}',
64
+ ending_id: '',
65
+ status: 'active',
66
+ board_message_id: '',
67
+ step_count: 0,
68
+ updated_at: now,
69
+ created_at: now,
70
+ };
71
+ await getModel(this.db, 'adv_sessions').create(row);
72
+ return row;
73
+ }
74
+ async updateSession(id, patch) {
75
+ await getModel(this.db, 'adv_sessions').updateWhere({ id }, { ...patch, updated_at: Date.now() });
76
+ }
77
+ async abortStale(idleMs) {
78
+ const cutoff = Date.now() - idleMs;
79
+ const sessions = getModel(this.db, 'adv_sessions');
80
+ const rows = await sessions.findAll({ status: 'active' });
81
+ let n = 0;
82
+ for (const row of rows) {
83
+ if (row.updated_at < cutoff) {
84
+ await sessions.updateWhere({ id: row.id }, { status: 'aborted', updated_at: Date.now() });
85
+ n++;
86
+ }
87
+ }
88
+ return n;
89
+ }
90
+ }
91
+ export function createServices(db) {
92
+ return {
93
+ sessions: new SessionService(db),
94
+ profiles: createProfileService(db),
95
+ };
96
+ }
97
+ export function resolveGameDatabase(feature) {
98
+ return feature.db;
99
+ }
100
+ //# 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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"}
@@ -0,0 +1,13 @@
1
+ /** 区域中文名(用于地图 / 成就展示) */
2
+ export declare const REGION_LABELS: Record<string, string>;
3
+ export declare const ENDING_LABELS: Record<string, string>;
4
+ /** 地图分区(便于 adv map 分组展示) */
5
+ export declare const MAP_ZONES: Array<{
6
+ name: string;
7
+ sceneIds: string[];
8
+ }>;
9
+ export declare function playableSceneIds(): string[];
10
+ export declare function endingIds(): string[];
11
+ export declare function regionLabel(id: string): string;
12
+ export declare function endingLabel(id: string): string;
13
+ //# sourceMappingURL=story-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"story-catalog.d.ts","sourceRoot":"","sources":["../src/story-catalog.ts"],"names":[],"mappings":"AAEA,yBAAyB;AACzB,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAgChD,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAgBhD,CAAC;AAEF,4BAA4B;AAC5B,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAiCjE,CAAC;AAEF,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAI3C;AAED,wBAAgB,SAAS,IAAI,MAAM,EAAE,CAIpC;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE9C"}