@sudobility/sudojo_lib 0.0.201 → 0.0.203
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.
- package/dist/admin/adminApi.d.ts +34 -0
- package/dist/admin/adminApi.d.ts.map +1 -0
- package/dist/admin/adminApi.js +59 -0
- package/dist/admin/adminApi.js.map +1 -0
- package/dist/admin/boardRules.d.ts +75 -0
- package/dist/admin/boardRules.d.ts.map +1 -0
- package/dist/admin/boardRules.js +127 -0
- package/dist/admin/boardRules.js.map +1 -0
- package/dist/admin/boardStrings.d.ts +55 -0
- package/dist/admin/boardStrings.d.ts.map +1 -0
- package/dist/admin/boardStrings.js +99 -0
- package/dist/admin/boardStrings.js.map +1 -0
- package/dist/admin/examples.d.ts +58 -0
- package/dist/admin/examples.d.ts.map +1 -0
- package/dist/admin/examples.js +104 -0
- package/dist/admin/examples.js.map +1 -0
- package/dist/admin/extraction.d.ts +87 -0
- package/dist/admin/extraction.d.ts.map +1 -0
- package/dist/admin/extraction.js +141 -0
- package/dist/admin/extraction.js.map +1 -0
- package/dist/admin/index.d.ts +32 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +22 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/jobs.d.ts +108 -0
- package/dist/admin/jobs.d.ts.map +1 -0
- package/dist/admin/jobs.js +435 -0
- package/dist/admin/jobs.js.map +1 -0
- package/dist/admin/regenerateHints.d.ts +16 -0
- package/dist/admin/regenerateHints.d.ts.map +1 -0
- package/dist/admin/regenerateHints.js +43 -0
- package/dist/admin/regenerateHints.js.map +1 -0
- package/dist/admin/types.d.ts +42 -0
- package/dist/admin/types.d.ts.map +1 -0
- package/dist/admin/types.js +21 -0
- package/dist/admin/types.js.map +1 -0
- package/dist/admin/useAdminJob.d.ts +28 -0
- package/dist/admin/useAdminJob.d.ts.map +1 -0
- package/dist/admin/useAdminJob.js +99 -0
- package/dist/admin/useAdminJob.js.map +1 -0
- package/dist/admin/useAdminStats.d.ts +46 -0
- package/dist/admin/useAdminStats.d.ts.map +1 -0
- package/dist/admin/useAdminStats.js +91 -0
- package/dist/admin/useAdminStats.js.map +1 -0
- package/dist/admin/useBoardGenerator.d.ts +29 -0
- package/dist/admin/useBoardGenerator.d.ts.map +1 -0
- package/dist/admin/useBoardGenerator.js +38 -0
- package/dist/admin/useBoardGenerator.js.map +1 -0
- package/dist/admin/useBoardTechniquesUpdater.d.ts +14 -0
- package/dist/admin/useBoardTechniquesUpdater.d.ts.map +1 -0
- package/dist/admin/useBoardTechniquesUpdater.js +28 -0
- package/dist/admin/useBoardTechniquesUpdater.js.map +1 -0
- package/dist/admin/useExampleCreator.d.ts +29 -0
- package/dist/admin/useExampleCreator.d.ts.map +1 -0
- package/dist/admin/useExampleCreator.js +58 -0
- package/dist/admin/useExampleCreator.js.map +1 -0
- package/dist/admin/useSingleBoardExtractor.d.ts +18 -0
- package/dist/admin/useSingleBoardExtractor.d.ts.map +1 -0
- package/dist/admin/useSingleBoardExtractor.js +19 -0
- package/dist/admin/useSingleBoardExtractor.js.map +1 -0
- package/dist/admin/useTechniqueExtractor.d.ts +26 -0
- package/dist/admin/useTechniqueExtractor.d.ts.map +1 -0
- package/dist/admin/useTechniqueExtractor.js +37 -0
- package/dist/admin/useTechniqueExtractor.js.map +1 -0
- package/dist/context/SudojoApiContext.d.ts +58 -0
- package/dist/context/SudojoApiContext.d.ts.map +1 -0
- package/dist/context/SudojoApiContext.js +52 -0
- package/dist/context/SudojoApiContext.js.map +1 -0
- package/dist/context/SudojoApiProvider.d.ts +21 -0
- package/dist/context/SudojoApiProvider.d.ts.map +1 -0
- package/dist/context/SudojoApiProvider.js +15 -0
- package/dist/context/SudojoApiProvider.js.map +1 -0
- package/dist/context/index.d.ts +3 -0
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +2 -0
- package/dist/context/index.js.map +1 -1
- package/dist/hooks/index.d.ts +24 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +22 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useBoardEntry.d.ts +65 -5
- package/dist/hooks/useBoardEntry.d.ts.map +1 -1
- package/dist/hooks/useBoardEntry.js +124 -27
- package/dist/hooks/useBoardEntry.js.map +1 -1
- package/dist/hooks/useBoardScan.d.ts +27 -0
- package/dist/hooks/useBoardScan.d.ts.map +1 -0
- package/dist/hooks/useBoardScan.js +27 -0
- package/dist/hooks/useBoardScan.js.map +1 -0
- package/dist/hooks/useCommunities.d.ts +6 -4
- package/dist/hooks/useCommunities.d.ts.map +1 -1
- package/dist/hooks/useCommunities.js +6 -1
- package/dist/hooks/useCommunities.js.map +1 -1
- package/dist/hooks/useCompletionTrigger.d.ts +23 -0
- package/dist/hooks/useCompletionTrigger.d.ts.map +1 -0
- package/dist/hooks/useCompletionTrigger.js +39 -0
- package/dist/hooks/useCompletionTrigger.js.map +1 -0
- package/dist/hooks/useDailyGame.d.ts +11 -6
- package/dist/hooks/useDailyGame.d.ts.map +1 -1
- package/dist/hooks/useDailyGame.js +20 -61
- package/dist/hooks/useDailyGame.js.map +1 -1
- package/dist/hooks/useDeleteAccount.d.ts +72 -0
- package/dist/hooks/useDeleteAccount.d.ts.map +1 -0
- package/dist/hooks/useDeleteAccount.js +71 -0
- package/dist/hooks/useDeleteAccount.js.map +1 -0
- package/dist/hooks/useEnteredGameSession.d.ts +73 -0
- package/dist/hooks/useEnteredGameSession.d.ts.map +1 -0
- package/dist/hooks/useEnteredGameSession.js +155 -0
- package/dist/hooks/useEnteredGameSession.js.map +1 -0
- package/dist/hooks/useGameSession.d.ts +8 -4
- package/dist/hooks/useGameSession.d.ts.map +1 -1
- package/dist/hooks/useGameSession.js +4 -1
- package/dist/hooks/useGameSession.js.map +1 -1
- package/dist/hooks/useGameTeaching.d.ts.map +1 -1
- package/dist/hooks/useGameTeaching.js +11 -13
- package/dist/hooks/useGameTeaching.js.map +1 -1
- package/dist/hooks/useHint.d.ts +7 -7
- package/dist/hooks/useHint.d.ts.map +1 -1
- package/dist/hooks/useHint.js +18 -9
- package/dist/hooks/useHint.js.map +1 -1
- package/dist/hooks/useIsSiteAdmin.d.ts +39 -0
- package/dist/hooks/useIsSiteAdmin.d.ts.map +1 -0
- package/dist/hooks/useIsSiteAdmin.js +31 -0
- package/dist/hooks/useIsSiteAdmin.js.map +1 -0
- package/dist/hooks/useLearning.d.ts +8 -8
- package/dist/hooks/useLearning.d.ts.map +1 -1
- package/dist/hooks/useLearning.js +5 -2
- package/dist/hooks/useLearning.js.map +1 -1
- package/dist/hooks/useLevelGame.d.ts +7 -7
- package/dist/hooks/useLevelGame.d.ts.map +1 -1
- package/dist/hooks/useLevelGame.js +13 -49
- package/dist/hooks/useLevelGame.js.map +1 -1
- package/dist/hooks/useLevels.d.ts +8 -8
- package/dist/hooks/useLevels.d.ts.map +1 -1
- package/dist/hooks/useLevels.js +7 -3
- package/dist/hooks/useLevels.js.map +1 -1
- package/dist/hooks/usePracticeGame.d.ts +53 -0
- package/dist/hooks/usePracticeGame.d.ts.map +1 -0
- package/dist/hooks/usePracticeGame.js +72 -0
- package/dist/hooks/usePracticeGame.js.map +1 -0
- package/dist/hooks/usePuzzleDistribution.d.ts +2 -0
- package/dist/hooks/usePuzzleDistribution.d.ts.map +1 -1
- package/dist/hooks/usePuzzleDistribution.js +4 -14
- package/dist/hooks/usePuzzleDistribution.js.map +1 -1
- package/dist/hooks/usePuzzleProgress.d.ts +37 -0
- package/dist/hooks/usePuzzleProgress.d.ts.map +1 -0
- package/dist/hooks/usePuzzleProgress.js +48 -0
- package/dist/hooks/usePuzzleProgress.js.map +1 -0
- package/dist/hooks/usePuzzleSession.d.ts +215 -0
- package/dist/hooks/usePuzzleSession.d.ts.map +1 -0
- package/dist/hooks/usePuzzleSession.js +358 -0
- package/dist/hooks/usePuzzleSession.js.map +1 -0
- package/dist/hooks/useResumeGame.d.ts +70 -0
- package/dist/hooks/useResumeGame.d.ts.map +1 -0
- package/dist/hooks/useResumeGame.js +123 -0
- package/dist/hooks/useResumeGame.js.map +1 -0
- package/dist/hooks/useStrategies.d.ts +39 -0
- package/dist/hooks/useStrategies.d.ts.map +1 -0
- package/dist/hooks/useStrategies.js +34 -0
- package/dist/hooks/useStrategies.js.map +1 -0
- package/dist/hooks/useSudoku.d.ts +5 -0
- package/dist/hooks/useSudoku.d.ts.map +1 -1
- package/dist/hooks/useSudoku.js +7 -1
- package/dist/hooks/useSudoku.js.map +1 -1
- package/dist/hooks/useTechniqueByPath.d.ts +46 -0
- package/dist/hooks/useTechniqueByPath.d.ts.map +1 -0
- package/dist/hooks/useTechniqueByPath.js +47 -0
- package/dist/hooks/useTechniqueByPath.js.map +1 -0
- package/dist/hooks/useTechniqueExample.d.ts +60 -0
- package/dist/hooks/useTechniqueExample.d.ts.map +1 -0
- package/dist/hooks/useTechniqueExample.js +63 -0
- package/dist/hooks/useTechniqueExample.js.map +1 -0
- package/dist/hooks/useTechniques.d.ts +8 -8
- package/dist/hooks/useTechniques.d.ts.map +1 -1
- package/dist/hooks/useTechniques.js +9 -21
- package/dist/hooks/useTechniques.js.map +1 -1
- package/dist/index.d.ts +418 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +276 -10
- package/dist/index.js.map +1 -1
- package/dist/types/currentGame.d.ts +9 -1
- package/dist/types/currentGame.d.ts.map +1 -1
- package/dist/types/currentGame.js.map +1 -1
- package/dist/utils/auth.d.ts +6 -0
- package/dist/utils/auth.d.ts.map +1 -1
- package/dist/utils/auth.js +8 -0
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/community.d.ts +64 -0
- package/dist/utils/community.d.ts.map +1 -0
- package/dist/utils/community.js +66 -0
- package/dist/utils/community.js.map +1 -0
- package/dist/utils/date.d.ts +37 -0
- package/dist/utils/date.d.ts.map +1 -0
- package/dist/utils/date.js +68 -0
- package/dist/utils/date.js.map +1 -0
- package/dist/utils/entityTranslate.d.ts +120 -0
- package/dist/utils/entityTranslate.d.ts.map +1 -0
- package/dist/utils/entityTranslate.js +146 -0
- package/dist/utils/entityTranslate.js.map +1 -0
- package/dist/utils/gameFetchStatus.d.ts +74 -0
- package/dist/utils/gameFetchStatus.d.ts.map +1 -0
- package/dist/utils/gameFetchStatus.js +118 -0
- package/dist/utils/gameFetchStatus.js.map +1 -0
- package/dist/utils/gamification.d.ts +36 -0
- package/dist/utils/gamification.d.ts.map +1 -0
- package/dist/utils/gamification.js +33 -0
- package/dist/utils/gamification.js.map +1 -0
- package/dist/utils/hintAccess.d.ts +64 -0
- package/dist/utils/hintAccess.d.ts.map +1 -0
- package/dist/utils/hintAccess.js +57 -0
- package/dist/utils/hintAccess.js.map +1 -0
- package/dist/utils/index.d.ts +31 -10
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +20 -9
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/language.d.ts +123 -0
- package/dist/utils/language.d.ts.map +1 -0
- package/dist/utils/language.js +95 -0
- package/dist/utils/language.js.map +1 -0
- package/dist/utils/localizedHint.d.ts +60 -0
- package/dist/utils/localizedHint.d.ts.map +1 -1
- package/dist/utils/localizedHint.js +90 -0
- package/dist/utils/localizedHint.js.map +1 -1
- package/dist/utils/progress.d.ts +10 -1
- package/dist/utils/progress.d.ts.map +1 -1
- package/dist/utils/progress.js +24 -0
- package/dist/utils/progress.js.map +1 -1
- package/dist/utils/scannedBoard.d.ts +79 -0
- package/dist/utils/scannedBoard.d.ts.map +1 -0
- package/dist/utils/scannedBoard.js +96 -0
- package/dist/utils/scannedBoard.js.map +1 -0
- package/dist/utils/shareUrl.d.ts +38 -15
- package/dist/utils/shareUrl.d.ts.map +1 -1
- package/dist/utils/shareUrl.js +75 -26
- package/dist/utils/shareUrl.js.map +1 -1
- package/dist/utils/subscription.d.ts +118 -0
- package/dist/utils/subscription.d.ts.map +1 -1
- package/dist/utils/subscription.js +212 -0
- package/dist/utils/subscription.js.map +1 -1
- package/dist/utils/sudokuPresenter.d.ts +42 -0
- package/dist/utils/sudokuPresenter.d.ts.map +1 -1
- package/dist/utils/sudokuPresenter.js +114 -1
- package/dist/utils/sudokuPresenter.js.map +1 -1
- package/dist/utils/sudokuScrambler.d.ts +8 -0
- package/dist/utils/sudokuScrambler.d.ts.map +1 -1
- package/dist/utils/sudokuScrambler.js +12 -0
- package/dist/utils/sudokuScrambler.js.map +1 -1
- package/dist/utils/technique.d.ts +112 -1
- package/dist/utils/technique.d.ts.map +1 -1
- package/dist/utils/technique.js +293 -1
- package/dist/utils/technique.js.map +1 -1
- package/dist/utils/techniqueBitmask.d.ts +31 -0
- package/dist/utils/techniqueBitmask.d.ts.map +1 -0
- package/dist/utils/techniqueBitmask.js +53 -0
- package/dist/utils/techniqueBitmask.js.map +1 -0
- package/dist/utils/techniqueExample.d.ts +42 -0
- package/dist/utils/techniqueExample.d.ts.map +1 -0
- package/dist/utils/techniqueExample.js +57 -0
- package/dist/utils/techniqueExample.js.map +1 -0
- package/dist/utils/theme.d.ts +2 -0
- package/dist/utils/theme.d.ts.map +1 -1
- package/dist/utils/theme.js +2 -0
- package/dist/utils/theme.js.map +1 -1
- package/package.json +7 -7
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure rules for the technique-example creator: which techniques still need
|
|
3
|
+
* examples, where to search for boards, and the example + linked practice
|
|
4
|
+
* requests built from a find.
|
|
5
|
+
*
|
|
6
|
+
* Ported from `sudojo_app/src/utils/admin/ExampleCreator.ts` and the
|
|
7
|
+
* constants of `sudojo_app/src/pages/AdminPage.tsx`.
|
|
8
|
+
*/
|
|
9
|
+
import { ALL_TECHNIQUE_IDS, formatTechniqueBitmask, MAX_LEVEL, MIN_LEVEL, techniqueIdsToBitmask, } from '@sudobility/sudojo_types';
|
|
10
|
+
import { adjustPracticeSolution, mergeBoardWithUserInput, } from './boardStrings';
|
|
11
|
+
/** Examples wanted per technique. */
|
|
12
|
+
export const ADMIN_EXAMPLE_TARGET_PER_TECHNIQUE = 1;
|
|
13
|
+
/** Every technique id, easiest (lowest id) first: the creator's work order. */
|
|
14
|
+
export const ADMIN_TECHNIQUE_ORDER = [
|
|
15
|
+
...ALL_TECHNIQUE_IDS,
|
|
16
|
+
].sort((a, b) => a - b);
|
|
17
|
+
/** Boards fetched per technique by bit. */
|
|
18
|
+
export const BOARDS_WITH_TECHNIQUE_LIMIT = 50;
|
|
19
|
+
/** Boards fetched per level in the level-based search. */
|
|
20
|
+
export const BOARDS_PER_LEVEL_LIMIT = 100;
|
|
21
|
+
/**
|
|
22
|
+
* Normalize an API counts map (string keys, e.g. `/examples/counts`) to
|
|
23
|
+
* numeric technique-id keys. null/undefined → {}.
|
|
24
|
+
*/
|
|
25
|
+
export function normalizeTechniqueCounts(data) {
|
|
26
|
+
const result = {};
|
|
27
|
+
if (!data)
|
|
28
|
+
return result;
|
|
29
|
+
for (const [key, value] of Object.entries(data)) {
|
|
30
|
+
const id = parseInt(key, 10);
|
|
31
|
+
if (!Number.isNaN(id))
|
|
32
|
+
result[id] = value;
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
/** Count for a technique (0 when absent). */
|
|
37
|
+
export function countForTechnique(counts, techniqueId) {
|
|
38
|
+
return counts[techniqueId] || 0;
|
|
39
|
+
}
|
|
40
|
+
/** True when the technique already has `target` examples. */
|
|
41
|
+
export function hasReachedTarget(counts, techniqueId, target) {
|
|
42
|
+
return countForTechnique(counts, techniqueId) >= target;
|
|
43
|
+
}
|
|
44
|
+
/** Techniques in `order` that still need examples. */
|
|
45
|
+
export function techniquesNeedingExamples(order, counts, target) {
|
|
46
|
+
return order.filter(id => !hasReachedTarget(counts, id, target));
|
|
47
|
+
}
|
|
48
|
+
/** Sum of all counts. */
|
|
49
|
+
export function totalTechniqueCount(counts) {
|
|
50
|
+
return Object.values(counts).reduce((sum, c) => sum + c, 0);
|
|
51
|
+
}
|
|
52
|
+
/** technique id → level (null when the technique has no level). */
|
|
53
|
+
export function buildTechniqueLevelMap(techniques) {
|
|
54
|
+
const map = new Map();
|
|
55
|
+
for (const tech of techniques ?? [])
|
|
56
|
+
map.set(tech.technique, tech.level);
|
|
57
|
+
return map;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Levels to search, in order, for a technique at `techniqueLevel`: one below,
|
|
61
|
+
* its own, then two above (a technique often first appears on harder
|
|
62
|
+
* boards). Clamped to MIN_LEVEL..MAX_LEVEL.
|
|
63
|
+
*/
|
|
64
|
+
export function levelsToSearchForTechnique(techniqueLevel) {
|
|
65
|
+
return [
|
|
66
|
+
techniqueLevel - 1,
|
|
67
|
+
techniqueLevel,
|
|
68
|
+
techniqueLevel + 1,
|
|
69
|
+
techniqueLevel + 2,
|
|
70
|
+
].filter(level => level >= MIN_LEVEL && level <= MAX_LEVEL);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Build the example and practice requests for a find on `board`.
|
|
74
|
+
*
|
|
75
|
+
* `found.userInput` holds only the solver's cells (never the givens), so the
|
|
76
|
+
* stored board is `mergeBoardWithUserInput(board.board, found.userInput)`.
|
|
77
|
+
* The practice's solution is blanked ('0') wherever that board is filled.
|
|
78
|
+
*/
|
|
79
|
+
export function buildExampleSaveRequests(board, found) {
|
|
80
|
+
const mergedBoard = mergeBoardWithUserInput(board.board, found.userInput);
|
|
81
|
+
const hintData = JSON.stringify(found.hintData);
|
|
82
|
+
const pencilmarks = found.pencilmarks || undefined;
|
|
83
|
+
return {
|
|
84
|
+
mergedBoard,
|
|
85
|
+
example: {
|
|
86
|
+
board: mergedBoard,
|
|
87
|
+
pencilmarks,
|
|
88
|
+
solution: board.solution,
|
|
89
|
+
techniques_bitfield: formatTechniqueBitmask(techniqueIdsToBitmask([found.techniqueId])),
|
|
90
|
+
primary_technique: found.techniqueId,
|
|
91
|
+
hint_data: hintData,
|
|
92
|
+
source_board_uuid: board.uuid,
|
|
93
|
+
},
|
|
94
|
+
practice: {
|
|
95
|
+
technique: found.techniqueId,
|
|
96
|
+
board: mergedBoard,
|
|
97
|
+
pencilmarks,
|
|
98
|
+
solution: adjustPracticeSolution(mergedBoard, board.solution),
|
|
99
|
+
hint_data: hintData,
|
|
100
|
+
source_example_uuid: undefined,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=examples.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"examples.js","sourceRoot":"","sources":["../../src/admin/examples.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure rules for the technique-example creator: which techniques still need\n * examples, where to search for boards, and the example + linked practice\n * requests built from a find.\n *\n * Ported from `sudojo_app/src/utils/admin/ExampleCreator.ts` and the\n * constants of `sudojo_app/src/pages/AdminPage.tsx`.\n */\n\nimport {\n ALL_TECHNIQUE_IDS,\n type Board,\n formatTechniqueBitmask,\n MAX_LEVEL,\n MIN_LEVEL,\n type Technique,\n type TechniqueExampleCreateRequest,\n type TechniqueId,\n techniqueIdsToBitmask,\n type TechniquePracticeCreateRequest,\n} from '@sudobility/sudojo_types';\nimport {\n adjustPracticeSolution,\n mergeBoardWithUserInput,\n} from './boardStrings';\nimport type { TechniqueExampleFound } from './extraction';\n\n/** Examples wanted per technique. */\nexport const ADMIN_EXAMPLE_TARGET_PER_TECHNIQUE = 1;\n\n/** Every technique id, easiest (lowest id) first: the creator's work order. */\nexport const ADMIN_TECHNIQUE_ORDER: readonly TechniqueId[] = [\n ...ALL_TECHNIQUE_IDS,\n].sort((a, b) => a - b);\n\n/** Boards fetched per technique by bit. */\nexport const BOARDS_WITH_TECHNIQUE_LIMIT = 50;\n\n/** Boards fetched per level in the level-based search. */\nexport const BOARDS_PER_LEVEL_LIMIT = 100;\n\n/** Example counts keyed by technique id. */\nexport type TechniqueCounts = Readonly<Record<number, number>>;\n\n/**\n * Normalize an API counts map (string keys, e.g. `/examples/counts`) to\n * numeric technique-id keys. null/undefined → {}.\n */\nexport function normalizeTechniqueCounts(\n data:\n | Readonly<Record<string, number>>\n | Readonly<Record<number, number>>\n | null\n | undefined\n): Record<number, number> {\n const result: Record<number, number> = {};\n if (!data) return result;\n for (const [key, value] of Object.entries(data)) {\n const id = parseInt(key, 10);\n if (!Number.isNaN(id)) result[id] = value;\n }\n return result;\n}\n\n/** Count for a technique (0 when absent). */\nexport function countForTechnique(\n counts: TechniqueCounts,\n techniqueId: number\n): number {\n return counts[techniqueId] || 0;\n}\n\n/** True when the technique already has `target` examples. */\nexport function hasReachedTarget(\n counts: TechniqueCounts,\n techniqueId: number,\n target: number\n): boolean {\n return countForTechnique(counts, techniqueId) >= target;\n}\n\n/** Techniques in `order` that still need examples. */\nexport function techniquesNeedingExamples(\n order: readonly TechniqueId[],\n counts: TechniqueCounts,\n target: number\n): TechniqueId[] {\n return order.filter(id => !hasReachedTarget(counts, id, target));\n}\n\n/** Sum of all counts. */\nexport function totalTechniqueCount(counts: TechniqueCounts): number {\n return Object.values(counts).reduce((sum, c) => sum + c, 0);\n}\n\n/** technique id → level (null when the technique has no level). */\nexport function buildTechniqueLevelMap(\n techniques: readonly Technique[] | null | undefined\n): Map<number, number | null> {\n const map = new Map<number, number | null>();\n for (const tech of techniques ?? []) map.set(tech.technique, tech.level);\n return map;\n}\n\n/**\n * Levels to search, in order, for a technique at `techniqueLevel`: one below,\n * its own, then two above (a technique often first appears on harder\n * boards). Clamped to MIN_LEVEL..MAX_LEVEL.\n */\nexport function levelsToSearchForTechnique(techniqueLevel: number): number[] {\n return [\n techniqueLevel - 1,\n techniqueLevel,\n techniqueLevel + 1,\n techniqueLevel + 2,\n ].filter(level => level >= MIN_LEVEL && level <= MAX_LEVEL);\n}\n\n/** Requests to save a find: the example, then (after it) the linked practice. */\nexport interface ExampleSaveRequests {\n /** Source givens + the cells the solver filled before reaching the technique */\n mergedBoard: string;\n example: TechniqueExampleCreateRequest;\n /** Practice request without `source_example_uuid` (set it from the example) */\n practice: TechniquePracticeCreateRequest;\n}\n\n/**\n * Build the example and practice requests for a find on `board`.\n *\n * `found.userInput` holds only the solver's cells (never the givens), so the\n * stored board is `mergeBoardWithUserInput(board.board, found.userInput)`.\n * The practice's solution is blanked ('0') wherever that board is filled.\n */\nexport function buildExampleSaveRequests(\n board: Pick<Board, 'uuid' | 'board' | 'solution'>,\n found: TechniqueExampleFound\n): ExampleSaveRequests {\n const mergedBoard = mergeBoardWithUserInput(board.board, found.userInput);\n const hintData = JSON.stringify(found.hintData);\n const pencilmarks = found.pencilmarks || undefined;\n return {\n mergedBoard,\n example: {\n board: mergedBoard,\n pencilmarks,\n solution: board.solution,\n techniques_bitfield: formatTechniqueBitmask(\n techniqueIdsToBitmask([found.techniqueId])\n ),\n primary_technique: found.techniqueId,\n hint_data: hintData,\n source_board_uuid: board.uuid,\n },\n practice: {\n technique: found.techniqueId,\n board: mergedBoard,\n pencilmarks,\n solution: adjustPracticeSolution(mergedBoard, board.solution),\n hint_data: hintData,\n source_example_uuid: undefined,\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single-board technique extraction: walk one board to completion with
|
|
3
|
+
* repeated /solve calls, accumulating the techniques bitmask and max level,
|
|
4
|
+
* or stop early when a wanted technique shows up.
|
|
5
|
+
*
|
|
6
|
+
* The step logic is pure; `extractBoardTechniques` is the loop and takes the
|
|
7
|
+
* solve call as a function, so it works with any transport (the hooks pass a
|
|
8
|
+
* `useSolverSolveMutation` call).
|
|
9
|
+
*
|
|
10
|
+
* Ported from `sudojo_app/src/utils/admin/SingleBoardExtractor.ts`.
|
|
11
|
+
*/
|
|
12
|
+
import { type BaseResponse, type SolveData, type SolveOptions, type SolverBoard, type SolverHints, type TechniqueId } from '@sudobility/sudojo_types';
|
|
13
|
+
/** Give up on a board after this many /solve steps. */
|
|
14
|
+
export declare const MAX_EXTRACTION_ITERATIONS = 200;
|
|
15
|
+
/** Techniques and level found by walking a board to the end. */
|
|
16
|
+
export interface BoardExtractionResult {
|
|
17
|
+
/** Exact techniques bitmask (bit N = technique N); can exceed 2^53 */
|
|
18
|
+
readonly techniques: bigint;
|
|
19
|
+
readonly level: number;
|
|
20
|
+
}
|
|
21
|
+
/** Extraction stopped with an error (e.g. invalid pencilmarks). */
|
|
22
|
+
export interface BoardExtractionError {
|
|
23
|
+
readonly error: string;
|
|
24
|
+
}
|
|
25
|
+
/** The wanted technique was reached; the board state where it applies. */
|
|
26
|
+
export interface TechniqueExampleFound {
|
|
27
|
+
readonly type: 'found';
|
|
28
|
+
/** Solver-filled cells only (no givens); merge with the original board. */
|
|
29
|
+
readonly userInput: string;
|
|
30
|
+
readonly pencilmarks: string;
|
|
31
|
+
readonly techniqueId: TechniqueId;
|
|
32
|
+
/** Full `SolverHints` for the step, all steps included */
|
|
33
|
+
readonly hintData: SolverHints;
|
|
34
|
+
}
|
|
35
|
+
export type BoardExtractionOutcome = BoardExtractionResult | TechniqueExampleFound | BoardExtractionError;
|
|
36
|
+
/** Board state carried between /solve steps. */
|
|
37
|
+
export interface ExtractionState {
|
|
38
|
+
readonly userInput: string;
|
|
39
|
+
readonly pencilmarks: string;
|
|
40
|
+
readonly autoPencilmarks: boolean;
|
|
41
|
+
readonly techniquesBitfield: bigint;
|
|
42
|
+
readonly maxLevel: number;
|
|
43
|
+
}
|
|
44
|
+
/** One step's outcome: a new state, a find, an error, or null (no progress). */
|
|
45
|
+
export type ExtractionStepOutcome = ExtractionState | TechniqueExampleFound | BoardExtractionError | null;
|
|
46
|
+
/** Type guards for the outcome unions. */
|
|
47
|
+
export declare const isExtractionError: (value: BoardExtractionOutcome | ExtractionStepOutcome) => value is BoardExtractionError;
|
|
48
|
+
export declare const isTechniqueFound: (value: BoardExtractionOutcome | ExtractionStepOutcome) => value is TechniqueExampleFound;
|
|
49
|
+
/** Initial state: empty user grid, no pencilmarks, auto-pencilmarks off. */
|
|
50
|
+
export declare function createInitialExtractionState(): ExtractionState;
|
|
51
|
+
/**
|
|
52
|
+
* Solve request for the current state. Pencilmarks (and the auto-pencilmark
|
|
53
|
+
* flag) are only sent when the state has pencilmark content; `techniques`
|
|
54
|
+
* filters the solver to the wanted technique.
|
|
55
|
+
*/
|
|
56
|
+
export declare function buildExtractionSolveOptions(original: string, state: ExtractionState, desiredTechnique?: TechniqueId): SolveOptions;
|
|
57
|
+
/**
|
|
58
|
+
* Next state from a hint, or null when the solver's board did not change
|
|
59
|
+
* (no progress possible). Technique 0 (auto-pencilmark / correction hints)
|
|
60
|
+
* adds no bit; level 0 does not lower the max.
|
|
61
|
+
*/
|
|
62
|
+
export declare function computeNextExtractionState(state: ExtractionState, hints: SolverHints, boardData: SolverBoard | undefined | null): ExtractionState | null;
|
|
63
|
+
/** Final result of a state. */
|
|
64
|
+
export declare function extractionStateToResult(state: ExtractionState): BoardExtractionResult;
|
|
65
|
+
/**
|
|
66
|
+
* Interpret one /solve response:
|
|
67
|
+
* - no hint steps → null (no progress)
|
|
68
|
+
* - an "Invalid Pencilmarks" step → error
|
|
69
|
+
* - the wanted technique → `found` with the state *before* the step
|
|
70
|
+
* - otherwise → the next state (null when the board did not change)
|
|
71
|
+
*/
|
|
72
|
+
export declare function interpretSolveResponse(response: BaseResponse<SolveData>, state: ExtractionState, desiredTechnique?: TechniqueId): ExtractionStepOutcome;
|
|
73
|
+
/**
|
|
74
|
+
* A thrown /solve call: messages containing "Invalid" or "400" are errors,
|
|
75
|
+
* anything else (network, timeout) counts as no progress.
|
|
76
|
+
*/
|
|
77
|
+
export declare function interpretSolveError(err: unknown): BoardExtractionError | null;
|
|
78
|
+
/** Performs one /solve call. */
|
|
79
|
+
export type SolveFn = (options: SolveOptions) => Promise<BaseResponse<SolveData>>;
|
|
80
|
+
/**
|
|
81
|
+
* Walk `original` with /solve until it is filled or stuck. With
|
|
82
|
+
* `desiredTechnique`, the solver is filtered to it and the first matching
|
|
83
|
+
* hint returns `found`. Returns an error after
|
|
84
|
+
* {@link MAX_EXTRACTION_ITERATIONS} steps.
|
|
85
|
+
*/
|
|
86
|
+
export declare function extractBoardTechniques(solve: SolveFn, original: string, desiredTechnique?: TechniqueId): Promise<BoardExtractionOutcome>;
|
|
87
|
+
//# sourceMappingURL=extraction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extraction.d.ts","sourceRoot":"","sources":["../../src/admin/extraction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single-board technique extraction: walk one board to completion with
|
|
3
|
+
* repeated /solve calls, accumulating the techniques bitmask and max level,
|
|
4
|
+
* or stop early when a wanted technique shows up.
|
|
5
|
+
*
|
|
6
|
+
* The step logic is pure; `extractBoardTechniques` is the loop and takes the
|
|
7
|
+
* solve call as a function, so it works with any transport (the hooks pass a
|
|
8
|
+
* `useSolverSolveMutation` call).
|
|
9
|
+
*
|
|
10
|
+
* Ported from `sudojo_app/src/utils/admin/SingleBoardExtractor.ts`.
|
|
11
|
+
*/
|
|
12
|
+
import { EMPTY_BOARD, hasPencilmarkContent, techniqueIdsToBitmask, } from '@sudobility/sudojo_types';
|
|
13
|
+
import { errorMessage, hasInvalidPencilmarksStep, isPuzzleFilled, } from './boardStrings';
|
|
14
|
+
/** Give up on a board after this many /solve steps. */
|
|
15
|
+
export const MAX_EXTRACTION_ITERATIONS = 200;
|
|
16
|
+
/** Type guards for the outcome unions. */
|
|
17
|
+
export const isExtractionError = (value) => value !== null && 'error' in value;
|
|
18
|
+
export const isTechniqueFound = (value) => value !== null && 'type' in value && value.type === 'found';
|
|
19
|
+
/** Initial state: empty user grid, no pencilmarks, auto-pencilmarks off. */
|
|
20
|
+
export function createInitialExtractionState() {
|
|
21
|
+
return {
|
|
22
|
+
userInput: EMPTY_BOARD,
|
|
23
|
+
pencilmarks: '',
|
|
24
|
+
autoPencilmarks: false,
|
|
25
|
+
techniquesBitfield: 0n,
|
|
26
|
+
maxLevel: 0,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Solve request for the current state. Pencilmarks (and the auto-pencilmark
|
|
31
|
+
* flag) are only sent when the state has pencilmark content; `techniques`
|
|
32
|
+
* filters the solver to the wanted technique.
|
|
33
|
+
*/
|
|
34
|
+
export function buildExtractionSolveOptions(original, state, desiredTechnique) {
|
|
35
|
+
const hasPencilmarks = state.pencilmarks !== '' && hasPencilmarkContent(state.pencilmarks);
|
|
36
|
+
const options = {
|
|
37
|
+
original,
|
|
38
|
+
user: state.userInput,
|
|
39
|
+
autoPencilmarks: hasPencilmarks ? state.autoPencilmarks : false,
|
|
40
|
+
};
|
|
41
|
+
if (hasPencilmarks)
|
|
42
|
+
options.pencilmarks = state.pencilmarks;
|
|
43
|
+
if (desiredTechnique !== undefined) {
|
|
44
|
+
options.techniques = desiredTechnique.toString();
|
|
45
|
+
}
|
|
46
|
+
return options;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Next state from a hint, or null when the solver's board did not change
|
|
50
|
+
* (no progress possible). Technique 0 (auto-pencilmark / correction hints)
|
|
51
|
+
* adds no bit; level 0 does not lower the max.
|
|
52
|
+
*/
|
|
53
|
+
export function computeNextExtractionState(state, hints, boardData) {
|
|
54
|
+
if (!boardData?.user)
|
|
55
|
+
return null;
|
|
56
|
+
const pencilmarks = boardData.pencilmark?.numbers ?? '';
|
|
57
|
+
if (boardData.user === state.userInput && pencilmarks === state.pencilmarks) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
userInput: boardData.user,
|
|
62
|
+
pencilmarks,
|
|
63
|
+
autoPencilmarks: boardData.pencilmark?.autopencil ?? false,
|
|
64
|
+
techniquesBitfield: hints.technique > 0
|
|
65
|
+
? state.techniquesBitfield |
|
|
66
|
+
techniqueIdsToBitmask([hints.technique])
|
|
67
|
+
: state.techniquesBitfield,
|
|
68
|
+
maxLevel: hints.level > 0 ? Math.max(state.maxLevel, hints.level) : state.maxLevel,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Final result of a state. */
|
|
72
|
+
export function extractionStateToResult(state) {
|
|
73
|
+
return { techniques: state.techniquesBitfield, level: state.maxLevel };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Interpret one /solve response:
|
|
77
|
+
* - no hint steps → null (no progress)
|
|
78
|
+
* - an "Invalid Pencilmarks" step → error
|
|
79
|
+
* - the wanted technique → `found` with the state *before* the step
|
|
80
|
+
* - otherwise → the next state (null when the board did not change)
|
|
81
|
+
*/
|
|
82
|
+
export function interpretSolveResponse(response, state, desiredTechnique) {
|
|
83
|
+
const hints = response.data?.hints;
|
|
84
|
+
if (!response.success || !hints?.steps?.length)
|
|
85
|
+
return null;
|
|
86
|
+
if (hasInvalidPencilmarksStep(hints.steps)) {
|
|
87
|
+
return { error: 'Invalid pencilmarks detected' };
|
|
88
|
+
}
|
|
89
|
+
if (desiredTechnique !== undefined &&
|
|
90
|
+
hints.technique > 0 &&
|
|
91
|
+
hints.technique === desiredTechnique) {
|
|
92
|
+
return {
|
|
93
|
+
type: 'found',
|
|
94
|
+
userInput: state.userInput,
|
|
95
|
+
pencilmarks: state.pencilmarks,
|
|
96
|
+
techniqueId: desiredTechnique,
|
|
97
|
+
hintData: hints,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return computeNextExtractionState(state, hints, response.data?.board);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A thrown /solve call: messages containing "Invalid" or "400" are errors,
|
|
104
|
+
* anything else (network, timeout) counts as no progress.
|
|
105
|
+
*/
|
|
106
|
+
export function interpretSolveError(err) {
|
|
107
|
+
const message = errorMessage(err);
|
|
108
|
+
if (message.includes('Invalid') || message.includes('400')) {
|
|
109
|
+
return { error: message };
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Walk `original` with /solve until it is filled or stuck. With
|
|
115
|
+
* `desiredTechnique`, the solver is filtered to it and the first matching
|
|
116
|
+
* hint returns `found`. Returns an error after
|
|
117
|
+
* {@link MAX_EXTRACTION_ITERATIONS} steps.
|
|
118
|
+
*/
|
|
119
|
+
export async function extractBoardTechniques(solve, original, desiredTechnique) {
|
|
120
|
+
let state = createInitialExtractionState();
|
|
121
|
+
for (let i = 0; i < MAX_EXTRACTION_ITERATIONS; i++) {
|
|
122
|
+
if (isPuzzleFilled(original, state.userInput)) {
|
|
123
|
+
return extractionStateToResult(state);
|
|
124
|
+
}
|
|
125
|
+
let step;
|
|
126
|
+
try {
|
|
127
|
+
const response = await solve(buildExtractionSolveOptions(original, state, desiredTechnique));
|
|
128
|
+
step = interpretSolveResponse(response, state, desiredTechnique);
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
step = interpretSolveError(err);
|
|
132
|
+
}
|
|
133
|
+
if (step === null)
|
|
134
|
+
return extractionStateToResult(state);
|
|
135
|
+
if (isExtractionError(step) || isTechniqueFound(step))
|
|
136
|
+
return step;
|
|
137
|
+
state = step;
|
|
138
|
+
}
|
|
139
|
+
return { error: 'Max iterations exceeded' };
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=extraction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extraction.js","sourceRoot":"","sources":["../../src/admin/extraction.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Single-board technique extraction: walk one board to completion with\n * repeated /solve calls, accumulating the techniques bitmask and max level,\n * or stop early when a wanted technique shows up.\n *\n * The step logic is pure; `extractBoardTechniques` is the loop and takes the\n * solve call as a function, so it works with any transport (the hooks pass a\n * `useSolverSolveMutation` call).\n *\n * Ported from `sudojo_app/src/utils/admin/SingleBoardExtractor.ts`.\n */\n\nimport {\n type BaseResponse,\n EMPTY_BOARD,\n hasPencilmarkContent,\n type SolveData,\n type SolveOptions,\n type SolverBoard,\n type SolverHints,\n type TechniqueId,\n techniqueIdsToBitmask,\n} from '@sudobility/sudojo_types';\nimport {\n errorMessage,\n hasInvalidPencilmarksStep,\n isPuzzleFilled,\n} from './boardStrings';\n\n/** Give up on a board after this many /solve steps. */\nexport const MAX_EXTRACTION_ITERATIONS = 200;\n\n/** Techniques and level found by walking a board to the end. */\nexport interface BoardExtractionResult {\n /** Exact techniques bitmask (bit N = technique N); can exceed 2^53 */\n readonly techniques: bigint;\n readonly level: number;\n}\n\n/** Extraction stopped with an error (e.g. invalid pencilmarks). */\nexport interface BoardExtractionError {\n readonly error: string;\n}\n\n/** The wanted technique was reached; the board state where it applies. */\nexport interface TechniqueExampleFound {\n readonly type: 'found';\n /** Solver-filled cells only (no givens); merge with the original board. */\n readonly userInput: string;\n readonly pencilmarks: string;\n readonly techniqueId: TechniqueId;\n /** Full `SolverHints` for the step, all steps included */\n readonly hintData: SolverHints;\n}\n\nexport type BoardExtractionOutcome =\n | BoardExtractionResult\n | TechniqueExampleFound\n | BoardExtractionError;\n\n/** Board state carried between /solve steps. */\nexport interface ExtractionState {\n readonly userInput: string;\n readonly pencilmarks: string;\n readonly autoPencilmarks: boolean;\n readonly techniquesBitfield: bigint;\n readonly maxLevel: number;\n}\n\n/** One step's outcome: a new state, a find, an error, or null (no progress). */\nexport type ExtractionStepOutcome =\n | ExtractionState\n | TechniqueExampleFound\n | BoardExtractionError\n | null;\n\n/** Type guards for the outcome unions. */\nexport const isExtractionError = (\n value: BoardExtractionOutcome | ExtractionStepOutcome\n): value is BoardExtractionError => value !== null && 'error' in value;\n\nexport const isTechniqueFound = (\n value: BoardExtractionOutcome | ExtractionStepOutcome\n): value is TechniqueExampleFound =>\n value !== null && 'type' in value && value.type === 'found';\n\n/** Initial state: empty user grid, no pencilmarks, auto-pencilmarks off. */\nexport function createInitialExtractionState(): ExtractionState {\n return {\n userInput: EMPTY_BOARD,\n pencilmarks: '',\n autoPencilmarks: false,\n techniquesBitfield: 0n,\n maxLevel: 0,\n };\n}\n\n/**\n * Solve request for the current state. Pencilmarks (and the auto-pencilmark\n * flag) are only sent when the state has pencilmark content; `techniques`\n * filters the solver to the wanted technique.\n */\nexport function buildExtractionSolveOptions(\n original: string,\n state: ExtractionState,\n desiredTechnique?: TechniqueId\n): SolveOptions {\n const hasPencilmarks =\n state.pencilmarks !== '' && hasPencilmarkContent(state.pencilmarks);\n const options: SolveOptions = {\n original,\n user: state.userInput,\n autoPencilmarks: hasPencilmarks ? state.autoPencilmarks : false,\n };\n if (hasPencilmarks) options.pencilmarks = state.pencilmarks;\n if (desiredTechnique !== undefined) {\n options.techniques = desiredTechnique.toString();\n }\n return options;\n}\n\n/**\n * Next state from a hint, or null when the solver's board did not change\n * (no progress possible). Technique 0 (auto-pencilmark / correction hints)\n * adds no bit; level 0 does not lower the max.\n */\nexport function computeNextExtractionState(\n state: ExtractionState,\n hints: SolverHints,\n boardData: SolverBoard | undefined | null\n): ExtractionState | null {\n if (!boardData?.user) return null;\n\n const pencilmarks = boardData.pencilmark?.numbers ?? '';\n if (boardData.user === state.userInput && pencilmarks === state.pencilmarks) {\n return null;\n }\n\n return {\n userInput: boardData.user,\n pencilmarks,\n autoPencilmarks: boardData.pencilmark?.autopencil ?? false,\n techniquesBitfield:\n hints.technique > 0\n ? state.techniquesBitfield |\n techniqueIdsToBitmask([hints.technique as TechniqueId])\n : state.techniquesBitfield,\n maxLevel:\n hints.level > 0 ? Math.max(state.maxLevel, hints.level) : state.maxLevel,\n };\n}\n\n/** Final result of a state. */\nexport function extractionStateToResult(\n state: ExtractionState\n): BoardExtractionResult {\n return { techniques: state.techniquesBitfield, level: state.maxLevel };\n}\n\n/**\n * Interpret one /solve response:\n * - no hint steps → null (no progress)\n * - an \"Invalid Pencilmarks\" step → error\n * - the wanted technique → `found` with the state *before* the step\n * - otherwise → the next state (null when the board did not change)\n */\nexport function interpretSolveResponse(\n response: BaseResponse<SolveData>,\n state: ExtractionState,\n desiredTechnique?: TechniqueId\n): ExtractionStepOutcome {\n const hints = response.data?.hints;\n if (!response.success || !hints?.steps?.length) return null;\n\n if (hasInvalidPencilmarksStep(hints.steps)) {\n return { error: 'Invalid pencilmarks detected' };\n }\n\n if (\n desiredTechnique !== undefined &&\n hints.technique > 0 &&\n hints.technique === desiredTechnique\n ) {\n return {\n type: 'found',\n userInput: state.userInput,\n pencilmarks: state.pencilmarks,\n techniqueId: desiredTechnique,\n hintData: hints,\n };\n }\n\n return computeNextExtractionState(state, hints, response.data?.board);\n}\n\n/**\n * A thrown /solve call: messages containing \"Invalid\" or \"400\" are errors,\n * anything else (network, timeout) counts as no progress.\n */\nexport function interpretSolveError(err: unknown): BoardExtractionError | null {\n const message = errorMessage(err);\n if (message.includes('Invalid') || message.includes('400')) {\n return { error: message };\n }\n return null;\n}\n\n/** Performs one /solve call. */\nexport type SolveFn = (\n options: SolveOptions\n) => Promise<BaseResponse<SolveData>>;\n\n/**\n * Walk `original` with /solve until it is filled or stuck. With\n * `desiredTechnique`, the solver is filtered to it and the first matching\n * hint returns `found`. Returns an error after\n * {@link MAX_EXTRACTION_ITERATIONS} steps.\n */\nexport async function extractBoardTechniques(\n solve: SolveFn,\n original: string,\n desiredTechnique?: TechniqueId\n): Promise<BoardExtractionOutcome> {\n let state = createInitialExtractionState();\n\n for (let i = 0; i < MAX_EXTRACTION_ITERATIONS; i++) {\n if (isPuzzleFilled(original, state.userInput)) {\n return extractionStateToResult(state);\n }\n\n let step: ExtractionStepOutcome;\n try {\n const response = await solve(\n buildExtractionSolveOptions(original, state, desiredTechnique)\n );\n step = interpretSolveResponse(response, state, desiredTechnique);\n } catch (err) {\n step = interpretSolveError(err);\n }\n\n if (step === null) return extractionStateToResult(state);\n if (isExtractionError(step) || isTechniqueFound(step)) return step;\n state = step;\n }\n\n return { error: 'Max iterations exceeded' };\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin batch jobs (board generation, technique extraction, example
|
|
3
|
+
* creation) and admin stats. Network calls go only through sudojo_client
|
|
4
|
+
* hooks; see `adminApi.ts`.
|
|
5
|
+
*/
|
|
6
|
+
export type { AbortHandle, AdminJobOptions, AdminJobState } from './types';
|
|
7
|
+
export { ADMIN_JOB_LOG_LIMIT, ADMIN_TOKEN_REFRESH_INTERVAL, createAbortHandle, } from './types';
|
|
8
|
+
export { adjustPracticeSolution, describeTechniqueMask, formatTechniqueMaskHex, hasInvalidPencilmarksStep, isPuzzleFilled, isPuzzleSolved, levelToSave, mergeBoardWithUserInput, } from './boardStrings';
|
|
9
|
+
export type { BoardExtractionError, BoardExtractionOutcome, BoardExtractionResult, ExtractionState, ExtractionStepOutcome, SolveFn, TechniqueExampleFound, } from './extraction';
|
|
10
|
+
export { buildExtractionSolveOptions, computeNextExtractionState, createInitialExtractionState, extractBoardTechniques, extractionStateToResult, interpretSolveError, interpretSolveResponse, isExtractionError, isTechniqueFound, MAX_EXTRACTION_ITERATIONS, } from './extraction';
|
|
11
|
+
export type { ExtractionMismatch, GeneratedPuzzle, ParseGeneratedBoardResult, ValidatedBoard, } from './boardRules';
|
|
12
|
+
export { boardsAtLevelQuery, boardsWithoutTechniquesQuery, boardsWithTechniqueQuery, buildBoardTechniquesUpdate, buildValidatedBoard, compareExtractionWithSolver, parseGeneratedBoard, } from './boardRules';
|
|
13
|
+
export type { ExampleSaveRequests, TechniqueCounts } from './examples';
|
|
14
|
+
export { ADMIN_EXAMPLE_TARGET_PER_TECHNIQUE, ADMIN_TECHNIQUE_ORDER, BOARDS_PER_LEVEL_LIMIT, BOARDS_WITH_TECHNIQUE_LIMIT, buildExampleSaveRequests, buildTechniqueLevelMap, countForTechnique, hasReachedTarget, levelsToSearchForTechnique, normalizeTechniqueCounts, techniquesNeedingExamples, totalTechniqueCount, } from './examples';
|
|
15
|
+
export type { AdminApi } from './adminApi';
|
|
16
|
+
export { useAdminApi } from './adminApi';
|
|
17
|
+
export type { AdminJobContext, AdminTokenManager, BoardGenerationOptions, ExampleCreationCallbacks, ExampleCreationRequest, TechniqueExtractionOptions, } from './jobs';
|
|
18
|
+
export { createAdminTokenManager, fetchBoardsWithTechnique, fetchBoardWithoutTechniques, runBoardGeneration, runExampleCreation, runTechniqueExtraction, shouldRefreshToken, updateBoardTechniques, } from './jobs';
|
|
19
|
+
export type { GeneratedBoardInfo, UseBoardGeneratorOptions, UseBoardGeneratorResult, } from './useBoardGenerator';
|
|
20
|
+
export { useBoardGenerator } from './useBoardGenerator';
|
|
21
|
+
export type { UseTechniqueExtractorOptions, UseTechniqueExtractorResult, } from './useTechniqueExtractor';
|
|
22
|
+
export { useTechniqueExtractor } from './useTechniqueExtractor';
|
|
23
|
+
export type { UseExampleCreatorOptions, UseExampleCreatorResult, } from './useExampleCreator';
|
|
24
|
+
export { useExampleCreator } from './useExampleCreator';
|
|
25
|
+
export type { UseSingleBoardExtractorOptions, UseSingleBoardExtractorResult, } from './useSingleBoardExtractor';
|
|
26
|
+
export { useSingleBoardExtractor } from './useSingleBoardExtractor';
|
|
27
|
+
export type { UseBoardTechniquesUpdaterOptions, UseBoardTechniquesUpdaterResult, } from './useBoardTechniquesUpdater';
|
|
28
|
+
export { useBoardTechniquesUpdater } from './useBoardTechniquesUpdater';
|
|
29
|
+
export type { UseAdminStatsOptions, UseAdminStatsResult, } from './useAdminStats';
|
|
30
|
+
export { describeUpdateStatsResult, useAdminStats } from './useAdminStats';
|
|
31
|
+
export { describeRegenerateHintsResponse, describeRegenerateHintsResult, } from './regenerateHints';
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin batch jobs (board generation, technique extraction, example
|
|
3
|
+
* creation) and admin stats. Network calls go only through sudojo_client
|
|
4
|
+
* hooks; see `adminApi.ts`.
|
|
5
|
+
*/
|
|
6
|
+
export { ADMIN_JOB_LOG_LIMIT, ADMIN_TOKEN_REFRESH_INTERVAL, createAbortHandle, } from './types';
|
|
7
|
+
// Pure board-string and bitmask helpers
|
|
8
|
+
export { adjustPracticeSolution, describeTechniqueMask, formatTechniqueMaskHex, hasInvalidPencilmarksStep, isPuzzleFilled, isPuzzleSolved, levelToSave, mergeBoardWithUserInput, } from './boardStrings';
|
|
9
|
+
export { buildExtractionSolveOptions, computeNextExtractionState, createInitialExtractionState, extractBoardTechniques, extractionStateToResult, interpretSolveError, interpretSolveResponse, isExtractionError, isTechniqueFound, MAX_EXTRACTION_ITERATIONS, } from './extraction';
|
|
10
|
+
export { boardsAtLevelQuery, boardsWithoutTechniquesQuery, boardsWithTechniqueQuery, buildBoardTechniquesUpdate, buildValidatedBoard, compareExtractionWithSolver, parseGeneratedBoard, } from './boardRules';
|
|
11
|
+
export { ADMIN_EXAMPLE_TARGET_PER_TECHNIQUE, ADMIN_TECHNIQUE_ORDER, BOARDS_PER_LEVEL_LIMIT, BOARDS_WITH_TECHNIQUE_LIMIT, buildExampleSaveRequests, buildTechniqueLevelMap, countForTechnique, hasReachedTarget, levelsToSearchForTechnique, normalizeTechniqueCounts, techniquesNeedingExamples, totalTechniqueCount, } from './examples';
|
|
12
|
+
export { useAdminApi } from './adminApi';
|
|
13
|
+
export { createAdminTokenManager, fetchBoardsWithTechnique, fetchBoardWithoutTechniques, runBoardGeneration, runExampleCreation, runTechniqueExtraction, shouldRefreshToken, updateBoardTechniques, } from './jobs';
|
|
14
|
+
export { useBoardGenerator } from './useBoardGenerator';
|
|
15
|
+
export { useTechniqueExtractor } from './useTechniqueExtractor';
|
|
16
|
+
export { useExampleCreator } from './useExampleCreator';
|
|
17
|
+
export { useSingleBoardExtractor } from './useSingleBoardExtractor';
|
|
18
|
+
export { useBoardTechniquesUpdater } from './useBoardTechniquesUpdater';
|
|
19
|
+
export { describeUpdateStatsResult, useAdminStats } from './useAdminStats';
|
|
20
|
+
// Regenerate-hints status line
|
|
21
|
+
export { describeRegenerateHintsResponse, describeRegenerateHintsResult, } from './regenerateHints';
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EACL,mBAAmB,EACnB,4BAA4B,EAC5B,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,wCAAwC;AACxC,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,yBAAyB,EACzB,cAAc,EACd,cAAc,EACd,WAAW,EACX,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AAYxB,OAAO,EACL,2BAA2B,EAC3B,0BAA0B,EAC1B,4BAA4B,EAC5B,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AAStB,OAAO,EACL,kBAAkB,EAClB,4BAA4B,EAC5B,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EACnB,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAItB,OAAO,EACL,kCAAkC,EAClC,qBAAqB,EACrB,sBAAsB,EACtB,2BAA2B,EAC3B,wBAAwB,EACxB,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EAChB,0BAA0B,EAC1B,wBAAwB,EACxB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAWzC,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,2BAA2B,EAC3B,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,QAAQ,CAAC;AAQhB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAKxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAKhE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAKxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAKpE,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAKxE,OAAO,EAAE,yBAAyB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE3E,+BAA+B;AAC/B,OAAO,EACL,+BAA+B,EAC/B,6BAA6B,GAC9B,MAAM,mBAAmB,CAAC","sourcesContent":["/**\n * Admin batch jobs (board generation, technique extraction, example\n * creation) and admin stats. Network calls go only through sudojo_client\n * hooks; see `adminApi.ts`.\n */\n\n// Types and constants\nexport type { AbortHandle, AdminJobOptions, AdminJobState } from './types';\nexport {\n ADMIN_JOB_LOG_LIMIT,\n ADMIN_TOKEN_REFRESH_INTERVAL,\n createAbortHandle,\n} from './types';\n\n// Pure board-string and bitmask helpers\nexport {\n adjustPracticeSolution,\n describeTechniqueMask,\n formatTechniqueMaskHex,\n hasInvalidPencilmarksStep,\n isPuzzleFilled,\n isPuzzleSolved,\n levelToSave,\n mergeBoardWithUserInput,\n} from './boardStrings';\n\n// Single-board extraction\nexport type {\n BoardExtractionError,\n BoardExtractionOutcome,\n BoardExtractionResult,\n ExtractionState,\n ExtractionStepOutcome,\n SolveFn,\n TechniqueExampleFound,\n} from './extraction';\nexport {\n buildExtractionSolveOptions,\n computeNextExtractionState,\n createInitialExtractionState,\n extractBoardTechniques,\n extractionStateToResult,\n interpretSolveError,\n interpretSolveResponse,\n isExtractionError,\n isTechniqueFound,\n MAX_EXTRACTION_ITERATIONS,\n} from './extraction';\n\n// Board rules\nexport type {\n ExtractionMismatch,\n GeneratedPuzzle,\n ParseGeneratedBoardResult,\n ValidatedBoard,\n} from './boardRules';\nexport {\n boardsAtLevelQuery,\n boardsWithoutTechniquesQuery,\n boardsWithTechniqueQuery,\n buildBoardTechniquesUpdate,\n buildValidatedBoard,\n compareExtractionWithSolver,\n parseGeneratedBoard,\n} from './boardRules';\n\n// Example rules\nexport type { ExampleSaveRequests, TechniqueCounts } from './examples';\nexport {\n ADMIN_EXAMPLE_TARGET_PER_TECHNIQUE,\n ADMIN_TECHNIQUE_ORDER,\n BOARDS_PER_LEVEL_LIMIT,\n BOARDS_WITH_TECHNIQUE_LIMIT,\n buildExampleSaveRequests,\n buildTechniqueLevelMap,\n countForTechnique,\n hasReachedTarget,\n levelsToSearchForTechnique,\n normalizeTechniqueCounts,\n techniquesNeedingExamples,\n totalTechniqueCount,\n} from './examples';\n\n// Network surface\nexport type { AdminApi } from './adminApi';\nexport { useAdminApi } from './adminApi';\n\n// Framework-agnostic jobs\nexport type {\n AdminJobContext,\n AdminTokenManager,\n BoardGenerationOptions,\n ExampleCreationCallbacks,\n ExampleCreationRequest,\n TechniqueExtractionOptions,\n} from './jobs';\nexport {\n createAdminTokenManager,\n fetchBoardsWithTechnique,\n fetchBoardWithoutTechniques,\n runBoardGeneration,\n runExampleCreation,\n runTechniqueExtraction,\n shouldRefreshToken,\n updateBoardTechniques,\n} from './jobs';\n\n// Hooks\nexport type {\n GeneratedBoardInfo,\n UseBoardGeneratorOptions,\n UseBoardGeneratorResult,\n} from './useBoardGenerator';\nexport { useBoardGenerator } from './useBoardGenerator';\nexport type {\n UseTechniqueExtractorOptions,\n UseTechniqueExtractorResult,\n} from './useTechniqueExtractor';\nexport { useTechniqueExtractor } from './useTechniqueExtractor';\nexport type {\n UseExampleCreatorOptions,\n UseExampleCreatorResult,\n} from './useExampleCreator';\nexport { useExampleCreator } from './useExampleCreator';\nexport type {\n UseSingleBoardExtractorOptions,\n UseSingleBoardExtractorResult,\n} from './useSingleBoardExtractor';\nexport { useSingleBoardExtractor } from './useSingleBoardExtractor';\nexport type {\n UseBoardTechniquesUpdaterOptions,\n UseBoardTechniquesUpdaterResult,\n} from './useBoardTechniquesUpdater';\nexport { useBoardTechniquesUpdater } from './useBoardTechniquesUpdater';\nexport type {\n UseAdminStatsOptions,\n UseAdminStatsResult,\n} from './useAdminStats';\nexport { describeUpdateStatsResult, useAdminStats } from './useAdminStats';\n\n// Regenerate-hints status line\nexport {\n describeRegenerateHintsResponse,\n describeRegenerateHintsResult,\n} from './regenerateHints';\n"]}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin batch jobs as framework-agnostic async functions over an
|
|
3
|
+
* {@link AdminApi}. The hooks in this folder wrap them with React state; the
|
|
4
|
+
* functions themselves hold the business rules (token refresh cadence, retry
|
|
5
|
+
* delays, stop conditions, technique → level search fallback).
|
|
6
|
+
*
|
|
7
|
+
* Ported from `sudojo_app/src/utils/admin/{BoardGenerator,TechniqueExtractor,
|
|
8
|
+
* ExampleCreator,boardTechniquesApi}.ts`; progress messages are unchanged.
|
|
9
|
+
*/
|
|
10
|
+
import { type Board, type TechniqueId } from '@sudobility/sudojo_types';
|
|
11
|
+
import type { AdminApi } from './adminApi';
|
|
12
|
+
import { type TechniqueCounts } from './examples';
|
|
13
|
+
import { type AbortHandle } from './types';
|
|
14
|
+
/** Current admin token, refreshable mid-job. */
|
|
15
|
+
export interface AdminTokenManager {
|
|
16
|
+
readonly current: string;
|
|
17
|
+
/** Ask `getToken` again; keeps the old token if it fails or returns null. */
|
|
18
|
+
refresh(): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get the starting token. Returns null when `getToken` yields none (the job
|
|
22
|
+
* should report "Not authenticated"). Refreshes log "Token refreshed,
|
|
23
|
+
* continuing..." through `onProgress`; refresh failures only warn.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createAdminTokenManager(getToken: () => Promise<string | null>, onProgress: (message: string) => void): Promise<AdminTokenManager | null>;
|
|
26
|
+
/** True when the job should refresh its token before item `processed + 1`. */
|
|
27
|
+
export declare function shouldRefreshToken(processed: number, interval?: number): boolean;
|
|
28
|
+
/** What every job needs. */
|
|
29
|
+
export interface AdminJobContext {
|
|
30
|
+
api: AdminApi;
|
|
31
|
+
token: AdminTokenManager;
|
|
32
|
+
abort: AbortHandle;
|
|
33
|
+
onProgress: (message: string) => void;
|
|
34
|
+
onError: (error: Error) => void;
|
|
35
|
+
/** Wait between retries (default: setTimeout). Injectable for tests. */
|
|
36
|
+
delay?: (ms: number) => Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Set a board's techniques bitmask (sent as an exact string) and level.
|
|
40
|
+
* Returns false on any failure.
|
|
41
|
+
*/
|
|
42
|
+
export declare function updateBoardTechniques(api: AdminApi, token: string, boardUuid: string, techniques: bigint, level: number | null): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Boards with the technique's bit set (API `technique_bit` filter), any
|
|
45
|
+
* level. Returns [] on any failure.
|
|
46
|
+
*/
|
|
47
|
+
export declare function fetchBoardsWithTechnique(api: AdminApi, token: string, techniqueId: TechniqueId, limit: number): Promise<Board[]>;
|
|
48
|
+
/** The next board whose techniques were never extracted, or null. */
|
|
49
|
+
export declare function fetchBoardWithoutTechniques(api: AdminApi, token: string): Promise<Board | null>;
|
|
50
|
+
export interface BoardGenerationOptions {
|
|
51
|
+
symmetrical: boolean;
|
|
52
|
+
/** After each saved board. `techniques` is the exact bitmask. */
|
|
53
|
+
onBoardGenerated?: (count: number, level: number, techniques: bigint) => void;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Generate, validate and save boards until aborted or a save fails.
|
|
57
|
+
* Each board: /generate → /validate (source of truth for level, techniques,
|
|
58
|
+
* solution) → create. Generate/validate failures wait 1 s and retry.
|
|
59
|
+
* Returns the number of boards saved.
|
|
60
|
+
*/
|
|
61
|
+
export declare function runBoardGeneration(ctx: AdminJobContext, options: BoardGenerationOptions): Promise<number>;
|
|
62
|
+
export interface TechniqueExtractionOptions {
|
|
63
|
+
/**
|
|
64
|
+
* false: trust /validate and save its techniques (fast).
|
|
65
|
+
* true: walk the board with /solve, compare with /validate, stop on any
|
|
66
|
+
* mismatch, and save only matching results.
|
|
67
|
+
*/
|
|
68
|
+
testWithFrontend: boolean;
|
|
69
|
+
/** After each saved board. */
|
|
70
|
+
onBoardExtracted?: () => void;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Process boards without techniques one by one until none are left, aborted,
|
|
74
|
+
* or a critical error (save failure, mismatch, invalid pencilmarks).
|
|
75
|
+
* Returns the number of boards saved.
|
|
76
|
+
*/
|
|
77
|
+
export declare function runTechniqueExtraction(ctx: AdminJobContext, options: TechniqueExtractionOptions): Promise<number>;
|
|
78
|
+
/**
|
|
79
|
+
* - `all`: every technique in `techniqueOrder` below target, by bit then level.
|
|
80
|
+
* - `bit`: one technique; boards with its bit set, else the level search.
|
|
81
|
+
* - `level`: one technique; level search only (finds techniques whose bit is
|
|
82
|
+
* missing on boards).
|
|
83
|
+
*/
|
|
84
|
+
export type ExampleCreationRequest = {
|
|
85
|
+
mode: 'all';
|
|
86
|
+
currentCounts: TechniqueCounts;
|
|
87
|
+
targetPerTechnique?: number;
|
|
88
|
+
techniqueOrder?: readonly TechniqueId[];
|
|
89
|
+
} | {
|
|
90
|
+
mode: 'bit' | 'level';
|
|
91
|
+
techniqueId: TechniqueId;
|
|
92
|
+
currentCounts: TechniqueCounts;
|
|
93
|
+
targetPerTechnique?: number;
|
|
94
|
+
};
|
|
95
|
+
export interface ExampleCreationCallbacks {
|
|
96
|
+
/** After an example + practice pair is saved. */
|
|
97
|
+
onExampleSaved?: (techniqueId: TechniqueId, newCount: number) => void;
|
|
98
|
+
/** After a board whose bit lied was reset to techniques 0 / level null. */
|
|
99
|
+
onBoardTechniquesReset?: (boardUuid: string) => void;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Create technique examples (each with a linked practice). A board fetched by
|
|
103
|
+
* technique bit that turns out not to contain the technique is reset to
|
|
104
|
+
* techniques 0 so the extractor re-processes it. Any failed save stops the
|
|
105
|
+
* job (aborts). Returns the final per-technique counts.
|
|
106
|
+
*/
|
|
107
|
+
export declare function runExampleCreation(ctx: AdminJobContext, request: ExampleCreationRequest, callbacks?: ExampleCreationCallbacks): Promise<Record<number, number>>;
|
|
108
|
+
//# sourceMappingURL=jobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jobs.d.ts","sourceRoot":"","sources":["../../src/admin/jobs.ts"],"names":[],"mappings":"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"}
|