@sudobility/sudojo_lib 0.0.163 → 0.0.165

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"techniqueWalkthrough.d.ts","sourceRoot":"","sources":["../../src/utils/techniqueWalkthrough.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAKzD,+CAA+C;AAC/C,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAID,sEAAsE;AACtE,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,GAAG,IAAI,GAC5B,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CASrB;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CACjC,gBAAgB,EAAE,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,GACpC,MAAM,CAIR;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,GAAG,IAAI,EAC7B,WAAW,EAAE,MAAM,GAClB,UAAU,EAAE,CAmBd;AAID,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAKlE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,UAAU,EAAE,EACnB,IAAI,EAAE,cAAc,GACnB;IAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAqD9C;AAID,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAO5E;AAID;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,iBAAiB,EAC1B,aAAa,CAAC,EAAE,MAAM,GACrB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAYjC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,UAAU,EAAE,EAC1B,QAAQ,EAAE,WAAW,GAAG,IAAI,EAC5B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,iBAAiB,EAC1B,aAAa,CAAC,EAAE,MAAM,GACrB,eAAe,EAAE,CAwCnB"}
1
+ {"version":3,"file":"techniqueWalkthrough.d.ts","sourceRoot":"","sources":["../../src/utils/techniqueWalkthrough.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAKzD,+CAA+C;AAC/C,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAID,sEAAsE;AACtE,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,GAAG,IAAI,GAC5B,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CASrB;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CACjC,gBAAgB,EAAE,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,GACpC,MAAM,CAIR;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,GAAG,IAAI,EAC7B,WAAW,EAAE,MAAM,GAClB,UAAU,EAAE,CAmBd;AAID,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAKlE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,UAAU,EAAE,EACnB,IAAI,EAAE,cAAc,GACnB;IAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAqD9C;AAID,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAO5E;AAID;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,iBAAiB,EAC1B,aAAa,CAAC,EAAE,MAAM,GACrB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAYjC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,UAAU,EAAE,EAC1B,QAAQ,EAAE,WAAW,GAAG,IAAI,EAC5B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,iBAAiB,EAC1B,aAAa,CAAC,EAAE,MAAM,GACrB,eAAe,EAAE,CAuCnB"}
@@ -168,8 +168,7 @@ export function buildWalkthroughSteps(initialBoard, hintData, lookForText, resul
168
168
  steps.push({ board: initialBoard, hint: null, title: '', text: lookForText });
169
169
  // Steps 1-N: Each hint step with overlay, then apply changes
170
170
  let currentBoard = cloneSudokuBoard(initialBoard);
171
- for (let i = 0; i < hintData.steps.length; i++) {
172
- const hintStep = hintData.steps[i];
171
+ for (const hintStep of hintData.steps) {
173
172
  const localized = localizeHintStep(hintStep, tHints, tCommon, techniquePath);
174
173
  steps.push({
175
174
  board: cloneSudokuBoard(currentBoard),
@@ -1 +1 @@
1
- {"version":3,"file":"techniqueWalkthrough.js","sourceRoot":"","sources":["../../src/utils/techniqueWalkthrough.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Technique walkthrough utilities.\n *\n * Shared logic for building step-by-step technique examples from\n * practice puzzle data. Used by both the web app and React Native app\n * TechniqueExample components.\n */\n\nimport type { SolverHints, SolverHintStep } from '@sudobility/sudojo_types';\nimport type { SudokuCell } from '../types/sudoku';\nimport type { TranslateFunction } from './localizedHint';\nimport { getLocalizedHintText, getLocalizedHintTitle } from './localizedHint';\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\n/** A single step in a technique walkthrough */\nexport interface WalkthroughStep {\n board: SudokuCell[];\n hint: SolverHintStep | null;\n title: string;\n text: string;\n}\n\n// ── Board parsing ───────────────────────────────────────────────────────────\n\n/** Parse a comma-delimited pencilmarks string into per-cell arrays */\nexport function parsePencilmarksString(\n pencilmarksStr: string | null\n): (number[] | null)[] {\n if (!pencilmarksStr) return [];\n return pencilmarksStr.split(',').map(pm => {\n if (!pm || pm.trim() === '') return null;\n return pm\n .split('')\n .map(d => parseInt(d, 10))\n .filter(n => n >= 1 && n <= 9);\n });\n}\n\n/** Convert per-cell pencilmarks arrays back to a comma-delimited string */\nexport function pencilmarksToString(\n pencilmarksArray: (number[] | null)[]\n): string {\n return pencilmarksArray\n .map(pm => (pm && pm.length > 0 ? pm.sort((a, b) => a - b).join('') : ''))\n .join(',');\n}\n\n/**\n * Parse board, pencilmarks and solution strings into a SudokuCell array.\n * This is the format returned by the practice API.\n */\nexport function parsePracticeBoard(\n boardStr: string,\n pencilmarksStr: string | null,\n solutionStr: string\n): SudokuCell[] {\n const pencilmarksArray = parsePencilmarksString(pencilmarksStr);\n\n return Array.from({ length: 81 }, (_, index) => {\n const boardChar = boardStr[index] || '0';\n const solutionChar = solutionStr[index] || '0';\n const boardValue = parseInt(boardChar, 10);\n const solutionValue = parseInt(solutionChar, 10);\n const hasValue = boardValue >= 1 && boardValue <= 9;\n\n return {\n index,\n solution: solutionValue >= 1 && solutionValue <= 9 ? solutionValue : null,\n given: hasValue ? boardValue : null,\n input: null,\n pencilmarks:\n !hasValue && pencilmarksArray[index] ? pencilmarksArray[index] : null,\n };\n });\n}\n\n// ── Board manipulation ──────────────────────────────────────────────────────\n\n/** Deep clone a SudokuCell array (preserves pencilmarks by value) */\nexport function cloneSudokuBoard(board: SudokuCell[]): SudokuCell[] {\n return board.map(cell => ({\n ...cell,\n pencilmarks: cell.pencilmarks ? [...cell.pencilmarks] : null,\n }));\n}\n\n/**\n * Apply a hint step's actions (select / remove / add) to a board,\n * returning the new board state and serialised pencilmarks.\n */\nexport function applyHintStep(\n board: SudokuCell[],\n step: SolverHintStep\n): { board: SudokuCell[]; pencilmarks: string } {\n const newBoard = cloneSudokuBoard(board);\n\n for (const hintCell of step.cells || []) {\n const index = hintCell.row * 9 + hintCell.column;\n const cell = newBoard[index];\n if (!cell || cell.given !== null) continue;\n\n const actions = hintCell.actions;\n if (!actions) continue;\n\n // Place digit\n if (actions.select && actions.select !== '') {\n const digit = parseInt(actions.select, 10);\n if (digit >= 1 && digit <= 9) {\n cell.input = digit;\n cell.pencilmarks = null;\n }\n }\n\n // Eliminate pencilmarks\n if (actions.remove && actions.remove !== '' && cell.pencilmarks) {\n const toRemove = new Set(\n actions.remove\n .split('')\n .map(d => parseInt(d, 10))\n .filter(n => n >= 1 && n <= 9)\n );\n cell.pencilmarks = cell.pencilmarks.filter(pm => !toRemove.has(pm));\n if (cell.pencilmarks.length === 0) {\n cell.pencilmarks = null;\n }\n }\n\n // Add pencilmarks\n if (actions.add && actions.add !== '') {\n const toAdd = actions.add\n .split('')\n .map(d => parseInt(d, 10))\n .filter(n => n >= 1 && n <= 9);\n if (toAdd.length > 0) {\n const existing = new Set(cell.pencilmarks || []);\n toAdd.forEach(d => existing.add(d));\n cell.pencilmarks = Array.from(existing).sort((a, b) => a - b);\n }\n }\n }\n\n const pencilmarksStr = pencilmarksToString(\n newBoard.map(cell => cell.pencilmarks)\n );\n\n return { board: newBoard, pencilmarks: pencilmarksStr };\n}\n\n// ── Hint data parsing ───────────────────────────────────────────────────────\n\n/** Parse a hint_data JSON string into SolverHints */\nexport function parseHintData(hintDataStr: string | null): SolverHints | null {\n if (!hintDataStr) return null;\n try {\n return JSON.parse(hintDataStr) as SolverHints;\n } catch {\n return null;\n }\n}\n\n// ── Walkthrough builder ─────────────────────────────────────────────────────\n\n/**\n * Resolve localised title and text for a single hint step.\n *\n * @param step - The solver hint step\n * @param tHints - Translation function scoped to the `hints` namespace\n * @param tCommon - Translation function scoped to the default namespace\n * @param techniquePath - Optional technique path slug for title fallback\n */\nexport function localizeHintStep(\n step: SolverHintStep,\n tHints: TranslateFunction,\n tCommon: TranslateFunction,\n techniquePath?: string\n): { title: string; text: string } {\n let title = getLocalizedHintTitle(tCommon, step);\n if (title === step.title && techniquePath) {\n const translated = tCommon(`techniques.${techniquePath}.title`);\n if (translated !== `techniques.${techniquePath}.title`) {\n title = translated;\n }\n }\n return {\n title,\n text: getLocalizedHintText(tHints, step),\n };\n}\n\n/**\n * Build the full walkthrough step array from an initial board and hint data.\n *\n * - Step 0: Original board with \"Look for {technique}\" text\n * - Steps 1-N: Each hint step with overlay; board progresses after each step\n * - Final step: Result board after all steps applied, no overlay\n *\n * @param initialBoard - Parsed SudokuCell[] from practice data\n * @param hintData - Parsed SolverHints (or null)\n * @param lookForText - Already-translated \"Look for …\" string\n * @param resultText - Already-translated result text\n * @param tHints - Translation function scoped to the `hints` namespace\n * @param tCommon - Translation function scoped to the default namespace\n * @param techniquePath - Optional technique path slug for title fallback\n */\nexport function buildWalkthroughSteps(\n initialBoard: SudokuCell[],\n hintData: SolverHints | null,\n lookForText: string,\n resultText: string,\n tHints: TranslateFunction,\n tCommon: TranslateFunction,\n techniquePath?: string\n): WalkthroughStep[] {\n const steps: WalkthroughStep[] = [];\n\n if (!hintData?.steps?.length) {\n steps.push({\n board: initialBoard,\n hint: null,\n title: '',\n text: lookForText,\n });\n return steps;\n }\n\n // Step 0: Original board\n steps.push({ board: initialBoard, hint: null, title: '', text: lookForText });\n\n // Steps 1-N: Each hint step with overlay, then apply changes\n let currentBoard = cloneSudokuBoard(initialBoard);\n for (let i = 0; i < hintData.steps.length; i++) {\n const hintStep = hintData.steps[i]!;\n const localized = localizeHintStep(\n hintStep,\n tHints,\n tCommon,\n techniquePath\n );\n steps.push({\n board: cloneSudokuBoard(currentBoard),\n hint: hintStep,\n title: localized.title,\n text: localized.text,\n });\n const result = applyHintStep(currentBoard, hintStep);\n currentBoard = result.board;\n }\n\n // Final step: Result after all steps applied\n steps.push({ board: currentBoard, hint: null, title: '', text: resultText });\n\n return steps;\n}\n"]}
1
+ {"version":3,"file":"techniqueWalkthrough.js","sourceRoot":"","sources":["../../src/utils/techniqueWalkthrough.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Technique walkthrough utilities.\n *\n * Shared logic for building step-by-step technique examples from\n * practice puzzle data. Used by both the web app and React Native app\n * TechniqueExample components.\n */\n\nimport type { SolverHints, SolverHintStep } from '@sudobility/sudojo_types';\nimport type { SudokuCell } from '../types/sudoku';\nimport type { TranslateFunction } from './localizedHint';\nimport { getLocalizedHintText, getLocalizedHintTitle } from './localizedHint';\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\n/** A single step in a technique walkthrough */\nexport interface WalkthroughStep {\n board: SudokuCell[];\n hint: SolverHintStep | null;\n title: string;\n text: string;\n}\n\n// ── Board parsing ───────────────────────────────────────────────────────────\n\n/** Parse a comma-delimited pencilmarks string into per-cell arrays */\nexport function parsePencilmarksString(\n pencilmarksStr: string | null\n): (number[] | null)[] {\n if (!pencilmarksStr) return [];\n return pencilmarksStr.split(',').map(pm => {\n if (!pm || pm.trim() === '') return null;\n return pm\n .split('')\n .map(d => parseInt(d, 10))\n .filter(n => n >= 1 && n <= 9);\n });\n}\n\n/** Convert per-cell pencilmarks arrays back to a comma-delimited string */\nexport function pencilmarksToString(\n pencilmarksArray: (number[] | null)[]\n): string {\n return pencilmarksArray\n .map(pm => (pm && pm.length > 0 ? pm.sort((a, b) => a - b).join('') : ''))\n .join(',');\n}\n\n/**\n * Parse board, pencilmarks and solution strings into a SudokuCell array.\n * This is the format returned by the practice API.\n */\nexport function parsePracticeBoard(\n boardStr: string,\n pencilmarksStr: string | null,\n solutionStr: string\n): SudokuCell[] {\n const pencilmarksArray = parsePencilmarksString(pencilmarksStr);\n\n return Array.from({ length: 81 }, (_, index) => {\n const boardChar = boardStr[index] || '0';\n const solutionChar = solutionStr[index] || '0';\n const boardValue = parseInt(boardChar, 10);\n const solutionValue = parseInt(solutionChar, 10);\n const hasValue = boardValue >= 1 && boardValue <= 9;\n\n return {\n index,\n solution: solutionValue >= 1 && solutionValue <= 9 ? solutionValue : null,\n given: hasValue ? boardValue : null,\n input: null,\n pencilmarks:\n !hasValue && pencilmarksArray[index] ? pencilmarksArray[index] : null,\n };\n });\n}\n\n// ── Board manipulation ──────────────────────────────────────────────────────\n\n/** Deep clone a SudokuCell array (preserves pencilmarks by value) */\nexport function cloneSudokuBoard(board: SudokuCell[]): SudokuCell[] {\n return board.map(cell => ({\n ...cell,\n pencilmarks: cell.pencilmarks ? [...cell.pencilmarks] : null,\n }));\n}\n\n/**\n * Apply a hint step's actions (select / remove / add) to a board,\n * returning the new board state and serialised pencilmarks.\n */\nexport function applyHintStep(\n board: SudokuCell[],\n step: SolverHintStep\n): { board: SudokuCell[]; pencilmarks: string } {\n const newBoard = cloneSudokuBoard(board);\n\n for (const hintCell of step.cells || []) {\n const index = hintCell.row * 9 + hintCell.column;\n const cell = newBoard[index];\n if (!cell || cell.given !== null) continue;\n\n const actions = hintCell.actions;\n if (!actions) continue;\n\n // Place digit\n if (actions.select && actions.select !== '') {\n const digit = parseInt(actions.select, 10);\n if (digit >= 1 && digit <= 9) {\n cell.input = digit;\n cell.pencilmarks = null;\n }\n }\n\n // Eliminate pencilmarks\n if (actions.remove && actions.remove !== '' && cell.pencilmarks) {\n const toRemove = new Set(\n actions.remove\n .split('')\n .map(d => parseInt(d, 10))\n .filter(n => n >= 1 && n <= 9)\n );\n cell.pencilmarks = cell.pencilmarks.filter(pm => !toRemove.has(pm));\n if (cell.pencilmarks.length === 0) {\n cell.pencilmarks = null;\n }\n }\n\n // Add pencilmarks\n if (actions.add && actions.add !== '') {\n const toAdd = actions.add\n .split('')\n .map(d => parseInt(d, 10))\n .filter(n => n >= 1 && n <= 9);\n if (toAdd.length > 0) {\n const existing = new Set(cell.pencilmarks || []);\n toAdd.forEach(d => existing.add(d));\n cell.pencilmarks = Array.from(existing).sort((a, b) => a - b);\n }\n }\n }\n\n const pencilmarksStr = pencilmarksToString(\n newBoard.map(cell => cell.pencilmarks)\n );\n\n return { board: newBoard, pencilmarks: pencilmarksStr };\n}\n\n// ── Hint data parsing ───────────────────────────────────────────────────────\n\n/** Parse a hint_data JSON string into SolverHints */\nexport function parseHintData(hintDataStr: string | null): SolverHints | null {\n if (!hintDataStr) return null;\n try {\n return JSON.parse(hintDataStr) as SolverHints;\n } catch {\n return null;\n }\n}\n\n// ── Walkthrough builder ─────────────────────────────────────────────────────\n\n/**\n * Resolve localised title and text for a single hint step.\n *\n * @param step - The solver hint step\n * @param tHints - Translation function scoped to the `hints` namespace\n * @param tCommon - Translation function scoped to the default namespace\n * @param techniquePath - Optional technique path slug for title fallback\n */\nexport function localizeHintStep(\n step: SolverHintStep,\n tHints: TranslateFunction,\n tCommon: TranslateFunction,\n techniquePath?: string\n): { title: string; text: string } {\n let title = getLocalizedHintTitle(tCommon, step);\n if (title === step.title && techniquePath) {\n const translated = tCommon(`techniques.${techniquePath}.title`);\n if (translated !== `techniques.${techniquePath}.title`) {\n title = translated;\n }\n }\n return {\n title,\n text: getLocalizedHintText(tHints, step),\n };\n}\n\n/**\n * Build the full walkthrough step array from an initial board and hint data.\n *\n * - Step 0: Original board with \"Look for {technique}\" text\n * - Steps 1-N: Each hint step with overlay; board progresses after each step\n * - Final step: Result board after all steps applied, no overlay\n *\n * @param initialBoard - Parsed SudokuCell[] from practice data\n * @param hintData - Parsed SolverHints (or null)\n * @param lookForText - Already-translated \"Look for …\" string\n * @param resultText - Already-translated result text\n * @param tHints - Translation function scoped to the `hints` namespace\n * @param tCommon - Translation function scoped to the default namespace\n * @param techniquePath - Optional technique path slug for title fallback\n */\nexport function buildWalkthroughSteps(\n initialBoard: SudokuCell[],\n hintData: SolverHints | null,\n lookForText: string,\n resultText: string,\n tHints: TranslateFunction,\n tCommon: TranslateFunction,\n techniquePath?: string\n): WalkthroughStep[] {\n const steps: WalkthroughStep[] = [];\n\n if (!hintData?.steps?.length) {\n steps.push({\n board: initialBoard,\n hint: null,\n title: '',\n text: lookForText,\n });\n return steps;\n }\n\n // Step 0: Original board\n steps.push({ board: initialBoard, hint: null, title: '', text: lookForText });\n\n // Steps 1-N: Each hint step with overlay, then apply changes\n let currentBoard = cloneSudokuBoard(initialBoard);\n for (const hintStep of hintData.steps) {\n const localized = localizeHintStep(\n hintStep,\n tHints,\n tCommon,\n techniquePath\n );\n steps.push({\n board: cloneSudokuBoard(currentBoard),\n hint: hintStep,\n title: localized.title,\n text: localized.text,\n });\n const result = applyHintStep(currentBoard, hintStep);\n currentBoard = result.board;\n }\n\n // Final step: Result after all steps applied\n steps.push({ board: currentBoard, hint: null, title: '', text: resultText });\n\n return steps;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sudobility/sudojo_lib",
3
- "version": "0.0.163",
3
+ "version": "0.0.165",
4
4
  "description": "Business logic library for Sudojo app",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -47,8 +47,8 @@
47
47
  "license": "BUSL-1.1",
48
48
  "devDependencies": {
49
49
  "@sudobility/di": "^1.5.58",
50
- "@sudobility/sudojo_client": "^0.0.120",
51
- "@sudobility/sudojo_types": "^1.2.61",
50
+ "@sudobility/sudojo_client": "^0.0.122",
51
+ "@sudobility/sudojo_types": "^1.2.63",
52
52
  "@sudobility/types": "^1.9.62",
53
53
  "@tanstack/react-query": "^5.90.11",
54
54
  "@testing-library/dom": "^10.4.1",
@@ -73,8 +73,8 @@
73
73
  },
74
74
  "peerDependencies": {
75
75
  "@sudobility/di": "^1.5.58",
76
- "@sudobility/sudojo_client": "^0.0.120",
77
- "@sudobility/sudojo_types": "^1.2.61",
76
+ "@sudobility/sudojo_client": "^0.0.122",
77
+ "@sudobility/sudojo_types": "^1.2.63",
78
78
  "@sudobility/types": "^1.9.62",
79
79
  "@tanstack/react-query": ">=5.0.0",
80
80
  "react": ">=18.0.0",