@sudobility/sudojo_client 0.0.111 → 0.0.113

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.
@@ -11,5 +11,6 @@ export { useSudojoChallenge, useSudojoChallenges, useSudojoCreateChallenge, useS
11
11
  export { useSudojoUser, useSudojoUserSubscription } from "./use-sudojo-users";
12
12
  export { useSudojoCreatePractice, useSudojoDeleteAllPractices, useSudojoRegeneratePracticeHints, useSudojoPracticeCounts, useSudojoRandomPractice, } from "./use-sudojo-practices";
13
13
  export { useSudojoBadgeDefinitions, useSudojoGamificationStats, useSudojoPlayFinish, useSudojoPlayStart, useSudojoPointHistory, } from "./use-sudojo-gamification";
14
+ export { useSudojoCommunities, useSudojoCreateCommunity, useSudojoDeleteCommunity, useSudojoUpdateCommunity, } from "./use-sudojo-communities";
14
15
  export { useSudojoInvalidation } from "./use-sudojo-invalidation";
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzE,YAAY,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAM7C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAMtD,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAM/B,OAAO,EACL,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAM9E,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAMhC,OAAO,EACL,yBAAyB,EACzB,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzE,YAAY,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAM7C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAMtD,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAM/B,OAAO,EACL,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAM9E,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAMhC,OAAO,EACL,yBAAyB,EACzB,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAMlC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -10,5 +10,6 @@ export { useSudojoChallenge, useSudojoChallenges, useSudojoCreateChallenge, useS
10
10
  export { useSudojoUser, useSudojoUserSubscription } from "./use-sudojo-users";
11
11
  export { useSudojoCreatePractice, useSudojoDeleteAllPractices, useSudojoRegeneratePracticeHints, useSudojoPracticeCounts, useSudojoRandomPractice, } from "./use-sudojo-practices";
12
12
  export { useSudojoBadgeDefinitions, useSudojoGamificationStats, useSudojoPlayFinish, useSudojoPlayStart, useSudojoPointHistory, } from "./use-sudojo-gamification";
13
+ export { useSudojoCommunities, useSudojoCreateCommunity, useSudojoDeleteCommunity, useSudojoUpdateCommunity, } from "./use-sudojo-communities";
13
14
  export { useSudojoInvalidation } from "./use-sudojo-invalidation";
14
15
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAM7C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAMtD,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAM/B,OAAO,EACL,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAM9E,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAMhC,OAAO,EACL,yBAAyB,EACzB,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC","sourcesContent":["/**\n * Sudojo API hooks for React\n */\n\n// ============================================================================\n// Query utilities\n// ============================================================================\n\nexport { createQueryKey, getServiceKeys, queryKeys } from \"./query-keys\";\nexport type { QueryKey } from \"./query-keys\";\nexport { STALE_TIMES } from \"./query-config\";\n\n// ============================================================================\n// Health hook\n// ============================================================================\n\nexport { useSudojoHealth } from \"./use-sudojo-health\";\n\n// ============================================================================\n// Level hooks\n// ============================================================================\n\nexport {\n useSudojoCreateLevel,\n useSudojoDeleteLevel,\n useSudojoLevel,\n useSudojoLevels,\n useSudojoUpdateLevel,\n} from \"./use-sudojo-levels\";\n\n// ============================================================================\n// Technique hooks\n// ============================================================================\n\nexport {\n useSudojoCreateTechnique,\n useSudojoDeleteTechnique,\n useSudojoTechnique,\n useSudojoTechniques,\n useSudojoUpdateTechnique,\n} from \"./use-sudojo-techniques\";\n\n// ============================================================================\n// Learning hooks\n// ============================================================================\n\nexport {\n useSudojoCreateLearning,\n useSudojoDeleteLearning,\n useSudojoLearning,\n useSudojoLearningItem,\n useSudojoUpdateLearning,\n} from \"./use-sudojo-learning\";\n\n// ============================================================================\n// Board hooks\n// ============================================================================\n\nexport {\n useSudojoBoard,\n useSudojoBoards,\n useSudojoCreateBoard,\n useSudojoDeleteBoard,\n useSudojoRandomBoard,\n useSudojoUpdateBoard,\n} from \"./use-sudojo-boards\";\n\n// ============================================================================\n// Daily hooks\n// ============================================================================\n\nexport {\n useSudojoCreateDaily,\n useSudojoDailies,\n useSudojoDaily,\n useSudojoDailyByDate,\n useSudojoDeleteDaily,\n useSudojoTodayDaily,\n useSudojoUpdateDaily,\n} from \"./use-sudojo-dailies\";\n\n// ============================================================================\n// Challenge hooks\n// ============================================================================\n\nexport {\n useSudojoChallenge,\n useSudojoChallenges,\n useSudojoCreateChallenge,\n useSudojoDeleteChallenge,\n useSudojoRandomChallenge,\n useSudojoUpdateChallenge,\n} from \"./use-sudojo-challenges\";\n\n// ============================================================================\n// User hooks\n// ============================================================================\n\nexport { useSudojoUser, useSudojoUserSubscription } from \"./use-sudojo-users\";\n\n// ============================================================================\n// Practice hooks\n// ============================================================================\n\nexport {\n useSudojoCreatePractice,\n useSudojoDeleteAllPractices,\n useSudojoRegeneratePracticeHints,\n useSudojoPracticeCounts,\n useSudojoRandomPractice,\n} from \"./use-sudojo-practices\";\n\n// ============================================================================\n// Gamification hooks (points, badges, levels, game sessions)\n// ============================================================================\n\nexport {\n useSudojoBadgeDefinitions,\n useSudojoGamificationStats,\n useSudojoPlayFinish,\n useSudojoPlayStart,\n useSudojoPointHistory,\n} from \"./use-sudojo-gamification\";\n\n// ============================================================================\n// Invalidation utilities\n// ============================================================================\n\nexport { useSudojoInvalidation } from \"./use-sudojo-invalidation\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAM7C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAMtD,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAM/B,OAAO,EACL,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAM9E,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAMhC,OAAO,EACL,yBAAyB,EACzB,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAMlC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC","sourcesContent":["/**\n * Sudojo API hooks for React\n */\n\n// ============================================================================\n// Query utilities\n// ============================================================================\n\nexport { createQueryKey, getServiceKeys, queryKeys } from \"./query-keys\";\nexport type { QueryKey } from \"./query-keys\";\nexport { STALE_TIMES } from \"./query-config\";\n\n// ============================================================================\n// Health hook\n// ============================================================================\n\nexport { useSudojoHealth } from \"./use-sudojo-health\";\n\n// ============================================================================\n// Level hooks\n// ============================================================================\n\nexport {\n useSudojoCreateLevel,\n useSudojoDeleteLevel,\n useSudojoLevel,\n useSudojoLevels,\n useSudojoUpdateLevel,\n} from \"./use-sudojo-levels\";\n\n// ============================================================================\n// Technique hooks\n// ============================================================================\n\nexport {\n useSudojoCreateTechnique,\n useSudojoDeleteTechnique,\n useSudojoTechnique,\n useSudojoTechniques,\n useSudojoUpdateTechnique,\n} from \"./use-sudojo-techniques\";\n\n// ============================================================================\n// Learning hooks\n// ============================================================================\n\nexport {\n useSudojoCreateLearning,\n useSudojoDeleteLearning,\n useSudojoLearning,\n useSudojoLearningItem,\n useSudojoUpdateLearning,\n} from \"./use-sudojo-learning\";\n\n// ============================================================================\n// Board hooks\n// ============================================================================\n\nexport {\n useSudojoBoard,\n useSudojoBoards,\n useSudojoCreateBoard,\n useSudojoDeleteBoard,\n useSudojoRandomBoard,\n useSudojoUpdateBoard,\n} from \"./use-sudojo-boards\";\n\n// ============================================================================\n// Daily hooks\n// ============================================================================\n\nexport {\n useSudojoCreateDaily,\n useSudojoDailies,\n useSudojoDaily,\n useSudojoDailyByDate,\n useSudojoDeleteDaily,\n useSudojoTodayDaily,\n useSudojoUpdateDaily,\n} from \"./use-sudojo-dailies\";\n\n// ============================================================================\n// Challenge hooks\n// ============================================================================\n\nexport {\n useSudojoChallenge,\n useSudojoChallenges,\n useSudojoCreateChallenge,\n useSudojoDeleteChallenge,\n useSudojoRandomChallenge,\n useSudojoUpdateChallenge,\n} from \"./use-sudojo-challenges\";\n\n// ============================================================================\n// User hooks\n// ============================================================================\n\nexport { useSudojoUser, useSudojoUserSubscription } from \"./use-sudojo-users\";\n\n// ============================================================================\n// Practice hooks\n// ============================================================================\n\nexport {\n useSudojoCreatePractice,\n useSudojoDeleteAllPractices,\n useSudojoRegeneratePracticeHints,\n useSudojoPracticeCounts,\n useSudojoRandomPractice,\n} from \"./use-sudojo-practices\";\n\n// ============================================================================\n// Gamification hooks (points, badges, levels, game sessions)\n// ============================================================================\n\nexport {\n useSudojoBadgeDefinitions,\n useSudojoGamificationStats,\n useSudojoPlayFinish,\n useSudojoPlayStart,\n useSudojoPointHistory,\n} from \"./use-sudojo-gamification\";\n\n// ============================================================================\n// Community hooks\n// ============================================================================\n\nexport {\n useSudojoCommunities,\n useSudojoCreateCommunity,\n useSudojoDeleteCommunity,\n useSudojoUpdateCommunity,\n} from \"./use-sudojo-communities\";\n\n// ============================================================================\n// Invalidation utilities\n// ============================================================================\n\nexport { useSudojoInvalidation } from \"./use-sudojo-invalidation\";\n"]}
@@ -8,5 +8,6 @@ export declare const STALE_TIMES: {
8
8
  readonly CHALLENGES: number;
9
9
  readonly USER: number;
10
10
  readonly USER_SUBSCRIPTION: number;
11
+ readonly COMMUNITIES: number;
11
12
  };
12
13
  //# sourceMappingURL=query-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-config.d.ts","sourceRoot":"","sources":["../../src/hooks/query-config.ts"],"names":[],"mappings":"AA2BA,eAAO,MAAM,WAAW;;;;;;;;;;CA2Bd,CAAC"}
1
+ {"version":3,"file":"query-config.d.ts","sourceRoot":"","sources":["../../src/hooks/query-config.ts"],"names":[],"mappings":"AA2BA,eAAO,MAAM,WAAW;;;;;;;;;;;CA8Bd,CAAC"}
@@ -8,5 +8,6 @@ export const STALE_TIMES = {
8
8
  CHALLENGES: 5 * 60 * 1000,
9
9
  USER: 5 * 60 * 1000,
10
10
  USER_SUBSCRIPTION: 2 * 60 * 1000,
11
+ COMMUNITIES: 10 * 60 * 1000,
11
12
  };
12
13
  //# sourceMappingURL=query-config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-config.js","sourceRoot":"","sources":["../../src/hooks/query-config.ts"],"names":[],"mappings":"AA2BA,MAAM,CAAC,MAAM,WAAW,GAAG;IAEzB,aAAa,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;IAG5B,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;IAGtB,UAAU,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;IAG1B,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;IAGxB,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;IAGrB,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;IAGtB,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;IAGzB,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;IAGnB,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;CACxB,CAAC","sourcesContent":["/**\n * Sudojo TanStack Query Configuration\n *\n * Provides stale time constants for Sudojo queries. Stale time determines how\n * long cached data is considered fresh before TanStack Query will refetch it\n * in the background on the next access.\n *\n * ## Design Rationale\n *\n * Stale times are chosen based on how frequently each resource type changes:\n * - **Static reference data** (levels, techniques, learning): 10 minutes.\n * These are admin-managed and rarely change during a user session.\n * - **Content data** (boards, dailies, challenges): 5 minutes.\n * Stable once created but new content may be added by admins.\n * - **User-specific data** (user info, subscriptions): 2-5 minutes.\n * Subscription status may change via in-app purchase flows.\n * - **Volatile data** (health): 1 minute. Used for connectivity checks.\n *\n * Some hooks override these defaults (e.g., random endpoints use `staleTime: 0`\n * to always fetch fresh data, and `useSudojoRandomBoard` uses `Infinity` to\n * only refetch on explicit user action).\n */\n\n/**\n * Default stale times (in milliseconds) for different types of Sudojo queries.\n * These values are used as the `staleTime` option in TanStack Query hooks.\n */\nexport const STALE_TIMES = {\n /** Health check - short cache since it monitors server availability (1 min). */\n HEALTH_STATUS: 1 * 60 * 1000, // 1 minute\n\n /** Levels list - admin-managed reference data that rarely changes (10 min). */\n LEVELS: 10 * 60 * 1000, // 10 minutes\n\n /** Techniques list - admin-managed reference data that rarely changes (10 min). */\n TECHNIQUES: 10 * 60 * 1000, // 10 minutes\n\n /** Learning content - admin-managed educational content that rarely changes (10 min). */\n LEARNING: 10 * 60 * 1000, // 10 minutes\n\n /** Boards - stable once created; new boards may be added by admins (5 min). */\n BOARDS: 5 * 60 * 1000, // 5 minutes\n\n /** Daily puzzles - one new puzzle per day; moderate cache (5 min). */\n DAILIES: 5 * 60 * 1000, // 5 minutes\n\n /** Challenges - stable once created; new challenges may be added (5 min). */\n CHALLENGES: 5 * 60 * 1000, // 5 minutes\n\n /** User info - admin status rarely changes during a session (5 min). */\n USER: 5 * 60 * 1000, // 5 minutes\n\n /** User subscription - may change via in-app purchase; shorter cache (2 min). */\n USER_SUBSCRIPTION: 2 * 60 * 1000, // 2 minutes\n} as const;\n"]}
1
+ {"version":3,"file":"query-config.js","sourceRoot":"","sources":["../../src/hooks/query-config.ts"],"names":[],"mappings":"AA2BA,MAAM,CAAC,MAAM,WAAW,GAAG;IAEzB,aAAa,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;IAG5B,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;IAGtB,UAAU,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;IAG1B,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;IAGxB,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;IAGrB,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;IAGtB,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;IAGzB,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;IAGnB,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;IAGhC,WAAW,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;CACnB,CAAC","sourcesContent":["/**\n * Sudojo TanStack Query Configuration\n *\n * Provides stale time constants for Sudojo queries. Stale time determines how\n * long cached data is considered fresh before TanStack Query will refetch it\n * in the background on the next access.\n *\n * ## Design Rationale\n *\n * Stale times are chosen based on how frequently each resource type changes:\n * - **Static reference data** (levels, techniques, learning): 10 minutes.\n * These are admin-managed and rarely change during a user session.\n * - **Content data** (boards, dailies, challenges): 5 minutes.\n * Stable once created but new content may be added by admins.\n * - **User-specific data** (user info, subscriptions): 2-5 minutes.\n * Subscription status may change via in-app purchase flows.\n * - **Volatile data** (health): 1 minute. Used for connectivity checks.\n *\n * Some hooks override these defaults (e.g., random endpoints use `staleTime: 0`\n * to always fetch fresh data, and `useSudojoRandomBoard` uses `Infinity` to\n * only refetch on explicit user action).\n */\n\n/**\n * Default stale times (in milliseconds) for different types of Sudojo queries.\n * These values are used as the `staleTime` option in TanStack Query hooks.\n */\nexport const STALE_TIMES = {\n /** Health check - short cache since it monitors server availability (1 min). */\n HEALTH_STATUS: 1 * 60 * 1000, // 1 minute\n\n /** Levels list - admin-managed reference data that rarely changes (10 min). */\n LEVELS: 10 * 60 * 1000, // 10 minutes\n\n /** Techniques list - admin-managed reference data that rarely changes (10 min). */\n TECHNIQUES: 10 * 60 * 1000, // 10 minutes\n\n /** Learning content - admin-managed educational content that rarely changes (10 min). */\n LEARNING: 10 * 60 * 1000, // 10 minutes\n\n /** Boards - stable once created; new boards may be added by admins (5 min). */\n BOARDS: 5 * 60 * 1000, // 5 minutes\n\n /** Daily puzzles - one new puzzle per day; moderate cache (5 min). */\n DAILIES: 5 * 60 * 1000, // 5 minutes\n\n /** Challenges - stable once created; new challenges may be added (5 min). */\n CHALLENGES: 5 * 60 * 1000, // 5 minutes\n\n /** User info - admin status rarely changes during a session (5 min). */\n USER: 5 * 60 * 1000, // 5 minutes\n\n /** User subscription - may change via in-app purchase; shorter cache (2 min). */\n USER_SUBSCRIPTION: 2 * 60 * 1000, // 2 minutes\n\n /** Communities - admin-managed reference data that rarely changes (10 min). */\n COMMUNITIES: 10 * 60 * 1000, // 10 minutes\n} as const;\n"]}
@@ -52,6 +52,11 @@ export declare const queryKeys: {
52
52
  readonly userSubscription: (userId: string) => readonly ["sudojo", "users", string, "subscription"];
53
53
  readonly practiceCounts: () => readonly ["sudojo", "practices", "counts"];
54
54
  readonly practiceRandom: (technique: number) => readonly ["sudojo", "practices", "random", number];
55
+ readonly communities: (filters?: {
56
+ language?: string | undefined;
57
+ }) => readonly ["sudojo", "communities", {
58
+ language?: string | undefined;
59
+ } | undefined];
55
60
  readonly gamificationStats: () => readonly ["sudojo", "gamification", "stats"];
56
61
  readonly gamificationBadges: () => readonly ["sudojo", "gamification", "badges"];
57
62
  readonly gamificationHistory: (options?: {
@@ -1 +1 @@
1
- {"version":3,"file":"query-keys.d.ts","sourceRoot":"","sources":["../../src/hooks/query-keys.ts"],"names":[],"mappings":"AAkCA,eAAO,MAAM,SAAS;;;;;gCAaH,MAAM;wCAIE;YAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE;oBAApB,MAAM,GAAG,SAAS;;wCAG5B,MAAM;sCAKR;YACnB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;YAC/B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;SACpC;wBAFa,MAAM,GAAG,SAAS;4BACd,MAAM,GAAG,SAAS;;sCAGf,MAAM;oCAKR;YAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE;oBAApB,MAAM,GAAG,SAAS;;yCAGvB;YAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE;oBAApB,MAAM,GAAG,SAAS;;+BAGtC,MAAM;;;qCAQA,MAAM;+BAGZ,MAAM;wCAIG;YACrB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;YAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;SACjC;oBAFS,MAAM,GAAG,SAAS;yBACb,MAAM,GAAG,SAAS;;6CAGL;YAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;YAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;SACjC;oBAFS,MAAM,GAAG,SAAS;yBACb,MAAM,GAAG,SAAS;;mCAGf,MAAM;gCAIT,MAAM;4CAEM,MAAM;;6CAOL,MAAM;;;iDAWF;YAAE,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE;oBAAzB,MAAM;qBAAW,MAAM;;;CAG3D,CAAC;AAMX,MAAM,MAAM,QAAQ,GAAG,SAAS,OAAO,EAAE,CAAC;AAgB1C,eAAO,MAAM,cAAc,GACzB,SAAS,MAAM,EACf,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,EAAE,KACrC,SAAS,OAAO,EAElB,CAAC;AAcF,eAAO,MAAM,cAAc,2BAE1B,CAAC"}
1
+ {"version":3,"file":"query-keys.d.ts","sourceRoot":"","sources":["../../src/hooks/query-keys.ts"],"names":[],"mappings":"AAkCA,eAAO,MAAM,SAAS;;;;;gCAaH,MAAM;wCAIE;YAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE;oBAApB,MAAM,GAAG,SAAS;;wCAG5B,MAAM;sCAKR;YACnB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;YAC/B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;SACpC;wBAFa,MAAM,GAAG,SAAS;4BACd,MAAM,GAAG,SAAS;;sCAGf,MAAM;oCAKR;YAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE;oBAApB,MAAM,GAAG,SAAS;;yCAGvB;YAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE;oBAApB,MAAM,GAAG,SAAS;;+BAGtC,MAAM;;;qCAQA,MAAM;+BAGZ,MAAM;wCAIG;YACrB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;YAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;SACjC;oBAFS,MAAM,GAAG,SAAS;yBACb,MAAM,GAAG,SAAS;;6CAGL;YAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;YAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;SACjC;oBAFS,MAAM,GAAG,SAAS;yBACb,MAAM,GAAG,SAAS;;mCAGf,MAAM;gCAIT,MAAM;4CAEM,MAAM;;6CAOL,MAAM;yCAKV;YAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE;uBAApB,MAAM,GAAG,SAAS;;;;iDAWvB;YAAE,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE;oBAAzB,MAAM;qBAAW,MAAM;;;CAG3D,CAAC;AAMX,MAAM,MAAM,QAAQ,GAAG,SAAS,OAAO,EAAE,CAAC;AAgB1C,eAAO,MAAM,cAAc,GACzB,SAAS,MAAM,EACf,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,EAAE,KACrC,SAAS,OAAO,EAElB,CAAC;AAcF,eAAO,MAAM,cAAc,2BAE1B,CAAC"}
@@ -23,6 +23,7 @@ export const queryKeys = {
23
23
  userSubscription: (userId) => [...sudojoBase(), "users", userId, "subscription"],
24
24
  practiceCounts: () => [...sudojoBase(), "practices", "counts"],
25
25
  practiceRandom: (technique) => [...sudojoBase(), "practices", "random", technique],
26
+ communities: (filters) => [...sudojoBase(), "communities", filters],
26
27
  gamificationStats: () => [...sudojoBase(), "gamification", "stats"],
27
28
  gamificationBadges: () => [...sudojoBase(), "gamification", "badges"],
28
29
  gamificationHistory: (options) => [...sudojoBase(), "gamification", "history", options],
@@ -1 +1 @@
1
- {"version":3,"file":"query-keys.js","sourceRoot":"","sources":["../../src/hooks/query-keys.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Query Key Factory for Sudojo TanStack Query\n *\n * Provides type-safe, consistent query keys for all Sudojo API endpoints.\n * Follows TanStack Query best practices for hierarchical key structure.\n *\n * ## Key Hierarchy\n *\n * All keys start with `[\"sudojo\"]` as the root, then branch by resource:\n * - `[\"sudojo\", \"levels\"]` - all levels\n * - `[\"sudojo\", \"levels\", 1]` - specific level\n * - `[\"sudojo\", \"boards\", { level: 3 }]` - boards filtered by level\n *\n * ## Invalidation Patterns\n *\n * Use the hierarchical structure for targeted invalidation:\n * - `queryKeys.sudojo.all()` invalidates ALL sudojo queries\n * - `queryKeys.sudojo.levels()` invalidates the levels list\n * - `queryKeys.sudojo.level(1)` invalidates only level 1\n *\n * For broader invalidation (e.g., all board queries including random):\n * ```ts\n * queryClient.invalidateQueries({ queryKey: [...queryKeys.sudojo.all(), \"boards\"] })\n * ```\n *\n * ## Filter Parameters\n *\n * Keys that accept filter objects (e.g., `boards`, `techniques`, `challenges`)\n * include the filter in the key so that different filter combinations produce\n * distinct cache entries.\n */\n\nconst sudojoBase = () => [\"sudojo\"] as const;\n\nexport const queryKeys = {\n sudojo: {\n /** Root key for all sudojo queries. Use for bulk invalidation. */\n all: sudojoBase,\n\n // Health\n /** Key for the server health check endpoint. */\n health: () => [...sudojoBase(), \"health\"] as const,\n\n // Levels\n /** Key for the levels list query. */\n levels: () => [...sudojoBase(), \"levels\"] as const,\n /** Key for a specific level query. @param level - Level number (1-12) */\n level: (level: number) => [...sudojoBase(), \"levels\", level] as const,\n\n // Techniques\n /** Key for the techniques list query, optionally filtered by level. */\n techniques: (filters?: { level?: number | undefined }) =>\n [...sudojoBase(), \"techniques\", filters] as const,\n /** Key for a specific technique query. @param technique - Technique number (>= 1) */\n technique: (technique: number) =>\n [...sudojoBase(), \"techniques\", technique] as const,\n\n // Learning\n /** Key for the learning entries list, optionally filtered by technique and/or language. */\n learning: (filters?: {\n technique?: number | undefined;\n language_code?: string | undefined;\n }) => [...sudojoBase(), \"learning\", filters] as const,\n /** Key for a specific learning item by UUID. */\n learningItem: (uuid: string) =>\n [...sudojoBase(), \"learning\", uuid] as const,\n\n // Boards\n /** Key for the boards list query, optionally filtered by level. */\n boards: (filters?: { level?: number | undefined }) =>\n [...sudojoBase(), \"boards\", filters] as const,\n /** Key for the random board query, optionally filtered by level. */\n boardRandom: (filters?: { level?: number | undefined }) =>\n [...sudojoBase(), \"boards\", \"random\", filters] as const,\n /** Key for a specific board by UUID. */\n board: (uuid: string) => [...sudojoBase(), \"boards\", uuid] as const,\n\n // Dailies\n /** Key for the dailies list query. */\n dailies: () => [...sudojoBase(), \"dailies\"] as const,\n /** Key for today's daily puzzle query. */\n dailyToday: () => [...sudojoBase(), \"dailies\", \"today\"] as const,\n /** Key for a daily puzzle by date. @param date - Date string in YYYY-MM-DD format */\n dailyByDate: (date: string) =>\n [...sudojoBase(), \"dailies\", \"date\", date] as const,\n /** Key for a specific daily by UUID. */\n daily: (uuid: string) => [...sudojoBase(), \"dailies\", uuid] as const,\n\n // Challenges\n /** Key for the challenges list, optionally filtered by level and/or difficulty. */\n challenges: (filters?: {\n level?: number | undefined;\n difficulty?: string | undefined;\n }) => [...sudojoBase(), \"challenges\", filters] as const,\n /** Key for the random challenge query, optionally filtered. */\n challengeRandom: (filters?: {\n level?: number | undefined;\n difficulty?: string | undefined;\n }) => [...sudojoBase(), \"challenges\", \"random\", filters] as const,\n /** Key for a specific challenge by UUID. */\n challenge: (uuid: string) => [...sudojoBase(), \"challenges\", uuid] as const,\n\n // Users\n /** Key for a user info query. @param userId - Firebase UID */\n user: (userId: string) => [...sudojoBase(), \"users\", userId] as const,\n /** Key for a user's subscription status query. @param userId - Firebase UID */\n userSubscription: (userId: string) =>\n [...sudojoBase(), \"users\", userId, \"subscription\"] as const,\n\n // Practices\n /** Key for practice counts across all techniques. */\n practiceCounts: () => [...sudojoBase(), \"practices\", \"counts\"] as const,\n /** Key for a random practice for a specific technique. */\n practiceRandom: (technique: number) =>\n [...sudojoBase(), \"practices\", \"random\", technique] as const,\n\n // Gamification\n /** Key for the user's gamification stats (points, level, badges). */\n gamificationStats: () =>\n [...sudojoBase(), \"gamification\", \"stats\"] as const,\n /** Key for badge definitions (public, no auth required). */\n gamificationBadges: () =>\n [...sudojoBase(), \"gamification\", \"badges\"] as const,\n /** Key for point transaction history with optional pagination. */\n gamificationHistory: (options?: { limit?: number; offset?: number }) =>\n [...sudojoBase(), \"gamification\", \"history\", options] as const,\n },\n} as const;\n\n/**\n * Utility type to extract query key from the factory.\n * All query keys are readonly arrays of unknown values.\n */\nexport type QueryKey = readonly unknown[];\n\n/**\n * Helper function to create a query key for custom or ad-hoc endpoints\n * that are not covered by the standard `queryKeys` factory.\n *\n * @param service - The service name (e.g., \"sudojo\", \"solver\")\n * @param parts - Additional key segments (strings, numbers, or filter objects)\n * @returns A readonly query key tuple\n *\n * @example\n * ```ts\n * const key = createQueryKey(\"sudojo\", \"custom-endpoint\", { filter: \"value\" });\n * // => [\"sudojo\", \"custom-endpoint\", { filter: \"value\" }]\n * ```\n */\nexport const createQueryKey = (\n service: string,\n ...parts: (string | number | object)[]\n): readonly unknown[] => {\n return [service, ...parts] as const;\n};\n\n/**\n * Helper to get the root key for all sudojo service queries.\n * Useful for bulk invalidation of the entire sudojo cache.\n *\n * @returns The root query key `[\"sudojo\"]`\n *\n * @example\n * ```ts\n * // Invalidate all sudojo queries at once\n * queryClient.invalidateQueries({ queryKey: getServiceKeys() });\n * ```\n */\nexport const getServiceKeys = () => {\n return queryKeys.sudojo.all();\n};\n"]}
1
+ {"version":3,"file":"query-keys.js","sourceRoot":"","sources":["../../src/hooks/query-keys.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Query Key Factory for Sudojo TanStack Query\n *\n * Provides type-safe, consistent query keys for all Sudojo API endpoints.\n * Follows TanStack Query best practices for hierarchical key structure.\n *\n * ## Key Hierarchy\n *\n * All keys start with `[\"sudojo\"]` as the root, then branch by resource:\n * - `[\"sudojo\", \"levels\"]` - all levels\n * - `[\"sudojo\", \"levels\", 1]` - specific level\n * - `[\"sudojo\", \"boards\", { level: 3 }]` - boards filtered by level\n *\n * ## Invalidation Patterns\n *\n * Use the hierarchical structure for targeted invalidation:\n * - `queryKeys.sudojo.all()` invalidates ALL sudojo queries\n * - `queryKeys.sudojo.levels()` invalidates the levels list\n * - `queryKeys.sudojo.level(1)` invalidates only level 1\n *\n * For broader invalidation (e.g., all board queries including random):\n * ```ts\n * queryClient.invalidateQueries({ queryKey: [...queryKeys.sudojo.all(), \"boards\"] })\n * ```\n *\n * ## Filter Parameters\n *\n * Keys that accept filter objects (e.g., `boards`, `techniques`, `challenges`)\n * include the filter in the key so that different filter combinations produce\n * distinct cache entries.\n */\n\nconst sudojoBase = () => [\"sudojo\"] as const;\n\nexport const queryKeys = {\n sudojo: {\n /** Root key for all sudojo queries. Use for bulk invalidation. */\n all: sudojoBase,\n\n // Health\n /** Key for the server health check endpoint. */\n health: () => [...sudojoBase(), \"health\"] as const,\n\n // Levels\n /** Key for the levels list query. */\n levels: () => [...sudojoBase(), \"levels\"] as const,\n /** Key for a specific level query. @param level - Level number (1-12) */\n level: (level: number) => [...sudojoBase(), \"levels\", level] as const,\n\n // Techniques\n /** Key for the techniques list query, optionally filtered by level. */\n techniques: (filters?: { level?: number | undefined }) =>\n [...sudojoBase(), \"techniques\", filters] as const,\n /** Key for a specific technique query. @param technique - Technique number (>= 1) */\n technique: (technique: number) =>\n [...sudojoBase(), \"techniques\", technique] as const,\n\n // Learning\n /** Key for the learning entries list, optionally filtered by technique and/or language. */\n learning: (filters?: {\n technique?: number | undefined;\n language_code?: string | undefined;\n }) => [...sudojoBase(), \"learning\", filters] as const,\n /** Key for a specific learning item by UUID. */\n learningItem: (uuid: string) =>\n [...sudojoBase(), \"learning\", uuid] as const,\n\n // Boards\n /** Key for the boards list query, optionally filtered by level. */\n boards: (filters?: { level?: number | undefined }) =>\n [...sudojoBase(), \"boards\", filters] as const,\n /** Key for the random board query, optionally filtered by level. */\n boardRandom: (filters?: { level?: number | undefined }) =>\n [...sudojoBase(), \"boards\", \"random\", filters] as const,\n /** Key for a specific board by UUID. */\n board: (uuid: string) => [...sudojoBase(), \"boards\", uuid] as const,\n\n // Dailies\n /** Key for the dailies list query. */\n dailies: () => [...sudojoBase(), \"dailies\"] as const,\n /** Key for today's daily puzzle query. */\n dailyToday: () => [...sudojoBase(), \"dailies\", \"today\"] as const,\n /** Key for a daily puzzle by date. @param date - Date string in YYYY-MM-DD format */\n dailyByDate: (date: string) =>\n [...sudojoBase(), \"dailies\", \"date\", date] as const,\n /** Key for a specific daily by UUID. */\n daily: (uuid: string) => [...sudojoBase(), \"dailies\", uuid] as const,\n\n // Challenges\n /** Key for the challenges list, optionally filtered by level and/or difficulty. */\n challenges: (filters?: {\n level?: number | undefined;\n difficulty?: string | undefined;\n }) => [...sudojoBase(), \"challenges\", filters] as const,\n /** Key for the random challenge query, optionally filtered. */\n challengeRandom: (filters?: {\n level?: number | undefined;\n difficulty?: string | undefined;\n }) => [...sudojoBase(), \"challenges\", \"random\", filters] as const,\n /** Key for a specific challenge by UUID. */\n challenge: (uuid: string) => [...sudojoBase(), \"challenges\", uuid] as const,\n\n // Users\n /** Key for a user info query. @param userId - Firebase UID */\n user: (userId: string) => [...sudojoBase(), \"users\", userId] as const,\n /** Key for a user's subscription status query. @param userId - Firebase UID */\n userSubscription: (userId: string) =>\n [...sudojoBase(), \"users\", userId, \"subscription\"] as const,\n\n // Practices\n /** Key for practice counts across all techniques. */\n practiceCounts: () => [...sudojoBase(), \"practices\", \"counts\"] as const,\n /** Key for a random practice for a specific technique. */\n practiceRandom: (technique: number) =>\n [...sudojoBase(), \"practices\", \"random\", technique] as const,\n\n // Communities\n /** Key for the communities list query, filtered by language. */\n communities: (filters?: { language?: string | undefined }) =>\n [...sudojoBase(), \"communities\", filters] as const,\n\n // Gamification\n /** Key for the user's gamification stats (points, level, badges). */\n gamificationStats: () =>\n [...sudojoBase(), \"gamification\", \"stats\"] as const,\n /** Key for badge definitions (public, no auth required). */\n gamificationBadges: () =>\n [...sudojoBase(), \"gamification\", \"badges\"] as const,\n /** Key for point transaction history with optional pagination. */\n gamificationHistory: (options?: { limit?: number; offset?: number }) =>\n [...sudojoBase(), \"gamification\", \"history\", options] as const,\n },\n} as const;\n\n/**\n * Utility type to extract query key from the factory.\n * All query keys are readonly arrays of unknown values.\n */\nexport type QueryKey = readonly unknown[];\n\n/**\n * Helper function to create a query key for custom or ad-hoc endpoints\n * that are not covered by the standard `queryKeys` factory.\n *\n * @param service - The service name (e.g., \"sudojo\", \"solver\")\n * @param parts - Additional key segments (strings, numbers, or filter objects)\n * @returns A readonly query key tuple\n *\n * @example\n * ```ts\n * const key = createQueryKey(\"sudojo\", \"custom-endpoint\", { filter: \"value\" });\n * // => [\"sudojo\", \"custom-endpoint\", { filter: \"value\" }]\n * ```\n */\nexport const createQueryKey = (\n service: string,\n ...parts: (string | number | object)[]\n): readonly unknown[] => {\n return [service, ...parts] as const;\n};\n\n/**\n * Helper to get the root key for all sudojo service queries.\n * Useful for bulk invalidation of the entire sudojo cache.\n *\n * @returns The root query key `[\"sudojo\"]`\n *\n * @example\n * ```ts\n * // Invalidate all sudojo queries at once\n * queryClient.invalidateQueries({ queryKey: getServiceKeys() });\n * ```\n */\nexport const getServiceKeys = () => {\n return queryKeys.sudojo.all();\n};\n"]}
@@ -0,0 +1,18 @@
1
+ import { UseMutationResult, UseQueryOptions, UseQueryResult } from "@tanstack/react-query";
2
+ import type { NetworkClient } from "@sudobility/types";
3
+ import type { BaseResponse, Community, CommunityCreateRequest, CommunityQueryParams, CommunityUpdateRequest } from "@sudobility/sudojo_types";
4
+ export declare const useSudojoCommunities: (networkClient: NetworkClient, baseUrl: string, token: string, queryParams?: CommunityQueryParams, options?: Omit<UseQueryOptions<BaseResponse<Community[]>>, "queryKey" | "queryFn">) => UseQueryResult<BaseResponse<Community[]>>;
5
+ export declare const useSudojoCreateCommunity: (networkClient: NetworkClient, baseUrl: string) => UseMutationResult<BaseResponse<Community>, Error, {
6
+ token: string;
7
+ data: CommunityCreateRequest;
8
+ }>;
9
+ export declare const useSudojoUpdateCommunity: (networkClient: NetworkClient, baseUrl: string) => UseMutationResult<BaseResponse<Community>, Error, {
10
+ token: string;
11
+ uuid: string;
12
+ data: CommunityUpdateRequest;
13
+ }>;
14
+ export declare const useSudojoDeleteCommunity: (networkClient: NetworkClient, baseUrl: string) => UseMutationResult<BaseResponse<Community>, Error, {
15
+ token: string;
16
+ uuid: string;
17
+ }>;
18
+ //# sourceMappingURL=use-sudojo-communities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-sudojo-communities.d.ts","sourceRoot":"","sources":["../../src/hooks/use-sudojo-communities.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,iBAAiB,EAGjB,eAAe,EACf,cAAc,EACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACT,sBAAsB,EACtB,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,0BAA0B,CAAC;AAmBlC,eAAO,MAAM,oBAAoB,GAC/B,eAAe,aAAa,EAC5B,SAAS,MAAM,EACf,OAAO,MAAM,EACb,cAAc,oBAAoB,EAClC,UAAU,IAAI,CACZ,eAAe,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC,EAC1C,UAAU,GAAG,SAAS,CACvB,KACA,cAAc,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,CAqB1C,CAAC;AAOF,eAAO,MAAM,wBAAwB,GACnC,eAAe,aAAa,EAC5B,SAAS,MAAM,KACd,iBAAiB,CAClB,YAAY,CAAC,SAAS,CAAC,EACvB,KAAK,EACL;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,sBAAsB,CAAA;CAAE,CAwBhD,CAAC;AAOF,eAAO,MAAM,wBAAwB,GACnC,eAAe,aAAa,EAC5B,SAAS,MAAM,KACd,iBAAiB,CAClB,YAAY,CAAC,SAAS,CAAC,EACvB,KAAK,EACL;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,sBAAsB,CAAA;CAAE,CA0B9D,CAAC;AAOF,eAAO,MAAM,wBAAwB,GACnC,eAAe,aAAa,EAC5B,SAAS,MAAM,KACd,iBAAiB,CAClB,YAAY,CAAC,SAAS,CAAC,EACvB,KAAK,EACL;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAkBhC,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { useCallback, useMemo } from "react";
2
+ import { useMutation, useQuery, useQueryClient, } from "@tanstack/react-query";
3
+ import { queryKeys } from "./query-keys";
4
+ import { STALE_TIMES } from "./query-config";
5
+ import { SudojoClient } from "../network/sudojo-client";
6
+ export const useSudojoCommunities = (networkClient, baseUrl, token, queryParams, options) => {
7
+ const client = useMemo(() => new SudojoClient(networkClient, baseUrl), [networkClient, baseUrl]);
8
+ const queryFn = useCallback(async () => {
9
+ return client.getCommunities(token, queryParams);
10
+ }, [client, token, queryParams]);
11
+ const isEnabled = options?.enabled !== undefined ? options.enabled : true;
12
+ return useQuery({
13
+ queryKey: queryKeys.sudojo.communities({
14
+ language: queryParams?.language ?? undefined,
15
+ }),
16
+ queryFn,
17
+ staleTime: STALE_TIMES.COMMUNITIES,
18
+ ...options,
19
+ enabled: isEnabled,
20
+ });
21
+ };
22
+ export const useSudojoCreateCommunity = (networkClient, baseUrl) => {
23
+ const client = useMemo(() => new SudojoClient(networkClient, baseUrl), [networkClient, baseUrl]);
24
+ const queryClient = useQueryClient();
25
+ return useMutation({
26
+ mutationFn: async ({ token, data, }) => {
27
+ return client.createCommunity(token, data);
28
+ },
29
+ onSuccess: () => {
30
+ queryClient.invalidateQueries({
31
+ queryKey: [...queryKeys.sudojo.all(), "communities"],
32
+ });
33
+ },
34
+ });
35
+ };
36
+ export const useSudojoUpdateCommunity = (networkClient, baseUrl) => {
37
+ const client = useMemo(() => new SudojoClient(networkClient, baseUrl), [networkClient, baseUrl]);
38
+ const queryClient = useQueryClient();
39
+ return useMutation({
40
+ mutationFn: async ({ token, uuid, data, }) => {
41
+ return client.updateCommunity(token, uuid, data);
42
+ },
43
+ onSuccess: () => {
44
+ queryClient.invalidateQueries({
45
+ queryKey: [...queryKeys.sudojo.all(), "communities"],
46
+ });
47
+ },
48
+ });
49
+ };
50
+ export const useSudojoDeleteCommunity = (networkClient, baseUrl) => {
51
+ const client = useMemo(() => new SudojoClient(networkClient, baseUrl), [networkClient, baseUrl]);
52
+ const queryClient = useQueryClient();
53
+ return useMutation({
54
+ mutationFn: async ({ token, uuid }) => {
55
+ return client.deleteCommunity(token, uuid);
56
+ },
57
+ onSuccess: () => {
58
+ queryClient.invalidateQueries({
59
+ queryKey: [...queryKeys.sudojo.all(), "communities"],
60
+ });
61
+ },
62
+ });
63
+ };
64
+ //# sourceMappingURL=use-sudojo-communities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-sudojo-communities.js","sourceRoot":"","sources":["../../src/hooks/use-sudojo-communities.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Hooks for Sudojo communities endpoints\n */\n\nimport { useCallback, useMemo } from \"react\";\nimport {\n useMutation,\n UseMutationResult,\n useQuery,\n useQueryClient,\n UseQueryOptions,\n UseQueryResult,\n} from \"@tanstack/react-query\";\nimport type { NetworkClient } from \"@sudobility/types\";\nimport type {\n BaseResponse,\n Community,\n CommunityCreateRequest,\n CommunityQueryParams,\n CommunityUpdateRequest,\n} from \"@sudobility/sudojo_types\";\nimport { queryKeys } from \"./query-keys\";\nimport { STALE_TIMES } from \"./query-config\";\nimport { SudojoClient } from \"../network/sudojo-client\";\n\n/**\n * Hook to fetch communities, optionally filtered by language.\n *\n * Communities are language-specific: different records per language.\n * The language filter is included in the query key so that switching\n * languages produces a separate cache entry and triggers a refetch.\n *\n * @param networkClient - Network client for making HTTP requests\n * @param baseUrl - Base URL of the Sudojo API\n * @param token - Firebase access token (optional for this public endpoint)\n * @param queryParams - Optional filter parameters (e.g., `{ language: \"en\" }`)\n * @param options - Additional TanStack Query options\n * @returns A UseQueryResult containing an array of Community objects\n */\nexport const useSudojoCommunities = (\n networkClient: NetworkClient,\n baseUrl: string,\n token: string,\n queryParams?: CommunityQueryParams,\n options?: Omit<\n UseQueryOptions<BaseResponse<Community[]>>,\n \"queryKey\" | \"queryFn\"\n >,\n): UseQueryResult<BaseResponse<Community[]>> => {\n const client = useMemo(\n () => new SudojoClient(networkClient, baseUrl),\n [networkClient, baseUrl],\n );\n\n const queryFn = useCallback(async (): Promise<BaseResponse<Community[]>> => {\n return client.getCommunities(token, queryParams);\n }, [client, token, queryParams]);\n\n const isEnabled = options?.enabled !== undefined ? options.enabled : true;\n\n return useQuery({\n queryKey: queryKeys.sudojo.communities({\n language: queryParams?.language ?? undefined,\n }),\n queryFn,\n staleTime: STALE_TIMES.COMMUNITIES,\n ...options,\n enabled: isEnabled,\n });\n};\n\n/**\n * Hook to create a new community. Requires admin authentication.\n *\n * On success, invalidates all community list queries.\n */\nexport const useSudojoCreateCommunity = (\n networkClient: NetworkClient,\n baseUrl: string,\n): UseMutationResult<\n BaseResponse<Community>,\n Error,\n { token: string; data: CommunityCreateRequest }\n> => {\n const client = useMemo(\n () => new SudojoClient(networkClient, baseUrl),\n [networkClient, baseUrl],\n );\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({\n token,\n data,\n }: {\n token: string;\n data: CommunityCreateRequest;\n }) => {\n return client.createCommunity(token, data);\n },\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: [...queryKeys.sudojo.all(), \"communities\"],\n });\n },\n });\n};\n\n/**\n * Hook to update an existing community. Requires admin authentication.\n *\n * On success, invalidates all community list queries.\n */\nexport const useSudojoUpdateCommunity = (\n networkClient: NetworkClient,\n baseUrl: string,\n): UseMutationResult<\n BaseResponse<Community>,\n Error,\n { token: string; uuid: string; data: CommunityUpdateRequest }\n> => {\n const client = useMemo(\n () => new SudojoClient(networkClient, baseUrl),\n [networkClient, baseUrl],\n );\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({\n token,\n uuid,\n data,\n }: {\n token: string;\n uuid: string;\n data: CommunityUpdateRequest;\n }) => {\n return client.updateCommunity(token, uuid, data);\n },\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: [...queryKeys.sudojo.all(), \"communities\"],\n });\n },\n });\n};\n\n/**\n * Hook to delete a community. Requires admin authentication.\n *\n * On success, invalidates all community list queries.\n */\nexport const useSudojoDeleteCommunity = (\n networkClient: NetworkClient,\n baseUrl: string,\n): UseMutationResult<\n BaseResponse<Community>,\n Error,\n { token: string; uuid: string }\n> => {\n const client = useMemo(\n () => new SudojoClient(networkClient, baseUrl),\n [networkClient, baseUrl],\n );\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ token, uuid }: { token: string; uuid: string }) => {\n return client.deleteCommunity(token, uuid);\n },\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: [...queryKeys.sudojo.all(), \"communities\"],\n });\n },\n });\n};\n"]}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { configureSolutionKey, createSudojoClient, isValidUUID, SudojoClient, validateUUID, } from "./network";
2
2
  export type { GenerateOptions, SolveOptions, ValidateOptions } from "./network";
3
3
  export { HintAccessDeniedError } from "./errors";
4
- export { createQueryKey, getServiceKeys, queryKeys, STALE_TIMES, useSudojoHealth, useSudojoCreateLevel, useSudojoDeleteLevel, useSudojoLevel, useSudojoLevels, useSudojoUpdateLevel, useSudojoCreateTechnique, useSudojoDeleteTechnique, useSudojoTechnique, useSudojoTechniques, useSudojoUpdateTechnique, useSudojoCreateLearning, useSudojoDeleteLearning, useSudojoLearning, useSudojoLearningItem, useSudojoUpdateLearning, useSudojoBoard, useSudojoBoards, useSudojoCreateBoard, useSudojoDeleteBoard, useSudojoRandomBoard, useSudojoUpdateBoard, useSudojoCreateDaily, useSudojoDailies, useSudojoDaily, useSudojoDailyByDate, useSudojoDeleteDaily, useSudojoTodayDaily, useSudojoUpdateDaily, useSudojoChallenge, useSudojoChallenges, useSudojoCreateChallenge, useSudojoDeleteChallenge, useSudojoRandomChallenge, useSudojoUpdateChallenge, useSudojoUser, useSudojoUserSubscription, useSudojoCreatePractice, useSudojoDeleteAllPractices, useSudojoRegeneratePracticeHints, useSudojoPracticeCounts, useSudojoRandomPractice, useSudojoBadgeDefinitions, useSudojoGamificationStats, useSudojoPlayFinish, useSudojoPlayStart, useSudojoPointHistory, useSudojoInvalidation, } from "./hooks";
4
+ export { createQueryKey, getServiceKeys, queryKeys, STALE_TIMES, useSudojoHealth, useSudojoCreateLevel, useSudojoDeleteLevel, useSudojoLevel, useSudojoLevels, useSudojoUpdateLevel, useSudojoCreateTechnique, useSudojoDeleteTechnique, useSudojoTechnique, useSudojoTechniques, useSudojoUpdateTechnique, useSudojoCreateLearning, useSudojoDeleteLearning, useSudojoLearning, useSudojoLearningItem, useSudojoUpdateLearning, useSudojoBoard, useSudojoBoards, useSudojoCreateBoard, useSudojoDeleteBoard, useSudojoRandomBoard, useSudojoUpdateBoard, useSudojoCreateDaily, useSudojoDailies, useSudojoDaily, useSudojoDailyByDate, useSudojoDeleteDaily, useSudojoTodayDaily, useSudojoUpdateDaily, useSudojoChallenge, useSudojoChallenges, useSudojoCreateChallenge, useSudojoDeleteChallenge, useSudojoRandomChallenge, useSudojoUpdateChallenge, useSudojoUser, useSudojoUserSubscription, useSudojoCreatePractice, useSudojoDeleteAllPractices, useSudojoRegeneratePracticeHints, useSudojoPracticeCounts, useSudojoRandomPractice, useSudojoCommunities, useSudojoCreateCommunity, useSudojoDeleteCommunity, useSudojoUpdateCommunity, useSudojoBadgeDefinitions, useSudojoGamificationStats, useSudojoPlayFinish, useSudojoPlayStart, useSudojoPointHistory, useSudojoInvalidation, } from "./hooks";
5
5
  export type { QueryKey } from "./hooks";
6
6
  export { getSolverServiceKeys, solverQueryKeys, SOLVER_STALE_TIMES, useSolverGenerate, useSolverSolve, useSolverValidate, } from "./solver";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAGhF,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGjD,OAAO,EAEL,cAAc,EACd,cAAc,EACd,SAAS,EACT,WAAW,EAEX,eAAe,EAEf,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,oBAAoB,EAEpB,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EAExB,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EAEvB,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EAEpB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EAEpB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EAExB,aAAa,EACb,yBAAyB,EAEzB,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,uBAAuB,EACvB,uBAAuB,EAEvB,yBAAyB,EACzB,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EAErB,qBAAqB,GACtB,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGxC,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,GAClB,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAGhF,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGjD,OAAO,EAEL,cAAc,EACd,cAAc,EACd,SAAS,EACT,WAAW,EAEX,eAAe,EAEf,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,oBAAoB,EAEpB,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EAExB,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EAEvB,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EAEpB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EAEpB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EAExB,aAAa,EACb,yBAAyB,EAEzB,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,uBAAuB,EACvB,uBAAuB,EAEvB,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EAExB,yBAAyB,EACzB,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EAErB,qBAAqB,GACtB,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGxC,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,GAClB,MAAM,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { configureSolutionKey, createSudojoClient, isValidUUID, SudojoClient, validateUUID, } from "./network";
2
2
  export { HintAccessDeniedError } from "./errors";
3
- export { createQueryKey, getServiceKeys, queryKeys, STALE_TIMES, useSudojoHealth, useSudojoCreateLevel, useSudojoDeleteLevel, useSudojoLevel, useSudojoLevels, useSudojoUpdateLevel, useSudojoCreateTechnique, useSudojoDeleteTechnique, useSudojoTechnique, useSudojoTechniques, useSudojoUpdateTechnique, useSudojoCreateLearning, useSudojoDeleteLearning, useSudojoLearning, useSudojoLearningItem, useSudojoUpdateLearning, useSudojoBoard, useSudojoBoards, useSudojoCreateBoard, useSudojoDeleteBoard, useSudojoRandomBoard, useSudojoUpdateBoard, useSudojoCreateDaily, useSudojoDailies, useSudojoDaily, useSudojoDailyByDate, useSudojoDeleteDaily, useSudojoTodayDaily, useSudojoUpdateDaily, useSudojoChallenge, useSudojoChallenges, useSudojoCreateChallenge, useSudojoDeleteChallenge, useSudojoRandomChallenge, useSudojoUpdateChallenge, useSudojoUser, useSudojoUserSubscription, useSudojoCreatePractice, useSudojoDeleteAllPractices, useSudojoRegeneratePracticeHints, useSudojoPracticeCounts, useSudojoRandomPractice, useSudojoBadgeDefinitions, useSudojoGamificationStats, useSudojoPlayFinish, useSudojoPlayStart, useSudojoPointHistory, useSudojoInvalidation, } from "./hooks";
3
+ export { createQueryKey, getServiceKeys, queryKeys, STALE_TIMES, useSudojoHealth, useSudojoCreateLevel, useSudojoDeleteLevel, useSudojoLevel, useSudojoLevels, useSudojoUpdateLevel, useSudojoCreateTechnique, useSudojoDeleteTechnique, useSudojoTechnique, useSudojoTechniques, useSudojoUpdateTechnique, useSudojoCreateLearning, useSudojoDeleteLearning, useSudojoLearning, useSudojoLearningItem, useSudojoUpdateLearning, useSudojoBoard, useSudojoBoards, useSudojoCreateBoard, useSudojoDeleteBoard, useSudojoRandomBoard, useSudojoUpdateBoard, useSudojoCreateDaily, useSudojoDailies, useSudojoDaily, useSudojoDailyByDate, useSudojoDeleteDaily, useSudojoTodayDaily, useSudojoUpdateDaily, useSudojoChallenge, useSudojoChallenges, useSudojoCreateChallenge, useSudojoDeleteChallenge, useSudojoRandomChallenge, useSudojoUpdateChallenge, useSudojoUser, useSudojoUserSubscription, useSudojoCreatePractice, useSudojoDeleteAllPractices, useSudojoRegeneratePracticeHints, useSudojoPracticeCounts, useSudojoRandomPractice, useSudojoCommunities, useSudojoCreateCommunity, useSudojoDeleteCommunity, useSudojoUpdateCommunity, useSudojoBadgeDefinitions, useSudojoGamificationStats, useSudojoPlayFinish, useSudojoPlayStart, useSudojoPointHistory, useSudojoInvalidation, } from "./hooks";
4
4
  export { getSolverServiceKeys, solverQueryKeys, SOLVER_STALE_TIMES, useSolverGenerate, useSolverSolve, useSolverValidate, } from "./solver";
5
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,YAAY,GACb,MAAM,WAAW,CAAC;AAInB,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGjD,OAAO,EAEL,cAAc,EACd,cAAc,EACd,SAAS,EACT,WAAW,EAEX,eAAe,EAEf,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,oBAAoB,EAEpB,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EAExB,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EAEvB,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EAEpB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EAEpB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EAExB,aAAa,EACb,yBAAyB,EAEzB,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,uBAAuB,EACvB,uBAAuB,EAEvB,yBAAyB,EACzB,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EAErB,qBAAqB,GACtB,MAAM,SAAS,CAAC;AAIjB,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,GAClB,MAAM,UAAU,CAAC","sourcesContent":["// Main library exports\nexport {\n configureSolutionKey,\n createSudojoClient,\n isValidUUID,\n SudojoClient,\n validateUUID,\n} from \"./network\";\nexport type { GenerateOptions, SolveOptions, ValidateOptions } from \"./network\";\n\n// Errors\nexport { HintAccessDeniedError } from \"./errors\";\n\n// React hooks\nexport {\n // Query utilities\n createQueryKey,\n getServiceKeys,\n queryKeys,\n STALE_TIMES,\n // Health\n useSudojoHealth,\n // Levels\n useSudojoCreateLevel,\n useSudojoDeleteLevel,\n useSudojoLevel,\n useSudojoLevels,\n useSudojoUpdateLevel,\n // Techniques\n useSudojoCreateTechnique,\n useSudojoDeleteTechnique,\n useSudojoTechnique,\n useSudojoTechniques,\n useSudojoUpdateTechnique,\n // Learning\n useSudojoCreateLearning,\n useSudojoDeleteLearning,\n useSudojoLearning,\n useSudojoLearningItem,\n useSudojoUpdateLearning,\n // Boards\n useSudojoBoard,\n useSudojoBoards,\n useSudojoCreateBoard,\n useSudojoDeleteBoard,\n useSudojoRandomBoard,\n useSudojoUpdateBoard,\n // Dailies\n useSudojoCreateDaily,\n useSudojoDailies,\n useSudojoDaily,\n useSudojoDailyByDate,\n useSudojoDeleteDaily,\n useSudojoTodayDaily,\n useSudojoUpdateDaily,\n // Challenges\n useSudojoChallenge,\n useSudojoChallenges,\n useSudojoCreateChallenge,\n useSudojoDeleteChallenge,\n useSudojoRandomChallenge,\n useSudojoUpdateChallenge,\n // Users\n useSudojoUser,\n useSudojoUserSubscription,\n // Practices\n useSudojoCreatePractice,\n useSudojoDeleteAllPractices,\n useSudojoRegeneratePracticeHints,\n useSudojoPracticeCounts,\n useSudojoRandomPractice,\n // Gamification\n useSudojoBadgeDefinitions,\n useSudojoGamificationStats,\n useSudojoPlayFinish,\n useSudojoPlayStart,\n useSudojoPointHistory,\n // Invalidation utilities\n useSudojoInvalidation,\n} from \"./hooks\";\nexport type { QueryKey } from \"./hooks\";\n\n// Solver hooks\nexport {\n getSolverServiceKeys,\n solverQueryKeys,\n SOLVER_STALE_TIMES,\n useSolverGenerate,\n useSolverSolve,\n useSolverValidate,\n} from \"./solver\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,YAAY,GACb,MAAM,WAAW,CAAC;AAInB,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGjD,OAAO,EAEL,cAAc,EACd,cAAc,EACd,SAAS,EACT,WAAW,EAEX,eAAe,EAEf,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,oBAAoB,EAEpB,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EAExB,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EAEvB,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EAEpB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EAEpB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EAExB,aAAa,EACb,yBAAyB,EAEzB,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,uBAAuB,EACvB,uBAAuB,EAEvB,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EAExB,yBAAyB,EACzB,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EAErB,qBAAqB,GACtB,MAAM,SAAS,CAAC;AAIjB,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,GAClB,MAAM,UAAU,CAAC","sourcesContent":["// Main library exports\nexport {\n configureSolutionKey,\n createSudojoClient,\n isValidUUID,\n SudojoClient,\n validateUUID,\n} from \"./network\";\nexport type { GenerateOptions, SolveOptions, ValidateOptions } from \"./network\";\n\n// Errors\nexport { HintAccessDeniedError } from \"./errors\";\n\n// React hooks\nexport {\n // Query utilities\n createQueryKey,\n getServiceKeys,\n queryKeys,\n STALE_TIMES,\n // Health\n useSudojoHealth,\n // Levels\n useSudojoCreateLevel,\n useSudojoDeleteLevel,\n useSudojoLevel,\n useSudojoLevels,\n useSudojoUpdateLevel,\n // Techniques\n useSudojoCreateTechnique,\n useSudojoDeleteTechnique,\n useSudojoTechnique,\n useSudojoTechniques,\n useSudojoUpdateTechnique,\n // Learning\n useSudojoCreateLearning,\n useSudojoDeleteLearning,\n useSudojoLearning,\n useSudojoLearningItem,\n useSudojoUpdateLearning,\n // Boards\n useSudojoBoard,\n useSudojoBoards,\n useSudojoCreateBoard,\n useSudojoDeleteBoard,\n useSudojoRandomBoard,\n useSudojoUpdateBoard,\n // Dailies\n useSudojoCreateDaily,\n useSudojoDailies,\n useSudojoDaily,\n useSudojoDailyByDate,\n useSudojoDeleteDaily,\n useSudojoTodayDaily,\n useSudojoUpdateDaily,\n // Challenges\n useSudojoChallenge,\n useSudojoChallenges,\n useSudojoCreateChallenge,\n useSudojoDeleteChallenge,\n useSudojoRandomChallenge,\n useSudojoUpdateChallenge,\n // Users\n useSudojoUser,\n useSudojoUserSubscription,\n // Practices\n useSudojoCreatePractice,\n useSudojoDeleteAllPractices,\n useSudojoRegeneratePracticeHints,\n useSudojoPracticeCounts,\n useSudojoRandomPractice,\n // Communities\n useSudojoCommunities,\n useSudojoCreateCommunity,\n useSudojoDeleteCommunity,\n useSudojoUpdateCommunity,\n // Gamification\n useSudojoBadgeDefinitions,\n useSudojoGamificationStats,\n useSudojoPlayFinish,\n useSudojoPlayStart,\n useSudojoPointHistory,\n // Invalidation utilities\n useSudojoInvalidation,\n} from \"./hooks\";\nexport type { QueryKey } from \"./hooks\";\n\n// Solver hooks\nexport {\n getSolverServiceKeys,\n solverQueryKeys,\n SOLVER_STALE_TIMES,\n useSolverGenerate,\n useSolverSolve,\n useSolverValidate,\n} from \"./solver\";\n"]}
@@ -1,5 +1,5 @@
1
1
  import type { NetworkClient, UserInfoResponse } from "@sudobility/types";
2
- import { type BadgeDefinition, type BaseResponse, type Board, type BoardCountsByTechniqueData, type BoardCountsData, type BoardCreateRequest, type BoardQueryParams, type BoardUpdateRequest, type Challenge, type ChallengeCreateRequest, type ChallengeQueryParams, type ChallengeUpdateRequest, type Daily, type DailyCreateRequest, type DailyUpdateRequest, type ExampleCountsData, type GameFinishRequest, type GameFinishResponse, type GameStartRequest, type GameStartResponse, type GamificationStats, type GenerateData, type GenerateOptions, type HealthCheckData, isValidUUID, type Learning, type LearningCreateRequest, type LearningQueryParams, type LearningUpdateRequest, type Level, type LevelCreateRequest, type LevelUpdateRequest, type PointTransaction, type PracticesBulkDeleteData, type PracticesRegenerateHintsData, type SolveData, type SolveOptions, type SubscriptionResult, type Technique, type TechniqueCreateRequest, type TechniqueExample, type TechniqueExampleCreateRequest, type TechniqueExampleQueryParams, type TechniquePractice, type TechniquePracticeCountItem, type TechniquePracticeCreateRequest, type TechniqueQueryParams, type TechniqueUpdateRequest, type UpdateStatsData, type ValidateData, type ValidateOptions, validateUUID } from "@sudobility/sudojo_types";
2
+ import { type BadgeDefinition, type BaseResponse, type Board, type BoardCountsByTechniqueData, type BoardCountsData, type BoardCreateRequest, type BoardQueryParams, type BoardUpdateRequest, type Challenge, type ChallengeCreateRequest, type ChallengeQueryParams, type ChallengeUpdateRequest, type Community, type CommunityCreateRequest, type CommunityQueryParams, type CommunityUpdateRequest, type Daily, type DailyCreateRequest, type DailyUpdateRequest, type ExampleCountsData, type GameFinishRequest, type GameFinishResponse, type GameStartRequest, type GameStartResponse, type GamificationStats, type GenerateData, type GenerateOptions, type HealthCheckData, isValidUUID, type Learning, type LearningCreateRequest, type LearningQueryParams, type LearningUpdateRequest, type Level, type LevelCreateRequest, type LevelUpdateRequest, type PointTransaction, type PracticesBulkDeleteData, type PracticesRegenerateHintsData, type SolveData, type SolveOptions, type SubscriptionResult, type Technique, type TechniqueCreateRequest, type TechniqueExample, type TechniqueExampleCreateRequest, type TechniqueExampleQueryParams, type TechniquePractice, type TechniquePracticeCountItem, type TechniquePracticeCreateRequest, type TechniqueQueryParams, type TechniqueUpdateRequest, type UpdateStatsData, type ValidateData, type ValidateOptions, validateUUID } from "@sudobility/sudojo_types";
3
3
  export type { SolveOptions, ValidateOptions, GenerateOptions };
4
4
  export declare function configureSolutionKey(keyHex: string): Promise<void>;
5
5
  export declare class SudojoClient {
@@ -63,6 +63,11 @@ export declare class SudojoClient {
63
63
  solverGenerate(token: string, options?: GenerateOptions): Promise<BaseResponse<GenerateData>>;
64
64
  playStart(token: string, data: GameStartRequest): Promise<BaseResponse<GameStartResponse>>;
65
65
  playFinish(token: string, data: GameFinishRequest): Promise<BaseResponse<GameFinishResponse>>;
66
+ getCommunities(token: string, queryParams?: CommunityQueryParams): Promise<BaseResponse<Community[]>>;
67
+ getCommunity(token: string, uuid: string): Promise<BaseResponse<Community>>;
68
+ createCommunity(token: string, data: CommunityCreateRequest): Promise<BaseResponse<Community>>;
69
+ updateCommunity(token: string, uuid: string, data: CommunityUpdateRequest): Promise<BaseResponse<Community>>;
70
+ deleteCommunity(token: string, uuid: string): Promise<BaseResponse<Community>>;
66
71
  getGamificationStats(token: string): Promise<BaseResponse<GamificationStats>>;
67
72
  getBadgeDefinitions(): Promise<BaseResponse<BadgeDefinition[]>>;
68
73
  getPointHistory(token: string, options?: {
@@ -1 +1 @@
1
- {"version":3,"file":"sudojo-client.d.ts","sourceRoot":"","sources":["../../src/network/sudojo-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sudojo-client.d.ts","sourceRoot":"","sources":["../../src/network/sudojo-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,0BAA0B,EAC/B,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACd,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,SAAS,EACd,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,KAAK,EACV,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,eAAe,EAEpB,WAAW,EACX,KAAK,QAAQ,EACb,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,KAAK,EACV,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,4BAA4B,EACjC,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACd,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,iBAAiB,EACtB,KAAK,0BAA0B,EAC/B,KAAK,8BAA8B,EACnC,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,YAAY,EACb,MAAM,0BAA0B,CAAC;AAIlC,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,CAAC;AAa/D,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYxE;AAkND,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,MAAM,CAAqC;gBAQvC,aAAa,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM;YAc3C,OAAO;IAuDf,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC;IAUnD,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC;IAMxD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAUpE,WAAW,CACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAQzB,WAAW,CACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAczB,WAAW,CACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAiBzB,aAAa,CACjB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,oBAAoB,GACjC,OAAO,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC;IAa/B,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAU7B,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAW7B,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAc7B,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAiB7B,WAAW,CACf,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,mBAAmB,GAChC,OAAO,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC;IAgB9B,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAQ5B,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAW5B,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAY5B,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAe5B,SAAS,CACb,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,gBAAgB,GAC7B,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC;IAyB3B,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,gBAAgB,GAC7B,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAiBzB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAQnE,WAAW,CACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAQzB,WAAW,CACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAYzB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAetE,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC;IAMzD,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAO1D,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAazB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAQnE,WAAW,CACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAQzB,WAAW,CACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAYzB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAetE,aAAa,CACjB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,oBAAoB,GACjC,OAAO,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC;IAgB/B,kBAAkB,CACtB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,oBAAoB,GACjC,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAgB7B,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAQ7B,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAW7B,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAY7B,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAe7B,OAAO,CACX,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;IAYpC,mBAAmB,CACvB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,OAAO,GACjB,OAAO,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC;IAmBtC,iBAAiB,CACrB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,0BAA0B,EAAE,CAAC,CAAC;IAUhD,iBAAiB,CACrB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;IAarC,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,8BAA8B,GACnC,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;IAcrC,kBAAkB,CACtB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC;IAc3C,uBAAuB,CAC3B,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,4BAA4B,CAAC,CAAC;IAkBhD,gBAAgB,CACpB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;IAUrC,WAAW,CACf,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,2BAA2B,GACxC,OAAO,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAgBtC,aAAa,CACjB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,6BAA6B,GAClC,OAAO,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;IAkBpC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC;IAWrE,yBAAyB,CAC7B,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,0BAA0B,CAAC,CAAC;IAW9C,iBAAiB,CACrB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC;IAiBzC,OAAO,CAAC,cAAc;IAsBhB,WAAW,CACf,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAkD7B,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;IAehC,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;IAehC,SAAS,CACb,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;IAcrC,UAAU,CACd,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC;IAetC,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,oBAAoB,GACjC,OAAO,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC;IAa/B,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAQ7B,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAW7B,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAY7B,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAkB7B,oBAAoB,CACxB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;IAUrC,mBAAmB,IAAI,OAAO,CAAC,YAAY,CAAC,eAAe,EAAE,CAAC,CAAC;IAS/D,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5C,OAAO,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC,CAAC;CAU7C;AAgBD,eAAO,MAAM,kBAAkB,GAC7B,eAAe,aAAa,EAC5B,SAAS,MAAM,KACd,YAEF,CAAC;AAgBF,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC"}
@@ -100,6 +100,8 @@ const createApiConfig = (baseUrl) => ({
100
100
  GAMIFICATION_STATS: "/api/v1/gamification/stats",
101
101
  GAMIFICATION_BADGES: "/api/v1/gamification/badges",
102
102
  GAMIFICATION_HISTORY: "/api/v1/gamification/history",
103
+ COMMUNITIES: "/api/v1/communities",
104
+ COMMUNITY: (uuid) => `/api/v1/communities/${uuid}`,
103
105
  },
104
106
  DEFAULT_HEADERS: {
105
107
  "Content-Type": "application/json",
@@ -560,6 +562,41 @@ export class SudojoClient {
560
562
  token,
561
563
  });
562
564
  }
565
+ async getCommunities(token, queryParams) {
566
+ const params = createURLSearchParams();
567
+ if (queryParams?.language !== undefined) {
568
+ params.append("language", queryParams.language);
569
+ }
570
+ const query = params.toString();
571
+ const endpoint = `${this.config.ENDPOINTS.COMMUNITIES}${query ? `?${query}` : ""}`;
572
+ return this.request(endpoint, { token });
573
+ }
574
+ async getCommunity(token, uuid) {
575
+ validateUUID(uuid);
576
+ return this.request(this.config.ENDPOINTS.COMMUNITY(uuid), { token });
577
+ }
578
+ async createCommunity(token, data) {
579
+ return this.request(this.config.ENDPOINTS.COMMUNITIES, {
580
+ method: "POST",
581
+ body: data,
582
+ token,
583
+ });
584
+ }
585
+ async updateCommunity(token, uuid, data) {
586
+ validateUUID(uuid);
587
+ return this.request(this.config.ENDPOINTS.COMMUNITY(uuid), {
588
+ method: "PUT",
589
+ body: data,
590
+ token,
591
+ });
592
+ }
593
+ async deleteCommunity(token, uuid) {
594
+ validateUUID(uuid);
595
+ return this.request(this.config.ENDPOINTS.COMMUNITY(uuid), {
596
+ method: "DELETE",
597
+ token,
598
+ });
599
+ }
563
600
  async getGamificationStats(token) {
564
601
  return this.request(this.config.ENDPOINTS.GAMIFICATION_STATS, { token });
565
602
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sudojo-client.js","sourceRoot":"","sources":["../../src/network/sudojo-client.ts"],"names":[],"mappings":"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","sourcesContent":["import type { NetworkClient, UserInfoResponse } from \"@sudobility/types\";\nimport {\n type BadgeDefinition,\n type BaseResponse,\n type Board,\n type BoardCountsByTechniqueData,\n type BoardCountsData,\n type BoardCreateRequest,\n type BoardQueryParams,\n type BoardUpdateRequest,\n type Challenge,\n type ChallengeCreateRequest,\n type ChallengeQueryParams,\n type ChallengeUpdateRequest,\n type Daily,\n type DailyCreateRequest,\n type DailyUpdateRequest,\n type ExampleCountsData,\n type GameFinishRequest,\n type GameFinishResponse,\n type GameStartRequest,\n type GameStartResponse,\n type GamificationStats,\n type GenerateData,\n type GenerateOptions,\n type HealthCheckData,\n type HintAccessDeniedResponse,\n isValidUUID,\n type Learning,\n type LearningCreateRequest,\n type LearningQueryParams,\n type LearningUpdateRequest,\n type Level,\n type LevelCreateRequest,\n type LevelUpdateRequest,\n type Optional,\n type PointTransaction,\n type PracticesBulkDeleteData,\n type PracticesRegenerateHintsData,\n type SolveData,\n type SolveOptions,\n type SubscriptionResult,\n type Technique,\n type TechniqueCreateRequest,\n type TechniqueExample,\n type TechniqueExampleCreateRequest,\n type TechniqueExampleQueryParams,\n type TechniquePractice,\n type TechniquePracticeCountItem,\n type TechniquePracticeCreateRequest,\n type TechniqueQueryParams,\n type TechniqueUpdateRequest,\n type UpdateStatsData,\n type ValidateData,\n type ValidateOptions,\n validateUUID,\n} from \"@sudobility/sudojo_types\";\nimport { HintAccessDeniedError } from \"../errors\";\n\n// Re-export option types for convenience\nexport type { SolveOptions, ValidateOptions, GenerateOptions };\n\n// =============================================================================\n// Solution Decryption\n// =============================================================================\n\nlet _solutionKey: CryptoKey | null = null;\n\n/**\n * Configure the symmetric key used to decrypt `solution` fields in API responses.\n * Call once at app startup with the hex-encoded 256-bit key.\n * If not called (or called with empty string), encrypted solutions pass through as-is.\n */\nexport async function configureSolutionKey(keyHex: string): Promise<void> {\n if (!keyHex) return;\n const hexPairs = keyHex.match(/.{2}/g);\n if (!hexPairs) return;\n const keyBytes = new Uint8Array(hexPairs.map((byte) => parseInt(byte, 16)));\n _solutionKey = await globalThis.crypto.subtle.importKey(\n \"raw\",\n keyBytes,\n \"AES-GCM\",\n false,\n [\"decrypt\"],\n );\n}\n\nasync function decryptSolution(encrypted: string): Promise<string> {\n if (!_solutionKey) return encrypted;\n\n const raw = globalThis.atob(encrypted.slice(4)); // strip \"enc:\" prefix\n const bytes = new Uint8Array(raw.length);\n for (let i = 0; i < raw.length; i++) {\n bytes[i] = raw.charCodeAt(i);\n }\n\n const nonce = bytes.slice(0, 12);\n const ciphertextWithTag = bytes.slice(12);\n\n const decrypted = await globalThis.crypto.subtle.decrypt(\n { name: \"AES-GCM\", iv: nonce },\n _solutionKey,\n ciphertextWithTag,\n );\n\n return new TextDecoder().decode(decrypted);\n}\n\nasync function decryptSolutionFields(data: unknown): Promise<unknown> {\n if (data === null || data === undefined) return data;\n\n if (Array.isArray(data)) {\n return Promise.all(data.map((item) => decryptSolutionFields(item)));\n }\n\n if (typeof data === \"object\") {\n const obj = data as Record<string, unknown>;\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n if (\n key === \"solution\" &&\n typeof obj[key] === \"string\" &&\n (obj[key] as string).startsWith(\"enc:\")\n ) {\n result[key] = await decryptSolution(obj[key] as string);\n } else {\n result[key] = await decryptSolutionFields(obj[key]);\n }\n }\n return result;\n }\n\n return data;\n}\n\n// =============================================================================\n// URL Search Params Utility\n// =============================================================================\n\n/**\n * Creates a lightweight URL search params builder.\n *\n * This is a custom implementation instead of the standard `URLSearchParams`\n * because the solver API requires a special encoding behavior: **commas must\n * NOT be percent-encoded** in pencilmark values. The standard `URLSearchParams`\n * encodes commas as `%2C`, which the Kotlin-based solver backend does not decode.\n *\n * @returns An object with `append(key, value)` and `toString()` methods\n *\n * @example\n * ```ts\n * const params = createURLSearchParams();\n * params.append(\"pencilmarks\", \"1,2,3\");\n * params.toString(); // \"pencilmarks=1,2,3\" (commas preserved)\n * ```\n */\nconst createURLSearchParams = () => {\n const params: Record<string, string[]> = {};\n return {\n append: (key: string, value: string) => {\n if (!params[key]) {\n params[key] = [];\n }\n params[key]?.push(value);\n },\n toString: () => {\n return Object.entries(params)\n .flatMap(([key, values]) =>\n values.map(\n (value) =>\n // Don't encode commas - the solver API expects literal commas in pencilmarks\n `${encodeURIComponent(key)}=${encodeURIComponent(value).replace(/%2C/g, \",\")}`,\n ),\n )\n .join(\"&\");\n },\n };\n};\n\n// =============================================================================\n// API Configuration Factory\n// =============================================================================\n\nconst createApiConfig = (baseUrl: string) => ({\n BASE_URL: baseUrl,\n ENDPOINTS: {\n // Health\n HEALTH: \"/\",\n\n // Levels\n LEVELS: \"/api/v1/levels\",\n LEVEL: (level: number) => `/api/v1/levels/${level}`,\n\n // Techniques\n TECHNIQUES: \"/api/v1/techniques\",\n TECHNIQUE: (technique: number) => `/api/v1/techniques/${technique}`,\n\n // Learning\n LEARNING: \"/api/v1/learning\",\n LEARNING_ITEM: (uuid: string) => `/api/v1/learning/${uuid}`,\n\n // Boards\n BOARDS: \"/api/v1/boards\",\n BOARDS_RANDOM: \"/api/v1/boards/random\",\n BOARD: (uuid: string) => `/api/v1/boards/${uuid}`,\n\n // Dailies\n DAILIES: \"/api/v1/dailies\",\n DAILIES_TODAY: \"/api/v1/dailies/today\",\n DAILIES_DATE: (date: string) => `/api/v1/dailies/date/${date}`,\n DAILY: (uuid: string) => `/api/v1/dailies/${uuid}`,\n\n // Challenges\n CHALLENGES: \"/api/v1/challenges\",\n CHALLENGES_RANDOM: \"/api/v1/challenges/random\",\n CHALLENGE: (uuid: string) => `/api/v1/challenges/${uuid}`,\n\n // Users\n USER: (userId: string) => `/api/v1/users/${userId}`,\n USER_SUBSCRIPTIONS: (userId: string) =>\n `/api/v1/users/${userId}/subscriptions`,\n\n // Solver\n SOLVER_SOLVE: \"/api/v1/solver/solve\",\n SOLVER_VALIDATE: \"/api/v1/solver/validate\",\n SOLVER_GENERATE: \"/api/v1/solver/generate\",\n\n // Practices\n PRACTICES: \"/api/v1/practices\",\n PRACTICES_COUNTS: \"/api/v1/practices/counts\",\n PRACTICE_RANDOM: (technique: number) =>\n `/api/v1/practices/technique/${technique}/random`,\n\n // Examples\n EXAMPLES: \"/api/v1/examples\",\n EXAMPLES_COUNTS: \"/api/v1/examples/counts\",\n\n // Boards counts\n BOARDS_COUNTS: \"/api/v1/boards/counts\",\n BOARDS_COUNTS_BY_TECHNIQUE: \"/api/v1/boards/counts/by-technique\",\n BOARDS_UPDATE_STATS: \"/api/v1/boards/update-stats\",\n\n // Play (game sessions)\n PLAY_START: \"/api/v1/play/start\",\n PLAY_FINISH: \"/api/v1/play/finish\",\n\n // Gamification\n GAMIFICATION_STATS: \"/api/v1/gamification/stats\",\n GAMIFICATION_BADGES: \"/api/v1/gamification/badges\",\n GAMIFICATION_HISTORY: \"/api/v1/gamification/history\",\n },\n DEFAULT_HEADERS: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n});\n\n// =============================================================================\n// Sudojo Client Class\n// =============================================================================\n\n/**\n * Type-safe client for the Sudojo REST API.\n *\n * Provides methods for all Sudojo API endpoints including levels, techniques,\n * boards, dailies, challenges, users, solver, practices, examples, and gamification.\n *\n * ## Error Handling\n *\n * All methods throw errors on failure:\n * - **Network errors**: Thrown by the underlying `NetworkClient` (e.g., connection refused, timeout)\n * - **Empty response**: Throws `Error(\"No data received from server\")` when the server returns no data\n * - **Validation errors**: Thrown before the request for invalid parameters (e.g., invalid UUID, level out of range)\n * - **HTTP 402**: `solverSolve()` throws {@link HintAccessDeniedError} when the hint level exceeds the user's tier\n * - **Other HTTP errors**: Depend on the `NetworkClient` implementation - typically thrown as generic `Error`\n *\n * ## Authentication\n *\n * Most methods accept a `token` parameter (Firebase ID token). The token is sent\n * as a `Bearer` token in the `Authorization` header. Public endpoints (health,\n * levels, boards, etc.) accept but do not require a token. User-specific endpoints\n * (subscriptions, gamification) require a valid token.\n *\n * ## Usage\n *\n * ```typescript\n * const client = new SudojoClient(networkClient, \"https://api.sudojo.com\");\n * const levels = await client.getLevels(token);\n * const daily = await client.getDailyByDate(token, \"2024-01-15\");\n * ```\n */\nexport class SudojoClient {\n private baseUrl: string;\n private headers: Record<string, string>;\n private networkClient: NetworkClient;\n private config: ReturnType<typeof createApiConfig>;\n\n /**\n * Create a SudojoClient instance.\n *\n * @param networkClient - Network client for making HTTP requests (from `@sudobility/types`)\n * @param baseUrl - Base URL for the Sudojo API (e.g., \"https://api.sudojo.com\")\n */\n constructor(networkClient: NetworkClient, baseUrl: string) {\n this.config = createApiConfig(baseUrl);\n this.baseUrl = this.config.BASE_URL;\n this.networkClient = networkClient;\n\n this.headers = {\n ...this.config.DEFAULT_HEADERS,\n };\n }\n\n // ===========================================================================\n // Private Request Method\n // ===========================================================================\n\n private async request<T>(\n endpoint: string,\n options: {\n method?: Optional<\"GET\" | \"POST\" | \"PUT\" | \"DELETE\">;\n body?: Optional<Record<string, unknown>>;\n headers?: Optional<Record<string, string>>;\n token?: Optional<string>;\n timeout?: Optional<number>;\n } = {},\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n\n const requestHeaders: Record<string, string> = {\n ...this.headers,\n ...options.headers,\n };\n\n // Add authorization header if token is provided\n if (options.token) {\n requestHeaders[\"Authorization\"] = `Bearer ${options.token}`;\n }\n\n const requestOptions: {\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n headers: Record<string, string>;\n body?: string;\n timeout?: number;\n } = {\n method: options.method || \"GET\",\n headers: requestHeaders,\n };\n\n // Add body for POST/PUT/DELETE requests\n if (options.body && options.method !== \"GET\") {\n requestOptions.body = JSON.stringify(options.body);\n }\n\n // Add timeout if specified\n if (options.timeout) {\n requestOptions.timeout = options.timeout;\n }\n\n const response = await this.networkClient.request<T>(url, requestOptions);\n\n if (response.data === undefined) {\n throw new Error(\"No data received from server\");\n }\n\n return (await decryptSolutionFields(response.data)) as T;\n }\n\n // ===========================================================================\n // Health Check\n // ===========================================================================\n\n async getHealth(): Promise<BaseResponse<HealthCheckData>> {\n return this.request<BaseResponse<HealthCheckData>>(\n this.config.ENDPOINTS.HEALTH,\n );\n }\n\n // ===========================================================================\n // Levels\n // ===========================================================================\n\n async getLevels(token: string): Promise<BaseResponse<Level[]>> {\n return this.request<BaseResponse<Level[]>>(this.config.ENDPOINTS.LEVELS, {\n token,\n });\n }\n\n async getLevel(token: string, level: number): Promise<BaseResponse<Level>> {\n if (level < 1 || level > 12) {\n throw new Error(`Invalid level: ${level}. Expected 1-12`);\n }\n return this.request<BaseResponse<Level>>(\n this.config.ENDPOINTS.LEVEL(level),\n { token },\n );\n }\n\n async createLevel(\n token: string,\n data: LevelCreateRequest,\n ): Promise<BaseResponse<Level>> {\n return this.request<BaseResponse<Level>>(this.config.ENDPOINTS.LEVELS, {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n });\n }\n\n async updateLevel(\n token: string,\n level: number,\n data: LevelUpdateRequest,\n ): Promise<BaseResponse<Level>> {\n if (level < 1 || level > 12) {\n throw new Error(`Invalid level: ${level}. Expected 1-12`);\n }\n return this.request<BaseResponse<Level>>(\n this.config.ENDPOINTS.LEVEL(level),\n {\n method: \"PUT\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async deleteLevel(\n token: string,\n level: number,\n ): Promise<BaseResponse<Level>> {\n if (level < 1 || level > 12) {\n throw new Error(`Invalid level: ${level}. Expected 1-12`);\n }\n return this.request<BaseResponse<Level>>(\n this.config.ENDPOINTS.LEVEL(level),\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Techniques\n // ===========================================================================\n\n async getTechniques(\n token: string,\n queryParams?: TechniqueQueryParams,\n ): Promise<BaseResponse<Technique[]>> {\n const params = createURLSearchParams();\n\n if (queryParams?.level !== undefined) {\n params.append(\"level\", String(queryParams.level));\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.TECHNIQUES}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<Technique[]>>(endpoint, { token });\n }\n\n async getTechnique(\n token: string,\n technique: number,\n ): Promise<BaseResponse<Technique>> {\n if (technique < 1) {\n throw new Error(`Invalid technique: ${technique}. Expected >= 1`);\n }\n return this.request<BaseResponse<Technique>>(\n this.config.ENDPOINTS.TECHNIQUE(technique),\n { token },\n );\n }\n\n async createTechnique(\n token: string,\n data: TechniqueCreateRequest,\n ): Promise<BaseResponse<Technique>> {\n return this.request<BaseResponse<Technique>>(\n this.config.ENDPOINTS.TECHNIQUES,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async updateTechnique(\n token: string,\n technique: number,\n data: TechniqueUpdateRequest,\n ): Promise<BaseResponse<Technique>> {\n if (technique < 1) {\n throw new Error(`Invalid technique: ${technique}. Expected >= 1`);\n }\n return this.request<BaseResponse<Technique>>(\n this.config.ENDPOINTS.TECHNIQUE(technique),\n {\n method: \"PUT\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async deleteTechnique(\n token: string,\n technique: number,\n ): Promise<BaseResponse<Technique>> {\n if (technique < 1) {\n throw new Error(`Invalid technique: ${technique}. Expected >= 1`);\n }\n return this.request<BaseResponse<Technique>>(\n this.config.ENDPOINTS.TECHNIQUE(technique),\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Learning\n // ===========================================================================\n\n async getLearning(\n token: string,\n queryParams?: LearningQueryParams,\n ): Promise<BaseResponse<Learning[]>> {\n const params = createURLSearchParams();\n\n if (queryParams?.technique !== undefined) {\n params.append(\"technique\", String(queryParams.technique));\n }\n if (queryParams?.language_code) {\n params.append(\"language_code\", queryParams.language_code);\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.LEARNING}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<Learning[]>>(endpoint, { token });\n }\n\n async getLearningItem(\n token: string,\n uuid: string,\n ): Promise<BaseResponse<Learning>> {\n const validatedUuid = validateUUID(uuid, \"Learning UUID\");\n return this.request<BaseResponse<Learning>>(\n this.config.ENDPOINTS.LEARNING_ITEM(validatedUuid),\n { token },\n );\n }\n\n async createLearning(\n token: string,\n data: LearningCreateRequest,\n ): Promise<BaseResponse<Learning>> {\n return this.request<BaseResponse<Learning>>(\n this.config.ENDPOINTS.LEARNING,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async updateLearning(\n token: string,\n uuid: string,\n data: LearningUpdateRequest,\n ): Promise<BaseResponse<Learning>> {\n const validatedUuid = validateUUID(uuid, \"Learning UUID\");\n return this.request<BaseResponse<Learning>>(\n this.config.ENDPOINTS.LEARNING_ITEM(validatedUuid),\n {\n method: \"PUT\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async deleteLearning(\n token: string,\n uuid: string,\n ): Promise<BaseResponse<Learning>> {\n const validatedUuid = validateUUID(uuid, \"Learning UUID\");\n return this.request<BaseResponse<Learning>>(\n this.config.ENDPOINTS.LEARNING_ITEM(validatedUuid),\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Boards\n // ===========================================================================\n\n async getBoards(\n token: string,\n queryParams?: BoardQueryParams,\n ): Promise<BaseResponse<Board[]>> {\n const params = createURLSearchParams();\n\n if (queryParams?.level !== undefined) {\n params.append(\"level\", String(queryParams.level));\n }\n if (queryParams?.limit !== undefined) {\n params.append(\"limit\", String(queryParams.limit));\n }\n if (queryParams?.offset !== undefined) {\n params.append(\"offset\", String(queryParams.offset));\n }\n if (queryParams?.techniques !== undefined) {\n params.append(\"techniques\", String(queryParams.techniques));\n }\n if (queryParams?.technique_bit !== undefined) {\n params.append(\"technique_bit\", String(queryParams.technique_bit));\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.BOARDS}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<Board[]>>(endpoint, { token });\n }\n\n async getRandomBoard(\n token: string,\n queryParams?: BoardQueryParams,\n ): Promise<BaseResponse<Board>> {\n const params = createURLSearchParams();\n\n if (queryParams?.level !== undefined) {\n params.append(\"level\", String(queryParams.level));\n }\n\n if (queryParams?.symmetrical !== undefined) {\n params.append(\"symmetrical\", String(queryParams.symmetrical));\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.BOARDS_RANDOM}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<Board>>(endpoint, { token });\n }\n\n async getBoard(token: string, uuid: string): Promise<BaseResponse<Board>> {\n const validatedUuid = validateUUID(uuid, \"Board UUID\");\n return this.request<BaseResponse<Board>>(\n this.config.ENDPOINTS.BOARD(validatedUuid),\n { token },\n );\n }\n\n async createBoard(\n token: string,\n data: BoardCreateRequest,\n ): Promise<BaseResponse<Board>> {\n return this.request<BaseResponse<Board>>(this.config.ENDPOINTS.BOARDS, {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n });\n }\n\n async updateBoard(\n token: string,\n uuid: string,\n data: BoardUpdateRequest,\n ): Promise<BaseResponse<Board>> {\n const validatedUuid = validateUUID(uuid, \"Board UUID\");\n return this.request<BaseResponse<Board>>(\n this.config.ENDPOINTS.BOARD(validatedUuid),\n {\n method: \"PUT\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async deleteBoard(token: string, uuid: string): Promise<BaseResponse<Board>> {\n const validatedUuid = validateUUID(uuid, \"Board UUID\");\n return this.request<BaseResponse<Board>>(\n this.config.ENDPOINTS.BOARD(validatedUuid),\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Dailies\n // ===========================================================================\n\n async getDailies(token: string): Promise<BaseResponse<Daily[]>> {\n return this.request<BaseResponse<Daily[]>>(this.config.ENDPOINTS.DAILIES, {\n token,\n });\n }\n\n async getTodayDaily(token: string): Promise<BaseResponse<Daily>> {\n return this.request<BaseResponse<Daily>>(\n this.config.ENDPOINTS.DAILIES_TODAY,\n { token },\n );\n }\n\n async getDailyByDate(\n token: string,\n date: string,\n ): Promise<BaseResponse<Daily>> {\n // Validate date format (YYYY-MM-DD)\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(date)) {\n throw new Error(\n `Invalid date format: \"${date}\". Expected YYYY-MM-DD format`,\n );\n }\n return this.request<BaseResponse<Daily>>(\n this.config.ENDPOINTS.DAILIES_DATE(date),\n { token },\n );\n }\n\n async getDaily(token: string, uuid: string): Promise<BaseResponse<Daily>> {\n const validatedUuid = validateUUID(uuid, \"Daily UUID\");\n return this.request<BaseResponse<Daily>>(\n this.config.ENDPOINTS.DAILY(validatedUuid),\n { token },\n );\n }\n\n async createDaily(\n token: string,\n data: DailyCreateRequest,\n ): Promise<BaseResponse<Daily>> {\n return this.request<BaseResponse<Daily>>(this.config.ENDPOINTS.DAILIES, {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n });\n }\n\n async updateDaily(\n token: string,\n uuid: string,\n data: DailyUpdateRequest,\n ): Promise<BaseResponse<Daily>> {\n const validatedUuid = validateUUID(uuid, \"Daily UUID\");\n return this.request<BaseResponse<Daily>>(\n this.config.ENDPOINTS.DAILY(validatedUuid),\n {\n method: \"PUT\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async deleteDaily(token: string, uuid: string): Promise<BaseResponse<Daily>> {\n const validatedUuid = validateUUID(uuid, \"Daily UUID\");\n return this.request<BaseResponse<Daily>>(\n this.config.ENDPOINTS.DAILY(validatedUuid),\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Challenges\n // ===========================================================================\n\n async getChallenges(\n token: string,\n queryParams?: ChallengeQueryParams,\n ): Promise<BaseResponse<Challenge[]>> {\n const params = createURLSearchParams();\n\n if (queryParams?.level !== undefined) {\n params.append(\"level\", String(queryParams.level));\n }\n if (queryParams?.difficulty) {\n params.append(\"difficulty\", queryParams.difficulty);\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.CHALLENGES}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<Challenge[]>>(endpoint, { token });\n }\n\n async getRandomChallenge(\n token: string,\n queryParams?: ChallengeQueryParams,\n ): Promise<BaseResponse<Challenge>> {\n const params = createURLSearchParams();\n\n if (queryParams?.level !== undefined) {\n params.append(\"level\", String(queryParams.level));\n }\n if (queryParams?.difficulty) {\n params.append(\"difficulty\", queryParams.difficulty);\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.CHALLENGES_RANDOM}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<Challenge>>(endpoint, { token });\n }\n\n async getChallenge(\n token: string,\n uuid: string,\n ): Promise<BaseResponse<Challenge>> {\n const validatedUuid = validateUUID(uuid, \"Challenge UUID\");\n return this.request<BaseResponse<Challenge>>(\n this.config.ENDPOINTS.CHALLENGE(validatedUuid),\n { token },\n );\n }\n\n async createChallenge(\n token: string,\n data: ChallengeCreateRequest,\n ): Promise<BaseResponse<Challenge>> {\n return this.request<BaseResponse<Challenge>>(\n this.config.ENDPOINTS.CHALLENGES,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async updateChallenge(\n token: string,\n uuid: string,\n data: ChallengeUpdateRequest,\n ): Promise<BaseResponse<Challenge>> {\n const validatedUuid = validateUUID(uuid, \"Challenge UUID\");\n return this.request<BaseResponse<Challenge>>(\n this.config.ENDPOINTS.CHALLENGE(validatedUuid),\n {\n method: \"PUT\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async deleteChallenge(\n token: string,\n uuid: string,\n ): Promise<BaseResponse<Challenge>> {\n const validatedUuid = validateUUID(uuid, \"Challenge UUID\");\n return this.request<BaseResponse<Challenge>>(\n this.config.ENDPOINTS.CHALLENGE(validatedUuid),\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Users\n // ===========================================================================\n\n async getUser(\n token: string,\n userId: string,\n ): Promise<BaseResponse<UserInfoResponse>> {\n if (!userId || userId.length === 0 || userId.length > 128) {\n throw new Error(`Invalid userId: \"${userId}\". Expected 1-128 characters`);\n }\n return this.request<BaseResponse<UserInfoResponse>>(\n this.config.ENDPOINTS.USER(userId),\n {\n token,\n },\n );\n }\n\n async getUserSubscription(\n token: string,\n userId: string,\n testMode?: boolean,\n ): Promise<BaseResponse<SubscriptionResult>> {\n if (!userId || userId.length === 0 || userId.length > 128) {\n throw new Error(`Invalid userId: \"${userId}\". Expected 1-128 characters`);\n }\n const endpoint = testMode\n ? `${this.config.ENDPOINTS.USER_SUBSCRIPTIONS(userId)}?testMode=true`\n : this.config.ENDPOINTS.USER_SUBSCRIPTIONS(userId);\n return this.request<BaseResponse<SubscriptionResult>>(endpoint, {\n token,\n });\n }\n\n // ===========================================================================\n // Practices\n // ===========================================================================\n\n /**\n * Get practice counts for all techniques\n */\n async getPracticeCounts(\n token: string,\n ): Promise<BaseResponse<TechniquePracticeCountItem[]>> {\n return this.request<BaseResponse<TechniquePracticeCountItem[]>>(\n this.config.ENDPOINTS.PRACTICES_COUNTS,\n { token },\n );\n }\n\n /**\n * Get a random practice for a specific technique\n */\n async getRandomPractice(\n token: string,\n technique: number,\n ): Promise<BaseResponse<TechniquePractice>> {\n if (technique < 1) {\n throw new Error(`Invalid technique: ${technique}. Expected >= 1`);\n }\n return this.request<BaseResponse<TechniquePractice>>(\n this.config.ENDPOINTS.PRACTICE_RANDOM(technique),\n { token },\n );\n }\n\n /**\n * Create a new practice (admin only)\n */\n async createPractice(\n token: string,\n data: TechniquePracticeCreateRequest,\n ): Promise<BaseResponse<TechniquePractice>> {\n return this.request<BaseResponse<TechniquePractice>>(\n this.config.ENDPOINTS.PRACTICES,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n /**\n * Delete all practices (admin only, requires confirm=true)\n */\n async deleteAllPractices(\n token: string,\n ): Promise<BaseResponse<PracticesBulkDeleteData>> {\n return this.request<BaseResponse<PracticesBulkDeleteData>>(\n `${this.config.ENDPOINTS.PRACTICES}?confirm=true`,\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n /**\n * Regenerate hint_data for all practices by calling the solver (admin only).\n * Uses a 10-minute timeout because this processes all practices sequentially.\n */\n async regeneratePracticeHints(\n token: string,\n ): Promise<BaseResponse<PracticesRegenerateHintsData>> {\n return this.request<BaseResponse<PracticesRegenerateHintsData>>(\n `${this.config.ENDPOINTS.PRACTICES}/regenerate-hints`,\n {\n method: \"POST\",\n token,\n timeout: 600000,\n },\n );\n }\n\n // ===========================================================================\n // Examples\n // ===========================================================================\n\n /**\n * Get example counts for all techniques\n */\n async getExampleCounts(\n token: string,\n ): Promise<BaseResponse<ExampleCountsData>> {\n return this.request<BaseResponse<ExampleCountsData>>(\n this.config.ENDPOINTS.EXAMPLES_COUNTS,\n { token },\n );\n }\n\n /**\n * Get examples, optionally filtered by technique\n */\n async getExamples(\n token: string,\n queryParams?: TechniqueExampleQueryParams,\n ): Promise<BaseResponse<TechniqueExample[]>> {\n const params = createURLSearchParams();\n\n if (queryParams?.technique !== undefined) {\n params.append(\"technique\", String(queryParams.technique));\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.EXAMPLES}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<TechniqueExample[]>>(endpoint, { token });\n }\n\n /**\n * Create a new example (admin only)\n */\n async createExample(\n token: string,\n data: TechniqueExampleCreateRequest,\n ): Promise<BaseResponse<TechniqueExample>> {\n return this.request<BaseResponse<TechniqueExample>>(\n this.config.ENDPOINTS.EXAMPLES,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n // ===========================================================================\n // Board Counts\n // ===========================================================================\n\n /**\n * Get board counts (total and without techniques)\n */\n async getBoardCounts(token: string): Promise<BaseResponse<BoardCountsData>> {\n return this.request<BaseResponse<BoardCountsData>>(\n this.config.ENDPOINTS.BOARDS_COUNTS,\n { token },\n );\n }\n\n /**\n * Get board counts by technique (count of boards with each technique bit set)\n * Returns Record<number, number> where key is technique ID and value is count\n */\n async getBoardCountsByTechnique(\n token: string,\n ): Promise<BaseResponse<BoardCountsByTechniqueData>> {\n return this.request<BaseResponse<BoardCountsByTechniqueData>>(\n this.config.ENDPOINTS.BOARDS_COUNTS_BY_TECHNIQUE,\n { token },\n );\n }\n\n /**\n * Calculate and update puzzle stats (percentages) on levels and techniques.\n * Requires admin authentication.\n */\n async updatePuzzleStats(\n token: string,\n ): Promise<BaseResponse<UpdateStatsData>> {\n return this.request<BaseResponse<UpdateStatsData>>(\n this.config.ENDPOINTS.BOARDS_UPDATE_STATS,\n {\n method: \"POST\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Solver\n // ===========================================================================\n\n /**\n * Builds an endpoint path with query parameters for solver endpoints\n */\n private buildSolverUrl(\n endpoint: string,\n params: Record<string, string | boolean | undefined>,\n ): string {\n const searchParams = createURLSearchParams();\n // Sort keys alphabetically to match Kotlin behavior\n const sortedKeys = Object.keys(params).sort();\n for (const key of sortedKeys) {\n const value = params[key];\n if (value !== undefined) {\n searchParams.append(key, String(value));\n }\n }\n const query = searchParams.toString();\n // Return endpoint + query only, baseUrl is added by request()\n return `${endpoint}${query ? `?${query}` : \"\"}`;\n }\n\n /**\n * Get hints for solving a Sudoku puzzle\n * @throws {HintAccessDeniedError} When hint level exceeds user's subscription tier\n */\n async solverSolve(\n token: string,\n options: SolveOptions,\n ): Promise<BaseResponse<SolveData>> {\n const url = this.buildSolverUrl(this.config.ENDPOINTS.SOLVER_SOLVE, {\n original: options.original,\n user: options.user,\n autopencilmarks: options.autoPencilmarks,\n pencilmarks: options.pencilmarks,\n filters: options.filters,\n techniques: options.techniques,\n });\n\n const fullUrl = `${this.baseUrl}${url}`;\n const requestHeaders: Record<string, string> = {\n ...this.headers,\n };\n\n if (token) {\n requestHeaders[\"Authorization\"] = `Bearer ${token}`;\n }\n\n // Use 120 second timeout for solve (advanced techniques can be slow)\n const response = await this.networkClient.request<\n BaseResponse<SolveData> | HintAccessDeniedResponse\n >(fullUrl, {\n method: \"GET\",\n headers: requestHeaders,\n timeout: 120000,\n });\n\n // Check for hint access denied (402)\n if (response.status === 402 && response.data) {\n const errorResponse = response.data as HintAccessDeniedResponse;\n if (errorResponse.error?.code === \"HINT_ACCESS_DENIED\") {\n throw new HintAccessDeniedError(errorResponse.error);\n }\n }\n\n // Check for other errors\n if (!response.ok || response.data === undefined) {\n throw new Error(\"Failed to get hints from solver\");\n }\n\n return (await decryptSolutionFields(\n response.data,\n )) as BaseResponse<SolveData>;\n }\n\n /**\n * Validate that a Sudoku puzzle has a unique solution.\n * Uses a longer timeout (120s) because validation involves iterative solving.\n */\n async solverValidate(\n token: string,\n options: ValidateOptions,\n ): Promise<BaseResponse<ValidateData>> {\n const url = this.buildSolverUrl(this.config.ENDPOINTS.SOLVER_VALIDATE, {\n original: options.original,\n });\n\n // Use 120 second timeout for validation (iterative solving can be slow)\n return this.request<BaseResponse<ValidateData>>(url, {\n token,\n timeout: 120000,\n });\n }\n\n /**\n * Generate a new random Sudoku puzzle\n */\n async solverGenerate(\n token: string,\n options: GenerateOptions = {},\n ): Promise<BaseResponse<GenerateData>> {\n const url = this.buildSolverUrl(this.config.ENDPOINTS.SOLVER_GENERATE, {\n symmetrical: options.symmetrical,\n });\n\n return this.request<BaseResponse<GenerateData>>(url, { token });\n }\n\n // ===========================================================================\n // Play (Game Session) Endpoints\n // ===========================================================================\n\n /**\n * Start a new game session\n */\n async playStart(\n token: string,\n data: GameStartRequest,\n ): Promise<BaseResponse<GameStartResponse>> {\n return this.request<BaseResponse<GameStartResponse>>(\n this.config.ENDPOINTS.PLAY_START,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n /**\n * Finish the current game session and get rewards\n */\n async playFinish(\n token: string,\n data: GameFinishRequest,\n ): Promise<BaseResponse<GameFinishResponse>> {\n return this.request<BaseResponse<GameFinishResponse>>(\n this.config.ENDPOINTS.PLAY_FINISH,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n // ===========================================================================\n // Gamification Endpoints\n // ===========================================================================\n\n /**\n * Get user's gamification stats (points, level, badges)\n */\n async getGamificationStats(\n token: string,\n ): Promise<BaseResponse<GamificationStats>> {\n return this.request<BaseResponse<GamificationStats>>(\n this.config.ENDPOINTS.GAMIFICATION_STATS,\n { token },\n );\n }\n\n /**\n * Get all badge definitions (public)\n */\n async getBadgeDefinitions(): Promise<BaseResponse<BadgeDefinition[]>> {\n return this.request<BaseResponse<BadgeDefinition[]>>(\n this.config.ENDPOINTS.GAMIFICATION_BADGES,\n );\n }\n\n /**\n * Get user's point transaction history\n */\n async getPointHistory(\n token: string,\n options?: { limit?: number; offset?: number },\n ): Promise<BaseResponse<PointTransaction[]>> {\n let endpoint = this.config.ENDPOINTS.GAMIFICATION_HISTORY;\n if (options?.limit || options?.offset) {\n const params = createURLSearchParams();\n if (options.limit) params.append(\"limit\", String(options.limit));\n if (options.offset) params.append(\"offset\", String(options.offset));\n endpoint = `${endpoint}?${params.toString()}`;\n }\n return this.request<BaseResponse<PointTransaction[]>>(endpoint, { token });\n }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Factory function to create a new SudojoClient instance.\n *\n * Equivalent to `new SudojoClient(networkClient, baseUrl)` but useful\n * for dependency injection and functional composition patterns.\n *\n * @param networkClient - Network client for making HTTP requests\n * @param baseUrl - Base URL for the Sudojo API\n * @returns A new SudojoClient instance\n */\nexport const createSudojoClient = (\n networkClient: NetworkClient,\n baseUrl: string,\n): SudojoClient => {\n return new SudojoClient(networkClient, baseUrl);\n};\n\n// =============================================================================\n// Utility Exports\n// =============================================================================\n\n/**\n * Re-exported UUID validation utilities from `@sudobility/sudojo_types`.\n *\n * These are used internally by the SudojoClient for parameter validation\n * and are also exported for consumer convenience. Use `isValidUUID` for\n * boolean checks and `validateUUID` when you want an error thrown on invalid input.\n *\n * - `isValidUUID(value)` - Returns true if the string is a valid UUID v4\n * - `validateUUID(value, label)` - Returns the UUID or throws an Error with the label\n */\nexport { isValidUUID, validateUUID };\n"]}
1
+ {"version":3,"file":"sudojo-client.js","sourceRoot":"","sources":["../../src/network/sudojo-client.ts"],"names":[],"mappings":"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","sourcesContent":["import type { NetworkClient, UserInfoResponse } from \"@sudobility/types\";\nimport {\n type BadgeDefinition,\n type BaseResponse,\n type Board,\n type BoardCountsByTechniqueData,\n type BoardCountsData,\n type BoardCreateRequest,\n type BoardQueryParams,\n type BoardUpdateRequest,\n type Challenge,\n type ChallengeCreateRequest,\n type ChallengeQueryParams,\n type ChallengeUpdateRequest,\n type Community,\n type CommunityCreateRequest,\n type CommunityQueryParams,\n type CommunityUpdateRequest,\n type Daily,\n type DailyCreateRequest,\n type DailyUpdateRequest,\n type ExampleCountsData,\n type GameFinishRequest,\n type GameFinishResponse,\n type GameStartRequest,\n type GameStartResponse,\n type GamificationStats,\n type GenerateData,\n type GenerateOptions,\n type HealthCheckData,\n type HintAccessDeniedResponse,\n isValidUUID,\n type Learning,\n type LearningCreateRequest,\n type LearningQueryParams,\n type LearningUpdateRequest,\n type Level,\n type LevelCreateRequest,\n type LevelUpdateRequest,\n type Optional,\n type PointTransaction,\n type PracticesBulkDeleteData,\n type PracticesRegenerateHintsData,\n type SolveData,\n type SolveOptions,\n type SubscriptionResult,\n type Technique,\n type TechniqueCreateRequest,\n type TechniqueExample,\n type TechniqueExampleCreateRequest,\n type TechniqueExampleQueryParams,\n type TechniquePractice,\n type TechniquePracticeCountItem,\n type TechniquePracticeCreateRequest,\n type TechniqueQueryParams,\n type TechniqueUpdateRequest,\n type UpdateStatsData,\n type ValidateData,\n type ValidateOptions,\n validateUUID,\n} from \"@sudobility/sudojo_types\";\nimport { HintAccessDeniedError } from \"../errors\";\n\n// Re-export option types for convenience\nexport type { SolveOptions, ValidateOptions, GenerateOptions };\n\n// =============================================================================\n// Solution Decryption\n// =============================================================================\n\nlet _solutionKey: CryptoKey | null = null;\n\n/**\n * Configure the symmetric key used to decrypt `solution` fields in API responses.\n * Call once at app startup with the hex-encoded 256-bit key.\n * If not called (or called with empty string), encrypted solutions pass through as-is.\n */\nexport async function configureSolutionKey(keyHex: string): Promise<void> {\n if (!keyHex) return;\n const hexPairs = keyHex.match(/.{2}/g);\n if (!hexPairs) return;\n const keyBytes = new Uint8Array(hexPairs.map((byte) => parseInt(byte, 16)));\n _solutionKey = await globalThis.crypto.subtle.importKey(\n \"raw\",\n keyBytes,\n \"AES-GCM\",\n false,\n [\"decrypt\"],\n );\n}\n\nasync function decryptSolution(encrypted: string): Promise<string> {\n if (!_solutionKey) return encrypted;\n\n const raw = globalThis.atob(encrypted.slice(4)); // strip \"enc:\" prefix\n const bytes = new Uint8Array(raw.length);\n for (let i = 0; i < raw.length; i++) {\n bytes[i] = raw.charCodeAt(i);\n }\n\n const nonce = bytes.slice(0, 12);\n const ciphertextWithTag = bytes.slice(12);\n\n const decrypted = await globalThis.crypto.subtle.decrypt(\n { name: \"AES-GCM\", iv: nonce },\n _solutionKey,\n ciphertextWithTag,\n );\n\n return new TextDecoder().decode(decrypted);\n}\n\nasync function decryptSolutionFields(data: unknown): Promise<unknown> {\n if (data === null || data === undefined) return data;\n\n if (Array.isArray(data)) {\n return Promise.all(data.map((item) => decryptSolutionFields(item)));\n }\n\n if (typeof data === \"object\") {\n const obj = data as Record<string, unknown>;\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n if (\n key === \"solution\" &&\n typeof obj[key] === \"string\" &&\n (obj[key] as string).startsWith(\"enc:\")\n ) {\n result[key] = await decryptSolution(obj[key] as string);\n } else {\n result[key] = await decryptSolutionFields(obj[key]);\n }\n }\n return result;\n }\n\n return data;\n}\n\n// =============================================================================\n// URL Search Params Utility\n// =============================================================================\n\n/**\n * Creates a lightweight URL search params builder.\n *\n * This is a custom implementation instead of the standard `URLSearchParams`\n * because the solver API requires a special encoding behavior: **commas must\n * NOT be percent-encoded** in pencilmark values. The standard `URLSearchParams`\n * encodes commas as `%2C`, which the Kotlin-based solver backend does not decode.\n *\n * @returns An object with `append(key, value)` and `toString()` methods\n *\n * @example\n * ```ts\n * const params = createURLSearchParams();\n * params.append(\"pencilmarks\", \"1,2,3\");\n * params.toString(); // \"pencilmarks=1,2,3\" (commas preserved)\n * ```\n */\nconst createURLSearchParams = () => {\n const params: Record<string, string[]> = {};\n return {\n append: (key: string, value: string) => {\n if (!params[key]) {\n params[key] = [];\n }\n params[key]?.push(value);\n },\n toString: () => {\n return Object.entries(params)\n .flatMap(([key, values]) =>\n values.map(\n (value) =>\n // Don't encode commas - the solver API expects literal commas in pencilmarks\n `${encodeURIComponent(key)}=${encodeURIComponent(value).replace(/%2C/g, \",\")}`,\n ),\n )\n .join(\"&\");\n },\n };\n};\n\n// =============================================================================\n// API Configuration Factory\n// =============================================================================\n\nconst createApiConfig = (baseUrl: string) => ({\n BASE_URL: baseUrl,\n ENDPOINTS: {\n // Health\n HEALTH: \"/\",\n\n // Levels\n LEVELS: \"/api/v1/levels\",\n LEVEL: (level: number) => `/api/v1/levels/${level}`,\n\n // Techniques\n TECHNIQUES: \"/api/v1/techniques\",\n TECHNIQUE: (technique: number) => `/api/v1/techniques/${technique}`,\n\n // Learning\n LEARNING: \"/api/v1/learning\",\n LEARNING_ITEM: (uuid: string) => `/api/v1/learning/${uuid}`,\n\n // Boards\n BOARDS: \"/api/v1/boards\",\n BOARDS_RANDOM: \"/api/v1/boards/random\",\n BOARD: (uuid: string) => `/api/v1/boards/${uuid}`,\n\n // Dailies\n DAILIES: \"/api/v1/dailies\",\n DAILIES_TODAY: \"/api/v1/dailies/today\",\n DAILIES_DATE: (date: string) => `/api/v1/dailies/date/${date}`,\n DAILY: (uuid: string) => `/api/v1/dailies/${uuid}`,\n\n // Challenges\n CHALLENGES: \"/api/v1/challenges\",\n CHALLENGES_RANDOM: \"/api/v1/challenges/random\",\n CHALLENGE: (uuid: string) => `/api/v1/challenges/${uuid}`,\n\n // Users\n USER: (userId: string) => `/api/v1/users/${userId}`,\n USER_SUBSCRIPTIONS: (userId: string) =>\n `/api/v1/users/${userId}/subscriptions`,\n\n // Solver\n SOLVER_SOLVE: \"/api/v1/solver/solve\",\n SOLVER_VALIDATE: \"/api/v1/solver/validate\",\n SOLVER_GENERATE: \"/api/v1/solver/generate\",\n\n // Practices\n PRACTICES: \"/api/v1/practices\",\n PRACTICES_COUNTS: \"/api/v1/practices/counts\",\n PRACTICE_RANDOM: (technique: number) =>\n `/api/v1/practices/technique/${technique}/random`,\n\n // Examples\n EXAMPLES: \"/api/v1/examples\",\n EXAMPLES_COUNTS: \"/api/v1/examples/counts\",\n\n // Boards counts\n BOARDS_COUNTS: \"/api/v1/boards/counts\",\n BOARDS_COUNTS_BY_TECHNIQUE: \"/api/v1/boards/counts/by-technique\",\n BOARDS_UPDATE_STATS: \"/api/v1/boards/update-stats\",\n\n // Play (game sessions)\n PLAY_START: \"/api/v1/play/start\",\n PLAY_FINISH: \"/api/v1/play/finish\",\n\n // Gamification\n GAMIFICATION_STATS: \"/api/v1/gamification/stats\",\n GAMIFICATION_BADGES: \"/api/v1/gamification/badges\",\n GAMIFICATION_HISTORY: \"/api/v1/gamification/history\",\n\n // Communities\n COMMUNITIES: \"/api/v1/communities\",\n COMMUNITY: (uuid: string) => `/api/v1/communities/${uuid}`,\n },\n DEFAULT_HEADERS: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n});\n\n// =============================================================================\n// Sudojo Client Class\n// =============================================================================\n\n/**\n * Type-safe client for the Sudojo REST API.\n *\n * Provides methods for all Sudojo API endpoints including levels, techniques,\n * boards, dailies, challenges, users, solver, practices, examples, and gamification.\n *\n * ## Error Handling\n *\n * All methods throw errors on failure:\n * - **Network errors**: Thrown by the underlying `NetworkClient` (e.g., connection refused, timeout)\n * - **Empty response**: Throws `Error(\"No data received from server\")` when the server returns no data\n * - **Validation errors**: Thrown before the request for invalid parameters (e.g., invalid UUID, level out of range)\n * - **HTTP 402**: `solverSolve()` throws {@link HintAccessDeniedError} when the hint level exceeds the user's tier\n * - **Other HTTP errors**: Depend on the `NetworkClient` implementation - typically thrown as generic `Error`\n *\n * ## Authentication\n *\n * Most methods accept a `token` parameter (Firebase ID token). The token is sent\n * as a `Bearer` token in the `Authorization` header. Public endpoints (health,\n * levels, boards, etc.) accept but do not require a token. User-specific endpoints\n * (subscriptions, gamification) require a valid token.\n *\n * ## Usage\n *\n * ```typescript\n * const client = new SudojoClient(networkClient, \"https://api.sudojo.com\");\n * const levels = await client.getLevels(token);\n * const daily = await client.getDailyByDate(token, \"2024-01-15\");\n * ```\n */\nexport class SudojoClient {\n private baseUrl: string;\n private headers: Record<string, string>;\n private networkClient: NetworkClient;\n private config: ReturnType<typeof createApiConfig>;\n\n /**\n * Create a SudojoClient instance.\n *\n * @param networkClient - Network client for making HTTP requests (from `@sudobility/types`)\n * @param baseUrl - Base URL for the Sudojo API (e.g., \"https://api.sudojo.com\")\n */\n constructor(networkClient: NetworkClient, baseUrl: string) {\n this.config = createApiConfig(baseUrl);\n this.baseUrl = this.config.BASE_URL;\n this.networkClient = networkClient;\n\n this.headers = {\n ...this.config.DEFAULT_HEADERS,\n };\n }\n\n // ===========================================================================\n // Private Request Method\n // ===========================================================================\n\n private async request<T>(\n endpoint: string,\n options: {\n method?: Optional<\"GET\" | \"POST\" | \"PUT\" | \"DELETE\">;\n body?: Optional<Record<string, unknown>>;\n headers?: Optional<Record<string, string>>;\n token?: Optional<string>;\n timeout?: Optional<number>;\n } = {},\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n\n const requestHeaders: Record<string, string> = {\n ...this.headers,\n ...options.headers,\n };\n\n // Add authorization header if token is provided\n if (options.token) {\n requestHeaders[\"Authorization\"] = `Bearer ${options.token}`;\n }\n\n const requestOptions: {\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n headers: Record<string, string>;\n body?: string;\n timeout?: number;\n } = {\n method: options.method || \"GET\",\n headers: requestHeaders,\n };\n\n // Add body for POST/PUT/DELETE requests\n if (options.body && options.method !== \"GET\") {\n requestOptions.body = JSON.stringify(options.body);\n }\n\n // Add timeout if specified\n if (options.timeout) {\n requestOptions.timeout = options.timeout;\n }\n\n const response = await this.networkClient.request<T>(url, requestOptions);\n\n if (response.data === undefined) {\n throw new Error(\"No data received from server\");\n }\n\n return (await decryptSolutionFields(response.data)) as T;\n }\n\n // ===========================================================================\n // Health Check\n // ===========================================================================\n\n async getHealth(): Promise<BaseResponse<HealthCheckData>> {\n return this.request<BaseResponse<HealthCheckData>>(\n this.config.ENDPOINTS.HEALTH,\n );\n }\n\n // ===========================================================================\n // Levels\n // ===========================================================================\n\n async getLevels(token: string): Promise<BaseResponse<Level[]>> {\n return this.request<BaseResponse<Level[]>>(this.config.ENDPOINTS.LEVELS, {\n token,\n });\n }\n\n async getLevel(token: string, level: number): Promise<BaseResponse<Level>> {\n if (level < 1 || level > 12) {\n throw new Error(`Invalid level: ${level}. Expected 1-12`);\n }\n return this.request<BaseResponse<Level>>(\n this.config.ENDPOINTS.LEVEL(level),\n { token },\n );\n }\n\n async createLevel(\n token: string,\n data: LevelCreateRequest,\n ): Promise<BaseResponse<Level>> {\n return this.request<BaseResponse<Level>>(this.config.ENDPOINTS.LEVELS, {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n });\n }\n\n async updateLevel(\n token: string,\n level: number,\n data: LevelUpdateRequest,\n ): Promise<BaseResponse<Level>> {\n if (level < 1 || level > 12) {\n throw new Error(`Invalid level: ${level}. Expected 1-12`);\n }\n return this.request<BaseResponse<Level>>(\n this.config.ENDPOINTS.LEVEL(level),\n {\n method: \"PUT\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async deleteLevel(\n token: string,\n level: number,\n ): Promise<BaseResponse<Level>> {\n if (level < 1 || level > 12) {\n throw new Error(`Invalid level: ${level}. Expected 1-12`);\n }\n return this.request<BaseResponse<Level>>(\n this.config.ENDPOINTS.LEVEL(level),\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Techniques\n // ===========================================================================\n\n async getTechniques(\n token: string,\n queryParams?: TechniqueQueryParams,\n ): Promise<BaseResponse<Technique[]>> {\n const params = createURLSearchParams();\n\n if (queryParams?.level !== undefined) {\n params.append(\"level\", String(queryParams.level));\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.TECHNIQUES}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<Technique[]>>(endpoint, { token });\n }\n\n async getTechnique(\n token: string,\n technique: number,\n ): Promise<BaseResponse<Technique>> {\n if (technique < 1) {\n throw new Error(`Invalid technique: ${technique}. Expected >= 1`);\n }\n return this.request<BaseResponse<Technique>>(\n this.config.ENDPOINTS.TECHNIQUE(technique),\n { token },\n );\n }\n\n async createTechnique(\n token: string,\n data: TechniqueCreateRequest,\n ): Promise<BaseResponse<Technique>> {\n return this.request<BaseResponse<Technique>>(\n this.config.ENDPOINTS.TECHNIQUES,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async updateTechnique(\n token: string,\n technique: number,\n data: TechniqueUpdateRequest,\n ): Promise<BaseResponse<Technique>> {\n if (technique < 1) {\n throw new Error(`Invalid technique: ${technique}. Expected >= 1`);\n }\n return this.request<BaseResponse<Technique>>(\n this.config.ENDPOINTS.TECHNIQUE(technique),\n {\n method: \"PUT\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async deleteTechnique(\n token: string,\n technique: number,\n ): Promise<BaseResponse<Technique>> {\n if (technique < 1) {\n throw new Error(`Invalid technique: ${technique}. Expected >= 1`);\n }\n return this.request<BaseResponse<Technique>>(\n this.config.ENDPOINTS.TECHNIQUE(technique),\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Learning\n // ===========================================================================\n\n async getLearning(\n token: string,\n queryParams?: LearningQueryParams,\n ): Promise<BaseResponse<Learning[]>> {\n const params = createURLSearchParams();\n\n if (queryParams?.technique !== undefined) {\n params.append(\"technique\", String(queryParams.technique));\n }\n if (queryParams?.language_code) {\n params.append(\"language_code\", queryParams.language_code);\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.LEARNING}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<Learning[]>>(endpoint, { token });\n }\n\n async getLearningItem(\n token: string,\n uuid: string,\n ): Promise<BaseResponse<Learning>> {\n const validatedUuid = validateUUID(uuid, \"Learning UUID\");\n return this.request<BaseResponse<Learning>>(\n this.config.ENDPOINTS.LEARNING_ITEM(validatedUuid),\n { token },\n );\n }\n\n async createLearning(\n token: string,\n data: LearningCreateRequest,\n ): Promise<BaseResponse<Learning>> {\n return this.request<BaseResponse<Learning>>(\n this.config.ENDPOINTS.LEARNING,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async updateLearning(\n token: string,\n uuid: string,\n data: LearningUpdateRequest,\n ): Promise<BaseResponse<Learning>> {\n const validatedUuid = validateUUID(uuid, \"Learning UUID\");\n return this.request<BaseResponse<Learning>>(\n this.config.ENDPOINTS.LEARNING_ITEM(validatedUuid),\n {\n method: \"PUT\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async deleteLearning(\n token: string,\n uuid: string,\n ): Promise<BaseResponse<Learning>> {\n const validatedUuid = validateUUID(uuid, \"Learning UUID\");\n return this.request<BaseResponse<Learning>>(\n this.config.ENDPOINTS.LEARNING_ITEM(validatedUuid),\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Boards\n // ===========================================================================\n\n async getBoards(\n token: string,\n queryParams?: BoardQueryParams,\n ): Promise<BaseResponse<Board[]>> {\n const params = createURLSearchParams();\n\n if (queryParams?.level !== undefined) {\n params.append(\"level\", String(queryParams.level));\n }\n if (queryParams?.limit !== undefined) {\n params.append(\"limit\", String(queryParams.limit));\n }\n if (queryParams?.offset !== undefined) {\n params.append(\"offset\", String(queryParams.offset));\n }\n if (queryParams?.techniques !== undefined) {\n params.append(\"techniques\", String(queryParams.techniques));\n }\n if (queryParams?.technique_bit !== undefined) {\n params.append(\"technique_bit\", String(queryParams.technique_bit));\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.BOARDS}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<Board[]>>(endpoint, { token });\n }\n\n async getRandomBoard(\n token: string,\n queryParams?: BoardQueryParams,\n ): Promise<BaseResponse<Board>> {\n const params = createURLSearchParams();\n\n if (queryParams?.level !== undefined) {\n params.append(\"level\", String(queryParams.level));\n }\n\n if (queryParams?.symmetrical !== undefined) {\n params.append(\"symmetrical\", String(queryParams.symmetrical));\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.BOARDS_RANDOM}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<Board>>(endpoint, { token });\n }\n\n async getBoard(token: string, uuid: string): Promise<BaseResponse<Board>> {\n const validatedUuid = validateUUID(uuid, \"Board UUID\");\n return this.request<BaseResponse<Board>>(\n this.config.ENDPOINTS.BOARD(validatedUuid),\n { token },\n );\n }\n\n async createBoard(\n token: string,\n data: BoardCreateRequest,\n ): Promise<BaseResponse<Board>> {\n return this.request<BaseResponse<Board>>(this.config.ENDPOINTS.BOARDS, {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n });\n }\n\n async updateBoard(\n token: string,\n uuid: string,\n data: BoardUpdateRequest,\n ): Promise<BaseResponse<Board>> {\n const validatedUuid = validateUUID(uuid, \"Board UUID\");\n return this.request<BaseResponse<Board>>(\n this.config.ENDPOINTS.BOARD(validatedUuid),\n {\n method: \"PUT\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async deleteBoard(token: string, uuid: string): Promise<BaseResponse<Board>> {\n const validatedUuid = validateUUID(uuid, \"Board UUID\");\n return this.request<BaseResponse<Board>>(\n this.config.ENDPOINTS.BOARD(validatedUuid),\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Dailies\n // ===========================================================================\n\n async getDailies(token: string): Promise<BaseResponse<Daily[]>> {\n return this.request<BaseResponse<Daily[]>>(this.config.ENDPOINTS.DAILIES, {\n token,\n });\n }\n\n async getTodayDaily(token: string): Promise<BaseResponse<Daily>> {\n return this.request<BaseResponse<Daily>>(\n this.config.ENDPOINTS.DAILIES_TODAY,\n { token },\n );\n }\n\n async getDailyByDate(\n token: string,\n date: string,\n ): Promise<BaseResponse<Daily>> {\n // Validate date format (YYYY-MM-DD)\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(date)) {\n throw new Error(\n `Invalid date format: \"${date}\". Expected YYYY-MM-DD format`,\n );\n }\n return this.request<BaseResponse<Daily>>(\n this.config.ENDPOINTS.DAILIES_DATE(date),\n { token },\n );\n }\n\n async getDaily(token: string, uuid: string): Promise<BaseResponse<Daily>> {\n const validatedUuid = validateUUID(uuid, \"Daily UUID\");\n return this.request<BaseResponse<Daily>>(\n this.config.ENDPOINTS.DAILY(validatedUuid),\n { token },\n );\n }\n\n async createDaily(\n token: string,\n data: DailyCreateRequest,\n ): Promise<BaseResponse<Daily>> {\n return this.request<BaseResponse<Daily>>(this.config.ENDPOINTS.DAILIES, {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n });\n }\n\n async updateDaily(\n token: string,\n uuid: string,\n data: DailyUpdateRequest,\n ): Promise<BaseResponse<Daily>> {\n const validatedUuid = validateUUID(uuid, \"Daily UUID\");\n return this.request<BaseResponse<Daily>>(\n this.config.ENDPOINTS.DAILY(validatedUuid),\n {\n method: \"PUT\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async deleteDaily(token: string, uuid: string): Promise<BaseResponse<Daily>> {\n const validatedUuid = validateUUID(uuid, \"Daily UUID\");\n return this.request<BaseResponse<Daily>>(\n this.config.ENDPOINTS.DAILY(validatedUuid),\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Challenges\n // ===========================================================================\n\n async getChallenges(\n token: string,\n queryParams?: ChallengeQueryParams,\n ): Promise<BaseResponse<Challenge[]>> {\n const params = createURLSearchParams();\n\n if (queryParams?.level !== undefined) {\n params.append(\"level\", String(queryParams.level));\n }\n if (queryParams?.difficulty) {\n params.append(\"difficulty\", queryParams.difficulty);\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.CHALLENGES}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<Challenge[]>>(endpoint, { token });\n }\n\n async getRandomChallenge(\n token: string,\n queryParams?: ChallengeQueryParams,\n ): Promise<BaseResponse<Challenge>> {\n const params = createURLSearchParams();\n\n if (queryParams?.level !== undefined) {\n params.append(\"level\", String(queryParams.level));\n }\n if (queryParams?.difficulty) {\n params.append(\"difficulty\", queryParams.difficulty);\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.CHALLENGES_RANDOM}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<Challenge>>(endpoint, { token });\n }\n\n async getChallenge(\n token: string,\n uuid: string,\n ): Promise<BaseResponse<Challenge>> {\n const validatedUuid = validateUUID(uuid, \"Challenge UUID\");\n return this.request<BaseResponse<Challenge>>(\n this.config.ENDPOINTS.CHALLENGE(validatedUuid),\n { token },\n );\n }\n\n async createChallenge(\n token: string,\n data: ChallengeCreateRequest,\n ): Promise<BaseResponse<Challenge>> {\n return this.request<BaseResponse<Challenge>>(\n this.config.ENDPOINTS.CHALLENGES,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async updateChallenge(\n token: string,\n uuid: string,\n data: ChallengeUpdateRequest,\n ): Promise<BaseResponse<Challenge>> {\n const validatedUuid = validateUUID(uuid, \"Challenge UUID\");\n return this.request<BaseResponse<Challenge>>(\n this.config.ENDPOINTS.CHALLENGE(validatedUuid),\n {\n method: \"PUT\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async deleteChallenge(\n token: string,\n uuid: string,\n ): Promise<BaseResponse<Challenge>> {\n const validatedUuid = validateUUID(uuid, \"Challenge UUID\");\n return this.request<BaseResponse<Challenge>>(\n this.config.ENDPOINTS.CHALLENGE(validatedUuid),\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Users\n // ===========================================================================\n\n async getUser(\n token: string,\n userId: string,\n ): Promise<BaseResponse<UserInfoResponse>> {\n if (!userId || userId.length === 0 || userId.length > 128) {\n throw new Error(`Invalid userId: \"${userId}\". Expected 1-128 characters`);\n }\n return this.request<BaseResponse<UserInfoResponse>>(\n this.config.ENDPOINTS.USER(userId),\n {\n token,\n },\n );\n }\n\n async getUserSubscription(\n token: string,\n userId: string,\n testMode?: boolean,\n ): Promise<BaseResponse<SubscriptionResult>> {\n if (!userId || userId.length === 0 || userId.length > 128) {\n throw new Error(`Invalid userId: \"${userId}\". Expected 1-128 characters`);\n }\n const endpoint = testMode\n ? `${this.config.ENDPOINTS.USER_SUBSCRIPTIONS(userId)}?testMode=true`\n : this.config.ENDPOINTS.USER_SUBSCRIPTIONS(userId);\n return this.request<BaseResponse<SubscriptionResult>>(endpoint, {\n token,\n });\n }\n\n // ===========================================================================\n // Practices\n // ===========================================================================\n\n /**\n * Get practice counts for all techniques\n */\n async getPracticeCounts(\n token: string,\n ): Promise<BaseResponse<TechniquePracticeCountItem[]>> {\n return this.request<BaseResponse<TechniquePracticeCountItem[]>>(\n this.config.ENDPOINTS.PRACTICES_COUNTS,\n { token },\n );\n }\n\n /**\n * Get a random practice for a specific technique\n */\n async getRandomPractice(\n token: string,\n technique: number,\n ): Promise<BaseResponse<TechniquePractice>> {\n if (technique < 1) {\n throw new Error(`Invalid technique: ${technique}. Expected >= 1`);\n }\n return this.request<BaseResponse<TechniquePractice>>(\n this.config.ENDPOINTS.PRACTICE_RANDOM(technique),\n { token },\n );\n }\n\n /**\n * Create a new practice (admin only)\n */\n async createPractice(\n token: string,\n data: TechniquePracticeCreateRequest,\n ): Promise<BaseResponse<TechniquePractice>> {\n return this.request<BaseResponse<TechniquePractice>>(\n this.config.ENDPOINTS.PRACTICES,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n /**\n * Delete all practices (admin only, requires confirm=true)\n */\n async deleteAllPractices(\n token: string,\n ): Promise<BaseResponse<PracticesBulkDeleteData>> {\n return this.request<BaseResponse<PracticesBulkDeleteData>>(\n `${this.config.ENDPOINTS.PRACTICES}?confirm=true`,\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n /**\n * Regenerate hint_data for all practices by calling the solver (admin only).\n * Uses a 10-minute timeout because this processes all practices sequentially.\n */\n async regeneratePracticeHints(\n token: string,\n ): Promise<BaseResponse<PracticesRegenerateHintsData>> {\n return this.request<BaseResponse<PracticesRegenerateHintsData>>(\n `${this.config.ENDPOINTS.PRACTICES}/regenerate-hints`,\n {\n method: \"POST\",\n token,\n timeout: 600000,\n },\n );\n }\n\n // ===========================================================================\n // Examples\n // ===========================================================================\n\n /**\n * Get example counts for all techniques\n */\n async getExampleCounts(\n token: string,\n ): Promise<BaseResponse<ExampleCountsData>> {\n return this.request<BaseResponse<ExampleCountsData>>(\n this.config.ENDPOINTS.EXAMPLES_COUNTS,\n { token },\n );\n }\n\n /**\n * Get examples, optionally filtered by technique\n */\n async getExamples(\n token: string,\n queryParams?: TechniqueExampleQueryParams,\n ): Promise<BaseResponse<TechniqueExample[]>> {\n const params = createURLSearchParams();\n\n if (queryParams?.technique !== undefined) {\n params.append(\"technique\", String(queryParams.technique));\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.EXAMPLES}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<TechniqueExample[]>>(endpoint, { token });\n }\n\n /**\n * Create a new example (admin only)\n */\n async createExample(\n token: string,\n data: TechniqueExampleCreateRequest,\n ): Promise<BaseResponse<TechniqueExample>> {\n return this.request<BaseResponse<TechniqueExample>>(\n this.config.ENDPOINTS.EXAMPLES,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n // ===========================================================================\n // Board Counts\n // ===========================================================================\n\n /**\n * Get board counts (total and without techniques)\n */\n async getBoardCounts(token: string): Promise<BaseResponse<BoardCountsData>> {\n return this.request<BaseResponse<BoardCountsData>>(\n this.config.ENDPOINTS.BOARDS_COUNTS,\n { token },\n );\n }\n\n /**\n * Get board counts by technique (count of boards with each technique bit set)\n * Returns Record<number, number> where key is technique ID and value is count\n */\n async getBoardCountsByTechnique(\n token: string,\n ): Promise<BaseResponse<BoardCountsByTechniqueData>> {\n return this.request<BaseResponse<BoardCountsByTechniqueData>>(\n this.config.ENDPOINTS.BOARDS_COUNTS_BY_TECHNIQUE,\n { token },\n );\n }\n\n /**\n * Calculate and update puzzle stats (percentages) on levels and techniques.\n * Requires admin authentication.\n */\n async updatePuzzleStats(\n token: string,\n ): Promise<BaseResponse<UpdateStatsData>> {\n return this.request<BaseResponse<UpdateStatsData>>(\n this.config.ENDPOINTS.BOARDS_UPDATE_STATS,\n {\n method: \"POST\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Solver\n // ===========================================================================\n\n /**\n * Builds an endpoint path with query parameters for solver endpoints\n */\n private buildSolverUrl(\n endpoint: string,\n params: Record<string, string | boolean | undefined>,\n ): string {\n const searchParams = createURLSearchParams();\n // Sort keys alphabetically to match Kotlin behavior\n const sortedKeys = Object.keys(params).sort();\n for (const key of sortedKeys) {\n const value = params[key];\n if (value !== undefined) {\n searchParams.append(key, String(value));\n }\n }\n const query = searchParams.toString();\n // Return endpoint + query only, baseUrl is added by request()\n return `${endpoint}${query ? `?${query}` : \"\"}`;\n }\n\n /**\n * Get hints for solving a Sudoku puzzle\n * @throws {HintAccessDeniedError} When hint level exceeds user's subscription tier\n */\n async solverSolve(\n token: string,\n options: SolveOptions,\n ): Promise<BaseResponse<SolveData>> {\n const url = this.buildSolverUrl(this.config.ENDPOINTS.SOLVER_SOLVE, {\n original: options.original,\n user: options.user,\n autopencilmarks: options.autoPencilmarks,\n pencilmarks: options.pencilmarks,\n filters: options.filters,\n techniques: options.techniques,\n });\n\n const fullUrl = `${this.baseUrl}${url}`;\n const requestHeaders: Record<string, string> = {\n ...this.headers,\n };\n\n if (token) {\n requestHeaders[\"Authorization\"] = `Bearer ${token}`;\n }\n\n // Use 120 second timeout for solve (advanced techniques can be slow)\n const response = await this.networkClient.request<\n BaseResponse<SolveData> | HintAccessDeniedResponse\n >(fullUrl, {\n method: \"GET\",\n headers: requestHeaders,\n timeout: 120000,\n });\n\n // Check for hint access denied (402)\n if (response.status === 402 && response.data) {\n const errorResponse = response.data as HintAccessDeniedResponse;\n if (errorResponse.error?.code === \"HINT_ACCESS_DENIED\") {\n throw new HintAccessDeniedError(errorResponse.error);\n }\n }\n\n // Check for other errors\n if (!response.ok || response.data === undefined) {\n throw new Error(\"Failed to get hints from solver\");\n }\n\n return (await decryptSolutionFields(\n response.data,\n )) as BaseResponse<SolveData>;\n }\n\n /**\n * Validate that a Sudoku puzzle has a unique solution.\n * Uses a longer timeout (120s) because validation involves iterative solving.\n */\n async solverValidate(\n token: string,\n options: ValidateOptions,\n ): Promise<BaseResponse<ValidateData>> {\n const url = this.buildSolverUrl(this.config.ENDPOINTS.SOLVER_VALIDATE, {\n original: options.original,\n });\n\n // Use 120 second timeout for validation (iterative solving can be slow)\n return this.request<BaseResponse<ValidateData>>(url, {\n token,\n timeout: 120000,\n });\n }\n\n /**\n * Generate a new random Sudoku puzzle\n */\n async solverGenerate(\n token: string,\n options: GenerateOptions = {},\n ): Promise<BaseResponse<GenerateData>> {\n const url = this.buildSolverUrl(this.config.ENDPOINTS.SOLVER_GENERATE, {\n symmetrical: options.symmetrical,\n });\n\n return this.request<BaseResponse<GenerateData>>(url, { token });\n }\n\n // ===========================================================================\n // Play (Game Session) Endpoints\n // ===========================================================================\n\n /**\n * Start a new game session\n */\n async playStart(\n token: string,\n data: GameStartRequest,\n ): Promise<BaseResponse<GameStartResponse>> {\n return this.request<BaseResponse<GameStartResponse>>(\n this.config.ENDPOINTS.PLAY_START,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n /**\n * Finish the current game session and get rewards\n */\n async playFinish(\n token: string,\n data: GameFinishRequest,\n ): Promise<BaseResponse<GameFinishResponse>> {\n return this.request<BaseResponse<GameFinishResponse>>(\n this.config.ENDPOINTS.PLAY_FINISH,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n // ===========================================================================\n // Communities\n // ===========================================================================\n\n async getCommunities(\n token: string,\n queryParams?: CommunityQueryParams,\n ): Promise<BaseResponse<Community[]>> {\n const params = createURLSearchParams();\n\n if (queryParams?.language !== undefined) {\n params.append(\"language\", queryParams.language);\n }\n\n const query = params.toString();\n const endpoint = `${this.config.ENDPOINTS.COMMUNITIES}${query ? `?${query}` : \"\"}`;\n\n return this.request<BaseResponse<Community[]>>(endpoint, { token });\n }\n\n async getCommunity(\n token: string,\n uuid: string,\n ): Promise<BaseResponse<Community>> {\n validateUUID(uuid);\n return this.request<BaseResponse<Community>>(\n this.config.ENDPOINTS.COMMUNITY(uuid),\n { token },\n );\n }\n\n async createCommunity(\n token: string,\n data: CommunityCreateRequest,\n ): Promise<BaseResponse<Community>> {\n return this.request<BaseResponse<Community>>(\n this.config.ENDPOINTS.COMMUNITIES,\n {\n method: \"POST\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async updateCommunity(\n token: string,\n uuid: string,\n data: CommunityUpdateRequest,\n ): Promise<BaseResponse<Community>> {\n validateUUID(uuid);\n return this.request<BaseResponse<Community>>(\n this.config.ENDPOINTS.COMMUNITY(uuid),\n {\n method: \"PUT\",\n body: data as unknown as Record<string, unknown>,\n token,\n },\n );\n }\n\n async deleteCommunity(\n token: string,\n uuid: string,\n ): Promise<BaseResponse<Community>> {\n validateUUID(uuid);\n return this.request<BaseResponse<Community>>(\n this.config.ENDPOINTS.COMMUNITY(uuid),\n {\n method: \"DELETE\",\n token,\n },\n );\n }\n\n // ===========================================================================\n // Gamification Endpoints\n // ===========================================================================\n\n /**\n * Get user's gamification stats (points, level, badges)\n */\n async getGamificationStats(\n token: string,\n ): Promise<BaseResponse<GamificationStats>> {\n return this.request<BaseResponse<GamificationStats>>(\n this.config.ENDPOINTS.GAMIFICATION_STATS,\n { token },\n );\n }\n\n /**\n * Get all badge definitions (public)\n */\n async getBadgeDefinitions(): Promise<BaseResponse<BadgeDefinition[]>> {\n return this.request<BaseResponse<BadgeDefinition[]>>(\n this.config.ENDPOINTS.GAMIFICATION_BADGES,\n );\n }\n\n /**\n * Get user's point transaction history\n */\n async getPointHistory(\n token: string,\n options?: { limit?: number; offset?: number },\n ): Promise<BaseResponse<PointTransaction[]>> {\n let endpoint = this.config.ENDPOINTS.GAMIFICATION_HISTORY;\n if (options?.limit || options?.offset) {\n const params = createURLSearchParams();\n if (options.limit) params.append(\"limit\", String(options.limit));\n if (options.offset) params.append(\"offset\", String(options.offset));\n endpoint = `${endpoint}?${params.toString()}`;\n }\n return this.request<BaseResponse<PointTransaction[]>>(endpoint, { token });\n }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Factory function to create a new SudojoClient instance.\n *\n * Equivalent to `new SudojoClient(networkClient, baseUrl)` but useful\n * for dependency injection and functional composition patterns.\n *\n * @param networkClient - Network client for making HTTP requests\n * @param baseUrl - Base URL for the Sudojo API\n * @returns A new SudojoClient instance\n */\nexport const createSudojoClient = (\n networkClient: NetworkClient,\n baseUrl: string,\n): SudojoClient => {\n return new SudojoClient(networkClient, baseUrl);\n};\n\n// =============================================================================\n// Utility Exports\n// =============================================================================\n\n/**\n * Re-exported UUID validation utilities from `@sudobility/sudojo_types`.\n *\n * These are used internally by the SudojoClient for parameter validation\n * and are also exported for consumer convenience. Use `isValidUUID` for\n * boolean checks and `validateUUID` when you want an error thrown on invalid input.\n *\n * - `isValidUUID(value)` - Returns true if the string is a valid UUID v4\n * - `validateUUID(value, label)` - Returns the UUID or throws an Error with the label\n */\nexport { isValidUUID, validateUUID };\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sudobility/sudojo_client",
3
- "version": "0.0.111",
3
+ "version": "0.0.113",
4
4
  "description": "TypeScript client library for Sudojo API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -36,15 +36,15 @@
36
36
  "author": "Sudobility Team",
37
37
  "license": "BUSL-1.1",
38
38
  "peerDependencies": {
39
- "@sudobility/di": "^1.5.56",
40
- "@sudobility/sudojo_types": "^1.2.56",
39
+ "@sudobility/di": "^1.5.57",
40
+ "@sudobility/sudojo_types": "^1.2.57",
41
41
  "@sudobility/types": "^1.9.62",
42
42
  "@tanstack/react-query": ">=5.0.0",
43
43
  "react": ">=18.0.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@eslint/js": "^9.38.0",
47
- "@sudobility/di": "^1.5.56",
47
+ "@sudobility/di": "^1.5.57",
48
48
  "@sudobility/sudojo_types": "^1.2.56",
49
49
  "@sudobility/types": "^1.9.62",
50
50
  "@tanstack/react-query": "^5.90.5",
@@ -68,5 +68,8 @@
68
68
  "repository": {
69
69
  "type": "git",
70
70
  "url": "https://github.com/johnqh/sudojo_client.git"
71
+ },
72
+ "dependencies": {
73
+ "@sudobility/sudojo_types": "^1.2.56"
71
74
  }
72
75
  }