qnce-engine 1.2.0 → 1.2.2

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 (125) hide show
  1. package/README.md +713 -7
  2. package/dist/cli/audit.js +0 -0
  3. package/dist/cli/init.js +0 -0
  4. package/dist/cli/perf.d.ts.map +1 -1
  5. package/dist/cli/perf.js +2 -1
  6. package/dist/cli/perf.js.map +1 -1
  7. package/dist/cli/play.d.ts +4 -0
  8. package/dist/cli/play.d.ts.map +1 -0
  9. package/dist/cli/play.js +259 -0
  10. package/dist/cli/play.js.map +1 -0
  11. package/dist/engine/condition.d.ts +69 -0
  12. package/dist/engine/condition.d.ts.map +1 -0
  13. package/dist/engine/condition.js +195 -0
  14. package/dist/engine/condition.js.map +1 -0
  15. package/dist/engine/core.d.ts +274 -3
  16. package/dist/engine/core.d.ts.map +1 -1
  17. package/dist/engine/core.js +1148 -9
  18. package/dist/engine/core.js.map +1 -1
  19. package/dist/engine/demo-story.d.ts.map +1 -1
  20. package/dist/engine/demo-story.js +99 -13
  21. package/dist/engine/demo-story.js.map +1 -1
  22. package/dist/engine/errors.d.ts +76 -0
  23. package/dist/engine/errors.d.ts.map +1 -0
  24. package/dist/engine/errors.js +178 -0
  25. package/dist/engine/errors.js.map +1 -0
  26. package/dist/engine/types.d.ts +445 -0
  27. package/dist/engine/types.d.ts.map +1 -0
  28. package/dist/engine/types.js +9 -0
  29. package/dist/engine/types.js.map +1 -0
  30. package/dist/engine/validation.d.ts +110 -0
  31. package/dist/engine/validation.d.ts.map +1 -0
  32. package/dist/engine/validation.js +261 -0
  33. package/dist/engine/validation.js.map +1 -0
  34. package/dist/examples/examples/autosave-undo-demo.js +248 -0
  35. package/dist/examples/examples/persistence-demo.js +63 -0
  36. package/dist/examples/src/engine/condition.js +194 -0
  37. package/dist/examples/src/engine/core.js +1382 -0
  38. package/dist/examples/src/engine/demo-story.js +200 -0
  39. package/dist/examples/src/engine/types.js +8 -0
  40. package/dist/examples/src/index.js +35 -0
  41. package/dist/examples/src/integrations/react.js +322 -0
  42. package/dist/examples/src/narrative/branching/engine-simple.js +348 -0
  43. package/dist/examples/src/narrative/branching/index.js +55 -0
  44. package/dist/examples/src/narrative/branching/models.js +5 -0
  45. package/dist/examples/src/performance/ObjectPool.js +296 -0
  46. package/dist/examples/src/performance/PerfReporter.js +280 -0
  47. package/dist/examples/src/performance/ThreadPool.js +347 -0
  48. package/dist/index.d.ts +4 -0
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +12 -1
  51. package/dist/index.js.map +1 -1
  52. package/dist/integrations/react.d.ts +200 -0
  53. package/dist/integrations/react.d.ts.map +1 -0
  54. package/dist/integrations/react.js +365 -0
  55. package/dist/integrations/react.js.map +1 -0
  56. package/dist/narrative/branching/engine-simple.js +3 -3
  57. package/dist/narrative/branching/engine-simple.js.map +1 -1
  58. package/dist/narrative/branching/engine.d.ts +1 -0
  59. package/dist/narrative/branching/engine.d.ts.map +1 -0
  60. package/dist/narrative/branching/engine.js +2 -0
  61. package/dist/narrative/branching/engine.js.map +1 -0
  62. package/dist/narrative/branching/models.d.ts.map +1 -1
  63. package/dist/performance/HotReloadDelta.d.ts +25 -8
  64. package/dist/performance/HotReloadDelta.d.ts.map +1 -1
  65. package/dist/performance/HotReloadDelta.js +10 -15
  66. package/dist/performance/HotReloadDelta.js.map +1 -1
  67. package/dist/ui/__tests__/AutosaveIndicator.test.d.ts +2 -0
  68. package/dist/ui/__tests__/AutosaveIndicator.test.d.ts.map +1 -0
  69. package/dist/ui/__tests__/AutosaveIndicator.test.js +329 -0
  70. package/dist/ui/__tests__/AutosaveIndicator.test.js.map +1 -0
  71. package/dist/ui/__tests__/UndoRedoControls.test.d.ts +2 -0
  72. package/dist/ui/__tests__/UndoRedoControls.test.d.ts.map +1 -0
  73. package/dist/ui/__tests__/UndoRedoControls.test.js +245 -0
  74. package/dist/ui/__tests__/UndoRedoControls.test.js.map +1 -0
  75. package/dist/ui/__tests__/autosave-simple.test.d.ts +2 -0
  76. package/dist/ui/__tests__/autosave-simple.test.d.ts.map +1 -0
  77. package/dist/ui/__tests__/autosave-simple.test.js +29 -0
  78. package/dist/ui/__tests__/autosave-simple.test.js.map +1 -0
  79. package/dist/ui/__tests__/setup.d.ts +2 -0
  80. package/dist/ui/__tests__/setup.d.ts.map +1 -0
  81. package/dist/ui/__tests__/setup.js +40 -0
  82. package/dist/ui/__tests__/setup.js.map +1 -0
  83. package/dist/ui/__tests__/smoke-test.d.ts +2 -0
  84. package/dist/ui/__tests__/smoke-test.d.ts.map +1 -0
  85. package/dist/ui/__tests__/smoke-test.js +18 -0
  86. package/dist/ui/__tests__/smoke-test.js.map +1 -0
  87. package/dist/ui/__tests__/smoke-test.test.d.ts +2 -0
  88. package/dist/ui/__tests__/smoke-test.test.d.ts.map +1 -0
  89. package/dist/ui/__tests__/smoke-test.test.js +18 -0
  90. package/dist/ui/__tests__/smoke-test.test.js.map +1 -0
  91. package/dist/ui/__tests__/useKeyboardShortcuts.test.d.ts +2 -0
  92. package/dist/ui/__tests__/useKeyboardShortcuts.test.d.ts.map +1 -0
  93. package/dist/ui/__tests__/useKeyboardShortcuts.test.js +374 -0
  94. package/dist/ui/__tests__/useKeyboardShortcuts.test.js.map +1 -0
  95. package/dist/ui/components/AutosaveIndicator.d.ts +18 -0
  96. package/dist/ui/components/AutosaveIndicator.d.ts.map +1 -0
  97. package/dist/ui/components/AutosaveIndicator.js +175 -0
  98. package/dist/ui/components/AutosaveIndicator.js.map +1 -0
  99. package/dist/ui/components/UndoRedoControls.d.ts +16 -0
  100. package/dist/ui/components/UndoRedoControls.d.ts.map +1 -0
  101. package/dist/ui/components/UndoRedoControls.js +144 -0
  102. package/dist/ui/components/UndoRedoControls.js.map +1 -0
  103. package/dist/ui/hooks/useKeyboardShortcuts.d.ts +22 -0
  104. package/dist/ui/hooks/useKeyboardShortcuts.d.ts.map +1 -0
  105. package/dist/ui/hooks/useKeyboardShortcuts.js +162 -0
  106. package/dist/ui/hooks/useKeyboardShortcuts.js.map +1 -0
  107. package/dist/ui/index.d.ts +9 -0
  108. package/dist/ui/index.d.ts.map +1 -0
  109. package/dist/ui/index.js +14 -0
  110. package/dist/ui/index.js.map +1 -0
  111. package/dist/ui/types.d.ts +141 -0
  112. package/dist/ui/types.d.ts.map +1 -0
  113. package/dist/ui/types.js +51 -0
  114. package/dist/ui/types.js.map +1 -0
  115. package/examples/autosave-undo-demo.ts +306 -0
  116. package/examples/branching-demo-simple.ts +0 -0
  117. package/examples/branching-demo.ts +0 -0
  118. package/examples/persistence-demo.ts +84 -0
  119. package/examples/tsconfig.json +13 -0
  120. package/examples/ui-components-demo.tsx +320 -0
  121. package/examples/validation-demo-story.json +177 -0
  122. package/examples/validation-demo.js +163 -0
  123. package/package.json +24 -4
  124. package/docs/branching/PDM.md +0 -443
  125. package/docs/branching/RELEASE-v1.2.0.md +0 -169
@@ -0,0 +1,261 @@
1
+ "use strict";
2
+ // QNCE Choice Validation System - Sprint 3.2
3
+ // Ensures only valid choices can be executed, providing robust error handling
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.DefaultChoiceValidator = exports.StandardValidationRules = void 0;
6
+ exports.createChoiceValidator = createChoiceValidator;
7
+ exports.createValidationContext = createValidationContext;
8
+ /**
9
+ * Built-in validation rules for common scenarios
10
+ */
11
+ class StandardValidationRules {
12
+ /**
13
+ * Validates that choice exists in the current node's choices
14
+ */
15
+ static CHOICE_EXISTS = {
16
+ name: 'choice-exists',
17
+ priority: 1,
18
+ validate(choice, context) {
19
+ const exists = context.currentNode.choices.some(c => c.text === choice.text && c.nextNodeId === choice.nextNodeId);
20
+ return {
21
+ isValid: exists,
22
+ reason: exists ? undefined : `Choice "${choice.text}" is not available from current node`,
23
+ suggestedChoices: exists ? undefined : context.currentNode.choices
24
+ };
25
+ }
26
+ };
27
+ /**
28
+ * Validates flag-based conditions for choice availability
29
+ */
30
+ static FLAG_CONDITIONS = {
31
+ name: 'flag-conditions',
32
+ priority: 2,
33
+ validate(choice, context) {
34
+ // Check if choice has flag requirements
35
+ if (choice.flagRequirements) {
36
+ const missingFlags = [];
37
+ const conflictingFlags = [];
38
+ for (const [flagName, requiredValue] of Object.entries(choice.flagRequirements)) {
39
+ const currentValue = context.state.flags[flagName];
40
+ if (requiredValue === true && !currentValue) {
41
+ missingFlags.push(flagName);
42
+ }
43
+ else if (requiredValue === false && currentValue) {
44
+ conflictingFlags.push(flagName);
45
+ }
46
+ else if (typeof requiredValue !== 'boolean' && currentValue !== requiredValue) {
47
+ missingFlags.push(`${flagName}=${requiredValue}`);
48
+ }
49
+ }
50
+ if (missingFlags.length > 0 || conflictingFlags.length > 0) {
51
+ const reasons = [];
52
+ if (missingFlags.length > 0) {
53
+ reasons.push(`Missing required flags: ${missingFlags.join(', ')}`);
54
+ }
55
+ if (conflictingFlags.length > 0) {
56
+ reasons.push(`Conflicting flags: ${conflictingFlags.join(', ')}`);
57
+ }
58
+ return {
59
+ isValid: false,
60
+ reason: `Flag conditions not met: ${reasons.join('; ')}`,
61
+ failedConditions: [...missingFlags, ...conflictingFlags],
62
+ metadata: {
63
+ missingFlags,
64
+ conflictingFlags,
65
+ currentFlags: context.state.flags
66
+ }
67
+ };
68
+ }
69
+ }
70
+ return {
71
+ isValid: true,
72
+ reason: undefined
73
+ };
74
+ }
75
+ };
76
+ /**
77
+ * Validates choice is not disabled or marked as unavailable
78
+ */
79
+ static CHOICE_ENABLED = {
80
+ name: 'choice-enabled',
81
+ priority: 3,
82
+ validate(choice, _context) {
83
+ if (choice.enabled === false) {
84
+ return {
85
+ isValid: false,
86
+ reason: `Choice "${choice.text}" is currently disabled`,
87
+ failedConditions: ['choice-disabled']
88
+ };
89
+ }
90
+ return {
91
+ isValid: true,
92
+ reason: undefined
93
+ };
94
+ }
95
+ };
96
+ /**
97
+ * Validates time-based requirements for choice availability
98
+ */
99
+ static TIME_CONDITIONS = {
100
+ name: 'time-conditions',
101
+ priority: 4,
102
+ validate(choice, context) {
103
+ if (choice.timeRequirements) {
104
+ const now = new Date();
105
+ const currentTime = context.timestamp || now.getTime();
106
+ const failures = [];
107
+ if (choice.timeRequirements.availableAfter) {
108
+ const afterTime = new Date(choice.timeRequirements.availableAfter).getTime();
109
+ if (currentTime < afterTime) {
110
+ failures.push(`not available until ${choice.timeRequirements.availableAfter}`);
111
+ }
112
+ }
113
+ if (choice.timeRequirements.availableBefore) {
114
+ const beforeTime = new Date(choice.timeRequirements.availableBefore).getTime();
115
+ if (currentTime > beforeTime) {
116
+ failures.push(`no longer available after ${choice.timeRequirements.availableBefore}`);
117
+ }
118
+ }
119
+ if (choice.timeRequirements.minTime && currentTime < choice.timeRequirements.minTime) {
120
+ failures.push(`minimum time not reached`);
121
+ }
122
+ if (choice.timeRequirements.maxTime && currentTime > choice.timeRequirements.maxTime) {
123
+ failures.push(`maximum time exceeded`);
124
+ }
125
+ if (failures.length > 0) {
126
+ return {
127
+ isValid: false,
128
+ reason: `Time conditions not met: ${failures.join(', ')}`,
129
+ failedConditions: failures,
130
+ metadata: {
131
+ currentTime,
132
+ timeRequirements: choice.timeRequirements
133
+ }
134
+ };
135
+ }
136
+ }
137
+ return {
138
+ isValid: true,
139
+ reason: undefined
140
+ };
141
+ }
142
+ };
143
+ /**
144
+ * Validates inventory-based requirements for choice availability
145
+ */
146
+ static INVENTORY_CONDITIONS = {
147
+ name: 'inventory-conditions',
148
+ priority: 5,
149
+ validate(choice, context) {
150
+ if (choice.inventoryRequirements) {
151
+ const inventory = context.state.flags.inventory || {};
152
+ const missingItems = [];
153
+ for (const [itemName, requiredQuantity] of Object.entries(choice.inventoryRequirements)) {
154
+ const currentQuantity = inventory[itemName] || 0;
155
+ if (currentQuantity < requiredQuantity) {
156
+ missingItems.push(`${itemName} (need ${requiredQuantity}, have ${currentQuantity})`);
157
+ }
158
+ }
159
+ if (missingItems.length > 0) {
160
+ return {
161
+ isValid: false,
162
+ reason: `Insufficient inventory: ${missingItems.join(', ')}`,
163
+ failedConditions: missingItems,
164
+ metadata: {
165
+ currentInventory: inventory,
166
+ requirements: choice.inventoryRequirements
167
+ }
168
+ };
169
+ }
170
+ }
171
+ return {
172
+ isValid: true,
173
+ reason: undefined
174
+ };
175
+ }
176
+ };
177
+ }
178
+ exports.StandardValidationRules = StandardValidationRules;
179
+ /**
180
+ * Default implementation of ChoiceValidator
181
+ * Uses a rule-based system for extensible validation logic
182
+ */
183
+ class DefaultChoiceValidator {
184
+ rules = [];
185
+ constructor() {
186
+ // Add standard validation rules by default
187
+ this.addRule(StandardValidationRules.CHOICE_EXISTS);
188
+ this.addRule(StandardValidationRules.FLAG_CONDITIONS);
189
+ this.addRule(StandardValidationRules.CHOICE_ENABLED);
190
+ this.addRule(StandardValidationRules.TIME_CONDITIONS);
191
+ this.addRule(StandardValidationRules.INVENTORY_CONDITIONS);
192
+ }
193
+ validate(choice, context) {
194
+ // Run all validation rules in priority order
195
+ const sortedRules = this.getRules();
196
+ for (const rule of sortedRules) {
197
+ const result = rule.validate(choice, context);
198
+ // If any rule fails, return that failure
199
+ if (!result.isValid) {
200
+ return {
201
+ ...result,
202
+ metadata: {
203
+ ...result.metadata,
204
+ failedRule: rule.name,
205
+ rulesPassed: sortedRules.indexOf(rule)
206
+ }
207
+ };
208
+ }
209
+ }
210
+ // All rules passed
211
+ return {
212
+ isValid: true,
213
+ metadata: {
214
+ rulesChecked: sortedRules.length,
215
+ allRulesPassed: true
216
+ }
217
+ };
218
+ }
219
+ getAvailableChoices(context) {
220
+ // Use the availableChoices from context (which may have been pre-filtered by conditions)
221
+ // instead of all choices from the node
222
+ return context.availableChoices.filter(choice => {
223
+ const result = this.validate(choice, context);
224
+ return result.isValid;
225
+ });
226
+ }
227
+ addRule(rule) {
228
+ // Remove any existing rule with the same name
229
+ this.removeRule(rule.name);
230
+ // Add the new rule
231
+ this.rules.push(rule);
232
+ // Sort by priority
233
+ this.rules.sort((a, b) => a.priority - b.priority);
234
+ }
235
+ removeRule(ruleName) {
236
+ this.rules = this.rules.filter(rule => rule.name !== ruleName);
237
+ }
238
+ getRules() {
239
+ return [...this.rules].sort((a, b) => a.priority - b.priority);
240
+ }
241
+ }
242
+ exports.DefaultChoiceValidator = DefaultChoiceValidator;
243
+ /**
244
+ * Factory function to create a choice validator with default rules
245
+ */
246
+ function createChoiceValidator() {
247
+ return new DefaultChoiceValidator();
248
+ }
249
+ /**
250
+ * Utility function to create validation context from engine state
251
+ */
252
+ function createValidationContext(currentNode, state, availableChoices, metadata) {
253
+ return {
254
+ currentNode,
255
+ state,
256
+ availableChoices,
257
+ timestamp: performance.now(),
258
+ metadata
259
+ };
260
+ }
261
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/engine/validation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,248 @@
1
+ "use strict";
2
+ /**
3
+ * QNCE Autosave & Undo/Redo Demo
4
+ *
5
+ * Demonstrates the Sprint 3.5 autosave and undo/redo functionality
6
+ * with interactive examples and performance metrics.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ const core_js_1 = require("../src/engine/core.js");
10
+ const demo_story_js_1 = require("../src/engine/demo-story.js");
11
+ console.log('🔄 QNCE Autosave & Undo/Redo Demo - Sprint 3.5');
12
+ console.log('='.repeat(50));
13
+ async function demonstrateUndoRedo() {
14
+ console.log('\n📝 Demonstrating Undo/Redo Functionality');
15
+ console.log('-'.repeat(40));
16
+ const engine = (0, core_js_1.createQNCEEngine)(demo_story_js_1.DEMO_STORY);
17
+ // Configure undo/redo with detailed logging
18
+ engine.configureUndoRedo({
19
+ enabled: true,
20
+ maxUndoEntries: 10,
21
+ maxRedoEntries: 5
22
+ });
23
+ console.log('Initial state:', engine.getCurrentNode().text.substring(0, 50) + '...');
24
+ console.log('Can undo:', engine.canUndo());
25
+ console.log('Can redo:', engine.canRedo());
26
+ // Make some choices
27
+ console.log('\n🎮 Making choices...');
28
+ const choices1 = engine.getAvailableChoices();
29
+ if (choices1.length > 0) {
30
+ console.log(`Selecting: "${choices1[0].text}"`);
31
+ engine.selectChoice(choices1[0]);
32
+ console.log('New state:', engine.getCurrentNode().text.substring(0, 50) + '...');
33
+ console.log('Undo count:', engine.getUndoCount());
34
+ }
35
+ const choices2 = engine.getAvailableChoices();
36
+ if (choices2.length > 0) {
37
+ console.log(`Selecting: "${choices2[0].text}"`);
38
+ engine.selectChoice(choices2[0]);
39
+ console.log('New state:', engine.getCurrentNode().text.substring(0, 50) + '...');
40
+ console.log('Undo count:', engine.getUndoCount());
41
+ }
42
+ // Demonstrate undo
43
+ console.log('\n⏪ Testing undo...');
44
+ const undoResult1 = engine.undo();
45
+ if (undoResult1.success) {
46
+ console.log('✅ Undo successful');
47
+ console.log('Restored to:', engine.getCurrentNode().text.substring(0, 50) + '...');
48
+ console.log('Can redo:', engine.canRedo());
49
+ }
50
+ const undoResult2 = engine.undo();
51
+ if (undoResult2.success) {
52
+ console.log('✅ Second undo successful');
53
+ console.log('Restored to:', engine.getCurrentNode().text.substring(0, 50) + '...');
54
+ console.log('Undo count:', engine.getUndoCount());
55
+ console.log('Redo count:', engine.getRedoCount());
56
+ }
57
+ // Demonstrate redo
58
+ console.log('\n⏩ Testing redo...');
59
+ const redoResult = engine.redo();
60
+ if (redoResult.success) {
61
+ console.log('✅ Redo successful');
62
+ console.log('Restored to:', engine.getCurrentNode().text.substring(0, 50) + '...');
63
+ console.log('Final state - Undo:', engine.getUndoCount(), 'Redo:', engine.getRedoCount());
64
+ }
65
+ // Show history summary
66
+ const history = engine.getHistorySummary();
67
+ console.log('\n📊 History Summary:');
68
+ console.log(`- Undo entries: ${history.undoEntries.length}`);
69
+ console.log(`- Redo entries: ${history.redoEntries.length}`);
70
+ return engine;
71
+ }
72
+ async function demonstrateAutosave() {
73
+ console.log('\n💾 Demonstrating Autosave Functionality');
74
+ console.log('-'.repeat(40));
75
+ const engine = (0, core_js_1.createQNCEEngine)(demo_story_js_1.DEMO_STORY);
76
+ // Configure autosave with custom settings
77
+ engine.configureAutosave({
78
+ enabled: true,
79
+ triggers: ['choice', 'flag-change'],
80
+ throttleMs: 50, // Very fast for demo
81
+ maxEntries: 5,
82
+ includeMetadata: true
83
+ });
84
+ console.log('Autosave configured with 50ms throttle');
85
+ // Track autosave events
86
+ let autosaveCount = 0;
87
+ const originalMethod = engine.manualAutosave.bind(engine);
88
+ engine.manualAutosave = async (metadata) => {
89
+ autosaveCount++;
90
+ console.log(`🔄 Autosave #${autosaveCount} triggered`);
91
+ return originalMethod(metadata);
92
+ };
93
+ // Make choices to trigger autosave
94
+ console.log('\n🎮 Making choices (autosave should trigger)...');
95
+ for (let i = 0; i < 3; i++) {
96
+ const choices = engine.getAvailableChoices();
97
+ if (choices.length > 0) {
98
+ console.log(`Choice ${i + 1}: "${choices[0].text}"`);
99
+ engine.selectChoice(choices[0]);
100
+ // Small delay to observe throttling
101
+ await new Promise(resolve => setTimeout(resolve, 25));
102
+ }
103
+ }
104
+ // Set some flags to trigger more autosaves
105
+ console.log('\n🏁 Setting flags (autosave should trigger)...');
106
+ engine.setFlag('demo_flag_1', true);
107
+ await new Promise(resolve => setTimeout(resolve, 60));
108
+ engine.setFlag('demo_flag_2', 'test_value');
109
+ await new Promise(resolve => setTimeout(resolve, 60));
110
+ // Manual autosave
111
+ console.log('\n💾 Triggering manual autosave...');
112
+ await engine.manualAutosave({ demo: 'manual_save' });
113
+ console.log(`\n📊 Total autosaves triggered: ${autosaveCount}`);
114
+ return engine;
115
+ }
116
+ async function demonstratePerformance() {
117
+ console.log('\n⚡ Performance Testing');
118
+ console.log('-'.repeat(40));
119
+ const engine = (0, core_js_1.createQNCEEngine)(demo_story_js_1.DEMO_STORY);
120
+ // Configure for performance testing
121
+ engine.configureUndoRedo({
122
+ enabled: true,
123
+ maxUndoEntries: 100,
124
+ maxRedoEntries: 50
125
+ });
126
+ // Build up some history
127
+ console.log('Building up history for performance test...');
128
+ for (let i = 0; i < 20; i++) {
129
+ const choices = engine.getAvailableChoices();
130
+ if (choices.length > 0) {
131
+ engine.selectChoice(choices[0]);
132
+ }
133
+ // Set some flags
134
+ engine.setFlag(`test_flag_${i}`, i * 2);
135
+ }
136
+ console.log(`History built: ${engine.getUndoCount()} undo entries`);
137
+ // Performance test undo operations
138
+ console.log('\n⏪ Testing undo performance...');
139
+ const undoTimes = [];
140
+ for (let i = 0; i < 10; i++) {
141
+ const startTime = performance.now();
142
+ const result = engine.undo();
143
+ const endTime = performance.now();
144
+ if (result.success) {
145
+ undoTimes.push(endTime - startTime);
146
+ }
147
+ }
148
+ const avgUndoTime = undoTimes.reduce((a, b) => a + b, 0) / undoTimes.length;
149
+ const maxUndoTime = Math.max(...undoTimes);
150
+ console.log(`Average undo time: ${avgUndoTime.toFixed(3)}ms`);
151
+ console.log(`Maximum undo time: ${maxUndoTime.toFixed(3)}ms`);
152
+ console.log(`Target: <1ms ${avgUndoTime < 1 ? '✅' : '❌'}`);
153
+ // Performance test redo operations
154
+ console.log('\n⏩ Testing redo performance...');
155
+ const redoTimes = [];
156
+ for (let i = 0; i < Math.min(10, engine.getRedoCount()); i++) {
157
+ const startTime = performance.now();
158
+ const result = engine.redo();
159
+ const endTime = performance.now();
160
+ if (result.success) {
161
+ redoTimes.push(endTime - startTime);
162
+ }
163
+ }
164
+ if (redoTimes.length > 0) {
165
+ const avgRedoTime = redoTimes.reduce((a, b) => a + b, 0) / redoTimes.length;
166
+ const maxRedoTime = Math.max(...redoTimes);
167
+ console.log(`Average redo time: ${avgRedoTime.toFixed(3)}ms`);
168
+ console.log(`Maximum redo time: ${maxRedoTime.toFixed(3)}ms`);
169
+ console.log(`Target: <1ms ${avgRedoTime < 1 ? '✅' : '❌'}`);
170
+ }
171
+ // Test autosave performance
172
+ console.log('\n💾 Testing autosave performance...');
173
+ const autosaveTimes = [];
174
+ for (let i = 0; i < 5; i++) {
175
+ const startTime = performance.now();
176
+ await engine.manualAutosave({ test: `performance_${i}` });
177
+ const endTime = performance.now();
178
+ autosaveTimes.push(endTime - startTime);
179
+ }
180
+ const avgAutosaveTime = autosaveTimes.reduce((a, b) => a + b, 0) / autosaveTimes.length;
181
+ const maxAutosaveTime = Math.max(...autosaveTimes);
182
+ console.log(`Average autosave time: ${avgAutosaveTime.toFixed(3)}ms`);
183
+ console.log(`Maximum autosave time: ${maxAutosaveTime.toFixed(3)}ms`);
184
+ console.log(`Target: <1ms ${avgAutosaveTime < 1 ? '✅' : '❌'}`);
185
+ }
186
+ async function demonstrateIntegration() {
187
+ console.log('\n🔗 Integration with Existing Features');
188
+ console.log('-'.repeat(40));
189
+ const engine = (0, core_js_1.createQNCEEngine)(demo_story_js_1.DEMO_STORY);
190
+ // Enable all features
191
+ engine.configureUndoRedo({ enabled: true, maxUndoEntries: 50, maxRedoEntries: 25 });
192
+ engine.configureAutosave({
193
+ enabled: true,
194
+ triggers: ['choice', 'flag-change', 'state-load'],
195
+ throttleMs: 100,
196
+ maxEntries: 10,
197
+ includeMetadata: true
198
+ });
199
+ console.log('✅ Undo/redo and autosave configured');
200
+ // Test with state persistence
201
+ console.log('\n💾 Testing state save/load with undo/redo...');
202
+ // Make some changes
203
+ const choices = engine.getAvailableChoices();
204
+ if (choices.length > 0) {
205
+ engine.selectChoice(choices[0]);
206
+ }
207
+ engine.setFlag('integration_test', true);
208
+ console.log(`State before save - Undo count: ${engine.getUndoCount()}`);
209
+ // Save state
210
+ const savedState = await engine.saveState();
211
+ console.log('✅ State saved successfully');
212
+ // Make more changes
213
+ const choices2 = engine.getAvailableChoices();
214
+ if (choices2.length > 0) {
215
+ engine.selectChoice(choices2[0]);
216
+ }
217
+ engine.setFlag('after_save', 'test');
218
+ console.log(`State after more changes - Undo count: ${engine.getUndoCount()}`);
219
+ // Load previous state
220
+ await engine.loadState(savedState);
221
+ console.log('✅ State loaded successfully');
222
+ console.log(`State after load - Undo count: ${engine.getUndoCount()}`);
223
+ console.log('Flags:', Object.keys(engine.getState().flags));
224
+ // Test undo after load
225
+ const undoAfterLoad = engine.undo();
226
+ console.log(`Undo after load: ${undoAfterLoad.success ? '✅ Success' : '❌ Failed'}`);
227
+ }
228
+ async function main() {
229
+ try {
230
+ await demonstrateUndoRedo();
231
+ await demonstrateAutosave();
232
+ await demonstratePerformance();
233
+ await demonstrateIntegration();
234
+ console.log('\n🎉 Demo completed successfully!');
235
+ console.log('\nSprint 3.5 Features Demonstrated:');
236
+ console.log('✅ Undo/Redo with configurable history limits');
237
+ console.log('✅ Autosave with throttling and event triggers');
238
+ console.log('✅ Sub-millisecond performance for operations');
239
+ console.log('✅ Integration with existing state persistence');
240
+ console.log('✅ Memory-efficient history management');
241
+ }
242
+ catch (error) {
243
+ console.error('❌ Demo failed:', error);
244
+ process.exit(1);
245
+ }
246
+ }
247
+ // Run the demo
248
+ main();
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const src_1 = require("../src");
4
+ /**
5
+ * Demonstrates the state persistence and checkpoint features of the QNCE Engine.
6
+ * This example covers:
7
+ * 1. Saving the complete narrative state.
8
+ * 2. Loading that state into a new engine instance.
9
+ * 3. Creating lightweight checkpoints for undo/redo functionality.
10
+ * 4. Restoring the state from a checkpoint.
11
+ */
12
+ async function runPersistenceDemo() {
13
+ console.log('🚀 Starting QNCE Engine Persistence Demo 🚀\n');
14
+ // 1. Initialize the engine and advance the story
15
+ const engine = (0, src_1.createQNCEEngine)(src_1.DEMO_STORY);
16
+ console.log('Initial Node:', engine.getCurrentNode().text);
17
+ let choices = engine.getAvailableChoices();
18
+ engine.selectChoice(choices[1]); // Choose "Examine the shimmering portal."
19
+ console.log('\nChoice Made. Current Node:', engine.getCurrentNode().text);
20
+ choices = engine.getAvailableChoices();
21
+ engine.selectChoice(choices[0]); // Choose "Step through the portal."
22
+ console.log('Choice Made. Current Node:', engine.getCurrentNode().text);
23
+ console.log('Current Flags:', engine.getFlags());
24
+ // 2. Create a checkpoint before making another choice
25
+ console.log('\n💾 Creating a checkpoint...');
26
+ const checkpoint = await engine.createCheckpoint('Before the final choice');
27
+ console.log(`Checkpoint '${checkpoint.name}' created with ID: ${checkpoint.id}`);
28
+ // 3. Save the complete engine state to a string
29
+ console.log('\n💾 Saving engine state to JSON...');
30
+ const savedState = await engine.saveState({ prettyPrint: true });
31
+ const savedStateJSON = JSON.stringify(savedState);
32
+ console.log('State saved successfully! Size:', savedStateJSON.length, 'bytes');
33
+ // In a real application, you would store this JSON string in localStorage,
34
+ // a file, or a remote database.
35
+ // 4. Continue the story
36
+ choices = engine.getAvailableChoices();
37
+ engine.selectChoice(choices[0]);
38
+ console.log('\nMade one more choice. Current Node:', engine.getCurrentNode().text);
39
+ console.log('Final Flags:', engine.getFlags());
40
+ // 5. Restore from the checkpoint to "undo" the last choice
41
+ console.log(`\n🔄 Restoring from checkpoint '${checkpoint.name}'...`);
42
+ await engine.restoreFromCheckpoint(checkpoint.id);
43
+ console.log('State restored from checkpoint!');
44
+ console.log('Current Node after restore:', engine.getCurrentNode().text);
45
+ console.log('Flags after restore:', engine.getFlags());
46
+ // 6. Create a new engine instance and load the saved state
47
+ console.log('\n🔄 Creating a new engine and loading the saved state...');
48
+ const newEngine = (0, src_1.createQNCEEngine)(src_1.DEMO_STORY);
49
+ // The state can be loaded from a JSON string or a parsed object
50
+ await newEngine.loadState(savedState);
51
+ console.log('State loaded into new engine instance!');
52
+ // 7. Verify that the state was restored correctly
53
+ console.log('\n🔍 Verifying restored state...');
54
+ console.log('Restored Node:', newEngine.getCurrentNode().text);
55
+ console.log('Restored Flags:', newEngine.getFlags());
56
+ console.log('History length:', newEngine.getHistory().length, '| Expected:', 2);
57
+ const areFlagsEqual = JSON.stringify(engine.getFlags()) === JSON.stringify(newEngine.getFlags());
58
+ console.log('Verification successful:', areFlagsEqual);
59
+ console.log('\n✅ Persistence Demo Completed Successfully! ✅');
60
+ }
61
+ runPersistenceDemo().catch(error => {
62
+ console.error('An error occurred during the persistence demo:', error);
63
+ });