@centrali-io/centrali-sdk 2.2.2 → 2.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.
Files changed (4) hide show
  1. package/README.md +64 -11
  2. package/dist/index.js +324 -1
  3. package/index.ts +530 -0
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -31,13 +31,9 @@ const product = await centrali.createRecord('Product', {
31
31
 
32
32
  console.log('Created product:', product.data);
33
33
 
34
- // Invoke a compute function
35
- const result = await centrali.invokeFunction('calculate-discount', {
36
- productId: product.id,
37
- couponCode: 'SAVE20'
38
- });
39
-
40
- console.log('Discount result:', result.data);
34
+ // Search for records
35
+ const results = await centrali.search('Awesome');
36
+ console.log('Found:', results.data.totalHits, 'results');
41
37
  ```
42
38
 
43
39
  ## Authentication
@@ -73,6 +69,8 @@ const centrali = new CentraliSDK({
73
69
  - ✅ **Automatic authentication** and token management
74
70
  - ✅ **Records management** - Create, read, update, delete records
75
71
  - ✅ **Query operations** - Powerful data querying with filters and sorting
72
+ - ✅ **Smart Queries** - Execute reusable, predefined queries
73
+ - ✅ **Full-text search** - Search records across structures with Meilisearch
76
74
  - ✅ **Realtime events** - Subscribe to record changes via SSE
77
75
  - ✅ **Compute functions** - Execute serverless functions
78
76
  - ✅ **File uploads** - Upload files to Centrali storage
@@ -119,6 +117,59 @@ const products = await centrali.queryRecords('Product', {
119
117
  });
120
118
  ```
121
119
 
120
+ ### Smart Queries
121
+
122
+ Smart queries are reusable, predefined queries that are created in the Centrali console and can be executed programmatically via the SDK. Pagination (limit/skip) is defined in the query definition itself.
123
+
124
+ ```typescript
125
+ // List all smart queries in the workspace
126
+ const allQueries = await centrali.smartQueries.listAll();
127
+
128
+ // List smart queries for a specific structure
129
+ const employeeQueries = await centrali.smartQueries.list('employee');
130
+
131
+ // Get a smart query by name
132
+ const query = await centrali.smartQueries.getByName('employee', 'Active Employees');
133
+ console.log('Query ID:', query.data.id);
134
+
135
+ // Execute a smart query
136
+ const results = await centrali.smartQueries.execute('employee', query.data.id);
137
+ console.log('Found:', results.data.length, 'employees');
138
+ ```
139
+
140
+ ### Search
141
+
142
+ Perform full-text search across workspace records using Meilisearch:
143
+
144
+ ```typescript
145
+ // Basic search
146
+ const results = await centrali.search('customer email');
147
+ console.log('Found:', results.data.totalHits, 'results');
148
+ results.data.hits.forEach(hit => {
149
+ console.log(hit.id, hit.structureSlug);
150
+ });
151
+
152
+ // Search with structure filter
153
+ const userResults = await centrali.search('john', {
154
+ structures: 'users'
155
+ });
156
+
157
+ // Search multiple structures with limit
158
+ const multiResults = await centrali.search('active', {
159
+ structures: ['users', 'orders'],
160
+ limit: 50
161
+ });
162
+ ```
163
+
164
+ #### Search Response
165
+
166
+ | Field | Type | Description |
167
+ |-------|------|-------------|
168
+ | `hits` | `SearchHit[]` | Array of matching records |
169
+ | `totalHits` | `number` | Estimated total matches |
170
+ | `processingTimeMs` | `number` | Search time in milliseconds |
171
+ | `query` | `string` | The original search query |
172
+
122
173
  ### Realtime Events
123
174
 
124
175
  Subscribe to record changes in real-time using Server-Sent Events (SSE):
@@ -217,13 +268,15 @@ const realtime = new RealtimeManager(
217
268
  );
218
269
  ```
219
270
 
220
- ### Compute Functions
271
+ ### Compute Functions (via Triggers)
221
272
 
222
273
  ```typescript
223
- // Execute a function
224
- const result = await centrali.invokeFunction('myFunction', {
225
- data: 'your-input-data'
274
+ // Invoke an on-demand trigger to execute a compute function
275
+ const job = await centrali.triggers.invoke('trigger-id', {
276
+ payload: { data: 'your-input-data' }
226
277
  });
278
+
279
+ console.log('Job queued:', job.data);
227
280
  ```
228
281
 
229
282
  ### File Uploads
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
18
18
  return (mod && mod.__esModule) ? mod : { "default": mod };
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.CentraliSDK = exports.TriggersManager = exports.RealtimeManager = void 0;
21
+ exports.CentraliSDK = exports.SmartQueriesManager = exports.TriggersManager = exports.RealtimeManager = void 0;
22
22
  exports.getApiUrl = getApiUrl;
23
23
  exports.getAuthUrl = getAuthUrl;
24
24
  exports.getRealtimeUrl = getRealtimeUrl;
@@ -27,6 +27,13 @@ exports.getRecordApiPath = getRecordApiPath;
27
27
  exports.getFileUploadApiPath = getFileUploadApiPath;
28
28
  exports.getFunctionTriggersApiPath = getFunctionTriggersApiPath;
29
29
  exports.getFunctionTriggerExecuteApiPath = getFunctionTriggerExecuteApiPath;
30
+ exports.getFunctionTriggerPauseApiPath = getFunctionTriggerPauseApiPath;
31
+ exports.getFunctionTriggerResumeApiPath = getFunctionTriggerResumeApiPath;
32
+ exports.getSmartQueriesApiPath = getSmartQueriesApiPath;
33
+ exports.getSmartQueriesStructureApiPath = getSmartQueriesStructureApiPath;
34
+ exports.getSmartQueryByNameApiPath = getSmartQueryByNameApiPath;
35
+ exports.getSmartQueryExecuteApiPath = getSmartQueryExecuteApiPath;
36
+ exports.getSearchApiPath = getSearchApiPath;
30
37
  const axios_1 = __importDefault(require("axios"));
31
38
  const qs_1 = __importDefault(require("qs"));
32
39
  const eventsource_1 = require("eventsource");
@@ -332,6 +339,49 @@ function getFunctionTriggersApiPath(workspaceId, triggerId) {
332
339
  function getFunctionTriggerExecuteApiPath(workspaceId, triggerId) {
333
340
  return `data/workspace/${workspaceId}/api/v1/function-triggers/${triggerId}/execute`;
334
341
  }
342
+ /**
343
+ * Generate Function Trigger pause API URL PATH.
344
+ */
345
+ function getFunctionTriggerPauseApiPath(workspaceId, triggerId) {
346
+ return `data/workspace/${workspaceId}/api/v1/function-triggers/${triggerId}/pause`;
347
+ }
348
+ /**
349
+ * Generate Function Trigger resume API URL PATH.
350
+ */
351
+ function getFunctionTriggerResumeApiPath(workspaceId, triggerId) {
352
+ return `data/workspace/${workspaceId}/api/v1/function-triggers/${triggerId}/resume`;
353
+ }
354
+ /**
355
+ * Generate Smart Queries base API URL PATH for workspace-level operations.
356
+ */
357
+ function getSmartQueriesApiPath(workspaceId) {
358
+ return `data/workspace/${workspaceId}/api/v1/smart-queries`;
359
+ }
360
+ /**
361
+ * Generate Smart Queries API URL PATH for structure-level operations.
362
+ */
363
+ function getSmartQueriesStructureApiPath(workspaceId, structureSlug, queryId) {
364
+ const basePath = `data/workspace/${workspaceId}/api/v1/smart-queries/slug/${structureSlug}`;
365
+ return queryId ? `${basePath}/${queryId}` : basePath;
366
+ }
367
+ /**
368
+ * Generate Smart Query by name API URL PATH.
369
+ */
370
+ function getSmartQueryByNameApiPath(workspaceId, structureSlug, name) {
371
+ return `data/workspace/${workspaceId}/api/v1/smart-queries/slug/${structureSlug}/name/${encodeURIComponent(name)}`;
372
+ }
373
+ /**
374
+ * Generate Smart Query execute API URL PATH.
375
+ */
376
+ function getSmartQueryExecuteApiPath(workspaceId, structureSlug, queryId) {
377
+ return `data/workspace/${workspaceId}/api/v1/smart-queries/slug/${structureSlug}/execute/${queryId}`;
378
+ }
379
+ /**
380
+ * Generate Search API URL PATH.
381
+ */
382
+ function getSearchApiPath(workspaceId) {
383
+ return `search/workspace/${workspaceId}/api/v1/records/search`;
384
+ }
335
385
  // =====================================================
336
386
  // Triggers Manager
337
387
  // =====================================================
@@ -442,8 +492,177 @@ class TriggersManager {
442
492
  const params = Object.assign(Object.assign({}, queryParams), { executionType: 'on-demand' });
443
493
  return this.requestFn('GET', path, null, params);
444
494
  }
495
+ /**
496
+ * Pause a function trigger.
497
+ *
498
+ * Pauses an event-driven or scheduled trigger to temporarily disable it from firing.
499
+ * When paused, the trigger will not execute until resumed.
500
+ *
501
+ * For scheduled triggers, this also pauses the underlying scheduler job.
502
+ *
503
+ * @param triggerId - The ID of the trigger to pause
504
+ * @returns The updated trigger with enabled = false
505
+ *
506
+ * @example
507
+ * ```ts
508
+ * // Pause a trigger
509
+ * const result = await client.triggers.pauseTrigger('trigger-id');
510
+ * console.log('Trigger paused:', result.data.enabled === false);
511
+ * ```
512
+ */
513
+ pauseTrigger(triggerId) {
514
+ const path = getFunctionTriggerPauseApiPath(this.workspaceId, triggerId);
515
+ return this.requestFn('PATCH', path, {});
516
+ }
517
+ /**
518
+ * Resume a paused function trigger.
519
+ *
520
+ * Resumes a paused event-driven or scheduled trigger to re-enable it.
521
+ * Once resumed, the trigger will start firing again on matching events or schedules.
522
+ *
523
+ * For scheduled triggers, this also resumes the underlying scheduler job.
524
+ *
525
+ * @param triggerId - The ID of the trigger to resume
526
+ * @returns The updated trigger with enabled = true
527
+ *
528
+ * @example
529
+ * ```ts
530
+ * // Resume a paused trigger
531
+ * const result = await client.triggers.resumeTrigger('trigger-id');
532
+ * console.log('Trigger resumed:', result.data.enabled === true);
533
+ * ```
534
+ */
535
+ resumeTrigger(triggerId) {
536
+ const path = getFunctionTriggerResumeApiPath(this.workspaceId, triggerId);
537
+ return this.requestFn('PATCH', path, {});
538
+ }
445
539
  }
446
540
  exports.TriggersManager = TriggersManager;
541
+ // =====================================================
542
+ // Smart Queries Manager
543
+ // =====================================================
544
+ /**
545
+ * SmartQueriesManager provides methods for listing and executing smart queries.
546
+ * Smart queries are reusable, parameterized queries defined in the console
547
+ * that can be executed programmatically via the SDK.
548
+ * Access via `client.smartQueries`.
549
+ *
550
+ * Usage:
551
+ * ```ts
552
+ * // List smart queries for a structure
553
+ * const queries = await client.smartQueries.list('employee');
554
+ *
555
+ * // Execute a smart query by ID
556
+ * const results = await client.smartQueries.execute('employee', 'query-uuid');
557
+ *
558
+ * // Get a smart query by name
559
+ * const query = await client.smartQueries.getByName('employee', 'Active Employees');
560
+ * ```
561
+ */
562
+ class SmartQueriesManager {
563
+ constructor(workspaceId, requestFn) {
564
+ this.workspaceId = workspaceId;
565
+ this.requestFn = requestFn;
566
+ }
567
+ /**
568
+ * List all smart queries in the workspace.
569
+ *
570
+ * @param options - Optional list parameters (pagination, search, etc.)
571
+ * @returns List of smart queries with pagination metadata
572
+ *
573
+ * @example
574
+ * ```ts
575
+ * // List all smart queries
576
+ * const queries = await client.smartQueries.listAll();
577
+ *
578
+ * // With pagination
579
+ * const queries = await client.smartQueries.listAll({ page: 1, limit: 20 });
580
+ * ```
581
+ */
582
+ listAll(options) {
583
+ const path = getSmartQueriesApiPath(this.workspaceId);
584
+ return this.requestFn('GET', path, null, options);
585
+ }
586
+ /**
587
+ * List smart queries for a specific structure.
588
+ *
589
+ * @param structureSlug - The structure's record slug (e.g., "employee")
590
+ * @param options - Optional list parameters (pagination, search, etc.)
591
+ * @returns List of smart queries for the structure
592
+ *
593
+ * @example
594
+ * ```ts
595
+ * // List queries for employee structure
596
+ * const queries = await client.smartQueries.list('employee');
597
+ *
598
+ * // With pagination and search
599
+ * const queries = await client.smartQueries.list('employee', {
600
+ * page: 1,
601
+ * limit: 10,
602
+ * search: 'active'
603
+ * });
604
+ * ```
605
+ */
606
+ list(structureSlug, options) {
607
+ const path = getSmartQueriesStructureApiPath(this.workspaceId, structureSlug);
608
+ return this.requestFn('GET', path, null, options);
609
+ }
610
+ /**
611
+ * Get a smart query by ID.
612
+ *
613
+ * @param structureSlug - The structure's record slug
614
+ * @param queryId - The smart query UUID
615
+ * @returns The smart query details
616
+ *
617
+ * @example
618
+ * ```ts
619
+ * const query = await client.smartQueries.get('employee', 'query-uuid');
620
+ * console.log('Query name:', query.data.name);
621
+ * ```
622
+ */
623
+ get(structureSlug, queryId) {
624
+ const path = getSmartQueriesStructureApiPath(this.workspaceId, structureSlug, queryId);
625
+ return this.requestFn('GET', path);
626
+ }
627
+ /**
628
+ * Get a smart query by name.
629
+ *
630
+ * @param structureSlug - The structure's record slug
631
+ * @param name - The smart query name
632
+ * @returns The smart query details
633
+ *
634
+ * @example
635
+ * ```ts
636
+ * const query = await client.smartQueries.getByName('employee', 'Active Employees');
637
+ * console.log('Query ID:', query.data.id);
638
+ * ```
639
+ */
640
+ getByName(structureSlug, name) {
641
+ const path = getSmartQueryByNameApiPath(this.workspaceId, structureSlug, name);
642
+ return this.requestFn('GET', path);
643
+ }
644
+ /**
645
+ * Execute a smart query and return results.
646
+ *
647
+ * Note: Pagination (limit/skip) is defined in the query definition itself,
648
+ * not at execution time.
649
+ *
650
+ * @param structureSlug - The structure's record slug
651
+ * @param queryId - The smart query UUID
652
+ * @returns Query results
653
+ *
654
+ * @example
655
+ * ```ts
656
+ * const results = await client.smartQueries.execute('employee', 'query-uuid');
657
+ * console.log('Found:', results.data.length, 'records');
658
+ * ```
659
+ */
660
+ execute(structureSlug, queryId) {
661
+ const path = getSmartQueryExecuteApiPath(this.workspaceId, structureSlug, queryId);
662
+ return this.requestFn('GET', path);
663
+ }
664
+ }
665
+ exports.SmartQueriesManager = SmartQueriesManager;
447
666
  /**
448
667
  * Main Centrali SDK client.
449
668
  */
@@ -452,6 +671,7 @@ class CentraliSDK {
452
671
  this.token = null;
453
672
  this._realtime = null;
454
673
  this._triggers = null;
674
+ this._smartQueries = null;
455
675
  this.options = options;
456
676
  this.token = options.token || null;
457
677
  const apiUrl = getApiUrl(options.baseUrl);
@@ -537,6 +757,31 @@ class CentraliSDK {
537
757
  }
538
758
  return this._triggers;
539
759
  }
760
+ /**
761
+ * Smart Queries namespace for listing and executing smart queries.
762
+ *
763
+ * Usage:
764
+ * ```ts
765
+ * // List all smart queries in workspace
766
+ * const allQueries = await client.smartQueries.listAll();
767
+ *
768
+ * // List smart queries for a structure
769
+ * const queries = await client.smartQueries.list('employee');
770
+ *
771
+ * // Get a smart query by name
772
+ * const query = await client.smartQueries.getByName('employee', 'Active Employees');
773
+ *
774
+ * // Execute a smart query
775
+ * const results = await client.smartQueries.execute('employee', query.data.id);
776
+ * console.log('Found:', results.data.length, 'records');
777
+ * ```
778
+ */
779
+ get smartQueries() {
780
+ if (!this._smartQueries) {
781
+ this._smartQueries = new SmartQueriesManager(this.options.workspaceId, this.request.bind(this));
782
+ }
783
+ return this._smartQueries;
784
+ }
540
785
  /**
541
786
  * Manually set or update the bearer token for subsequent requests.
542
787
  */
@@ -570,6 +815,10 @@ class CentraliSDK {
570
815
  if (Array.isArray(resp.data)) {
571
816
  return { data: resp.data };
572
817
  }
818
+ // Handle { result } responses (smart queries and some other endpoints)
819
+ if ('result' in resp.data && !('data' in resp.data)) {
820
+ return { data: resp.data.result };
821
+ }
573
822
  // Handle objects that don't have a data property (legacy endpoints)
574
823
  if (!('data' in resp.data)) {
575
824
  return { data: resp.data };
@@ -636,6 +885,47 @@ class CentraliSDK {
636
885
  });
637
886
  });
638
887
  }
888
+ // ------------------ Search API Methods ------------------
889
+ /**
890
+ * Search records across the workspace using full-text search.
891
+ *
892
+ * @param query - The search query string
893
+ * @param options - Optional search parameters
894
+ * @returns Search results with hits and metadata
895
+ *
896
+ * @example
897
+ * ```ts
898
+ * // Basic search
899
+ * const results = await client.search('customer email');
900
+ * console.log('Found:', results.data.totalHits, 'results');
901
+ * results.data.hits.forEach(hit => console.log(hit.id, hit.structureSlug));
902
+ *
903
+ * // Search with structure filter
904
+ * const userResults = await client.search('john', { structures: 'users' });
905
+ *
906
+ * // Search multiple structures with limit
907
+ * const results = await client.search('active', {
908
+ * structures: ['users', 'orders'],
909
+ * limit: 50
910
+ * });
911
+ * ```
912
+ */
913
+ search(query, options) {
914
+ return __awaiter(this, void 0, void 0, function* () {
915
+ const path = getSearchApiPath(this.options.workspaceId);
916
+ const queryParams = { q: query };
917
+ if (options === null || options === void 0 ? void 0 : options.structures) {
918
+ const structures = Array.isArray(options.structures)
919
+ ? options.structures.join(',')
920
+ : options.structures;
921
+ queryParams.structures = structures;
922
+ }
923
+ if (options === null || options === void 0 ? void 0 : options.limit) {
924
+ queryParams.limit = String(options.limit);
925
+ }
926
+ return this.request('GET', path, null, queryParams);
927
+ });
928
+ }
639
929
  }
640
930
  exports.CentraliSDK = CentraliSDK;
641
931
  /**
@@ -696,5 +986,38 @@ exports.CentraliSDK = CentraliSDK;
696
986
  * // List all triggers:
697
987
  * const triggers = await client.triggers.list();
698
988
  * triggers.data.forEach(t => console.log(t.name));
989
+ *
990
+ * // ---- Smart Queries ----
991
+ *
992
+ * // List all smart queries in the workspace:
993
+ * const allQueries = await client.smartQueries.listAll();
994
+ *
995
+ * // List smart queries for a specific structure:
996
+ * const employeeQueries = await client.smartQueries.list('employee');
997
+ * employeeQueries.data.forEach(q => console.log(q.name));
998
+ *
999
+ * // Get a smart query by name:
1000
+ * const activeQuery = await client.smartQueries.getByName('employee', 'Active Employees');
1001
+ * console.log('Query ID:', activeQuery.data.id);
1002
+ *
1003
+ * // Execute a smart query:
1004
+ * const results = await client.smartQueries.execute('employee', activeQuery.data.id);
1005
+ * console.log('Found:', results.data.length, 'employees');
1006
+ *
1007
+ * // ---- Search ----
1008
+ *
1009
+ * // Basic full-text search:
1010
+ * const searchResults = await client.search('customer email');
1011
+ * console.log('Found:', searchResults.data.totalHits, 'results');
1012
+ * searchResults.data.hits.forEach(hit => console.log(hit.id, hit.structureSlug));
1013
+ *
1014
+ * // Search with structure filter:
1015
+ * const userResults = await client.search('john', { structures: 'users' });
1016
+ *
1017
+ * // Search multiple structures with limit:
1018
+ * const multiResults = await client.search('active', {
1019
+ * structures: ['users', 'orders'],
1020
+ * limit: 50
1021
+ * });
699
1022
  *```
700
1023
  */
package/index.ts CHANGED
@@ -200,7 +200,186 @@ export interface DeleteRecordOptions {
200
200
  */
201
201
  export type TriggerInvokeResponse = string;
202
202
 
203
+ // =====================================================
204
+ // Smart Query Types
205
+ // =====================================================
206
+
207
+ /**
208
+ * Smart query definition stored in the database.
209
+ */
210
+ export interface SmartQuery {
211
+ /** Unique identifier (UUID) */
212
+ id: string;
213
+ /** Workspace slug where the query belongs */
214
+ workspaceSlug: string;
215
+ /** Structure's record slug (e.g., "employee") */
216
+ recordSlug: string;
217
+ /** Human-readable name (unique within workspace) */
218
+ name: string;
219
+ /** Optional description */
220
+ description?: string;
221
+ /** Query definition object */
222
+ queryDefinition: SmartQueryDefinition;
223
+ /** Status (active, archived) */
224
+ status: string;
225
+ /** User ID who created the query */
226
+ createdBy: string;
227
+ /** User ID who last updated the query */
228
+ updatedBy: string;
229
+ /** ISO timestamp of creation */
230
+ createdAt: string;
231
+ /** ISO timestamp of last update */
232
+ updatedAt: string;
233
+ }
234
+
235
+ /**
236
+ * Query definition format for smart queries.
237
+ * Supports filtering, selection, joins, sorting, and pagination.
238
+ */
239
+ export interface SmartQueryDefinition {
240
+ /** Fields to select from the structure */
241
+ select?: string[];
242
+ /** Filter conditions */
243
+ where?: SmartQueryWhereClause;
244
+ /** Join to another structure */
245
+ join?: SmartQueryJoin;
246
+ /** Sorting specification */
247
+ sort?: SmartQuerySort[];
248
+ /** Maximum number of results */
249
+ limit?: number;
250
+ /** Number of results to skip */
251
+ skip?: number;
252
+ }
253
+
254
+ /**
255
+ * Where clause for smart query filtering.
256
+ * Supports comparison operators and logical operators.
257
+ */
258
+ export interface SmartQueryWhereClause {
259
+ /** Field-level conditions */
260
+ [field: string]: SmartQueryFieldCondition | SmartQueryWhereClause[] | undefined;
261
+ /** Logical AND of multiple conditions */
262
+ $and?: SmartQueryWhereClause[];
263
+ /** Logical OR of multiple conditions */
264
+ $or?: SmartQueryWhereClause[];
265
+ }
266
+
267
+ /**
268
+ * Field-level condition operators for smart query filtering.
269
+ */
270
+ export interface SmartQueryFieldCondition {
271
+ /** Equality */
272
+ $eq?: any;
273
+ /** Not equal */
274
+ $ne?: any;
275
+ /** Greater than */
276
+ $gt?: number;
277
+ /** Greater than or equal */
278
+ $gte?: number;
279
+ /** Less than */
280
+ $lt?: number;
281
+ /** Less than or equal */
282
+ $lte?: number;
283
+ /** String starts with */
284
+ $startsWith?: string;
285
+ /** String ends with */
286
+ $endsWith?: string;
287
+ /** String contains */
288
+ $contains?: string;
289
+ /** Regex pattern match */
290
+ $regex?: string;
291
+ /** Value in array */
292
+ $in?: any[];
293
+ /** Value not in array */
294
+ $nin?: any[];
295
+ /** Field exists check */
296
+ $exists?: boolean;
297
+ /** JSONB type check */
298
+ $type?: string;
299
+ }
300
+
301
+ /**
302
+ * Join definition for smart queries.
303
+ */
304
+ export interface SmartQueryJoin {
305
+ /** Target structure slug to join */
306
+ foreignSlug: string;
307
+ /** Field in the main structure */
308
+ localField: string;
309
+ /** Field in the foreign structure */
310
+ foreignField: string;
311
+ /** Fields to select from the joined structure */
312
+ select?: string[];
313
+ }
314
+
315
+ /**
316
+ * Sort specification for smart queries.
317
+ */
318
+ export interface SmartQuerySort {
319
+ /** Field to sort by */
320
+ field: string;
321
+ /** Sort direction */
322
+ direction: 'asc' | 'desc';
323
+ }
324
+
325
+
326
+ /**
327
+ * Options for listing smart queries.
328
+ */
329
+ export interface ListSmartQueryOptions {
330
+ /** Page number (default: 1) */
331
+ page?: number;
332
+ /** Results per page (default: 20) */
333
+ limit?: number;
334
+ /** Search term */
335
+ search?: string;
336
+ /** Sort field */
337
+ sort?: string;
338
+ /** Sort direction */
339
+ sortDirection?: 'asc' | 'desc';
340
+ }
341
+
342
+ // =====================================================
343
+ // Search Types
344
+ // =====================================================
345
+
346
+ /**
347
+ * Options for searching records.
348
+ */
349
+ export interface SearchOptions {
350
+ /** Filter by structure slug(s). Can be a single slug or array of slugs */
351
+ structures?: string | string[];
352
+ /** Maximum number of results to return (default: 20, max: 100) */
353
+ limit?: number;
354
+ }
355
+
356
+ /**
357
+ * A single search result hit.
358
+ */
359
+ export interface SearchHit {
360
+ /** The record ID */
361
+ id: string;
362
+ /** The record slug (structure type) */
363
+ recordSlug: string;
364
+ /** The structure slug */
365
+ structureSlug: string;
366
+ /** The indexed record data */
367
+ [key: string]: unknown;
368
+ }
203
369
 
370
+ /**
371
+ * Response from a search query.
372
+ */
373
+ export interface SearchResponse {
374
+ /** Array of matching records */
375
+ hits: SearchHit[];
376
+ /** Estimated total number of matching records */
377
+ totalHits: number;
378
+ /** Time taken to process the search in milliseconds */
379
+ processingTimeMs: number;
380
+ /** The original search query */
381
+ query: string;
382
+ }
204
383
 
205
384
  /**
206
385
  * Generate the API URL from the base URL by adding the 'api.' subdomain.
@@ -540,6 +719,56 @@ export function getFunctionTriggerExecuteApiPath(workspaceId: string, triggerId:
540
719
  return `data/workspace/${workspaceId}/api/v1/function-triggers/${triggerId}/execute`;
541
720
  }
542
721
 
722
+ /**
723
+ * Generate Function Trigger pause API URL PATH.
724
+ */
725
+ export function getFunctionTriggerPauseApiPath(workspaceId: string, triggerId: string): string {
726
+ return `data/workspace/${workspaceId}/api/v1/function-triggers/${triggerId}/pause`;
727
+ }
728
+
729
+ /**
730
+ * Generate Function Trigger resume API URL PATH.
731
+ */
732
+ export function getFunctionTriggerResumeApiPath(workspaceId: string, triggerId: string): string {
733
+ return `data/workspace/${workspaceId}/api/v1/function-triggers/${triggerId}/resume`;
734
+ }
735
+
736
+ /**
737
+ * Generate Smart Queries base API URL PATH for workspace-level operations.
738
+ */
739
+ export function getSmartQueriesApiPath(workspaceId: string): string {
740
+ return `data/workspace/${workspaceId}/api/v1/smart-queries`;
741
+ }
742
+
743
+ /**
744
+ * Generate Smart Queries API URL PATH for structure-level operations.
745
+ */
746
+ export function getSmartQueriesStructureApiPath(workspaceId: string, structureSlug: string, queryId?: string): string {
747
+ const basePath = `data/workspace/${workspaceId}/api/v1/smart-queries/slug/${structureSlug}`;
748
+ return queryId ? `${basePath}/${queryId}` : basePath;
749
+ }
750
+
751
+ /**
752
+ * Generate Smart Query by name API URL PATH.
753
+ */
754
+ export function getSmartQueryByNameApiPath(workspaceId: string, structureSlug: string, name: string): string {
755
+ return `data/workspace/${workspaceId}/api/v1/smart-queries/slug/${structureSlug}/name/${encodeURIComponent(name)}`;
756
+ }
757
+
758
+ /**
759
+ * Generate Smart Query execute API URL PATH.
760
+ */
761
+ export function getSmartQueryExecuteApiPath(workspaceId: string, structureSlug: string, queryId: string): string {
762
+ return `data/workspace/${workspaceId}/api/v1/smart-queries/slug/${structureSlug}/execute/${queryId}`;
763
+ }
764
+
765
+ /**
766
+ * Generate Search API URL PATH.
767
+ */
768
+ export function getSearchApiPath(workspaceId: string): string {
769
+ return `search/workspace/${workspaceId}/api/v1/records/search`;
770
+ }
771
+
543
772
  // =====================================================
544
773
  // Triggers Manager
545
774
  // =====================================================
@@ -665,6 +894,192 @@ export class TriggersManager {
665
894
  };
666
895
  return this.requestFn<FunctionTrigger[]>('GET', path, null, params);
667
896
  }
897
+
898
+ /**
899
+ * Pause a function trigger.
900
+ *
901
+ * Pauses an event-driven or scheduled trigger to temporarily disable it from firing.
902
+ * When paused, the trigger will not execute until resumed.
903
+ *
904
+ * For scheduled triggers, this also pauses the underlying scheduler job.
905
+ *
906
+ * @param triggerId - The ID of the trigger to pause
907
+ * @returns The updated trigger with enabled = false
908
+ *
909
+ * @example
910
+ * ```ts
911
+ * // Pause a trigger
912
+ * const result = await client.triggers.pauseTrigger('trigger-id');
913
+ * console.log('Trigger paused:', result.data.enabled === false);
914
+ * ```
915
+ */
916
+ public pauseTrigger(triggerId: string): Promise<ApiResponse<FunctionTrigger>> {
917
+ const path = getFunctionTriggerPauseApiPath(this.workspaceId, triggerId);
918
+ return this.requestFn<FunctionTrigger>('PATCH', path, {});
919
+ }
920
+
921
+ /**
922
+ * Resume a paused function trigger.
923
+ *
924
+ * Resumes a paused event-driven or scheduled trigger to re-enable it.
925
+ * Once resumed, the trigger will start firing again on matching events or schedules.
926
+ *
927
+ * For scheduled triggers, this also resumes the underlying scheduler job.
928
+ *
929
+ * @param triggerId - The ID of the trigger to resume
930
+ * @returns The updated trigger with enabled = true
931
+ *
932
+ * @example
933
+ * ```ts
934
+ * // Resume a paused trigger
935
+ * const result = await client.triggers.resumeTrigger('trigger-id');
936
+ * console.log('Trigger resumed:', result.data.enabled === true);
937
+ * ```
938
+ */
939
+ public resumeTrigger(triggerId: string): Promise<ApiResponse<FunctionTrigger>> {
940
+ const path = getFunctionTriggerResumeApiPath(this.workspaceId, triggerId);
941
+ return this.requestFn<FunctionTrigger>('PATCH', path, {});
942
+ }
943
+ }
944
+
945
+ // =====================================================
946
+ // Smart Queries Manager
947
+ // =====================================================
948
+
949
+ /**
950
+ * SmartQueriesManager provides methods for listing and executing smart queries.
951
+ * Smart queries are reusable, parameterized queries defined in the console
952
+ * that can be executed programmatically via the SDK.
953
+ * Access via `client.smartQueries`.
954
+ *
955
+ * Usage:
956
+ * ```ts
957
+ * // List smart queries for a structure
958
+ * const queries = await client.smartQueries.list('employee');
959
+ *
960
+ * // Execute a smart query by ID
961
+ * const results = await client.smartQueries.execute('employee', 'query-uuid');
962
+ *
963
+ * // Get a smart query by name
964
+ * const query = await client.smartQueries.getByName('employee', 'Active Employees');
965
+ * ```
966
+ */
967
+ export class SmartQueriesManager {
968
+ private requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>;
969
+ private workspaceId: string;
970
+
971
+ constructor(
972
+ workspaceId: string,
973
+ requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>
974
+ ) {
975
+ this.workspaceId = workspaceId;
976
+ this.requestFn = requestFn;
977
+ }
978
+
979
+ /**
980
+ * List all smart queries in the workspace.
981
+ *
982
+ * @param options - Optional list parameters (pagination, search, etc.)
983
+ * @returns List of smart queries with pagination metadata
984
+ *
985
+ * @example
986
+ * ```ts
987
+ * // List all smart queries
988
+ * const queries = await client.smartQueries.listAll();
989
+ *
990
+ * // With pagination
991
+ * const queries = await client.smartQueries.listAll({ page: 1, limit: 20 });
992
+ * ```
993
+ */
994
+ public listAll(options?: ListSmartQueryOptions): Promise<ApiResponse<SmartQuery[]>> {
995
+ const path = getSmartQueriesApiPath(this.workspaceId);
996
+ return this.requestFn<SmartQuery[]>('GET', path, null, options);
997
+ }
998
+
999
+ /**
1000
+ * List smart queries for a specific structure.
1001
+ *
1002
+ * @param structureSlug - The structure's record slug (e.g., "employee")
1003
+ * @param options - Optional list parameters (pagination, search, etc.)
1004
+ * @returns List of smart queries for the structure
1005
+ *
1006
+ * @example
1007
+ * ```ts
1008
+ * // List queries for employee structure
1009
+ * const queries = await client.smartQueries.list('employee');
1010
+ *
1011
+ * // With pagination and search
1012
+ * const queries = await client.smartQueries.list('employee', {
1013
+ * page: 1,
1014
+ * limit: 10,
1015
+ * search: 'active'
1016
+ * });
1017
+ * ```
1018
+ */
1019
+ public list(structureSlug: string, options?: ListSmartQueryOptions): Promise<ApiResponse<SmartQuery[]>> {
1020
+ const path = getSmartQueriesStructureApiPath(this.workspaceId, structureSlug);
1021
+ return this.requestFn<SmartQuery[]>('GET', path, null, options);
1022
+ }
1023
+
1024
+ /**
1025
+ * Get a smart query by ID.
1026
+ *
1027
+ * @param structureSlug - The structure's record slug
1028
+ * @param queryId - The smart query UUID
1029
+ * @returns The smart query details
1030
+ *
1031
+ * @example
1032
+ * ```ts
1033
+ * const query = await client.smartQueries.get('employee', 'query-uuid');
1034
+ * console.log('Query name:', query.data.name);
1035
+ * ```
1036
+ */
1037
+ public get(structureSlug: string, queryId: string): Promise<ApiResponse<SmartQuery>> {
1038
+ const path = getSmartQueriesStructureApiPath(this.workspaceId, structureSlug, queryId);
1039
+ return this.requestFn<SmartQuery>('GET', path);
1040
+ }
1041
+
1042
+ /**
1043
+ * Get a smart query by name.
1044
+ *
1045
+ * @param structureSlug - The structure's record slug
1046
+ * @param name - The smart query name
1047
+ * @returns The smart query details
1048
+ *
1049
+ * @example
1050
+ * ```ts
1051
+ * const query = await client.smartQueries.getByName('employee', 'Active Employees');
1052
+ * console.log('Query ID:', query.data.id);
1053
+ * ```
1054
+ */
1055
+ public getByName(structureSlug: string, name: string): Promise<ApiResponse<SmartQuery>> {
1056
+ const path = getSmartQueryByNameApiPath(this.workspaceId, structureSlug, name);
1057
+ return this.requestFn<SmartQuery>('GET', path);
1058
+ }
1059
+
1060
+ /**
1061
+ * Execute a smart query and return results.
1062
+ *
1063
+ * Note: Pagination (limit/skip) is defined in the query definition itself,
1064
+ * not at execution time.
1065
+ *
1066
+ * @param structureSlug - The structure's record slug
1067
+ * @param queryId - The smart query UUID
1068
+ * @returns Query results
1069
+ *
1070
+ * @example
1071
+ * ```ts
1072
+ * const results = await client.smartQueries.execute('employee', 'query-uuid');
1073
+ * console.log('Found:', results.data.length, 'records');
1074
+ * ```
1075
+ */
1076
+ public execute<T = any>(
1077
+ structureSlug: string,
1078
+ queryId: string
1079
+ ): Promise<ApiResponse<T[]>> {
1080
+ const path = getSmartQueryExecuteApiPath(this.workspaceId, structureSlug, queryId);
1081
+ return this.requestFn<T[]>('GET', path);
1082
+ }
668
1083
  }
669
1084
 
670
1085
  /**
@@ -676,6 +1091,7 @@ export class CentraliSDK {
676
1091
  private options: CentraliSDKOptions;
677
1092
  private _realtime: RealtimeManager | null = null;
678
1093
  private _triggers: TriggersManager | null = null;
1094
+ private _smartQueries: SmartQueriesManager | null = null;
679
1095
 
680
1096
  constructor(options: CentraliSDKOptions) {
681
1097
  this.options = options;
@@ -790,6 +1206,35 @@ export class CentraliSDK {
790
1206
  return this._triggers;
791
1207
  }
792
1208
 
1209
+ /**
1210
+ * Smart Queries namespace for listing and executing smart queries.
1211
+ *
1212
+ * Usage:
1213
+ * ```ts
1214
+ * // List all smart queries in workspace
1215
+ * const allQueries = await client.smartQueries.listAll();
1216
+ *
1217
+ * // List smart queries for a structure
1218
+ * const queries = await client.smartQueries.list('employee');
1219
+ *
1220
+ * // Get a smart query by name
1221
+ * const query = await client.smartQueries.getByName('employee', 'Active Employees');
1222
+ *
1223
+ * // Execute a smart query
1224
+ * const results = await client.smartQueries.execute('employee', query.data.id);
1225
+ * console.log('Found:', results.data.length, 'records');
1226
+ * ```
1227
+ */
1228
+ public get smartQueries(): SmartQueriesManager {
1229
+ if (!this._smartQueries) {
1230
+ this._smartQueries = new SmartQueriesManager(
1231
+ this.options.workspaceId,
1232
+ this.request.bind(this)
1233
+ );
1234
+ }
1235
+ return this._smartQueries;
1236
+ }
1237
+
793
1238
  /**
794
1239
  * Manually set or update the bearer token for subsequent requests.
795
1240
  */
@@ -839,6 +1284,10 @@ export class CentraliSDK {
839
1284
  if (Array.isArray(resp.data)) {
840
1285
  return { data: resp.data as T };
841
1286
  }
1287
+ // Handle { result } responses (smart queries and some other endpoints)
1288
+ if ('result' in resp.data && !('data' in resp.data)) {
1289
+ return { data: (resp.data as any).result as T };
1290
+ }
842
1291
  // Handle objects that don't have a data property (legacy endpoints)
843
1292
  if (!('data' in resp.data)) {
844
1293
  return { data: resp.data as T };
@@ -948,6 +1397,54 @@ export class CentraliSDK {
948
1397
  });
949
1398
  }
950
1399
 
1400
+ // ------------------ Search API Methods ------------------
1401
+
1402
+ /**
1403
+ * Search records across the workspace using full-text search.
1404
+ *
1405
+ * @param query - The search query string
1406
+ * @param options - Optional search parameters
1407
+ * @returns Search results with hits and metadata
1408
+ *
1409
+ * @example
1410
+ * ```ts
1411
+ * // Basic search
1412
+ * const results = await client.search('customer email');
1413
+ * console.log('Found:', results.data.totalHits, 'results');
1414
+ * results.data.hits.forEach(hit => console.log(hit.id, hit.structureSlug));
1415
+ *
1416
+ * // Search with structure filter
1417
+ * const userResults = await client.search('john', { structures: 'users' });
1418
+ *
1419
+ * // Search multiple structures with limit
1420
+ * const results = await client.search('active', {
1421
+ * structures: ['users', 'orders'],
1422
+ * limit: 50
1423
+ * });
1424
+ * ```
1425
+ */
1426
+ public async search(
1427
+ query: string,
1428
+ options?: SearchOptions
1429
+ ): Promise<ApiResponse<SearchResponse>> {
1430
+ const path = getSearchApiPath(this.options.workspaceId);
1431
+
1432
+ const queryParams: Record<string, string> = { q: query };
1433
+
1434
+ if (options?.structures) {
1435
+ const structures = Array.isArray(options.structures)
1436
+ ? options.structures.join(',')
1437
+ : options.structures;
1438
+ queryParams.structures = structures;
1439
+ }
1440
+
1441
+ if (options?.limit) {
1442
+ queryParams.limit = String(options.limit);
1443
+ }
1444
+
1445
+ return this.request<SearchResponse>('GET', path, null, queryParams);
1446
+ }
1447
+
951
1448
  }
952
1449
 
953
1450
  /**
@@ -1008,5 +1505,38 @@ export class CentraliSDK {
1008
1505
  * // List all triggers:
1009
1506
  * const triggers = await client.triggers.list();
1010
1507
  * triggers.data.forEach(t => console.log(t.name));
1508
+ *
1509
+ * // ---- Smart Queries ----
1510
+ *
1511
+ * // List all smart queries in the workspace:
1512
+ * const allQueries = await client.smartQueries.listAll();
1513
+ *
1514
+ * // List smart queries for a specific structure:
1515
+ * const employeeQueries = await client.smartQueries.list('employee');
1516
+ * employeeQueries.data.forEach(q => console.log(q.name));
1517
+ *
1518
+ * // Get a smart query by name:
1519
+ * const activeQuery = await client.smartQueries.getByName('employee', 'Active Employees');
1520
+ * console.log('Query ID:', activeQuery.data.id);
1521
+ *
1522
+ * // Execute a smart query:
1523
+ * const results = await client.smartQueries.execute('employee', activeQuery.data.id);
1524
+ * console.log('Found:', results.data.length, 'employees');
1525
+ *
1526
+ * // ---- Search ----
1527
+ *
1528
+ * // Basic full-text search:
1529
+ * const searchResults = await client.search('customer email');
1530
+ * console.log('Found:', searchResults.data.totalHits, 'results');
1531
+ * searchResults.data.hits.forEach(hit => console.log(hit.id, hit.structureSlug));
1532
+ *
1533
+ * // Search with structure filter:
1534
+ * const userResults = await client.search('john', { structures: 'users' });
1535
+ *
1536
+ * // Search multiple structures with limit:
1537
+ * const multiResults = await client.search('active', {
1538
+ * structures: ['users', 'orders'],
1539
+ * limit: 50
1540
+ * });
1011
1541
  *```
1012
1542
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centrali-io/centrali-sdk",
3
- "version": "2.2.2",
3
+ "version": "2.3.0",
4
4
  "description": "Centrali Node SDK",
5
5
  "main": "dist/index.js",
6
6
  "type": "commonjs",