@01.software/sdk 0.10.1 → 0.12.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.
@@ -59,7 +59,6 @@ interface Config {
59
59
  'playlist-tags': PlaylistTag;
60
60
  tracks: Track;
61
61
  'track-assets': TrackAsset;
62
- 'playlist-tracks': PlaylistTrack;
63
62
  'track-categories': TrackCategory;
64
63
  'track-tags': TrackTag;
65
64
  galleries: Gallery;
@@ -130,12 +129,6 @@ interface Config {
130
129
  'post-authors': {
131
130
  posts: 'posts';
132
131
  };
133
- playlists: {
134
- items: 'playlist-tracks';
135
- };
136
- tracks: {
137
- playlistEntries: 'playlist-tracks';
138
- };
139
132
  galleries: {
140
133
  items: 'gallery-items';
141
134
  };
@@ -194,7 +187,6 @@ interface Config {
194
187
  'playlist-tags': PlaylistTagsSelect<false> | PlaylistTagsSelect<true>;
195
188
  tracks: TracksSelect<false> | TracksSelect<true>;
196
189
  'track-assets': TrackAssetsSelect<false> | TrackAssetsSelect<true>;
197
- 'playlist-tracks': PlaylistTracksSelect<false> | PlaylistTracksSelect<true>;
198
190
  'track-categories': TrackCategoriesSelect<false> | TrackCategoriesSelect<true>;
199
191
  'track-tags': TrackTagsSelect<false> | TrackTagsSelect<true>;
200
192
  galleries: GalleriesSelect<false> | GalleriesSelect<true>;
@@ -522,7 +514,7 @@ interface Image {
522
514
  interface FieldConfig {
523
515
  id: string;
524
516
  tenant?: (string | null) | Tenant;
525
- collectionSlug: 'products' | 'product-variants' | 'product-options' | 'product-option-values' | 'product-collections' | 'product-categories' | 'product-tags' | 'brands' | 'discounts' | 'shipping-policies' | 'orders' | 'carts' | 'transactions' | 'fulfillments' | 'returns' | 'customers' | 'customer-groups' | 'post-authors' | 'posts' | 'post-categories' | 'post-tags' | 'documents' | 'document-categories' | 'document-types' | 'playlists' | 'playlist-categories' | 'playlist-tags' | 'tracks' | 'playlist-tracks' | 'track-categories' | 'track-tags' | 'galleries' | 'gallery-categories' | 'gallery-tags' | 'gallery-items' | 'links' | 'link-categories' | 'link-tags' | 'canvases' | 'canvas-categories' | 'canvas-tags' | 'canvas-node-types' | 'canvas-edge-types' | 'videos' | 'video-categories' | 'video-tags' | 'live-streams' | 'forms' | 'threads' | 'comments' | 'reactions' | 'reaction-types' | 'bookmarks' | 'thread-categories';
517
+ collectionSlug: 'products' | 'product-variants' | 'product-options' | 'product-option-values' | 'product-collections' | 'product-categories' | 'product-tags' | 'brands' | 'discounts' | 'shipping-policies' | 'orders' | 'carts' | 'transactions' | 'fulfillments' | 'returns' | 'customers' | 'customer-groups' | 'post-authors' | 'posts' | 'post-categories' | 'post-tags' | 'documents' | 'document-categories' | 'document-types' | 'playlists' | 'playlist-categories' | 'playlist-tags' | 'tracks' | 'track-categories' | 'track-tags' | 'galleries' | 'gallery-categories' | 'gallery-tags' | 'gallery-items' | 'links' | 'link-categories' | 'link-tags' | 'canvases' | 'canvas-categories' | 'canvas-tags' | 'canvas-node-types' | 'canvas-edge-types' | 'videos' | 'video-categories' | 'video-tags' | 'live-streams' | 'forms' | 'threads' | 'comments' | 'reactions' | 'reaction-types' | 'bookmarks' | 'thread-categories';
526
518
  isHidden?: boolean | null;
527
519
  hiddenFields?: {
528
520
  [k: string]: unknown;
@@ -1255,6 +1247,10 @@ interface Product {
1255
1247
  * Maximum order quantity
1256
1248
  */
1257
1249
  maxOrderQuantity?: number | null;
1250
+ /**
1251
+ * Primary option used to expand this product into option-value listing cards (for example, Color)
1252
+ */
1253
+ listingPrimaryOption?: (string | null) | ProductOption;
1258
1254
  /**
1259
1255
  * Derived listing projection for product cards and search
1260
1256
  */
@@ -1814,7 +1810,7 @@ interface ShippingPolicy {
1814
1810
  /**
1815
1811
  * Amount in KRW (won)
1816
1812
  */
1817
- baseAmount: number;
1813
+ baseAmount?: number | null;
1818
1814
  /**
1819
1815
  * Amount in KRW (won)
1820
1816
  */
@@ -2492,12 +2488,12 @@ interface Discount {
2492
2488
  /**
2493
2489
  * Minimum order amount for this tier
2494
2490
  */
2495
- minAmount: number;
2496
- discountType: 'percentage' | 'fixed_amount';
2491
+ minAmount?: number | null;
2492
+ discountType?: ('percentage' | 'fixed_amount') | null;
2497
2493
  /**
2498
2494
  * Discount rate (%) or fixed amount
2499
2495
  */
2500
- value: number;
2496
+ value?: number | null;
2501
2497
  id?: string | null;
2502
2498
  }[] | null;
2503
2499
  /**
@@ -2907,11 +2903,7 @@ interface Playlist {
2907
2903
  videos?: (string | Video)[] | null;
2908
2904
  categories?: (string | PlaylistCategory)[] | null;
2909
2905
  tags?: (string | PlaylistTag)[] | null;
2910
- items?: {
2911
- docs?: (string | PlaylistTrack)[];
2912
- hasNextPage?: boolean;
2913
- totalDocs?: number;
2914
- };
2906
+ tracks?: (string | Track)[] | null;
2915
2907
  seo?: {
2916
2908
  /**
2917
2909
  * Search result title (falls back to document title)
@@ -3013,30 +3005,6 @@ interface PlaylistTag {
3013
3005
  createdAt: string;
3014
3006
  deletedAt?: string | null;
3015
3007
  }
3016
- /**
3017
- * This interface was referenced by `Config`'s JSON-Schema
3018
- * via the `definition` "playlist-tracks".
3019
- */
3020
- interface PlaylistTrack {
3021
- id: string;
3022
- '_playlist-tracks_items_order'?: string | null;
3023
- _order?: string | null;
3024
- tenant?: (string | null) | Tenant;
3025
- playlist?: (string | null) | Playlist;
3026
- track?: (string | null) | Track;
3027
- addedAt?: string | null;
3028
- addedBy?: (string | null) | Customer;
3029
- titleOverride?: string | null;
3030
- artistOverride?: string | null;
3031
- note?: string | null;
3032
- visibility?: ('visible' | 'hidden') | null;
3033
- metadata?: {
3034
- [k: string]: unknown;
3035
- } | unknown[] | string | number | boolean | null;
3036
- updatedAt: string;
3037
- createdAt: string;
3038
- deletedAt?: string | null;
3039
- }
3040
3008
  /**
3041
3009
  * This interface was referenced by `Config`'s JSON-Schema
3042
3010
  * via the `definition` "tracks".
@@ -3045,10 +3013,6 @@ interface Track {
3045
3013
  id: string;
3046
3014
  _order?: string | null;
3047
3015
  tenant?: (string | null) | Tenant;
3048
- /**
3049
- * Source type of this track
3050
- */
3051
- kind?: ('owned_asset' | 'external_reference') | null;
3052
3016
  title: string;
3053
3017
  /**
3054
3018
  * Short summary for listing/cards
@@ -3074,11 +3038,6 @@ interface Track {
3074
3038
  releaseDate?: string | null;
3075
3039
  categories?: (string | TrackCategory)[] | null;
3076
3040
  tags?: (string | TrackTag)[] | null;
3077
- playlistEntries?: {
3078
- docs?: (string | PlaylistTrack)[];
3079
- hasNextPage?: boolean;
3080
- totalDocs?: number;
3081
- };
3082
3041
  asset?: (string | null) | TrackAsset;
3083
3042
  /**
3084
3043
  * When enabled, the slug will auto-generate from the title field on save and autosave.
@@ -3587,12 +3546,12 @@ interface CanvasNodeType {
3587
3546
  /**
3588
3547
  * English key (e.g. body, url)
3589
3548
  */
3590
- name: string;
3591
- label: string;
3592
- fieldType: 'text' | 'textarea' | 'number' | 'url' | 'color' | 'image' | 'date' | 'select' | 'toggle';
3549
+ name?: string | null;
3550
+ label?: string | null;
3551
+ fieldType?: ('text' | 'textarea' | 'number' | 'url' | 'color' | 'image' | 'date' | 'select' | 'toggle') | null;
3593
3552
  options?: {
3594
- label: string;
3595
- value: string;
3553
+ label?: string | null;
3554
+ value?: string | null;
3596
3555
  id?: string | null;
3597
3556
  }[] | null;
3598
3557
  /**
@@ -3649,12 +3608,12 @@ interface CanvasEdgeType {
3649
3608
  /**
3650
3609
  * English key (e.g. condition, weight)
3651
3610
  */
3652
- name: string;
3653
- label: string;
3654
- fieldType: 'text' | 'textarea' | 'number' | 'url' | 'color' | 'select' | 'toggle';
3611
+ name?: string | null;
3612
+ label?: string | null;
3613
+ fieldType?: ('text' | 'textarea' | 'number' | 'url' | 'color' | 'select' | 'toggle') | null;
3655
3614
  options?: {
3656
- label: string;
3657
- value: string;
3615
+ label?: string | null;
3616
+ value?: string | null;
3658
3617
  id?: string | null;
3659
3618
  }[] | null;
3660
3619
  defaultValue?: string | null;
@@ -4245,9 +4204,6 @@ interface PayloadLockedDocument {
4245
4204
  } | null) | ({
4246
4205
  relationTo: 'track-assets';
4247
4206
  value: string | TrackAsset;
4248
- } | null) | ({
4249
- relationTo: 'playlist-tracks';
4250
- value: string | PlaylistTrack;
4251
4207
  } | null) | ({
4252
4208
  relationTo: 'track-categories';
4253
4209
  value: string | TrackCategory;
@@ -4900,6 +4856,7 @@ interface ProductsSelect<T extends boolean = true> {
4900
4856
  collections?: T;
4901
4857
  minOrderQuantity?: T;
4902
4858
  maxOrderQuantity?: T;
4859
+ listingPrimaryOption?: T;
4903
4860
  listing?: T | {
4904
4861
  selectionHintVariant?: T;
4905
4862
  primaryImage?: T;
@@ -5817,7 +5774,7 @@ interface PlaylistsSelect<T extends boolean = true> {
5817
5774
  videos?: T;
5818
5775
  categories?: T;
5819
5776
  tags?: T;
5820
- items?: T;
5777
+ tracks?: T;
5821
5778
  seo?: T | {
5822
5779
  title?: T;
5823
5780
  description?: T;
@@ -5886,7 +5843,6 @@ interface PlaylistTagsSelect<T extends boolean = true> {
5886
5843
  interface TracksSelect<T extends boolean = true> {
5887
5844
  _order?: T;
5888
5845
  tenant?: T;
5889
- kind?: T;
5890
5846
  title?: T;
5891
5847
  description?: T;
5892
5848
  content?: T;
@@ -5895,7 +5851,6 @@ interface TracksSelect<T extends boolean = true> {
5895
5851
  releaseDate?: T;
5896
5852
  categories?: T;
5897
5853
  tags?: T;
5898
- playlistEntries?: T;
5899
5854
  asset?: T;
5900
5855
  generateSlug?: T;
5901
5856
  slug?: T;
@@ -5939,27 +5894,6 @@ interface TrackAssetsSelect<T extends boolean = true> {
5939
5894
  focalX?: T;
5940
5895
  focalY?: T;
5941
5896
  }
5942
- /**
5943
- * This interface was referenced by `Config`'s JSON-Schema
5944
- * via the `definition` "playlist-tracks_select".
5945
- */
5946
- interface PlaylistTracksSelect<T extends boolean = true> {
5947
- '_playlist-tracks_items_order'?: T;
5948
- _order?: T;
5949
- tenant?: T;
5950
- playlist?: T;
5951
- track?: T;
5952
- addedAt?: T;
5953
- addedBy?: T;
5954
- titleOverride?: T;
5955
- artistOverride?: T;
5956
- note?: T;
5957
- visibility?: T;
5958
- metadata?: T;
5959
- updatedAt?: T;
5960
- createdAt?: T;
5961
- deletedAt?: T;
5962
- }
5963
5897
  /**
5964
5898
  * This interface was referenced by `Config`'s JSON-Schema
5965
5899
  * via the `definition` "track-categories_select".
@@ -59,7 +59,6 @@ interface Config {
59
59
  'playlist-tags': PlaylistTag;
60
60
  tracks: Track;
61
61
  'track-assets': TrackAsset;
62
- 'playlist-tracks': PlaylistTrack;
63
62
  'track-categories': TrackCategory;
64
63
  'track-tags': TrackTag;
65
64
  galleries: Gallery;
@@ -130,12 +129,6 @@ interface Config {
130
129
  'post-authors': {
131
130
  posts: 'posts';
132
131
  };
133
- playlists: {
134
- items: 'playlist-tracks';
135
- };
136
- tracks: {
137
- playlistEntries: 'playlist-tracks';
138
- };
139
132
  galleries: {
140
133
  items: 'gallery-items';
141
134
  };
@@ -194,7 +187,6 @@ interface Config {
194
187
  'playlist-tags': PlaylistTagsSelect<false> | PlaylistTagsSelect<true>;
195
188
  tracks: TracksSelect<false> | TracksSelect<true>;
196
189
  'track-assets': TrackAssetsSelect<false> | TrackAssetsSelect<true>;
197
- 'playlist-tracks': PlaylistTracksSelect<false> | PlaylistTracksSelect<true>;
198
190
  'track-categories': TrackCategoriesSelect<false> | TrackCategoriesSelect<true>;
199
191
  'track-tags': TrackTagsSelect<false> | TrackTagsSelect<true>;
200
192
  galleries: GalleriesSelect<false> | GalleriesSelect<true>;
@@ -522,7 +514,7 @@ interface Image {
522
514
  interface FieldConfig {
523
515
  id: string;
524
516
  tenant?: (string | null) | Tenant;
525
- collectionSlug: 'products' | 'product-variants' | 'product-options' | 'product-option-values' | 'product-collections' | 'product-categories' | 'product-tags' | 'brands' | 'discounts' | 'shipping-policies' | 'orders' | 'carts' | 'transactions' | 'fulfillments' | 'returns' | 'customers' | 'customer-groups' | 'post-authors' | 'posts' | 'post-categories' | 'post-tags' | 'documents' | 'document-categories' | 'document-types' | 'playlists' | 'playlist-categories' | 'playlist-tags' | 'tracks' | 'playlist-tracks' | 'track-categories' | 'track-tags' | 'galleries' | 'gallery-categories' | 'gallery-tags' | 'gallery-items' | 'links' | 'link-categories' | 'link-tags' | 'canvases' | 'canvas-categories' | 'canvas-tags' | 'canvas-node-types' | 'canvas-edge-types' | 'videos' | 'video-categories' | 'video-tags' | 'live-streams' | 'forms' | 'threads' | 'comments' | 'reactions' | 'reaction-types' | 'bookmarks' | 'thread-categories';
517
+ collectionSlug: 'products' | 'product-variants' | 'product-options' | 'product-option-values' | 'product-collections' | 'product-categories' | 'product-tags' | 'brands' | 'discounts' | 'shipping-policies' | 'orders' | 'carts' | 'transactions' | 'fulfillments' | 'returns' | 'customers' | 'customer-groups' | 'post-authors' | 'posts' | 'post-categories' | 'post-tags' | 'documents' | 'document-categories' | 'document-types' | 'playlists' | 'playlist-categories' | 'playlist-tags' | 'tracks' | 'track-categories' | 'track-tags' | 'galleries' | 'gallery-categories' | 'gallery-tags' | 'gallery-items' | 'links' | 'link-categories' | 'link-tags' | 'canvases' | 'canvas-categories' | 'canvas-tags' | 'canvas-node-types' | 'canvas-edge-types' | 'videos' | 'video-categories' | 'video-tags' | 'live-streams' | 'forms' | 'threads' | 'comments' | 'reactions' | 'reaction-types' | 'bookmarks' | 'thread-categories';
526
518
  isHidden?: boolean | null;
527
519
  hiddenFields?: {
528
520
  [k: string]: unknown;
@@ -1255,6 +1247,10 @@ interface Product {
1255
1247
  * Maximum order quantity
1256
1248
  */
1257
1249
  maxOrderQuantity?: number | null;
1250
+ /**
1251
+ * Primary option used to expand this product into option-value listing cards (for example, Color)
1252
+ */
1253
+ listingPrimaryOption?: (string | null) | ProductOption;
1258
1254
  /**
1259
1255
  * Derived listing projection for product cards and search
1260
1256
  */
@@ -1814,7 +1810,7 @@ interface ShippingPolicy {
1814
1810
  /**
1815
1811
  * Amount in KRW (won)
1816
1812
  */
1817
- baseAmount: number;
1813
+ baseAmount?: number | null;
1818
1814
  /**
1819
1815
  * Amount in KRW (won)
1820
1816
  */
@@ -2492,12 +2488,12 @@ interface Discount {
2492
2488
  /**
2493
2489
  * Minimum order amount for this tier
2494
2490
  */
2495
- minAmount: number;
2496
- discountType: 'percentage' | 'fixed_amount';
2491
+ minAmount?: number | null;
2492
+ discountType?: ('percentage' | 'fixed_amount') | null;
2497
2493
  /**
2498
2494
  * Discount rate (%) or fixed amount
2499
2495
  */
2500
- value: number;
2496
+ value?: number | null;
2501
2497
  id?: string | null;
2502
2498
  }[] | null;
2503
2499
  /**
@@ -2907,11 +2903,7 @@ interface Playlist {
2907
2903
  videos?: (string | Video)[] | null;
2908
2904
  categories?: (string | PlaylistCategory)[] | null;
2909
2905
  tags?: (string | PlaylistTag)[] | null;
2910
- items?: {
2911
- docs?: (string | PlaylistTrack)[];
2912
- hasNextPage?: boolean;
2913
- totalDocs?: number;
2914
- };
2906
+ tracks?: (string | Track)[] | null;
2915
2907
  seo?: {
2916
2908
  /**
2917
2909
  * Search result title (falls back to document title)
@@ -3013,30 +3005,6 @@ interface PlaylistTag {
3013
3005
  createdAt: string;
3014
3006
  deletedAt?: string | null;
3015
3007
  }
3016
- /**
3017
- * This interface was referenced by `Config`'s JSON-Schema
3018
- * via the `definition` "playlist-tracks".
3019
- */
3020
- interface PlaylistTrack {
3021
- id: string;
3022
- '_playlist-tracks_items_order'?: string | null;
3023
- _order?: string | null;
3024
- tenant?: (string | null) | Tenant;
3025
- playlist?: (string | null) | Playlist;
3026
- track?: (string | null) | Track;
3027
- addedAt?: string | null;
3028
- addedBy?: (string | null) | Customer;
3029
- titleOverride?: string | null;
3030
- artistOverride?: string | null;
3031
- note?: string | null;
3032
- visibility?: ('visible' | 'hidden') | null;
3033
- metadata?: {
3034
- [k: string]: unknown;
3035
- } | unknown[] | string | number | boolean | null;
3036
- updatedAt: string;
3037
- createdAt: string;
3038
- deletedAt?: string | null;
3039
- }
3040
3008
  /**
3041
3009
  * This interface was referenced by `Config`'s JSON-Schema
3042
3010
  * via the `definition` "tracks".
@@ -3045,10 +3013,6 @@ interface Track {
3045
3013
  id: string;
3046
3014
  _order?: string | null;
3047
3015
  tenant?: (string | null) | Tenant;
3048
- /**
3049
- * Source type of this track
3050
- */
3051
- kind?: ('owned_asset' | 'external_reference') | null;
3052
3016
  title: string;
3053
3017
  /**
3054
3018
  * Short summary for listing/cards
@@ -3074,11 +3038,6 @@ interface Track {
3074
3038
  releaseDate?: string | null;
3075
3039
  categories?: (string | TrackCategory)[] | null;
3076
3040
  tags?: (string | TrackTag)[] | null;
3077
- playlistEntries?: {
3078
- docs?: (string | PlaylistTrack)[];
3079
- hasNextPage?: boolean;
3080
- totalDocs?: number;
3081
- };
3082
3041
  asset?: (string | null) | TrackAsset;
3083
3042
  /**
3084
3043
  * When enabled, the slug will auto-generate from the title field on save and autosave.
@@ -3587,12 +3546,12 @@ interface CanvasNodeType {
3587
3546
  /**
3588
3547
  * English key (e.g. body, url)
3589
3548
  */
3590
- name: string;
3591
- label: string;
3592
- fieldType: 'text' | 'textarea' | 'number' | 'url' | 'color' | 'image' | 'date' | 'select' | 'toggle';
3549
+ name?: string | null;
3550
+ label?: string | null;
3551
+ fieldType?: ('text' | 'textarea' | 'number' | 'url' | 'color' | 'image' | 'date' | 'select' | 'toggle') | null;
3593
3552
  options?: {
3594
- label: string;
3595
- value: string;
3553
+ label?: string | null;
3554
+ value?: string | null;
3596
3555
  id?: string | null;
3597
3556
  }[] | null;
3598
3557
  /**
@@ -3649,12 +3608,12 @@ interface CanvasEdgeType {
3649
3608
  /**
3650
3609
  * English key (e.g. condition, weight)
3651
3610
  */
3652
- name: string;
3653
- label: string;
3654
- fieldType: 'text' | 'textarea' | 'number' | 'url' | 'color' | 'select' | 'toggle';
3611
+ name?: string | null;
3612
+ label?: string | null;
3613
+ fieldType?: ('text' | 'textarea' | 'number' | 'url' | 'color' | 'select' | 'toggle') | null;
3655
3614
  options?: {
3656
- label: string;
3657
- value: string;
3615
+ label?: string | null;
3616
+ value?: string | null;
3658
3617
  id?: string | null;
3659
3618
  }[] | null;
3660
3619
  defaultValue?: string | null;
@@ -4245,9 +4204,6 @@ interface PayloadLockedDocument {
4245
4204
  } | null) | ({
4246
4205
  relationTo: 'track-assets';
4247
4206
  value: string | TrackAsset;
4248
- } | null) | ({
4249
- relationTo: 'playlist-tracks';
4250
- value: string | PlaylistTrack;
4251
4207
  } | null) | ({
4252
4208
  relationTo: 'track-categories';
4253
4209
  value: string | TrackCategory;
@@ -4900,6 +4856,7 @@ interface ProductsSelect<T extends boolean = true> {
4900
4856
  collections?: T;
4901
4857
  minOrderQuantity?: T;
4902
4858
  maxOrderQuantity?: T;
4859
+ listingPrimaryOption?: T;
4903
4860
  listing?: T | {
4904
4861
  selectionHintVariant?: T;
4905
4862
  primaryImage?: T;
@@ -5817,7 +5774,7 @@ interface PlaylistsSelect<T extends boolean = true> {
5817
5774
  videos?: T;
5818
5775
  categories?: T;
5819
5776
  tags?: T;
5820
- items?: T;
5777
+ tracks?: T;
5821
5778
  seo?: T | {
5822
5779
  title?: T;
5823
5780
  description?: T;
@@ -5886,7 +5843,6 @@ interface PlaylistTagsSelect<T extends boolean = true> {
5886
5843
  interface TracksSelect<T extends boolean = true> {
5887
5844
  _order?: T;
5888
5845
  tenant?: T;
5889
- kind?: T;
5890
5846
  title?: T;
5891
5847
  description?: T;
5892
5848
  content?: T;
@@ -5895,7 +5851,6 @@ interface TracksSelect<T extends boolean = true> {
5895
5851
  releaseDate?: T;
5896
5852
  categories?: T;
5897
5853
  tags?: T;
5898
- playlistEntries?: T;
5899
5854
  asset?: T;
5900
5855
  generateSlug?: T;
5901
5856
  slug?: T;
@@ -5939,27 +5894,6 @@ interface TrackAssetsSelect<T extends boolean = true> {
5939
5894
  focalX?: T;
5940
5895
  focalY?: T;
5941
5896
  }
5942
- /**
5943
- * This interface was referenced by `Config`'s JSON-Schema
5944
- * via the `definition` "playlist-tracks_select".
5945
- */
5946
- interface PlaylistTracksSelect<T extends boolean = true> {
5947
- '_playlist-tracks_items_order'?: T;
5948
- _order?: T;
5949
- tenant?: T;
5950
- playlist?: T;
5951
- track?: T;
5952
- addedAt?: T;
5953
- addedBy?: T;
5954
- titleOverride?: T;
5955
- artistOverride?: T;
5956
- note?: T;
5957
- visibility?: T;
5958
- metadata?: T;
5959
- updatedAt?: T;
5960
- createdAt?: T;
5961
- deletedAt?: T;
5962
- }
5963
5897
  /**
5964
5898
  * This interface was referenced by `Config`'s JSON-Schema
5965
5899
  * via the `definition` "track-categories_select".
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/realtime.ts","../src/core/query/realtime-hooks.ts","../src/core/query/realtime.ts","../src/core/client/types.ts","../src/core/query/query-keys.ts"],"sourcesContent":["export { useRealtimeQuery } from './core/query/realtime-hooks'\nexport type {\n UseRealtimeQueryOptions,\n UseRealtimeQueryResult,\n RealtimeEvent,\n} from './core/query/realtime-hooks'\nexport { RealtimeConnection, type RealtimeListener } from './core/query/realtime'\n","import { useEffect, useRef, useState } from 'react'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { RealtimeConnection, type RealtimeEvent } from './realtime'\nimport { resolveApiUrl, type PublicCollection } from '../client/types'\nimport { collectionKeys } from './query-keys'\n\nexport type { RealtimeEvent }\n\nexport interface UseRealtimeQueryOptions {\n /** Filter events to specific collections. Empty/undefined = all collections. */\n collections?: PublicCollection[]\n /** Enable/disable the SSE connection. Default: true. */\n enabled?: boolean\n}\n\nexport interface UseRealtimeQueryResult {\n /** Whether the SSE connection is currently active. */\n connected: boolean\n /** The last received event, or null. */\n lastEvent: RealtimeEvent | null\n}\n\n/**\n * React hook that subscribes to real-time collection change events via SSE.\n * Automatically invalidates React Query cache when changes are detected.\n *\n * @example\n * ```tsx\n * const { connected } = useRealtimeQuery({\n * publishableKey: 'your-key',\n * getToken: () => client.customer.getToken(),\n * collections: ['products', 'orders'],\n * })\n * ```\n */\nexport function useRealtimeQuery(options: {\n publishableKey: string\n getToken: () => string | null\n collections?: PublicCollection[]\n enabled?: boolean\n}): UseRealtimeQueryResult {\n const { getToken, collections, enabled = true } = options\n const publishableKey = options.publishableKey\n const queryClient = useQueryClient()\n const [connected, setConnected] = useState(false)\n const [lastEvent, setLastEvent] = useState<RealtimeEvent | null>(null)\n const connectionRef = useRef<RealtimeConnection | null>(null)\n\n useEffect(() => {\n if (!enabled || !publishableKey) return\n\n const baseUrl = resolveApiUrl()\n const conn = new RealtimeConnection(\n baseUrl,\n publishableKey,\n getToken,\n collections,\n )\n connectionRef.current = conn\n\n // Listen for events and invalidate queries\n const removeListener = conn.addListener((event) => {\n setLastEvent(event)\n\n // Invalidate all queries for the changed collection\n const keys = collectionKeys(event.collection as PublicCollection)\n queryClient.invalidateQueries({ queryKey: keys.all })\n })\n\n // Track connection state\n const pollInterval = setInterval(() => {\n setConnected(conn.connected)\n }, 1000)\n\n conn.connect()\n\n return () => {\n conn.disconnect()\n removeListener()\n clearInterval(pollInterval)\n connectionRef.current = null\n setConnected(false)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [publishableKey, enabled, collections?.join(',')])\n\n return { connected, lastEvent }\n}\n","/**\n * Fetch-based SSE connection manager for real-time collection change events.\n * Uses fetch + ReadableStream to support custom auth headers (unlike native EventSource).\n */\n\nexport interface RealtimeEvent {\n collection: string\n operation: string\n id: string | null\n timestamp: string\n}\n\nexport type RealtimeListener = (event: RealtimeEvent) => void\n\nconst INITIAL_RECONNECT_DELAY = 1_000\nconst MAX_RECONNECT_DELAY = 30_000\nconst RECONNECT_BACKOFF_FACTOR = 2\nconst MAX_NO_TOKEN_RETRIES = 5\n\nexport class RealtimeConnection {\n private abortController: AbortController | null = null\n private reconnectAttempt = 0\n private noTokenAttempts = 0\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null\n private listeners = new Set<RealtimeListener>()\n private _connected = false\n\n constructor(\n private baseUrl: string,\n private publishableKey: string,\n private getToken: () => string | null,\n private collections?: string[],\n ) {}\n\n get connected(): boolean {\n return this._connected\n }\n\n addListener(fn: RealtimeListener): () => void {\n this.listeners.add(fn)\n return () => this.listeners.delete(fn)\n }\n\n connect(): void {\n if (this.abortController) return // Already connecting/connected\n\n this.abortController = new AbortController()\n this.startStream(this.abortController.signal)\n }\n\n disconnect(): void {\n this._connected = false\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n if (this.abortController) {\n this.abortController.abort()\n this.abortController = null\n }\n this.reconnectAttempt = 0\n this.noTokenAttempts = 0\n }\n\n private async startStream(signal: AbortSignal): Promise<void> {\n const token = this.getToken()\n if (!token) {\n this.noTokenAttempts++\n if (this.noTokenAttempts >= MAX_NO_TOKEN_RETRIES) {\n // Stop reconnecting — no token available after multiple attempts\n this._connected = false\n this.abortController = null\n return\n }\n this.scheduleReconnect()\n return\n }\n this.noTokenAttempts = 0\n\n const params = this.collections?.length\n ? `?collections=${this.collections.join(',')}`\n : ''\n const url = `${this.baseUrl}/api/events/stream${params}`\n\n try {\n const response = await fetch(url, {\n headers: {\n 'X-Publishable-Key': this.publishableKey,\n Authorization: `Bearer ${token}`,\n },\n signal,\n })\n\n if (!response.ok) {\n if (response.status === 401) {\n // Token expired — try reconnecting (will get fresh token)\n this.scheduleReconnect()\n return\n }\n throw new Error(`SSE connection failed: ${response.status}`)\n }\n\n if (!response.body) {\n throw new Error('SSE response has no body')\n }\n\n this._connected = true\n this.reconnectAttempt = 0\n\n await this.readStream(response.body, signal)\n } catch {\n if (signal.aborted) return // Intentional disconnect\n this._connected = false\n this.scheduleReconnect()\n }\n }\n\n private async readStream(\n body: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n ): Promise<void> {\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n let currentEvent = ''\n let currentData = ''\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done || signal.aborted) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? '' // Keep incomplete last line in buffer\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n currentEvent = line.slice(7)\n } else if (line.startsWith('data: ')) {\n currentData += (currentData ? '\\n' : '') + line.slice(6)\n } else if (line === '') {\n // Empty line = end of event\n if (currentEvent === 'collection:change' && currentData) {\n try {\n const event: RealtimeEvent = JSON.parse(currentData)\n for (const listener of this.listeners) {\n try {\n listener(event)\n } catch {\n // Listener error — ignore\n }\n }\n } catch {\n // Malformed JSON — ignore\n }\n }\n currentEvent = ''\n currentData = ''\n }\n // Ignore comment lines (: heartbeat)\n }\n }\n } catch {\n // Stream read error\n } finally {\n reader.releaseLock()\n this._connected = false\n if (!signal.aborted) {\n this.scheduleReconnect()\n }\n }\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) return\n\n const delay = Math.min(\n INITIAL_RECONNECT_DELAY *\n Math.pow(RECONNECT_BACKOFF_FACTOR, this.reconnectAttempt),\n MAX_RECONNECT_DELAY,\n )\n this.reconnectAttempt++\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null\n this.abortController = new AbortController()\n this.startStream(this.abortController.signal)\n }, delay)\n }\n}\n","import type { Sort, Where } from 'payload'\n\nimport type { Collection, PublicCollection } from '../collection/const'\n\nexport type { Collection, PublicCollection }\n\n// ============================================================================\n// API URL Configuration\n// ============================================================================\n\ndeclare const __DEFAULT_API_URL__: string\n\n/**\n * API URL을 반환합니다.\n * 환경변수 SOFTWARE_API_URL 또는 NEXT_PUBLIC_SOFTWARE_API_URL로 오버라이드 가능.\n * 빌드 시 버전에 따라 기본값 결정: dev 빌드 → api-dev, 정식 → api.01.software\n */\nexport function resolveApiUrl(): string {\n if (typeof process !== 'undefined' && process.env) {\n const envUrl =\n process.env.SOFTWARE_API_URL || process.env.NEXT_PUBLIC_SOFTWARE_API_URL\n if (envUrl) {\n return envUrl.replace(/\\/$/, '')\n }\n }\n return __DEFAULT_API_URL__\n}\n\n// ============================================================================\n// Client Configuration\n// ============================================================================\n\nexport interface ClientConfig {\n publishableKey: string\n /**\n * Customer authentication options.\n * Used to initialize CustomerAuth on Client.\n */\n customer?: {\n /**\n * Persist token in localStorage. Defaults to `true`.\n * - `true` (default): uses key `'customer-token'`\n * - `string`: uses the given string as localStorage key\n * - `false`: disables persistence (token/onTokenChange used instead)\n *\n * Handles SSR safely (no-op on server).\n * When enabled, `token` and `onTokenChange` are ignored.\n */\n persist?: boolean | string\n /** Initial token (e.g. from SSR cookie) */\n token?: string\n /** Called when token changes (login/logout) — use to persist in localStorage/cookie */\n onTokenChange?: (token: string | null) => void\n }\n}\n\n// Server client: requires both publishableKey (for CDN routing + rate limit +\n// monthly quota enforcement via the edge proxy) and secretKey (sk01_ opaque\n// bearer token, the authentication credential).\n// The proxy keys its tenant lookup off `X-Publishable-Key`, so omitting\n// publishableKey would silently bypass rate limiting and plan-based quota\n// enforcement.\nexport interface ClientServerConfig extends ClientConfig {\n secretKey: string\n}\n\n\nexport interface ClientMetadata {\n userAgent?: string\n timestamp: number\n}\n\nexport interface ClientState {\n metadata: ClientMetadata\n}\n\n// ============================================================================\n// API Response Types\n// ============================================================================\n\nexport interface PaginationMeta {\n page: number\n limit: number\n totalDocs: number\n totalPages: number\n hasNextPage: boolean\n hasPrevPage: boolean\n pagingCounter: number\n prevPage: number | null\n nextPage: number | null\n}\n\n// ============================================================================\n// Payload CMS Native Response Types\n// ============================================================================\n\n/**\n * Payload CMS Find (List) Response\n * GET /api/{collection}\n */\nexport interface PayloadFindResponse<T = unknown> {\n docs: T[]\n totalDocs: number\n limit: number\n totalPages: number\n page: number\n pagingCounter: number\n hasPrevPage: boolean\n hasNextPage: boolean\n prevPage: number | null\n nextPage: number | null\n}\n\n/**\n * Payload CMS Create/Update Response\n * POST /api/{collection}\n * PATCH /api/{collection}/{id}\n */\nexport interface PayloadMutationResponse<T = unknown> {\n message: string\n doc: T\n errors?: unknown[]\n}\n\n// ============================================================================\n// Query Options\n// ============================================================================\n\nexport interface ApiQueryOptions {\n page?: number\n limit?: number\n sort?: Sort\n where?: Where\n depth?: number\n select?: Record<string, boolean>\n /** Per-collection field selection for populated relationships (keyed by collection slug) */\n populate?: Record<string, boolean | Record<string, boolean>>\n /** Join field control: pagination/filter per join, or false to disable */\n joins?:\n | Record<\n string,\n | {\n limit?: number\n page?: number\n sort?: string\n where?: Where\n count?: boolean\n }\n | false\n >\n | false\n}\n\n// ============================================================================\n// Debug & Retry Configuration\n// ============================================================================\n\nexport interface DebugConfig {\n logRequests?: boolean\n logResponses?: boolean\n logErrors?: boolean\n}\n\nexport interface RetryConfig {\n maxRetries?: number\n retryableStatuses?: number[]\n retryDelay?: (attempt: number) => number\n}\n\n\n// ============================================================================\n// Collection Types (re-exported from collection/const)\n// ============================================================================\n\n// ============================================================================\n// Type Utilities\n// ============================================================================\n\nexport type DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]\n}\n\nexport type ExtractArrayType<T> = T extends (infer U)[] ? U : never\n","import type { PublicCollection, ApiQueryOptions } from '../client/types'\n\nexport function collectionKeys<T extends PublicCollection>(collection: T) {\n return {\n all: [collection] as const,\n lists: () => [collection, 'list'] as const,\n list: (options?: ApiQueryOptions) => [collection, 'list', options] as const,\n details: () => [collection, 'detail'] as const,\n detail: (id: string, options?: ApiQueryOptions) =>\n [collection, 'detail', id, options] as const,\n infinites: () => [collection, 'infinite'] as const,\n infinite: (options?: Omit<ApiQueryOptions, 'page'>) =>\n [collection, 'infinite', options] as const,\n }\n}\n\nexport const customerKeys = {\n all: ['customer'] as const,\n me: () => ['customer', 'me'] as const,\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/realtime.ts","../src/core/query/realtime-hooks.ts","../src/core/query/realtime.ts","../src/core/client/types.ts","../src/core/query/query-keys.ts"],"sourcesContent":["export { useRealtimeQuery } from './core/query/realtime-hooks'\nexport type {\n UseRealtimeQueryOptions,\n UseRealtimeQueryResult,\n RealtimeEvent,\n} from './core/query/realtime-hooks'\nexport { RealtimeConnection, type RealtimeListener } from './core/query/realtime'\n","import { useEffect, useRef, useState } from 'react'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { RealtimeConnection, type RealtimeEvent } from './realtime'\nimport { resolveApiUrl, type PublicCollection } from '../client/types'\nimport { collectionKeys } from './query-keys'\n\nexport type { RealtimeEvent }\n\nexport interface UseRealtimeQueryOptions {\n /** Filter events to specific collections. Empty/undefined = all collections. */\n collections?: PublicCollection[]\n /** Enable/disable the SSE connection. Default: true. */\n enabled?: boolean\n}\n\nexport interface UseRealtimeQueryResult {\n /** Whether the SSE connection is currently active. */\n connected: boolean\n /** The last received event, or null. */\n lastEvent: RealtimeEvent | null\n}\n\n/**\n * React hook that subscribes to real-time collection change events via SSE.\n * Automatically invalidates React Query cache when changes are detected.\n *\n * @example\n * ```tsx\n * const { connected } = useRealtimeQuery({\n * publishableKey: 'your-key',\n * getToken: () => client.customer.getToken(),\n * collections: ['products', 'orders'],\n * })\n * ```\n */\nexport function useRealtimeQuery(options: {\n publishableKey: string\n getToken: () => string | null\n collections?: PublicCollection[]\n enabled?: boolean\n}): UseRealtimeQueryResult {\n const { getToken, collections, enabled = true } = options\n const publishableKey = options.publishableKey\n const queryClient = useQueryClient()\n const [connected, setConnected] = useState(false)\n const [lastEvent, setLastEvent] = useState<RealtimeEvent | null>(null)\n const connectionRef = useRef<RealtimeConnection | null>(null)\n\n useEffect(() => {\n if (!enabled || !publishableKey) return\n\n const baseUrl = resolveApiUrl()\n const conn = new RealtimeConnection(\n baseUrl,\n publishableKey,\n getToken,\n collections,\n )\n connectionRef.current = conn\n\n // Listen for events and invalidate queries\n const removeListener = conn.addListener((event) => {\n setLastEvent(event)\n\n // Invalidate all queries for the changed collection\n const keys = collectionKeys(event.collection as PublicCollection)\n queryClient.invalidateQueries({ queryKey: keys.all })\n })\n\n // Track connection state\n const pollInterval = setInterval(() => {\n setConnected(conn.connected)\n }, 1000)\n\n conn.connect()\n\n return () => {\n conn.disconnect()\n removeListener()\n clearInterval(pollInterval)\n connectionRef.current = null\n setConnected(false)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [publishableKey, enabled, collections?.join(',')])\n\n return { connected, lastEvent }\n}\n","/**\n * Fetch-based SSE connection manager for real-time collection change events.\n * Uses fetch + ReadableStream to support custom auth headers (unlike native EventSource).\n */\n\nexport interface RealtimeEvent {\n collection: string\n operation: string\n id: string | null\n timestamp: string\n}\n\nexport type RealtimeListener = (event: RealtimeEvent) => void\n\nconst INITIAL_RECONNECT_DELAY = 1_000\nconst MAX_RECONNECT_DELAY = 30_000\nconst RECONNECT_BACKOFF_FACTOR = 2\nconst MAX_NO_TOKEN_RETRIES = 5\n\nexport class RealtimeConnection {\n private abortController: AbortController | null = null\n private reconnectAttempt = 0\n private noTokenAttempts = 0\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null\n private listeners = new Set<RealtimeListener>()\n private _connected = false\n\n constructor(\n private baseUrl: string,\n private publishableKey: string,\n private getToken: () => string | null,\n private collections?: string[],\n ) {}\n\n get connected(): boolean {\n return this._connected\n }\n\n addListener(fn: RealtimeListener): () => void {\n this.listeners.add(fn)\n return () => this.listeners.delete(fn)\n }\n\n connect(): void {\n if (this.abortController) return // Already connecting/connected\n\n this.abortController = new AbortController()\n this.startStream(this.abortController.signal)\n }\n\n disconnect(): void {\n this._connected = false\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n if (this.abortController) {\n this.abortController.abort()\n this.abortController = null\n }\n this.reconnectAttempt = 0\n this.noTokenAttempts = 0\n }\n\n private async startStream(signal: AbortSignal): Promise<void> {\n const token = this.getToken()\n if (!token) {\n this.noTokenAttempts++\n if (this.noTokenAttempts >= MAX_NO_TOKEN_RETRIES) {\n // Stop reconnecting — no token available after multiple attempts\n this._connected = false\n this.abortController = null\n return\n }\n this.scheduleReconnect()\n return\n }\n this.noTokenAttempts = 0\n\n const params = this.collections?.length\n ? `?collections=${this.collections.join(',')}`\n : ''\n const url = `${this.baseUrl}/api/events/stream${params}`\n\n try {\n const response = await fetch(url, {\n headers: {\n 'X-Publishable-Key': this.publishableKey,\n Authorization: `Bearer ${token}`,\n },\n signal,\n })\n\n if (!response.ok) {\n if (response.status === 401) {\n // Token expired — try reconnecting (will get fresh token)\n this.scheduleReconnect()\n return\n }\n throw new Error(`SSE connection failed: ${response.status}`)\n }\n\n if (!response.body) {\n throw new Error('SSE response has no body')\n }\n\n this._connected = true\n this.reconnectAttempt = 0\n\n await this.readStream(response.body, signal)\n } catch {\n if (signal.aborted) return // Intentional disconnect\n this._connected = false\n this.scheduleReconnect()\n }\n }\n\n private async readStream(\n body: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n ): Promise<void> {\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n let currentEvent = ''\n let currentData = ''\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done || signal.aborted) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? '' // Keep incomplete last line in buffer\n\n for (const line of lines) {\n if (line.startsWith('event: ')) {\n currentEvent = line.slice(7)\n } else if (line.startsWith('data: ')) {\n currentData += (currentData ? '\\n' : '') + line.slice(6)\n } else if (line === '') {\n // Empty line = end of event\n if (currentEvent === 'collection:change' && currentData) {\n try {\n const event: RealtimeEvent = JSON.parse(currentData)\n for (const listener of this.listeners) {\n try {\n listener(event)\n } catch {\n // Listener error — ignore\n }\n }\n } catch {\n // Malformed JSON — ignore\n }\n }\n currentEvent = ''\n currentData = ''\n }\n // Ignore comment lines (: heartbeat)\n }\n }\n } catch {\n // Stream read error\n } finally {\n reader.releaseLock()\n this._connected = false\n if (!signal.aborted) {\n this.scheduleReconnect()\n }\n }\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) return\n\n const delay = Math.min(\n INITIAL_RECONNECT_DELAY *\n Math.pow(RECONNECT_BACKOFF_FACTOR, this.reconnectAttempt),\n MAX_RECONNECT_DELAY,\n )\n this.reconnectAttempt++\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null\n this.abortController = new AbortController()\n this.startStream(this.abortController.signal)\n }, delay)\n }\n}\n","import type { Sort, Where } from 'payload'\n\nimport type { Collection, PublicCollection } from '../collection/const'\n\nexport type { Collection, PublicCollection }\n\n// ============================================================================\n// API URL Configuration\n// ============================================================================\n\ndeclare const __DEFAULT_API_URL__: string\n\n/**\n * API URL을 반환합니다.\n * 환경변수 SOFTWARE_API_URL 또는 NEXT_PUBLIC_SOFTWARE_API_URL로 오버라이드 가능.\n * 빌드 시 버전에 따라 기본값 결정: dev 빌드 → api-dev, 정식 → api.01.software\n */\nexport function resolveApiUrl(): string {\n if (typeof process !== 'undefined' && process.env) {\n const envUrl =\n process.env.SOFTWARE_API_URL || process.env.NEXT_PUBLIC_SOFTWARE_API_URL\n if (envUrl) {\n return envUrl.replace(/\\/$/, '')\n }\n }\n return __DEFAULT_API_URL__\n}\n\n// ============================================================================\n// Client Configuration\n// ============================================================================\n\nexport interface ClientConfig {\n publishableKey: string\n /**\n * Customer authentication options.\n * Used to initialize CustomerAuth on Client.\n */\n customer?: {\n /**\n * Persist token in localStorage. Defaults to `true`.\n * - `true` (default): uses key `'customer-token'`\n * - `string`: uses the given string as localStorage key\n * - `false`: disables persistence (token/onTokenChange used instead)\n *\n * Handles SSR safely (no-op on server).\n * When enabled, `token` and `onTokenChange` are ignored.\n */\n persist?: boolean | string\n /** Initial token (e.g. from SSR cookie) */\n token?: string\n /** Called when token changes (login/logout) — use to persist in localStorage/cookie */\n onTokenChange?: (token: string | null) => void\n }\n}\n\n// Server client: requires both publishableKey (for CDN routing + rate limit +\n// monthly quota enforcement via the edge proxy) and secretKey (sk01_ opaque\n// bearer token, the authentication credential).\n// The proxy keys its tenant lookup off `X-Publishable-Key`, so omitting\n// publishableKey would silently bypass rate limiting and plan-based quota\n// enforcement.\nexport interface ClientServerConfig extends ClientConfig {\n secretKey: string\n}\n\n\nexport interface ClientMetadata {\n userAgent?: string\n timestamp: number\n}\n\nexport interface ClientState {\n metadata: ClientMetadata\n}\n\n// ============================================================================\n// API Response Types\n// ============================================================================\n\nexport interface PaginationMeta {\n page: number\n limit: number\n totalDocs: number\n totalPages: number\n hasNextPage: boolean\n hasPrevPage: boolean\n pagingCounter: number\n prevPage: number | null\n nextPage: number | null\n}\n\n// ============================================================================\n// Payload CMS Native Response Types\n// ============================================================================\n\n/**\n * Payload CMS Find (List) Response\n * GET /api/{collection}\n */\nexport interface PayloadFindResponse<T = unknown> {\n docs: T[]\n totalDocs: number\n limit: number\n totalPages: number\n page: number\n pagingCounter: number\n hasPrevPage: boolean\n hasNextPage: boolean\n prevPage: number | null\n nextPage: number | null\n}\n\n/**\n * Payload CMS Create/Update Response\n * POST /api/{collection}\n * PATCH /api/{collection}/{id}\n */\nexport interface PayloadMutationResponse<T = unknown> {\n message: string\n doc: T\n errors?: unknown[]\n}\n\n// ============================================================================\n// Query Options\n// ============================================================================\n\nexport interface ApiQueryOptions {\n page?: number\n limit?: number\n sort?: Sort\n where?: Where\n depth?: number\n select?: Record<string, boolean>\n /** Per-collection field selection for populated relationships (keyed by collection slug) */\n populate?: Record<string, boolean | Record<string, boolean>>\n /** Join field control: pagination/filter per join, or false to disable */\n joins?:\n | Record<\n string,\n | {\n limit?: number\n page?: number\n sort?: string\n where?: Where\n count?: boolean\n }\n | false\n >\n | false\n}\n\n// ============================================================================\n// Debug & Retry Configuration\n// ============================================================================\n\nexport interface DebugConfig {\n logRequests?: boolean\n logResponses?: boolean\n logErrors?: boolean\n}\n\nexport interface RetryConfig {\n maxRetries?: number\n retryableStatuses?: number[]\n retryDelay?: (attempt: number) => number\n}\n\n\n// ============================================================================\n// Collection Types (re-exported from collection/const)\n// ============================================================================\n\n// ============================================================================\n// Type Utilities\n// ============================================================================\n\nexport type DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]\n}\n\nexport type ExtractArrayType<T> = T extends (infer U)[] ? U : never\n","import type { PublicCollection, ApiQueryOptions } from '../client/types'\nimport type { ProductListingGroupsQueryOptions } from './query-hooks'\n\nexport function collectionKeys<T extends PublicCollection>(collection: T) {\n return {\n all: [collection] as const,\n lists: () => [collection, 'list'] as const,\n list: (options?: ApiQueryOptions) => [collection, 'list', options] as const,\n details: () => [collection, 'detail'] as const,\n detail: (id: string, options?: ApiQueryOptions) =>\n [collection, 'detail', id, options] as const,\n infinites: () => [collection, 'infinite'] as const,\n infinite: (options?: Omit<ApiQueryOptions, 'page'>) =>\n [collection, 'infinite', options] as const,\n }\n}\n\nexport const customerKeys = {\n all: ['customer'] as const,\n me: () => ['customer', 'me'] as const,\n}\n\nexport const productKeys = {\n listingGroups: (options?: ProductListingGroupsQueryOptions) =>\n ['products', 'listing-groups', 'list', options] as const,\n listingGroupsInfinite: (\n options?: Omit<ProductListingGroupsQueryOptions, 'page' | 'limit'>,\n ) =>\n ['products', 'listing-groups', 'infinite', options] as const,\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  import { R as RealtimeEvent } from './realtime-D7HtUpqt.cjs';
2
2
  export { a as RealtimeConnection, b as RealtimeListener } from './realtime-D7HtUpqt.cjs';
3
- import { P as PublicCollection } from './const-RfHA7d5C.cjs';
4
- import './payload-types-Bz2HCi4m.cjs';
3
+ import { P as PublicCollection } from './const-DBZBjsZH.cjs';
4
+ import './payload-types-BX9al1wy.cjs';
5
5
 
6
6
  interface UseRealtimeQueryOptions {
7
7
  /** Filter events to specific collections. Empty/undefined = all collections. */
@@ -1,7 +1,7 @@
1
1
  import { R as RealtimeEvent } from './realtime-D7HtUpqt.js';
2
2
  export { a as RealtimeConnection, b as RealtimeListener } from './realtime-D7HtUpqt.js';
3
- import { P as PublicCollection } from './const-Cv2Wikcq.js';
4
- import './payload-types-Bz2HCi4m.js';
3
+ import { P as PublicCollection } from './const-CWbOFesW.js';
4
+ import './payload-types-BX9al1wy.js';
5
5
 
6
6
  interface UseRealtimeQueryOptions {
7
7
  /** Filter events to specific collections. Empty/undefined = all collections. */