@react-text-game/core 0.2.2 → 0.4.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 (76) hide show
  1. package/README.md +100 -1
  2. package/dist/game.d.ts.map +1 -1
  3. package/dist/game.js +15 -0
  4. package/dist/game.js.map +1 -1
  5. package/dist/i18n/constants.d.ts +21 -0
  6. package/dist/i18n/constants.d.ts.map +1 -0
  7. package/dist/i18n/constants.js +21 -0
  8. package/dist/i18n/constants.js.map +1 -0
  9. package/dist/i18n/hooks/index.d.ts +13 -0
  10. package/dist/i18n/hooks/index.d.ts.map +1 -0
  11. package/dist/i18n/hooks/index.js +13 -0
  12. package/dist/i18n/hooks/index.js.map +1 -0
  13. package/dist/i18n/hooks/useGameTranslation.d.ts +81 -0
  14. package/dist/i18n/hooks/useGameTranslation.d.ts.map +1 -0
  15. package/dist/i18n/hooks/useGameTranslation.js +102 -0
  16. package/dist/i18n/hooks/useGameTranslation.js.map +1 -0
  17. package/dist/i18n/index.d.ts +69 -0
  18. package/dist/i18n/index.d.ts.map +1 -0
  19. package/dist/i18n/index.js +69 -0
  20. package/dist/i18n/index.js.map +1 -0
  21. package/dist/i18n/init.d.ts +62 -0
  22. package/dist/i18n/init.d.ts.map +1 -0
  23. package/dist/i18n/init.js +114 -0
  24. package/dist/i18n/init.js.map +1 -0
  25. package/dist/i18n/types.d.ts +54 -0
  26. package/dist/i18n/types.d.ts.map +1 -0
  27. package/dist/i18n/types.js +2 -0
  28. package/dist/i18n/types.js.map +1 -0
  29. package/dist/i18n/utils.d.ts +55 -0
  30. package/dist/i18n/utils.d.ts.map +1 -0
  31. package/dist/i18n/utils.js +69 -0
  32. package/dist/i18n/utils.js.map +1 -0
  33. package/dist/index.d.ts +2 -2
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/options.d.ts +2 -0
  36. package/dist/options.d.ts.map +1 -1
  37. package/dist/options.js +2 -0
  38. package/dist/options.js.map +1 -1
  39. package/dist/saves/hooks/useLoadGame.d.ts +3 -0
  40. package/dist/saves/hooks/useLoadGame.d.ts.map +1 -1
  41. package/dist/saves/hooks/useLoadGame.js +23 -1
  42. package/dist/saves/hooks/useLoadGame.js.map +1 -1
  43. package/dist/saves/index.d.ts +1 -0
  44. package/dist/saves/index.d.ts.map +1 -1
  45. package/dist/saves/index.js +1 -0
  46. package/dist/saves/index.js.map +1 -1
  47. package/dist/saves/migrations/EXAMPLE.d.ts +113 -0
  48. package/dist/saves/migrations/EXAMPLE.d.ts.map +1 -0
  49. package/dist/saves/migrations/EXAMPLE.js +304 -0
  50. package/dist/saves/migrations/EXAMPLE.js.map +1 -0
  51. package/dist/saves/migrations/index.d.ts +41 -0
  52. package/dist/saves/migrations/index.d.ts.map +1 -0
  53. package/dist/saves/migrations/index.js +40 -0
  54. package/dist/saves/migrations/index.js.map +1 -0
  55. package/dist/saves/migrations/registry.d.ts +72 -0
  56. package/dist/saves/migrations/registry.d.ts.map +1 -0
  57. package/dist/saves/migrations/registry.js +174 -0
  58. package/dist/saves/migrations/registry.js.map +1 -0
  59. package/dist/saves/migrations/runner.d.ts +45 -0
  60. package/dist/saves/migrations/runner.d.ts.map +1 -0
  61. package/dist/saves/migrations/runner.js +139 -0
  62. package/dist/saves/migrations/runner.js.map +1 -0
  63. package/dist/saves/migrations/types.d.ts +182 -0
  64. package/dist/saves/migrations/types.d.ts.map +1 -0
  65. package/dist/saves/migrations/types.js +2 -0
  66. package/dist/saves/migrations/types.js.map +1 -0
  67. package/dist/tests/game.test.js.map +1 -1
  68. package/dist/tests/i18n.test.d.ts +2 -0
  69. package/dist/tests/i18n.test.d.ts.map +1 -0
  70. package/dist/tests/i18n.test.js +590 -0
  71. package/dist/tests/i18n.test.js.map +1 -0
  72. package/dist/tests/migrations.test.d.ts +2 -0
  73. package/dist/tests/migrations.test.d.ts.map +1 -0
  74. package/dist/tests/migrations.test.js +602 -0
  75. package/dist/tests/migrations.test.js.map +1 -0
  76. package/package.json +17 -7
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EXAMPLE.d.ts","sourceRoot":"","sources":["../../../src/saves/migrations/EXAMPLE.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA+KH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,SAYpC;AAMD;;;GAGG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6CrB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,kBAgCvC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG"}
@@ -0,0 +1,304 @@
1
+ /**
2
+ * EXAMPLE: Save Migration System Usage
3
+ *
4
+ * This file demonstrates how to use the save migration system in a real game.
5
+ * It shows a complete migration history from version 1.0.0 to 3.0.0.
6
+ */
7
+ import { registerMigration } from "./index";
8
+ // ============================================================================
9
+ // MIGRATION HISTORY
10
+ // ============================================================================
11
+ /**
12
+ * Version 1.0.0 → 1.1.0
13
+ * Added: Inventory system
14
+ *
15
+ * In version 1.1.0, we added an inventory system to the game.
16
+ * Players who saved in 1.0.0 don't have an inventory field,
17
+ * so we add an empty array as the default.
18
+ *
19
+ * NOTE: This migration uses the generic type parameter to specify
20
+ * the exact shape of the data it operates on. This provides:
21
+ * - Better type safety when accessing save.player.inventory
22
+ * - IDE autocomplete for the specific fields
23
+ * - Compile-time validation of the migration logic
24
+ */
25
+ const migration_1_0_to_1_1 = {
26
+ from: "1.0.0",
27
+ to: "1.1.0",
28
+ description: "Added player inventory system",
29
+ migrate: (save) => {
30
+ const player = save.player || {};
31
+ return {
32
+ ...save,
33
+ player: {
34
+ ...player,
35
+ inventory: [],
36
+ },
37
+ };
38
+ },
39
+ };
40
+ /**
41
+ * Version 1.1.0 → 1.2.0
42
+ * Added: Quest tracking system
43
+ *
44
+ * We added a quest system with active and completed quests.
45
+ *
46
+ * NOTE: This migration does NOT use the generic type parameter,
47
+ * relying on the default GameSaveState type. This is fine for simple
48
+ * migrations where type safety is less critical. Use generics when:
49
+ * - You need type safety for complex nested structures
50
+ * - You want IDE autocomplete for specific fields
51
+ * - The migration logic is non-trivial and could benefit from type checking
52
+ */
53
+ const migration_1_1_to_1_2 = {
54
+ from: "1.1.0",
55
+ to: "1.2.0",
56
+ description: "Added quest tracking system",
57
+ migrate: (save) => ({
58
+ ...save,
59
+ quests: {
60
+ active: [],
61
+ completed: [],
62
+ },
63
+ }),
64
+ };
65
+ /**
66
+ * Version 1.2.0 → 2.0.0 (MAJOR VERSION)
67
+ * Changed: Renamed 'hp' to 'health', 'mp' to 'mana'
68
+ * Changed: Moved stats into a separate 'stats' object
69
+ *
70
+ * This is a breaking change that restructures how player stats are stored.
71
+ */
72
+ const migration_1_2_to_2_0 = {
73
+ from: "1.2.0",
74
+ to: "2.0.0",
75
+ description: "Restructured player stats: renamed hp→health, mp→mana, moved to stats object",
76
+ migrate: (save) => {
77
+ const player = save.player;
78
+ return {
79
+ ...save,
80
+ player: {
81
+ name: player.name,
82
+ level: player.level ?? 1,
83
+ experience: player.experience ?? 0,
84
+ inventory: player.inventory ?? [],
85
+ stats: {
86
+ health: player.hp ?? 100,
87
+ mana: player.mp ?? 50,
88
+ maxHealth: player.maxHp ?? 100,
89
+ maxMana: player.maxMp ?? 50,
90
+ strength: player.strength ?? 10,
91
+ intelligence: player.intelligence ?? 10,
92
+ agility: player.agility ?? 10,
93
+ },
94
+ },
95
+ };
96
+ },
97
+ };
98
+ /**
99
+ * Version 2.0.0 → 2.1.0
100
+ * Added: Skills system
101
+ * Added: Player location tracking
102
+ */
103
+ const migration_2_0_to_2_1 = {
104
+ from: "2.0.0",
105
+ to: "2.1.0",
106
+ description: "Added skills system and location tracking",
107
+ migrate: (save) => {
108
+ const player = (save.player || {});
109
+ return {
110
+ ...save,
111
+ player: {
112
+ ...player,
113
+ skills: {
114
+ combat: 1,
115
+ magic: 1,
116
+ crafting: 1,
117
+ },
118
+ location: {
119
+ passageId: "start",
120
+ zone: "village",
121
+ },
122
+ },
123
+ };
124
+ },
125
+ };
126
+ /**
127
+ * Version 2.1.0 → 3.0.0 (MAJOR VERSION)
128
+ * Changed: Completely redesigned inventory system
129
+ * - Old: Array of item names
130
+ * - New: Array of item objects with id, quantity, metadata
131
+ *
132
+ * This migration converts the old simple inventory to the new detailed format.
133
+ */
134
+ const migration_2_1_to_3_0 = {
135
+ from: "2.1.0",
136
+ to: "3.0.0",
137
+ description: "Redesigned inventory to use item objects instead of strings",
138
+ migrate: (save) => {
139
+ const player = save.player;
140
+ const oldInventory = (player.inventory || []);
141
+ // Count duplicate items
142
+ const itemCounts = new Map();
143
+ for (const itemName of oldInventory) {
144
+ itemCounts.set(itemName, (itemCounts.get(itemName) || 0) + 1);
145
+ }
146
+ // Convert to new format
147
+ const newInventory = Array.from(itemCounts.entries()).map(([name, quantity], index) => ({
148
+ id: `item_${index}`,
149
+ name,
150
+ quantity,
151
+ metadata: {},
152
+ }));
153
+ return {
154
+ ...save,
155
+ player: {
156
+ ...player,
157
+ inventory: newInventory,
158
+ },
159
+ };
160
+ },
161
+ };
162
+ // ============================================================================
163
+ // MIGRATION REGISTRATION
164
+ // ============================================================================
165
+ /**
166
+ * Call this function during game initialization to register all migrations.
167
+ *
168
+ * @example
169
+ * ```typescript
170
+ * import { Game } from '@react-text-game/core';
171
+ * import { registerAllMigrations } from './migrations';
172
+ *
173
+ * async function initGame() {
174
+ * await Game.init({ gameVersion: "3.0.0", ... });
175
+ * registerAllMigrations();
176
+ * }
177
+ * ```
178
+ */
179
+ export function registerAllMigrations() {
180
+ // Register in chronological order for clarity
181
+ // The order doesn't actually matter - the system uses BFS to find the path
182
+ registerMigration(migration_1_0_to_1_1);
183
+ registerMigration(migration_1_1_to_1_2);
184
+ registerMigration(migration_1_2_to_2_0);
185
+ registerMigration(migration_2_0_to_2_1);
186
+ registerMigration(migration_2_1_to_3_0);
187
+ console.log("✓ Registered 5 save migrations covering versions 1.0.0 → 3.0.0");
188
+ }
189
+ // ============================================================================
190
+ // TESTING MIGRATIONS
191
+ // ============================================================================
192
+ /**
193
+ * Example test data for each version.
194
+ * Use these to test your migrations.
195
+ */
196
+ export const testSaves = {
197
+ "1.0.0": {
198
+ player: {
199
+ name: "Hero",
200
+ hp: 80,
201
+ mp: 30,
202
+ maxHp: 100,
203
+ maxMp: 50,
204
+ level: 5,
205
+ experience: 1200,
206
+ },
207
+ },
208
+ "1.1.0": {
209
+ player: {
210
+ name: "Hero",
211
+ hp: 80,
212
+ mp: 30,
213
+ maxHp: 100,
214
+ maxMp: 50,
215
+ level: 5,
216
+ experience: 1200,
217
+ inventory: ["sword", "potion", "potion"],
218
+ },
219
+ },
220
+ "2.0.0": {
221
+ player: {
222
+ name: "Hero",
223
+ level: 5,
224
+ experience: 1200,
225
+ inventory: ["sword", "potion", "potion"],
226
+ stats: {
227
+ health: 80,
228
+ mana: 30,
229
+ maxHealth: 100,
230
+ maxMana: 50,
231
+ strength: 12,
232
+ intelligence: 8,
233
+ agility: 10,
234
+ },
235
+ },
236
+ quests: {
237
+ active: ["main_quest_1"],
238
+ completed: ["tutorial"],
239
+ },
240
+ },
241
+ };
242
+ /**
243
+ * Example test function to verify migrations work correctly.
244
+ *
245
+ * @example
246
+ * ```typescript
247
+ * import { testMigrationChain } from './migrations/example';
248
+ *
249
+ * // In your test file or dev console
250
+ * testMigrationChain();
251
+ * ```
252
+ */
253
+ export async function testMigrationChain() {
254
+ const { runMigrations } = await import("./runner");
255
+ console.group("Testing Save Migration Chain");
256
+ // Test 1.0.0 → 3.0.0 (full chain)
257
+ console.log("\nTest 1: Migrating from 1.0.0 to 3.0.0");
258
+ const result1 = runMigrations(testSaves["1.0.0"], "1.0.0", "3.0.0", {
259
+ verbose: true,
260
+ });
261
+ console.log(result1.success ? "✓ Success" : "✗ Failed:", result1.error || result1.data);
262
+ // Test 1.1.0 → 3.0.0 (partial chain)
263
+ console.log("\nTest 2: Migrating from 1.1.0 to 3.0.0");
264
+ const result2 = runMigrations(testSaves["1.1.0"], "1.1.0", "3.0.0");
265
+ console.log(result2.success ? "✓ Success" : "✗ Failed:", result2.error || result2.data);
266
+ // Test 2.0.0 → 3.0.0 (single migration)
267
+ console.log("\nTest 3: Migrating from 2.0.0 to 3.0.0");
268
+ const result3 = runMigrations(testSaves["2.0.0"], "2.0.0", "3.0.0");
269
+ console.log(result3.success ? "✓ Success" : "✗ Failed:", result3.error || result3.data);
270
+ console.groupEnd();
271
+ }
272
+ // ============================================================================
273
+ // USAGE IN YOUR GAME
274
+ // ============================================================================
275
+ /**
276
+ * How to integrate this into your game:
277
+ *
278
+ * 1. Create a migrations file (like this one) in your game
279
+ * 2. Define migration functions for each version change
280
+ * 3. Call registerAllMigrations() after Game.init()
281
+ * 4. Migrations will automatically apply when players load old saves
282
+ *
283
+ * Example:
284
+ *
285
+ * ```typescript
286
+ * // src/index.tsx
287
+ * import { Game } from '@react-text-game/core';
288
+ * import { registerAllMigrations } from './game/migrations';
289
+ *
290
+ * async function init() {
291
+ * await Game.init({
292
+ * gameName: "My Adventure",
293
+ * gameVersion: "3.0.0",
294
+ * isDevMode: import.meta.env.DEV
295
+ * });
296
+ *
297
+ * registerAllMigrations();
298
+ *
299
+ * // Dev mode will validate your migration chain
300
+ * // and warn if there are any issues
301
+ * }
302
+ * ```
303
+ */
304
+ //# sourceMappingURL=EXAMPLE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EXAMPLE.js","sourceRoot":"","sources":["../../../src/saves/migrations/EXAMPLE.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Save Migration System
3
+ *
4
+ * This module provides a complete solution for versioning and migrating game saves.
5
+ * It allows developers to register migration functions that transform save data
6
+ * from older versions to newer versions.
7
+ *
8
+ * ## Key Concepts
9
+ *
10
+ * - **Migration**: A function that transforms save data from version A to version B
11
+ * - **Migration Path**: A sequence of migrations needed to go from an old version to the current version
12
+ * - **Migration Chain**: Migrations are applied sequentially (1.0.0 → 1.1.0 → 1.2.0 → 2.0.0)
13
+ *
14
+ * ## Usage
15
+ *
16
+ * ```typescript
17
+ * import { registerMigration } from '@react-text-game/core/saves';
18
+ *
19
+ * // Register a migration when you make a breaking change
20
+ * registerMigration({
21
+ * from: "1.0.0",
22
+ * to: "1.1.0",
23
+ * description: "Added player inventory system",
24
+ * migrate: (data) => ({
25
+ * ...data,
26
+ * player: {
27
+ * ...data.player,
28
+ * inventory: [] // Add default value
29
+ * }
30
+ * })
31
+ * });
32
+ * ```
33
+ *
34
+ * Migrations are automatically applied when loading saves via `useLoadGame()`.
35
+ *
36
+ * @module saves/migrations
37
+ */
38
+ export { clearMigrations, findMigrationPath, getAllMigrations, registerMigration, validateMigrations, } from "./registry";
39
+ export { migrateToCurrentVersion, runMigrations } from "./runner";
40
+ export type { MigrationOptions, MigrationResult, SaveMigration, SaveMigrationFn, } from "./types";
41
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/saves/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EACH,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAClE,YAAY,EACR,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,eAAe,GAClB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Save Migration System
3
+ *
4
+ * This module provides a complete solution for versioning and migrating game saves.
5
+ * It allows developers to register migration functions that transform save data
6
+ * from older versions to newer versions.
7
+ *
8
+ * ## Key Concepts
9
+ *
10
+ * - **Migration**: A function that transforms save data from version A to version B
11
+ * - **Migration Path**: A sequence of migrations needed to go from an old version to the current version
12
+ * - **Migration Chain**: Migrations are applied sequentially (1.0.0 → 1.1.0 → 1.2.0 → 2.0.0)
13
+ *
14
+ * ## Usage
15
+ *
16
+ * ```typescript
17
+ * import { registerMigration } from '@react-text-game/core/saves';
18
+ *
19
+ * // Register a migration when you make a breaking change
20
+ * registerMigration({
21
+ * from: "1.0.0",
22
+ * to: "1.1.0",
23
+ * description: "Added player inventory system",
24
+ * migrate: (data) => ({
25
+ * ...data,
26
+ * player: {
27
+ * ...data.player,
28
+ * inventory: [] // Add default value
29
+ * }
30
+ * })
31
+ * });
32
+ * ```
33
+ *
34
+ * Migrations are automatically applied when loading saves via `useLoadGame()`.
35
+ *
36
+ * @module saves/migrations
37
+ */
38
+ export { clearMigrations, findMigrationPath, getAllMigrations, registerMigration, validateMigrations, } from "./registry";
39
+ export { migrateToCurrentVersion, runMigrations } from "./runner";
40
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/saves/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EACH,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,72 @@
1
+ import { SaveMigration } from "./types";
2
+ /**
3
+ * Registers a migration function for moving from one version to another.
4
+ *
5
+ * Migrations should be registered during game initialization, typically in
6
+ * your game's entry point after calling `Game.init()`.
7
+ *
8
+ * @param migration - The migration definition
9
+ * @throws Error if a migration with the same from->to path already exists
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * registerMigration({
14
+ * from: "1.0.0",
15
+ * to: "1.1.0",
16
+ * description: "Added player inventory",
17
+ * migrate: (data) => ({
18
+ * ...data,
19
+ * player: { ...data.player, inventory: [] }
20
+ * })
21
+ * });
22
+ * ```
23
+ */
24
+ export declare function registerMigration(migration: SaveMigration): void;
25
+ /**
26
+ * Clears all registered migrations.
27
+ * Primarily used for testing.
28
+ *
29
+ * @internal
30
+ */
31
+ export declare function clearMigrations(): void;
32
+ /**
33
+ * Gets all registered migrations.
34
+ *
35
+ * @returns Array of all registered migration definitions
36
+ */
37
+ export declare function getAllMigrations(): SaveMigration[];
38
+ /**
39
+ * Finds the shortest migration path from one version to another using BFS.
40
+ *
41
+ * This function builds a graph of all registered migrations and uses
42
+ * breadth-first search to find the shortest sequence of migrations
43
+ * needed to go from the source version to the target version.
44
+ *
45
+ * @param fromVersion - The starting version (e.g., "1.0.0")
46
+ * @param toVersion - The target version (e.g., "2.0.0")
47
+ * @returns Array of migrations to apply in order, or null if no path exists
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * // Registered migrations: 1.0.0→1.1.0, 1.1.0→1.2.0, 1.2.0→2.0.0
52
+ * const path = findMigrationPath("1.0.0", "2.0.0");
53
+ * // Returns: [migration_1_0_to_1_1, migration_1_1_to_1_2, migration_1_2_to_2_0]
54
+ * ```
55
+ */
56
+ export declare function findMigrationPath(fromVersion: string, toVersion: string): SaveMigration[] | null;
57
+ /**
58
+ * Validates that the migration registry forms a valid chain.
59
+ *
60
+ * Checks for:
61
+ * - Orphaned migrations (from versions with no incoming migrations)
62
+ * - Dead ends (to versions with no outgoing migrations, except latest)
63
+ * - Duplicate migrations
64
+ *
65
+ * @param latestVersion - The current/latest version of the game
66
+ * @returns Validation result with any issues found
67
+ */
68
+ export declare function validateMigrations(latestVersion: string): {
69
+ valid: boolean;
70
+ issues: string[];
71
+ };
72
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/saves/migrations/registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAaxC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI,CAahE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,EAAE,CAElD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAC7B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAClB,aAAa,EAAE,GAAG,IAAI,CA+DxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG;IACvD,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CACpB,CA6CA"}
@@ -0,0 +1,174 @@
1
+ import { logger } from "../../logger";
2
+ /**
3
+ * In-memory registry of all registered migrations.
4
+ * Maps "from -> to" version pairs to migration objects.
5
+ */
6
+ const migrations = new Map();
7
+ /**
8
+ * Helper to create a unique key for a migration edge
9
+ */
10
+ const getMigrationKey = (from, to) => `${from}→${to}`;
11
+ /**
12
+ * Registers a migration function for moving from one version to another.
13
+ *
14
+ * Migrations should be registered during game initialization, typically in
15
+ * your game's entry point after calling `Game.init()`.
16
+ *
17
+ * @param migration - The migration definition
18
+ * @throws Error if a migration with the same from->to path already exists
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * registerMigration({
23
+ * from: "1.0.0",
24
+ * to: "1.1.0",
25
+ * description: "Added player inventory",
26
+ * migrate: (data) => ({
27
+ * ...data,
28
+ * player: { ...data.player, inventory: [] }
29
+ * })
30
+ * });
31
+ * ```
32
+ */
33
+ export function registerMigration(migration) {
34
+ const key = getMigrationKey(migration.from, migration.to);
35
+ if (migrations.has(key)) {
36
+ throw new Error(`Migration from ${migration.from} to ${migration.to} is already registered`);
37
+ }
38
+ migrations.set(key, migration);
39
+ logger.log(`Registered save migration: ${migration.from} → ${migration.to} (${migration.description})`);
40
+ }
41
+ /**
42
+ * Clears all registered migrations.
43
+ * Primarily used for testing.
44
+ *
45
+ * @internal
46
+ */
47
+ export function clearMigrations() {
48
+ migrations.clear();
49
+ }
50
+ /**
51
+ * Gets all registered migrations.
52
+ *
53
+ * @returns Array of all registered migration definitions
54
+ */
55
+ export function getAllMigrations() {
56
+ return Array.from(migrations.values());
57
+ }
58
+ /**
59
+ * Finds the shortest migration path from one version to another using BFS.
60
+ *
61
+ * This function builds a graph of all registered migrations and uses
62
+ * breadth-first search to find the shortest sequence of migrations
63
+ * needed to go from the source version to the target version.
64
+ *
65
+ * @param fromVersion - The starting version (e.g., "1.0.0")
66
+ * @param toVersion - The target version (e.g., "2.0.0")
67
+ * @returns Array of migrations to apply in order, or null if no path exists
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * // Registered migrations: 1.0.0→1.1.0, 1.1.0→1.2.0, 1.2.0→2.0.0
72
+ * const path = findMigrationPath("1.0.0", "2.0.0");
73
+ * // Returns: [migration_1_0_to_1_1, migration_1_1_to_1_2, migration_1_2_to_2_0]
74
+ * ```
75
+ */
76
+ export function findMigrationPath(fromVersion, toVersion) {
77
+ // If versions are the same, no migration needed
78
+ if (fromVersion === toVersion) {
79
+ return [];
80
+ }
81
+ // Build adjacency list of version graph
82
+ const graph = new Map();
83
+ const migrationMap = new Map();
84
+ for (const migration of migrations.values()) {
85
+ if (!graph.has(migration.from)) {
86
+ graph.set(migration.from, []);
87
+ }
88
+ graph.get(migration.from).push(migration.to);
89
+ migrationMap.set(getMigrationKey(migration.from, migration.to), migration);
90
+ }
91
+ // BFS to find shortest path
92
+ const queue = [
93
+ { version: fromVersion, path: [] },
94
+ ];
95
+ const visited = new Set([fromVersion]);
96
+ while (queue.length > 0) {
97
+ const current = queue.shift();
98
+ // Check if we reached the target
99
+ if (current.version === toVersion) {
100
+ // Reconstruct the migration path
101
+ const migrationPath = [];
102
+ for (let i = 0; i < current.path.length; i++) {
103
+ const from = i === 0 ? fromVersion : current.path[i - 1];
104
+ const to = current.path[i];
105
+ if (!from || !to) {
106
+ continue; // Skip if either is undefined
107
+ }
108
+ const migration = migrationMap.get(getMigrationKey(from, to));
109
+ if (migration) {
110
+ migrationPath.push(migration);
111
+ }
112
+ }
113
+ return migrationPath;
114
+ }
115
+ // Explore neighbors
116
+ const neighbors = graph.get(current.version) || [];
117
+ for (const neighbor of neighbors) {
118
+ if (!visited.has(neighbor)) {
119
+ visited.add(neighbor);
120
+ queue.push({
121
+ version: neighbor,
122
+ path: [...current.path, neighbor],
123
+ });
124
+ }
125
+ }
126
+ }
127
+ // No path found
128
+ return null;
129
+ }
130
+ /**
131
+ * Validates that the migration registry forms a valid chain.
132
+ *
133
+ * Checks for:
134
+ * - Orphaned migrations (from versions with no incoming migrations)
135
+ * - Dead ends (to versions with no outgoing migrations, except latest)
136
+ * - Duplicate migrations
137
+ *
138
+ * @param latestVersion - The current/latest version of the game
139
+ * @returns Validation result with any issues found
140
+ */
141
+ export function validateMigrations(latestVersion) {
142
+ const issues = [];
143
+ const allMigrations = getAllMigrations();
144
+ if (allMigrations.length === 0) {
145
+ return { valid: true, issues: [] };
146
+ }
147
+ // Collect all version nodes
148
+ const fromVersions = new Set();
149
+ const toVersions = new Set();
150
+ for (const migration of allMigrations) {
151
+ fromVersions.add(migration.from);
152
+ toVersions.add(migration.to);
153
+ }
154
+ // Find orphaned versions (versions that are targets but have no path from any base version)
155
+ const baseVersions = new Set(Array.from(fromVersions).filter((v) => !toVersions.has(v)));
156
+ // Check if all versions can reach the latest version
157
+ for (const baseVersion of baseVersions) {
158
+ const path = findMigrationPath(baseVersion, latestVersion);
159
+ if (path === null) {
160
+ issues.push(`No migration path from base version ${baseVersion} to latest version ${latestVersion}`);
161
+ }
162
+ }
163
+ // Check for dead ends (versions that have no outgoing migrations, except latest)
164
+ for (const toVersion of toVersions) {
165
+ if (toVersion !== latestVersion && !fromVersions.has(toVersion)) {
166
+ issues.push(`Dead end detected: Version ${toVersion} has no outgoing migrations`);
167
+ }
168
+ }
169
+ return {
170
+ valid: issues.length === 0,
171
+ issues,
172
+ };
173
+ }
174
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/saves/migrations/registry.ts"],"names":[],"mappings":"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"}