@rubixstudios/payload-typesense 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,22 +1,22 @@
1
- MIT License
2
-
3
- Copyright (c) 2024 Front Tribe (https://fronttribe.com)
4
- Copyright (c) 2025 Rubix Studios Pty. Ltd. <hello@rubixstudios.com.au>
5
-
6
- Permission is hereby granted, free of charge, to any person obtaining a copy
7
- of this software and associated documentation files (the "Software"), to deal
8
- in the Software without restriction, including without limitation the rights
9
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- copies of the Software, and to permit persons to whom the Software is
11
- furnished to do so, subject to the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be included in all
14
- copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Front Tribe (https://fronttribe.com)
4
+ Copyright (c) 2025 Rubix Studios Pty. Ltd. <hello@rubixstudios.com.au>
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md CHANGED
@@ -1,182 +1,177 @@
1
- # Typesense Plugin for Payload CMS
2
-
3
- This plugin is a fork of FrontTribe's Typesense Search Plugin for Payload CMS…
4
-
5
- A production-ready search plugin that integrates Typesense with Payload CMS, offering fast, typo-tolerant search with real-time synchronization. This fork by Rubix Studios reduces bloat and introduces targeted changes for improved performance, maintainability, and flexibility.
6
-
7
- ## Installation
8
-
9
- ```sh
10
- pnpm add @rubixstudios/typesense
11
- ```
12
-
13
- ```typescript
14
- // payload.config.ts
15
- import { buildConfig } from 'payload/config'
16
- import { typesenseSearch } from '@rubixstudios/typesense'
17
-
18
- export default buildConfig({
19
- plugins: [
20
- typesenseSearch({
21
- typesense: {
22
- apiKey: 'xyz',
23
- nodes: [{ host: 'localhost', port: 8108, protocol: 'http' }],
24
- },
25
- collections: {
26
- posts: {
27
- enabled: true,
28
- searchFields: ['title', 'content'],
29
- facetFields: ['category', 'status'],
30
- displayName: 'Blog Posts',
31
- icon: '📝',
32
- },
33
- },
34
- }),
35
- ],
36
- })
37
- ```
38
-
39
- ```tsx
40
- // 4. Use the search component
41
- import { HeadlessSearchInput } from '@rubixstudios/typesense'
42
-
43
- function SearchPage() {
44
- return (
45
- <HeadlessSearchInput
46
- baseUrl="http://localhost:3000"
47
- theme="modern" // Choose from: modern, dark
48
- placeholder="Search everything..."
49
- onResultClick={(result) => {
50
- console.log('Selected:', result.document)
51
- }}
52
- />
53
- )
54
- }
55
-
56
- // Multi-collection search
57
- function MultiCollectionSearch() {
58
- return (
59
- <HeadlessSearchInput
60
- baseUrl="http://localhost:3000"
61
- collections={['posts', 'products']}
62
- placeholder="Search posts & products..."
63
- onResultClick={(result) => {
64
- console.log('Selected:', result.document)
65
- }}
66
- />
67
- )
68
- }
69
-
70
- // Single collection search
71
- function PostSearch() {
72
- return (
73
- <HeadlessSearchInput
74
- baseUrl="http://localhost:3000"
75
- collection="posts"
76
- placeholder="Search posts..."
77
- onResultClick={(result) => {
78
- console.log('Selected:', result.document)
79
- }}
80
- />
81
- )
82
- }
83
- ```
84
-
85
- ## Features
86
-
87
- - **Performance**: Sub-millisecond response times for search queries
88
- - **Flexible Search**: Single, multiple, or universal collection search with one component
89
- - **Modern Interface**: Responsive design implemented with Tailwind CSS
90
- - **Optimized API**: Automatically routes requests to the most efficient endpoint
91
- - **Real-Time Sync**: Continuous data sync with Payload CMS
92
- - **Built-in Caching**: In-memory cache with configurable time-to-live settings
93
- - **Production Ready**: Robust error handling and performance optimization
94
- - **Responsive**: Mobile-first architecture ensuring compatibility across devices
95
-
96
- ## API Endpoints
97
-
98
- - `GET /api/search` - Universal search across all collections
99
- - `GET /api/search/{collection}` - Search specific collection
100
- - `POST /api/search/{collection}` - Advanced search with filters
101
- - `GET /api/search/{collection}/suggest` - Search suggestions
102
- - `GET /api/search/collections` - Collection metadata
103
- - `GET /api/search/health` - Health check
104
-
105
- ## Components
106
-
107
- - **HeadlessSearchInput** - Single component supporting all search patterns:
108
- - **Single Collection**: `collection="posts"` - Direct API calls for optimal performance
109
- - **Multiple Collections**: `collections={['posts', 'products']}` - Smart filtering with universal search
110
- - **Universal Search**: No collection props - Search across all collections
111
- - **Complete UI Control**: Customizable rendering with comprehensive theme system
112
-
113
- ## Theme System
114
-
115
- The plugin includes a powerful theme system with 5 pre-built themes and unlimited customization:
116
-
117
- ### Pre-built Themes
118
-
119
- ```tsx
120
- // Modern theme (default) - Clean and professional
121
- <HeadlessSearchInput theme="modern" />
122
-
123
- // Minimal theme - Flat design with minimal styling
124
- <HeadlessSearchInput theme="minimal" />
125
-
126
- // Elegant theme - Sophisticated with gradients
127
- <HeadlessSearchInput theme="elegant" />
128
-
129
- // Dark theme - Perfect for dark mode
130
- <HeadlessSearchInput theme="dark" />
131
-
132
- // Colorful theme - Vibrant and modern
133
- <HeadlessSearchInput theme="colorful" />
134
- ```
135
-
136
- ### Custom Themes
137
-
138
- ```tsx
139
- const customTheme = {
140
- theme: 'modern',
141
- colors: {
142
- inputBorderFocus: '#10b981',
143
- inputBackground: '#f0fdf4',
144
- resultsBackground: '#f0fdf4',
145
- },
146
- spacing: {
147
- inputPadding: '1rem 1.25rem',
148
- inputBorderRadius: '1.5rem',
149
- },
150
- enableAnimations: true,
151
- enableShadows: true,
152
- }
153
-
154
- <HeadlessSearchInput theme={customTheme} />
155
- ```
156
-
157
- ### Theme Features
158
-
159
- - **2 Pre-built Themes**: Modern, Dark
160
- - **Unlimited Customization**: Override any color, spacing, typography, or animation
161
- - **Performance Options**: Disable animations/shadows for better performance
162
- - **Responsive Design**: Automatic mobile optimization
163
- - **CSS Variables**: Advanced styling with CSS custom properties
164
- - **TypeScript Support**: Full type safety for all theme configurations
165
-
166
- ## Contributing
167
-
168
- 1. Fork the repository
169
- 2. Create a feature branch
170
- 3. Make your changes
171
- 4. Add tests
172
- 5. Submit a pull request
173
-
174
- ## License
175
-
176
- MIT License - see [LICENSE](LICENSE) file for details.
177
-
178
- ## Acknowledgments
179
-
180
- - [FrontTribe](https://github.com/FrontTribe/typesense-search)
181
- - [Typesense](https://typesense.org/)
182
- - [Payload CMS](https://payloadcms.com/)
1
+ # Typesense Plugin for Payload CMS
2
+
3
+ This plugin is a fork of FrontTribe's Typesense Search Plugin for Payload CMS…
4
+
5
+ A production-ready search plugin that integrates Typesense with Payload CMS, offering fast, typo-tolerant search with real-time synchronization. This fork by Rubix Studios reduces bloat and introduces targeted changes for improved performance, maintainability, and flexibility.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@rubixstudios/payload-typesense.svg)](https://www.npmjs.com/package/@rubixstudios/payload-typesense)
8
+ ![Release](https://github.com/rubix-studios-pty-ltd/payload-typesense/actions/workflows/release.yml/badge.svg)
9
+
10
+ ## Installation
11
+
12
+ ```sh
13
+ pnpm add @rubixstudios/payload-typesense
14
+ ```
15
+
16
+ ```typescript
17
+ // payload.config.ts
18
+ import { buildConfig } from 'payload/config'
19
+ import { typesenseSearch } from '@rubixstudios/payload-typesense'
20
+
21
+ export default buildConfig({
22
+ plugins: [
23
+ typesenseSearch({
24
+ typesense: {
25
+ apiKey: 'xyz',
26
+ nodes: [{ host: 'localhost', port: 8108, protocol: 'http' }],
27
+ },
28
+ collections: {
29
+ posts: {
30
+ enabled: true,
31
+ searchFields: ['title', 'content'],
32
+ facetFields: ['category', 'status'],
33
+ displayName: 'Blog Posts',
34
+ icon: '📝',
35
+ },
36
+ },
37
+ }),
38
+ ],
39
+ })
40
+ ```
41
+
42
+ ```tsx
43
+ import { HeadlessSearchInput } from '@rubixstudios/payload-typesense'
44
+
45
+ function SearchPage() {
46
+ return (
47
+ <HeadlessSearchInput
48
+ baseUrl="http://localhost:3000"
49
+ theme="modern" // Choose from: modern, dark
50
+ placeholder="Search everything..."
51
+ onResultClick={(result) => {
52
+ console.log('Selected:', result.document)
53
+ }}
54
+ />
55
+ )
56
+ }
57
+
58
+ // Multi-collection search
59
+ function MultiCollectionSearch() {
60
+ return (
61
+ <HeadlessSearchInput
62
+ baseUrl="http://localhost:3000"
63
+ collections={['posts', 'products']}
64
+ placeholder="Search posts & products..."
65
+ onResultClick={(result) => {
66
+ console.log('Selected:', result.document)
67
+ }}
68
+ />
69
+ )
70
+ }
71
+
72
+ // Single collection search
73
+ function PostSearch() {
74
+ return (
75
+ <HeadlessSearchInput
76
+ baseUrl="http://localhost:3000"
77
+ collection="posts"
78
+ placeholder="Search posts..."
79
+ onResultClick={(result) => {
80
+ console.log('Selected:', result.document)
81
+ }}
82
+ />
83
+ )
84
+ }
85
+ ```
86
+
87
+ ## Features
88
+
89
+ - **Performance**: Sub-millisecond response times for search queries
90
+ - **Flexible**: Single, multiple, or universal collection search with one component
91
+ - **Modern**: Responsive design implemented with Tailwind CSS
92
+ - **Optimized API**: Automatically routes requests to the most efficient endpoint
93
+ - **Real-Time**: Continuous data sync with Payload CMS
94
+ - **Caching**: In-memory cache with configurable time-to-live settings
95
+ - **Production Ready**: Robust error handling and performance optimization
96
+ - **Responsive**: Mobile-first architecture ensuring compatibility across devices
97
+
98
+ ## API Endpoints
99
+
100
+ - `GET /api/search` - Universal search across all collections
101
+ - `GET /api/search/{collection}` - Search specific collection
102
+ - `POST /api/search/{collection}` - Advanced search with filters
103
+ - `GET /api/search/{collection}/suggest` - Search suggestions
104
+ - `GET /api/search/collections` - Collection metadata
105
+ - `GET /api/search/health` - Health check
106
+
107
+ ## Components
108
+
109
+ - **HeadlessSearchInput**: Single component supporting all search patterns:
110
+ - **Single Collection**: `collection="posts"` - Direct API calls for optimal performance
111
+ - **Multiple Collections**: `collections={['posts', 'products']}` - Smart filtering with universal search
112
+ - **Universal Search**: No collection props - Search across all collections
113
+ - **Complete UI Control**: Customizable rendering with comprehensive theme system
114
+
115
+ ## Theme System
116
+
117
+ The plugin includes a powerful theme system with 2 pre-built themes and unlimited customization:
118
+
119
+ ### Pre-built Themes
120
+
121
+ ```tsx
122
+ // Modern theme (default)
123
+ <HeadlessSearchInput theme="modern" />
124
+
125
+ // Dark theme
126
+ <HeadlessSearchInput theme="dark" />
127
+ ```
128
+
129
+ ### Custom Themes
130
+
131
+ ```tsx
132
+ const customTheme = {
133
+ theme: 'modern',
134
+ colors: {
135
+ inputBorderFocus: '#10b981',
136
+ inputBackground: '#f0fdf4',
137
+ resultsBackground: '#f0fdf4',
138
+ },
139
+ spacing: {
140
+ inputPadding: '1rem 1.25rem',
141
+ inputBorderRadius: '1.5rem',
142
+ },
143
+ enableAnimations: true,
144
+ enableShadows: true,
145
+ }
146
+
147
+ <HeadlessSearchInput theme={customTheme} />
148
+ ```
149
+
150
+ ### Theme Features
151
+
152
+ - **2 Pre-built Themes**: Modern, Dark
153
+ - **Unlimited Customization**: Override any color, spacing, typography, or animation
154
+ - **Performance Options**: Disable animations/shadows for better performance
155
+ - **Responsive Design**: Automatic mobile optimization
156
+ - **CSS Variables**: Advanced styling with CSS custom properties
157
+ - **TypeScript Support**: Full type safety for all theme configurations
158
+
159
+ ## License
160
+
161
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
162
+
163
+ ## Support
164
+
165
+ For support or inquiries:
166
+
167
+ - LinkedIn: [rubixvi](https://www.linkedin.com/in/rubixvi/)
168
+ - Website: [Rubix Studios](https://rubixstudios.com.au)
169
+
170
+ ## Author
171
+
172
+ Rubix Studios Pty. Ltd.
173
+ [https://rubixstudios.com.au](https://rubixstudios.com.au)
174
+
175
+ ## Acknowledgments
176
+
177
+ - [FrontTribe](https://github.com/FrontTribe/typesense-search)
@@ -3,8 +3,8 @@ import { createContext, useCallback, useContext, useMemo } from 'react';
3
3
  import { applyTheme, generateThemeClasses, getThemeVariables, isDarkTheme, isLightTheme, mergeThemeConfig } from './utils.js';
4
4
  // Theme context
5
5
  const ThemeContext = createContext(null);
6
- /**
7
- * Hook to access theme context
6
+ /**
7
+ * Hook to access theme context
8
8
  */ export function useTheme() {
9
9
  const context = useContext(ThemeContext);
10
10
  if (!context) {
@@ -12,8 +12,8 @@ const ThemeContext = createContext(null);
12
12
  }
13
13
  return context;
14
14
  }
15
- /**
16
- * Hook to create theme configuration
15
+ /**
16
+ * Hook to create theme configuration
17
17
  */ export function useThemeConfig(config) {
18
18
  const theme = useMemo(()=>mergeThemeConfig(config), [
19
19
  config
@@ -39,8 +39,8 @@ const ThemeContext = createContext(null);
39
39
  applyThemeToElement
40
40
  ]);
41
41
  }
42
- /**
43
- * Hook to apply theme styles to CSS variables
42
+ /**
43
+ * Hook to apply theme styles to CSS variables
44
44
  */ export function useThemeStyles(config) {
45
45
  return useMemo(()=>{
46
46
  const theme = mergeThemeConfig(config);
@@ -49,8 +49,8 @@ const ThemeContext = createContext(null);
49
49
  config
50
50
  ]);
51
51
  }
52
- /**
53
- * Hook to get responsive theme configuration
52
+ /**
53
+ * Hook to get responsive theme configuration
54
54
  */ export function useResponsiveTheme(baseConfig, isMobile) {
55
55
  return useMemo(()=>{
56
56
  if (!baseConfig.responsive) {
@@ -81,8 +81,8 @@ const ThemeContext = createContext(null);
81
81
  isMobile
82
82
  ]);
83
83
  }
84
- /**
85
- * Hook to toggle between light and dark themes
84
+ /**
85
+ * Hook to toggle between light and dark themes
86
86
  */ export function useThemeToggle(lightConfig, darkConfig, isDark) {
87
87
  return useMemo(()=>{
88
88
  return isDark ? darkConfig : lightConfig;
@@ -92,8 +92,8 @@ const ThemeContext = createContext(null);
92
92
  isDark
93
93
  ]);
94
94
  }
95
- /**
96
- * Hook to create theme-aware CSS classes
95
+ /**
96
+ * Hook to create theme-aware CSS classes
97
97
  */ export function useThemeClasses(config) {
98
98
  return useMemo(()=>{
99
99
  const theme = mergeThemeConfig(config);
@@ -108,8 +108,8 @@ const ThemeContext = createContext(null);
108
108
  config
109
109
  ]);
110
110
  }
111
- /**
112
- * Hook to get theme-aware color values
111
+ /**
112
+ * Hook to get theme-aware color values
113
113
  */ export function useThemeColors(config) {
114
114
  return useMemo(()=>{
115
115
  const theme = mergeThemeConfig(config);
@@ -118,8 +118,8 @@ const ThemeContext = createContext(null);
118
118
  config
119
119
  ]);
120
120
  }
121
- /**
122
- * Hook to get theme-aware spacing values
121
+ /**
122
+ * Hook to get theme-aware spacing values
123
123
  */ export function useThemeSpacing(config) {
124
124
  return useMemo(()=>{
125
125
  const theme = mergeThemeConfig(config);
@@ -128,8 +128,8 @@ const ThemeContext = createContext(null);
128
128
  config
129
129
  ]);
130
130
  }
131
- /**
132
- * Hook to get theme-aware typography values
131
+ /**
132
+ * Hook to get theme-aware typography values
133
133
  */ export function useThemeTypography(config) {
134
134
  return useMemo(()=>{
135
135
  const theme = mergeThemeConfig(config);
@@ -138,8 +138,8 @@ const ThemeContext = createContext(null);
138
138
  config
139
139
  ]);
140
140
  }
141
- /**
142
- * Hook to detect system theme preference
141
+ /**
142
+ * Hook to detect system theme preference
143
143
  */ export function useSystemTheme() {
144
144
  return useMemo(()=>{
145
145
  if (typeof window === 'undefined') {
@@ -148,8 +148,8 @@ const ThemeContext = createContext(null);
148
148
  return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
149
149
  }, []);
150
150
  }
151
- /**
152
- * Hook to create auto theme configuration based on system preference
151
+ /**
152
+ * Hook to create auto theme configuration based on system preference
153
153
  */ export function useAutoTheme(lightTheme, darkTheme) {
154
154
  const systemTheme = useSystemTheme();
155
155
  return useMemo(()=>{
@@ -160,8 +160,8 @@ const ThemeContext = createContext(null);
160
160
  darkTheme
161
161
  ]);
162
162
  }
163
- /**
164
- * Hook to create theme with custom overrides
163
+ /**
164
+ * Hook to create theme with custom overrides
165
165
  */ export function useCustomTheme(baseThemeName, overrides) {
166
166
  return useMemo(()=>{
167
167
  return {
@@ -1,11 +1,11 @@
1
1
  import { defaultTheme, themes } from './themes.js';
2
- /**
3
- * Get a theme by name or return the default theme
2
+ /**
3
+ * Get a theme by name or return the default theme
4
4
  */ export function getTheme(themeName) {
5
5
  return themes[themeName] || defaultTheme;
6
6
  }
7
- /**
8
- * Merge theme configurations with custom overrides
7
+ /**
8
+ * Merge theme configurations with custom overrides
9
9
  */ export function mergeThemeConfig(config) {
10
10
  const baseTheme = typeof config.theme === 'string' ? getTheme(config.theme) : config.theme;
11
11
  return {
@@ -32,8 +32,8 @@ import { defaultTheme, themes } from './themes.js';
32
32
  }
33
33
  };
34
34
  }
35
- /**
36
- * Generate CSS classes from theme configuration
35
+ /**
36
+ * Generate CSS classes from theme configuration
37
37
  */ export function generateThemeClasses(theme, config = {}) {
38
38
  const enableAnimations = config.enableAnimations !== false;
39
39
  const enableShadows = config.enableShadows !== false;
@@ -340,8 +340,8 @@ import { defaultTheme, themes } from './themes.js';
340
340
  visible: visibleStyles
341
341
  };
342
342
  }
343
- /**
344
- * Apply theme to a CSS class with optional variant
343
+ /**
344
+ * Apply theme to a CSS class with optional variant
345
345
  */ export function applyTheme(theme, element, variant) {
346
346
  const classes = generateThemeClasses(theme);
347
347
  if (variant) {
@@ -350,18 +350,18 @@ import { defaultTheme, themes } from './themes.js';
350
350
  }
351
351
  return classes[element] || '';
352
352
  }
353
- /**
354
- * Check if theme is dark mode
353
+ /**
354
+ * Check if theme is dark mode
355
355
  */ export function isDarkTheme(theme) {
356
356
  return theme.name === 'dark' || theme.colors.inputBackground.includes('#1f') || theme.colors.inputBackground.includes('#0f');
357
357
  }
358
- /**
359
- * Check if theme is light mode
358
+ /**
359
+ * Check if theme is light mode
360
360
  */ export function isLightTheme(theme) {
361
361
  return !isDarkTheme(theme);
362
362
  }
363
- /**
364
- * Get theme-specific CSS variables
363
+ /**
364
+ * Get theme-specific CSS variables
365
365
  */ export function getThemeVariables(theme) {
366
366
  return {
367
367
  '--search-collection-badge': theme.colors.collectionBadge,
@@ -1,7 +1,7 @@
1
1
  import pkg from '../../package.json';
2
2
  import { searchCache } from '../lib/cache.js';
3
- /**
4
- * Test Typesense connection
3
+ /**
4
+ * Test Typesense connection
5
5
  */ const testTypesenseConnection = async (typesenseClient)=>{
6
6
  try {
7
7
  const health = await typesenseClient.health.retrieve();
@@ -11,8 +11,8 @@ import { searchCache } from '../lib/cache.js';
11
11
  return false;
12
12
  }
13
13
  };
14
- /**
15
- * Get collection information
14
+ /**
15
+ * Get collection information
16
16
  */ const getCollectionInfo = async (typesenseClient)=>{
17
17
  try {
18
18
  const collections = await typesenseClient.collections().retrieve();
@@ -22,8 +22,8 @@ import { searchCache } from '../lib/cache.js';
22
22
  return [];
23
23
  }
24
24
  };
25
- /**
26
- * Get cache statistics
25
+ /**
26
+ * Get cache statistics
27
27
  */ const getCacheStats = ()=>{
28
28
  const stats = searchCache.getStats();
29
29
  return {
@@ -32,8 +32,8 @@ import { searchCache } from '../lib/cache.js';
32
32
  size: stats.size
33
33
  };
34
34
  };
35
- /**
36
- * Create health check handler
35
+ /**
36
+ * Create health check handler
37
37
  */ export const createHealthCheckHandler = (typesenseClient, pluginOptions, lastSyncTime)=>{
38
38
  return async ()=>{
39
39
  try {
@@ -93,8 +93,8 @@ import { searchCache } from '../lib/cache.js';
93
93
  }
94
94
  };
95
95
  };
96
- /**
97
- * Create detailed health check handler with more information
96
+ /**
97
+ * Create detailed health check handler with more information
98
98
  */ export const createDetailedHealthCheckHandler = (typesenseClient, pluginOptions, lastSyncTime)=>{
99
99
  return async ()=>{
100
100
  try {
package/dist/lib/cache.js CHANGED
@@ -6,8 +6,8 @@ export class SearchCache {
6
6
  this.defaultTTL = options.ttl || 5 * 60 * 1000; // 5 minutes default
7
7
  this.maxSize = options.maxSize || 1000; // 1000 entries default
8
8
  }
9
- /**
10
- * Generate cache key from search parameters
9
+ /**
10
+ * Generate cache key from search parameters
11
11
  */ generateKey(query, collection, params) {
12
12
  const baseKey = `${collection || 'universal'}:${query}`;
13
13
  if (params) {
@@ -16,8 +16,8 @@ export class SearchCache {
16
16
  }
17
17
  return baseKey;
18
18
  }
19
- /**
20
- * Clear expired entries
19
+ /**
20
+ * Clear expired entries
21
21
  */ cleanup() {
22
22
  const now = Date.now();
23
23
  for (const [key, entry] of this.cache.entries()){
@@ -26,8 +26,8 @@ export class SearchCache {
26
26
  }
27
27
  }
28
28
  }
29
- /**
30
- * Clear cache entries matching pattern
29
+ /**
30
+ * Clear cache entries matching pattern
31
31
  */ clear(pattern) {
32
32
  if (!pattern) {
33
33
  this.cache.clear();
@@ -39,8 +39,8 @@ export class SearchCache {
39
39
  }
40
40
  }
41
41
  }
42
- /**
43
- * Get cached search result
42
+ /**
43
+ * Get cached search result
44
44
  */ get(query, collection, params) {
45
45
  const key = this.generateKey(query, collection || '', params);
46
46
  const entry = this.cache.get(key);
@@ -54,21 +54,21 @@ export class SearchCache {
54
54
  }
55
55
  return entry.data;
56
56
  }
57
- /**
58
- * Get cache statistics
57
+ /**
58
+ * Get cache statistics
59
59
  */ getStats() {
60
60
  return {
61
61
  maxSize: this.maxSize,
62
62
  size: this.cache.size
63
63
  };
64
64
  }
65
- /**
66
- * Check if cache has valid entry
65
+ /**
66
+ * Check if cache has valid entry
67
67
  */ has(query, collection, params) {
68
68
  return this.get(query, collection, params) !== null;
69
69
  }
70
- /**
71
- * Set cached search result
70
+ /**
71
+ * Set cached search result
72
72
  */ set(query, data, collection, params, ttl) {
73
73
  const key = this.generateKey(query, collection || '', params);
74
74
  // Enforce max size by removing oldest entries
@@ -39,8 +39,8 @@ export const TypesenseSearchConfigSchema = z.object({
39
39
  retryIntervalSeconds: z.number().int().min(1).optional().default(1)
40
40
  })
41
41
  });
42
- /**
43
- * Validate plugin configuration
42
+ /**
43
+ * Validate plugin configuration
44
44
  */ export function validateConfig(config) {
45
45
  try {
46
46
  const validatedConfig = TypesenseSearchConfigSchema.parse(config);
@@ -67,8 +67,8 @@ export const TypesenseSearchConfigSchema = z.object({
67
67
  };
68
68
  }
69
69
  }
70
- /**
71
- * Validate and transform configuration with defaults
70
+ /**
71
+ * Validate and transform configuration with defaults
72
72
  */ export function validateAndTransformConfig(config) {
73
73
  try {
74
74
  const validatedConfig = TypesenseSearchConfigSchema.parse(config);
@@ -95,8 +95,8 @@ export const TypesenseSearchConfigSchema = z.object({
95
95
  };
96
96
  }
97
97
  }
98
- /**
99
- * Validate individual collection configuration
98
+ /**
99
+ * Validate individual collection configuration
100
100
  */ export function validateCollectionConfig(collectionSlug, config) {
101
101
  try {
102
102
  const validatedConfig = CollectionConfigSchema.parse(config);
@@ -125,13 +125,13 @@ export const TypesenseSearchConfigSchema = z.object({
125
125
  };
126
126
  }
127
127
  }
128
- /**
129
- * Get configuration validation errors in a user-friendly format
128
+ /**
129
+ * Get configuration validation errors in a user-friendly format
130
130
  */ export function getValidationErrors(errors) {
131
131
  return errors.map((error, index)=>`${index + 1}. ${error}`).join('\n');
132
132
  }
133
- /**
134
- * Validate search parameters
133
+ /**
134
+ * Validate search parameters
135
135
  */ export const SearchParamsSchema = z.object({
136
136
  facets: z.array(z.string()).optional(),
137
137
  filters: z.record(z.string(), z.any()).optional(),
@@ -144,8 +144,8 @@ export const TypesenseSearchConfigSchema = z.object({
144
144
  sort_by: z.string().optional(),
145
145
  typo_tokens_threshold: z.number().int().min(1).optional().default(1)
146
146
  });
147
- /**
148
- * Validate search parameters
147
+ /**
148
+ * Validate search parameters
149
149
  */ export function validateSearchParams(params) {
150
150
  try {
151
151
  const validatedParams = SearchParamsSchema.parse(params);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubixstudios/payload-typesense",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "A production-ready search plugin that integrates Typesense with Payload CMS, offering fast, typo-tolerant search with real-time synchronization. This fork by Rubix Studios reduces bloat and introduces targeted changes for improved performance, maintainability, and flexibility.",
5
5
  "license": "MIT",
6
6
  "author": "Rubix Studios <hello@rubixstudios.com.au> (https://rubixstudios.com.au)",
@@ -46,15 +46,6 @@
46
46
  "files": [
47
47
  "dist"
48
48
  ],
49
- "scripts": {
50
- "build": "pnpm build:types && pnpm build:swc",
51
- "build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
52
- "build:types": "tsc -p tsconfig.json",
53
- "clean": "rimraf -g {dist,*.tsbuildinfo}",
54
- "lint": "eslint .",
55
- "lint:fix": "eslint . --fix",
56
- "prepublishOnly": "pnpm clean && pnpm build"
57
- },
58
49
  "devDependencies": {
59
50
  "@payloadcms/eslint-config": "3.28.0",
60
51
  "@swc/cli": "^0.7.8",
@@ -73,20 +64,22 @@
73
64
  },
74
65
  "publishConfig": {
75
66
  "access": "public",
76
- "registry": "https://registry.npmjs.org/",
77
- "exports": {
78
- ".": {
79
- "import": "./dist/index.js",
80
- "types": "./dist/index.d.ts",
81
- "default": "./dist/index.js"
82
- }
83
- },
84
- "main": "./dist/index.js",
85
- "types": "./dist/index.d.ts"
67
+ "registry": "https://registry.npmjs.org/"
86
68
  },
87
69
  "dependencies": {
88
70
  "typesense": "^2.1.0",
89
71
  "zod": "^4.1.11"
90
72
  },
91
- "packageManager": "pnpm@10.17.1"
92
- }
73
+ "scripts": {
74
+ "build": "pnpm build:types && pnpm build:swc",
75
+ "build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
76
+ "build:types": "tsc -p tsconfig.json",
77
+ "clean": "rimraf -g {dist,*.tsbuildinfo}",
78
+ "lint": "eslint .",
79
+ "lint:fix": "eslint . --fix",
80
+ "update": "pnpm update --latest && pnpm install && pnpm prune && pnpm dedupe",
81
+ "release:patch": "pnpm clean && pnpm build && pnpm version patch -m \"chore(release): %s\" && pnpm publish --access public",
82
+ "release:minor": "pnpm clean && pnpm build && pnpm version minor -m \"chore(release): %s\" && pnpm publish --access public",
83
+ "release:major": "pnpm clean && pnpm build && pnpm version major -m \"chore(release): %s\" && pnpm publish --access public"
84
+ }
85
+ }