@connectedxm/admin 6.2.0 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -95,6 +95,7 @@ src/
95
95
  **Purpose**: Centralized TypeScript interfaces and enums that define all API response types, domain models, and constants used throughout the SDK.
96
96
 
97
97
  **Key Contents**:
98
+
98
99
  - `ConnectedXMResponse<T>` - Wrapper interface for all API responses
99
100
  - Domain models: `Account`, `Event`, `Group`, `Channel`, etc.
100
101
  - Enums: `EventType`, `AccountAccess`, `PassTypeVisibility`, etc.
@@ -116,16 +117,17 @@ export interface ConnectedXMResponse<TData> {
116
117
 
117
118
  ```typescript
118
119
  // Response type for a single account
119
- ConnectedXMResponse<Account>
120
+ ConnectedXMResponse<Account>;
120
121
 
121
122
  // Response type for a list of accounts
122
- ConnectedXMResponse<Account[]>
123
+ ConnectedXMResponse<Account[]>;
123
124
 
124
125
  // Response type with cursor for pagination
125
- ConnectedXMResponse<Account[]> // cursor field included
126
+ ConnectedXMResponse<Account[]>; // cursor field included
126
127
  ```
127
128
 
128
129
  **Conventions**:
130
+
129
131
  - All domain models are PascalCase (e.g., `Account`, `EventSession`)
130
132
  - Enums use PascalCase for the enum name and SCREAMING_SNAKE_CASE for values
131
133
  - Nested interfaces follow the pattern `ParentChild` (e.g., `EventSession`, `AccountAddress`)
@@ -135,6 +137,7 @@ ConnectedXMResponse<Account[]> // cursor field included
135
137
  **Purpose**: Input parameter interfaces for all mutations. These define the shape of data sent to the API when creating or updating resources.
136
138
 
137
139
  **Pattern**: All mutation inputs follow naming conventions:
140
+
138
141
  - `*CreateInputs` - For creating new resources (e.g., `AccountCreateInputs`)
139
142
  - `*UpdateInputs` - For updating existing resources (e.g., `AccountUpdateInputs`)
140
143
  - `*TranslationUpdateInputs` - For updating translated fields (e.g., `EventTranslationUpdateInputs`)
@@ -160,6 +163,7 @@ export interface AccountUpdateInputs {
160
163
  ```
161
164
 
162
165
  **Key Patterns**:
166
+
163
167
  - Create inputs typically have required fields (e.g., `email: string`)
164
168
  - Update inputs make most fields optional (e.g., `firstName?: string | null`)
165
169
  - Fields can be `null` to explicitly clear values
@@ -178,9 +182,10 @@ export interface AccountUpdateInputs {
178
182
 
179
183
  ```typescript
180
184
  export interface AdminApiParams {
181
- apiUrl: "https://admin-api.connected.dev"
182
- | "https://staging-admin-api.connected.dev"
183
- | "http://localhost:4001";
185
+ apiUrl:
186
+ | "https://admin-api.connected.dev"
187
+ | "https://staging-admin-api.connected.dev"
188
+ | "http://localhost:4001";
184
189
  organizationId: string;
185
190
  getToken?: () => Promise<string | undefined> | string | undefined;
186
191
  apiKey?: string;
@@ -189,6 +194,7 @@ export interface AdminApiParams {
189
194
  ```
190
195
 
191
196
  **Parameters**:
197
+
192
198
  - `apiUrl`: The base URL for the API (production, staging, or local)
193
199
  - `organizationId`: Required organization identifier
194
200
  - `getToken`: Optional function to retrieve authentication token
@@ -279,11 +285,11 @@ onMutationError?: (
279
285
  getToken={getToken}
280
286
  onNotAuthorized={(error) => {
281
287
  // Handle 401 errors
282
- router.push('/login');
288
+ router.push("/login");
283
289
  }}
284
290
  onModuleForbidden={(error) => {
285
291
  // Handle 403/460/461 errors
286
- showError('You do not have permission');
292
+ showError("You do not have permission");
287
293
  }}
288
294
  >
289
295
  {children}
@@ -314,6 +320,7 @@ const { data: account, isLoading } = useGetAccount(accountId);
314
320
  ```
315
321
 
316
322
  **Characteristics**:
323
+
317
324
  - Returns a single resource
318
325
  - Automatically handles 404 errors
319
326
  - 60-second stale time
@@ -330,18 +337,18 @@ const { data: account, isLoading } = useGetAccount(accountId);
330
337
  **Example**:
331
338
 
332
339
  ```typescript
333
- const {
334
- data,
335
- fetchNextPage,
336
- hasNextPage,
337
- isFetchingNextPage
338
- } = useGetAccounts(verified, online, {
339
- pageSize: 25,
340
- search: "john"
341
- });
340
+ const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useGetAccounts(
341
+ verified,
342
+ online,
343
+ {
344
+ pageSize: 25,
345
+ search: "john",
346
+ }
347
+ );
342
348
  ```
343
349
 
344
350
  **Characteristics**:
351
+
345
352
  - Uses `pageParam` (number) for pagination
346
353
  - Default page size: 25
347
354
  - Automatically determines next page based on response length
@@ -370,16 +377,13 @@ const getNextPageParam = (lastPage, allPages) => {
370
377
  **Example**:
371
378
 
372
379
  ```typescript
373
- const {
374
- data,
375
- fetchNextPage,
376
- hasNextPage
377
- } = useGetSomeCursorBasedList({
378
- pageSize: 50
380
+ const { data, fetchNextPage, hasNextPage } = useGetSomeCursorBasedList({
381
+ pageSize: 50,
379
382
  });
380
383
  ```
381
384
 
382
385
  **Characteristics**:
386
+
383
387
  - Uses `cursor` (string | number | null) for pagination
384
388
  - Initial cursor is `null`
385
389
  - Next cursor comes from `response.cursor`
@@ -416,6 +420,7 @@ export const ACCOUNT_QUERY_KEY = (accountId: string) => [
416
420
  ```
417
421
 
418
422
  **Conventions**:
423
+
419
424
  - Named: `*_QUERY_KEY`
420
425
  - Returns an array (React Query key format)
421
426
  - Can accept parameters for filtering/variants
@@ -440,6 +445,7 @@ export const SET_ACCOUNT_QUERY_DATA = (
440
445
  ```
441
446
 
442
447
  **Conventions**:
448
+
443
449
  - Named: `SET_*_QUERY_DATA`
444
450
  - Takes QueryClient, key parameters, and response data
445
451
  - Used in mutations to optimistically update cache
@@ -464,6 +470,7 @@ export const GetAccount = async ({
464
470
  ```
465
471
 
466
472
  **Conventions**:
473
+
467
474
  - Named: `Get*` (PascalCase)
468
475
  - Accepts `adminApiParams` (and other params)
469
476
  - Returns `Promise<ConnectedXMResponse<T>>`
@@ -495,6 +502,7 @@ export const useGetAccount = (
495
502
  ```
496
503
 
497
504
  **Conventions**:
505
+
498
506
  - Named: `useGet*` (camelCase with "use" prefix)
499
507
  - Wraps the query function with `useConnectedSingleQuery` or similar
500
508
  - Accepts options that extend base query options
@@ -507,55 +515,62 @@ Query keys follow a hierarchical structure that enables efficient cache manageme
507
515
  #### Structure Pattern
508
516
 
509
517
  ```typescript
510
- ["RESOURCE_TYPE", ...filters, ...identifiers]
518
+ ["RESOURCE_TYPE", ...filters, ...identifiers];
511
519
  ```
512
520
 
513
521
  #### Examples
514
522
 
515
523
  **Base List Query**:
524
+
516
525
  ```typescript
517
- ACCOUNTS_QUERY_KEY()
526
+ ACCOUNTS_QUERY_KEY();
518
527
  // Returns: ["ACCOUNTS"]
519
528
  ```
520
529
 
521
530
  **Filtered List Query**:
531
+
522
532
  ```typescript
523
- ACCOUNTS_QUERY_KEY(true, false) // verified=true, online=false
533
+ ACCOUNTS_QUERY_KEY(true, false); // verified=true, online=false
524
534
  // Returns: ["ACCOUNTS", "VERIFIED", "OFFLINE"]
525
535
  ```
526
536
 
527
537
  **Single Resource Query**:
538
+
528
539
  ```typescript
529
- ACCOUNT_QUERY_KEY("account-123")
540
+ ACCOUNT_QUERY_KEY("account-123");
530
541
  // Returns: ["ACCOUNTS", "account-123"]
531
542
  // Note: Spreads parent key for hierarchy
532
543
  ```
533
544
 
534
545
  **Nested Resource Query**:
546
+
535
547
  ```typescript
536
- EVENT_SESSION_QUERY_KEY("event-123", "session-456")
548
+ EVENT_SESSION_QUERY_KEY("event-123", "session-456");
537
549
  // Returns: ["EVENTS", "event-123", "SESSIONS", "session-456"]
538
550
  ```
539
551
 
540
552
  #### Key Design Principles
541
553
 
542
554
  1. **Hierarchical Inheritance**: Child keys include parent keys
555
+
543
556
  ```typescript
544
557
  export const ACCOUNT_QUERY_KEY = (accountId: string) => [
545
- ...ACCOUNTS_QUERY_KEY(), // Includes parent
558
+ ...ACCOUNTS_QUERY_KEY(), // Includes parent
546
559
  accountId,
547
560
  ];
548
561
  ```
549
562
 
550
563
  2. **Filter Representation**: Filters are included as string constants
564
+
551
565
  ```typescript
552
566
  if (typeof verified !== "undefined")
553
567
  keys.push(verified ? "VERIFIED" : "UNVERIFIED");
554
568
  ```
555
569
 
556
570
  3. **Identifier Last**: Resource IDs come after filters
571
+
557
572
  ```typescript
558
- ["EVENTS", "PAST", "FEATURED", "event-123"]
573
+ ["EVENTS", "PAST", "FEATURED", "event-123"];
559
574
  ```
560
575
 
561
576
  4. **Consistent Naming**: Use SCREAMING_SNAKE_CASE for constants
@@ -590,6 +605,7 @@ export interface CreateAccountParams extends MutationParams {
590
605
  ```
591
606
 
592
607
  **Conventions**:
608
+
593
609
  - Extends `MutationParams` (includes `adminApiParams` and `queryClient`)
594
610
  - Named: `*Params` (e.g., `CreateAccountParams`, `UpdateAccountParams`)
595
611
  - Includes domain-specific parameters
@@ -613,17 +629,18 @@ export const CreateAccount = async ({
613
629
  `/accounts`,
614
630
  account
615
631
  );
616
-
632
+
617
633
  if (queryClient && data.status === "ok") {
618
634
  queryClient.invalidateQueries({ queryKey: ACCOUNTS_QUERY_KEY() });
619
635
  SET_ACCOUNT_QUERY_DATA(queryClient, [data?.data.id], data);
620
636
  }
621
-
637
+
622
638
  return data;
623
639
  };
624
640
  ```
625
641
 
626
642
  **Conventions**:
643
+
627
644
  - Named: `Create*`, `Update*`, `Delete*` (PascalCase)
628
645
  - Accepts params including `adminApiParams` and `queryClient`
629
646
  - Returns `Promise<ConnectedXMResponse<T>>`
@@ -655,6 +672,7 @@ export const useCreateAccount = (
655
672
  ```
656
673
 
657
674
  **Conventions**:
675
+
658
676
  - Named: `useCreate*`, `useUpdate*`, `useDelete*`
659
677
  - Wraps mutation function with `useConnectedMutation`
660
678
  - Options exclude `queryClient` and `adminApiParams` (injected automatically)
@@ -675,16 +693,19 @@ if (queryClient && data.status === "ok") {
675
693
  ```
676
694
 
677
695
  **When to Use**:
696
+
678
697
  - After creating new resources (adds to list)
679
698
  - After deleting resources (removes from list)
680
699
  - When you want fresh data from the server
681
700
 
682
701
  **Benefits**:
702
+
683
703
  - Ensures data consistency
684
704
  - Handles edge cases automatically
685
705
  - Simple to implement
686
706
 
687
707
  **Drawbacks**:
708
+
688
709
  - Causes network request
689
710
  - May cause loading states
690
711
 
@@ -696,29 +717,33 @@ Directly update the cache with known data.
696
717
  if (queryClient && data.status === "ok") {
697
718
  // Invalidate list to show new item
698
719
  queryClient.invalidateQueries({ queryKey: ACCOUNTS_QUERY_KEY() });
699
-
720
+
700
721
  // Optimistically update single item cache
701
722
  SET_ACCOUNT_QUERY_DATA(queryClient, [data?.data.id], data);
702
723
  }
703
724
  ```
704
725
 
705
726
  **When to Use**:
727
+
706
728
  - After updating existing resources
707
729
  - When you have the complete updated data
708
730
  - To provide instant UI feedback
709
731
 
710
732
  **Benefits**:
733
+
711
734
  - Instant UI updates
712
735
  - Better user experience
713
736
  - Reduces unnecessary requests
714
737
 
715
738
  **Drawbacks**:
739
+
716
740
  - Must ensure data consistency
717
741
  - More complex implementation
718
742
 
719
743
  #### Common Patterns
720
744
 
721
745
  **Create Pattern**:
746
+
722
747
  ```typescript
723
748
  // 1. Invalidate list (to show new item)
724
749
  queryClient.invalidateQueries({ queryKey: ACCOUNTS_QUERY_KEY() });
@@ -728,6 +753,7 @@ SET_ACCOUNT_QUERY_DATA(queryClient, [data?.data.id], data);
728
753
  ```
729
754
 
730
755
  **Update Pattern**:
756
+
731
757
  ```typescript
732
758
  // 1. Invalidate list (in case item appears in filtered views)
733
759
  queryClient.invalidateQueries({ queryKey: ACCOUNTS_QUERY_KEY() });
@@ -737,6 +763,7 @@ SET_ACCOUNT_QUERY_DATA(queryClient, [accountId], data);
737
763
  ```
738
764
 
739
765
  **Delete Pattern**:
766
+
740
767
  ```typescript
741
768
  // 1. Invalidate list (to remove item)
742
769
  queryClient.invalidateQueries({ queryKey: ACCOUNTS_QUERY_KEY() });
@@ -746,6 +773,7 @@ queryClient.removeQueries({ queryKey: ACCOUNT_QUERY_KEY(accountId) });
746
773
  ```
747
774
 
748
775
  **Complex Invalidation**:
776
+
749
777
  ```typescript
750
778
  // Invalidate multiple related queries
751
779
  queryClient.invalidateQueries({ queryKey: ACCOUNTS_QUERY_KEY() });
@@ -822,6 +850,7 @@ queries/
822
850
  #### Domain Organization
823
851
 
824
852
  Each domain folder contains:
853
+
825
854
  - **Multiple query files**: One per endpoint/resource
826
855
  - **index.ts**: Barrel export file that re-exports all queries from the domain
827
856
 
@@ -838,11 +867,13 @@ export * from "./useGetAccountEvents";
838
867
  #### Base Utilities
839
868
 
840
869
  The root `queries/` directory contains reusable query hooks:
870
+
841
871
  - `useConnectedSingleQuery.ts` - Wrapper for single resource queries
842
872
  - `useConnectedInfiniteQuery.ts` - Wrapper for paginated list queries
843
873
  - `useConnectedCursorQuery.ts` - Wrapper for cursor-based queries
844
874
 
845
875
  These provide:
876
+
846
877
  - Consistent error handling
847
878
  - Automatic retry logic
848
879
  - Standardized query options
@@ -877,6 +908,7 @@ mutations/
877
908
  #### Domain Organization
878
909
 
879
910
  Similar to queries:
911
+
880
912
  - **Multiple mutation files**: One per operation (Create, Update, Delete, etc.)
881
913
  - **index.ts**: Barrel export file
882
914
  - **translations/**: Subfolder for translation-specific mutations (when applicable)
@@ -884,6 +916,7 @@ Similar to queries:
884
916
  #### Base Utility
885
917
 
886
918
  `useConnectedMutation.ts` provides:
919
+
887
920
  - Automatic `adminApiParams` injection
888
921
  - Error handling integration
889
922
  - QueryClient access
@@ -896,19 +929,23 @@ Utility functions used across queries and mutations.
896
929
  #### Available Utilities
897
930
 
898
931
  **Cache Management**:
932
+
899
933
  - `CacheIndividualQueries.ts` - Caches individual items from list responses
900
934
  - Used in queries to populate single-item caches from list responses
901
935
 
902
936
  **Data Transformation**:
937
+
903
938
  - `TransformPrice.ts` - Formats price values
904
939
  - `GetImageVariant.ts` - Generates image URLs with variants
905
940
  - `CalculateDuration.ts` - Calculates time durations
906
941
 
907
942
  **Query Helpers**:
943
+
908
944
  - `MergeInfinitePages.ts` - Flattens infinite query pages into single array
909
945
  - `AppendInfiniteQuery.ts` - Appends new page to infinite query cache
910
946
 
911
947
  **Type Utilities**:
948
+
912
949
  - `IsUUID.ts` - Validates UUID format
913
950
  - `GetErrorMessage.ts` - Extracts error messages from responses
914
951
 
@@ -933,46 +970,56 @@ The SDK implements standardized error handling across all queries and mutations.
933
970
  All query hooks handle these status codes consistently:
934
971
 
935
972
  **401 - Unauthorized**:
973
+
936
974
  ```typescript
937
975
  if (error.response?.status === 401) {
938
976
  if (onNotAuthorized) onNotAuthorized(error, queryKeys, shouldRedirect);
939
977
  return false; // Don't retry
940
978
  }
941
979
  ```
980
+
942
981
  - Triggers `onNotAuthorized` callback
943
982
  - Typically indicates expired token
944
983
  - No automatic retry
945
984
 
946
985
  **403/460/461 - Forbidden**:
986
+
947
987
  ```typescript
948
- if (error.response?.status === 403 ||
949
- error.response?.status === 460 ||
950
- error.response?.status === 461) {
988
+ if (
989
+ error.response?.status === 403 ||
990
+ error.response?.status === 460 ||
991
+ error.response?.status === 461
992
+ ) {
951
993
  if (onModuleForbidden) onModuleForbidden(error, queryKeys, shouldRedirect);
952
994
  return false; // Don't retry
953
995
  }
954
996
  ```
997
+
955
998
  - Triggers `onModuleForbidden` callback
956
999
  - Indicates user lacks permission
957
1000
  - No automatic retry
958
1001
 
959
1002
  **404 - Not Found**:
1003
+
960
1004
  ```typescript
961
1005
  if (error.response?.status === 404) {
962
1006
  if (onNotFound) onNotFound(error, queryKeys, shouldRedirect);
963
1007
  return false; // Don't retry
964
1008
  }
965
1009
  ```
1010
+
966
1011
  - Triggers `onNotFound` callback
967
1012
  - Resource doesn't exist
968
1013
  - No automatic retry
969
1014
 
970
1015
  **Other Errors**:
1016
+
971
1017
  ```typescript
972
1018
  // Default retry logic
973
1019
  if (failureCount < 3) return true;
974
1020
  return false;
975
1021
  ```
1022
+
976
1023
  - Retries up to 3 times
977
1024
  - For network errors, timeouts, etc.
978
1025
 
@@ -985,6 +1032,7 @@ return false;
985
1032
  #### Error Callbacks
986
1033
 
987
1034
  All error callbacks receive:
1035
+
988
1036
  1. **Error object**: Axios error with response data
989
1037
  2. **Query key**: The React Query key that failed
990
1038
  3. **Should redirect flag**: Whether redirect should occur
@@ -1118,6 +1166,7 @@ Caches individual items from a list response into their respective single-item q
1118
1166
  **Purpose**: When fetching a list, also populate individual item caches for instant access.
1119
1167
 
1120
1168
  **Signature**:
1169
+
1121
1170
  ```typescript
1122
1171
  export const CacheIndividualQueries = <TData extends ItemWithId>(
1123
1172
  page: ConnectedXMResponse<TData[]>,
@@ -1128,22 +1177,21 @@ export const CacheIndividualQueries = <TData extends ItemWithId>(
1128
1177
  ```
1129
1178
 
1130
1179
  **Usage Example**:
1180
+
1131
1181
  ```typescript
1132
- const { data } = await adminApi.get('/accounts');
1133
- CacheIndividualQueries(
1134
- data,
1135
- queryClient,
1136
- (id) => ACCOUNT_QUERY_KEY(id)
1137
- );
1182
+ const { data } = await adminApi.get("/accounts");
1183
+ CacheIndividualQueries(data, queryClient, (id) => ACCOUNT_QUERY_KEY(id));
1138
1184
  ```
1139
1185
 
1140
1186
  **Features**:
1187
+
1141
1188
  - Caches by `id`
1142
1189
  - Also caches by `slug`, `username`, `name`, `code`, `alternateId` if available
1143
1190
  - Sets cache timestamp to 1 minute ago (allows refetch if needed)
1144
1191
  - Optional `itemMap` for data transformation
1145
1192
 
1146
1193
  **When to Use**:
1194
+
1147
1195
  - In list queries to populate individual caches
1148
1196
  - After fetching paginated lists
1149
1197
  - To enable instant navigation to detail pages
@@ -1155,11 +1203,13 @@ Direct cache update helpers for each resource type.
1155
1203
  **Purpose**: Update cache with known data (optimistic updates).
1156
1204
 
1157
1205
  **Pattern**:
1206
+
1158
1207
  ```typescript
1159
1208
  SET_ACCOUNT_QUERY_DATA(queryClient, [accountId], response);
1160
1209
  ```
1161
1210
 
1162
1211
  **Usage**:
1212
+
1163
1213
  - After mutations to update cache immediately
1164
1214
  - For optimistic UI updates
1165
1215
  - When you have complete data
@@ -1171,13 +1221,15 @@ SET_ACCOUNT_QUERY_DATA(queryClient, [accountId], response);
1171
1221
  Flattens infinite query pages into a single array.
1172
1222
 
1173
1223
  **Signature**:
1224
+
1174
1225
  ```typescript
1175
1226
  export function MergeInfinitePages<TData>(
1176
1227
  data: InfiniteData<ConnectedXMResponse<TData[]>>
1177
- ): TData[]
1228
+ ): TData[];
1178
1229
  ```
1179
1230
 
1180
1231
  **Usage Example**:
1232
+
1181
1233
  ```typescript
1182
1234
  const { data } = useGetAccounts();
1183
1235
  const allAccounts = MergeInfinitePages(data);
@@ -1185,6 +1237,7 @@ const allAccounts = MergeInfinitePages(data);
1185
1237
  ```
1186
1238
 
1187
1239
  **When to Use**:
1240
+
1188
1241
  - Displaying all items from infinite query
1189
1242
  - Filtering/searching across all pages
1190
1243
  - Calculating totals across pages
@@ -1305,6 +1358,7 @@ export const useGet[Resource] = (
1305
1358
  #### Step 6: Export from Index
1306
1359
 
1307
1360
  Add to `src/queries/[domain]/index.ts`:
1361
+
1308
1362
  ```typescript
1309
1363
  export * from "./useGet[Resource]";
1310
1364
  ```
@@ -1418,12 +1472,12 @@ export const Create[Resource] = async ({
1418
1472
  `/[endpoint]`,
1419
1473
  [resource]
1420
1474
  );
1421
-
1475
+
1422
1476
  if (queryClient && data.status === "ok") {
1423
1477
  queryClient.invalidateQueries({ queryKey: [RESOURCES]_QUERY_KEY() });
1424
1478
  SET_[RESOURCE]_QUERY_DATA(queryClient, [data?.data.id], data);
1425
1479
  }
1426
-
1480
+
1427
1481
  return data;
1428
1482
  };
1429
1483
  ```
@@ -1454,6 +1508,7 @@ export const useCreate[Resource] = (
1454
1508
  #### Step 5: Export from Index
1455
1509
 
1456
1510
  Add to `src/mutations/[domain]/index.ts`:
1511
+
1457
1512
  ```typescript
1458
1513
  export * from "./useCreate[Resource]";
1459
1514
  ```
@@ -1533,19 +1588,19 @@ export const useCreateGroup = (
1533
1588
 
1534
1589
  ```typescript
1535
1590
  // Simple list
1536
- ACCOUNTS_QUERY_KEY()
1591
+ ACCOUNTS_QUERY_KEY();
1537
1592
  // ["ACCOUNTS"]
1538
1593
 
1539
1594
  // Filtered list
1540
- ACCOUNTS_QUERY_KEY(true, false)
1595
+ ACCOUNTS_QUERY_KEY(true, false);
1541
1596
  // ["ACCOUNTS", "VERIFIED", "OFFLINE"]
1542
1597
 
1543
1598
  // Single item (inherits parent)
1544
- ACCOUNT_QUERY_KEY("123")
1599
+ ACCOUNT_QUERY_KEY("123");
1545
1600
  // ["ACCOUNTS", "123"]
1546
1601
 
1547
1602
  // Nested resource
1548
- EVENT_SESSION_QUERY_KEY("event-123", "session-456")
1603
+ EVENT_SESSION_QUERY_KEY("event-123", "session-456");
1549
1604
  // ["EVENTS", "event-123", "SESSIONS", "session-456"]
1550
1605
  ```
1551
1606
 
@@ -1553,14 +1608,14 @@ EVENT_SESSION_QUERY_KEY("event-123", "session-456")
1553
1608
 
1554
1609
  ```typescript
1555
1610
  // ❌ Don't use IDs in base list keys
1556
- ACCOUNTS_QUERY_KEY("account-123") // Wrong!
1611
+ ACCOUNTS_QUERY_KEY("account-123"); // Wrong!
1557
1612
 
1558
1613
  // ❌ Don't forget to inherit parent
1559
- ACCOUNT_QUERY_KEY("123")
1614
+ ACCOUNT_QUERY_KEY("123");
1560
1615
  // Should be: [...ACCOUNTS_QUERY_KEY(), "123"]
1561
1616
 
1562
1617
  // ❌ Don't use inconsistent naming
1563
- accounts_query_key() // Should be ACCOUNTS_QUERY_KEY
1618
+ accounts_query_key(); // Should be ACCOUNTS_QUERY_KEY
1564
1619
  ```
1565
1620
 
1566
1621
  ### 8.4 Cache Management
@@ -1568,11 +1623,13 @@ accounts_query_key() // Should be ACCOUNTS_QUERY_KEY
1568
1623
  #### When to Invalidate
1569
1624
 
1570
1625
  **Always Invalidate**:
1626
+
1571
1627
  - After creating new resources
1572
1628
  - After deleting resources
1573
1629
  - When data might be stale
1574
1630
 
1575
1631
  **Example**:
1632
+
1576
1633
  ```typescript
1577
1634
  // After create
1578
1635
  queryClient.invalidateQueries({ queryKey: ACCOUNTS_QUERY_KEY() });
@@ -1581,11 +1638,13 @@ queryClient.invalidateQueries({ queryKey: ACCOUNTS_QUERY_KEY() });
1581
1638
  #### When to Update Directly
1582
1639
 
1583
1640
  **Update Directly**:
1641
+
1584
1642
  - After updating existing resources (you have the new data)
1585
1643
  - For optimistic updates
1586
1644
  - When you want instant UI feedback
1587
1645
 
1588
1646
  **Example**:
1647
+
1589
1648
  ```typescript
1590
1649
  // After update
1591
1650
  SET_ACCOUNT_QUERY_DATA(queryClient, [accountId], updatedData);
@@ -1594,18 +1653,21 @@ SET_ACCOUNT_QUERY_DATA(queryClient, [accountId], updatedData);
1594
1653
  #### Best Practices
1595
1654
 
1596
1655
  1. **Combine Both**: Invalidate lists, update individual items
1656
+
1597
1657
  ```typescript
1598
1658
  queryClient.invalidateQueries({ queryKey: ACCOUNTS_QUERY_KEY() });
1599
1659
  SET_ACCOUNT_QUERY_DATA(queryClient, [accountId], data);
1600
1660
  ```
1601
1661
 
1602
1662
  2. **Invalidate Related Queries**: If an account update affects events, invalidate both
1663
+
1603
1664
  ```typescript
1604
1665
  queryClient.invalidateQueries({ queryKey: ACCOUNTS_QUERY_KEY() });
1605
1666
  queryClient.invalidateQueries({ queryKey: EVENTS_QUERY_KEY() });
1606
1667
  ```
1607
1668
 
1608
1669
  3. **Use Hierarchical Keys**: Invalidating parent invalidates children
1670
+
1609
1671
  ```typescript
1610
1672
  // This invalidates all account queries
1611
1673
  queryClient.invalidateQueries({ queryKey: ACCOUNTS_QUERY_KEY() });
@@ -1627,10 +1689,10 @@ SET_ACCOUNT_QUERY_DATA(queryClient, [accountId], updatedData);
1627
1689
  #### Mocking AdminAPI
1628
1690
 
1629
1691
  ```typescript
1630
- import { vi } from 'vitest';
1631
- import { GetAdminAPI } from '@src/AdminAPI';
1692
+ import { vi } from "vitest";
1693
+ import { GetAdminAPI } from "@src/AdminAPI";
1632
1694
 
1633
- vi.mock('@src/AdminAPI', () => ({
1695
+ vi.mock("@src/AdminAPI", () => ({
1634
1696
  GetAdminAPI: vi.fn(),
1635
1697
  }));
1636
1698
  ```
@@ -1638,22 +1700,22 @@ vi.mock('@src/AdminAPI', () => ({
1638
1700
  #### Testing Query Hooks
1639
1701
 
1640
1702
  ```typescript
1641
- import { renderHook, waitFor } from '@testing-library/react';
1642
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
1643
- import { useGetAccount } from '@src/queries';
1703
+ import { renderHook, waitFor } from "@testing-library/react";
1704
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
1705
+ import { useGetAccount } from "@src/queries";
1644
1706
 
1645
- test('fetches account data', async () => {
1707
+ test("fetches account data", async () => {
1646
1708
  const queryClient = new QueryClient();
1647
1709
  const wrapper = ({ children }) => (
1648
- <QueryClientProvider client={queryClient}>
1649
- {children}
1650
- </QueryClientProvider>
1710
+ <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
1651
1711
  );
1652
1712
 
1653
- const { result } = renderHook(() => useGetAccount('account-123'), { wrapper });
1713
+ const { result } = renderHook(() => useGetAccount("account-123"), {
1714
+ wrapper,
1715
+ });
1654
1716
 
1655
1717
  await waitFor(() => expect(result.current.isSuccess).toBe(true));
1656
- expect(result.current.data?.data.id).toBe('account-123');
1718
+ expect(result.current.data?.data.id).toBe("account-123");
1657
1719
  });
1658
1720
  ```
1659
1721
 
@@ -1662,14 +1724,14 @@ test('fetches account data', async () => {
1662
1724
  #### Testing Mutation Hooks
1663
1725
 
1664
1726
  ```typescript
1665
- import { renderHook, waitFor } from '@testing-library/react';
1666
- import { useCreateAccount } from '@src/mutations';
1727
+ import { renderHook, waitFor } from "@testing-library/react";
1728
+ import { useCreateAccount } from "@src/mutations";
1667
1729
 
1668
- test('creates account and updates cache', async () => {
1730
+ test("creates account and updates cache", async () => {
1669
1731
  const { result } = renderHook(() => useCreateAccount());
1670
1732
 
1671
1733
  result.current.mutate({
1672
- account: { email: 'test@example.com' }
1734
+ account: { email: "test@example.com" },
1673
1735
  });
1674
1736
 
1675
1737
  await waitFor(() => expect(result.current.isSuccess).toBe(true));
@@ -1682,17 +1744,17 @@ test('creates account and updates cache', async () => {
1682
1744
 
1683
1745
  ```typescript
1684
1746
  const mockAccountResponse = {
1685
- status: 'ok',
1686
- message: 'Success',
1747
+ status: "ok",
1748
+ message: "Success",
1687
1749
  data: {
1688
- id: 'account-123',
1689
- email: 'test@example.com',
1750
+ id: "account-123",
1751
+ email: "test@example.com",
1690
1752
  // ... other fields
1691
- }
1753
+ },
1692
1754
  };
1693
1755
 
1694
1756
  (GetAdminAPI as any).mockResolvedValue({
1695
- get: vi.fn().mockResolvedValue({ data: mockAccountResponse })
1757
+ get: vi.fn().mockResolvedValue({ data: mockAccountResponse }),
1696
1758
  });
1697
1759
  ```
1698
1760
 
@@ -1713,6 +1775,7 @@ The SDK uses `tsup` for building:
1713
1775
  ```
1714
1776
 
1715
1777
  **Output**:
1778
+
1716
1779
  - CommonJS: `dist/index.cjs`
1717
1780
  - ES Modules: `dist/index.js`
1718
1781
  - Type Definitions: `dist/index.d.ts`
@@ -1769,18 +1832,21 @@ dist/
1769
1832
  ### Common Patterns Quick Reference
1770
1833
 
1771
1834
  **Query Pattern**:
1835
+
1772
1836
  ```typescript
1773
1837
  QUERY_KEY → SETTER → QUERY_FUNCTION → REACT_HOOK
1774
1838
  ```
1775
1839
 
1776
1840
  **Mutation Pattern**:
1841
+
1777
1842
  ```typescript
1778
1843
  PARAMS_INTERFACE → MUTATION_FUNCTION → REACT_HOOK
1779
1844
  ```
1780
1845
 
1781
1846
  **Cache Update Pattern**:
1847
+
1782
1848
  ```typescript
1783
- invalidateQueries() + SET_*_QUERY_DATA()
1849
+ invalidateQueries() + SET_ * _QUERY_DATA();
1784
1850
  ```
1785
1851
 
1786
1852
  ---
@@ -1788,5 +1854,3 @@ invalidateQueries() + SET_*_QUERY_DATA()
1788
1854
  ## Questions or Issues?
1789
1855
 
1790
1856
  For questions about this SDK or to report issues, please contact the ConnectedXM development team or refer to the main repository documentation.
1791
-
1792
-