@centrali-io/centrali-sdk 2.9.5 → 2.9.7

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/README.md CHANGED
@@ -122,6 +122,69 @@ const products = await centrali.queryRecords('Product', {
122
122
  });
123
123
  ```
124
124
 
125
+ ### Expanding References
126
+
127
+ When querying records with reference fields, use the `expand` parameter to include the full referenced record data:
128
+
129
+ ```typescript
130
+ // Expand a single reference field
131
+ const orders = await centrali.queryRecords('Order', {
132
+ expand: 'customer'
133
+ });
134
+
135
+ // Expand multiple reference fields
136
+ const orders = await centrali.queryRecords('Order', {
137
+ expand: 'customer,product'
138
+ });
139
+
140
+ // Nested expansion (up to 3 levels deep)
141
+ const orders = await centrali.queryRecords('Order', {
142
+ expand: 'customer,customer.address'
143
+ });
144
+
145
+ // Get a single record with expanded references
146
+ const order = await centrali.getRecord('Order', 'order-id', {
147
+ expand: 'customer,items'
148
+ });
149
+ ```
150
+
151
+ Expanded data is placed in the `_expanded` object within the record's data:
152
+
153
+ ```typescript
154
+ // Response structure
155
+ {
156
+ "id": "order-123",
157
+ "data": {
158
+ "customerId": "cust-456",
159
+ "total": 99.99,
160
+ "_expanded": {
161
+ "customerId": {
162
+ "id": "cust-456",
163
+ "data": {
164
+ "name": "John Doe",
165
+ "email": "john@example.com"
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
171
+
172
+ // Access expanded data
173
+ const customerName = order.data.data._expanded.customerId.data.name;
174
+ ```
175
+
176
+ For many-to-many relationships, the expanded field contains an array:
177
+
178
+ ```typescript
179
+ // Many-to-many expansion
180
+ const post = await centrali.getRecord('Post', 'post-id', {
181
+ expand: 'tags'
182
+ });
183
+
184
+ // _expanded.tags will be an array of tag records
185
+ const tagNames = post.data.data._expanded.tags.map(tag => tag.data.name);
186
+ ```
187
+
125
188
  ### Smart Queries
126
189
 
127
190
  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.
@@ -140,6 +203,15 @@ console.log('Query ID:', query.data.id);
140
203
  // Execute a smart query
141
204
  const results = await centrali.smartQueries.execute('employee', query.data.id);
142
205
  console.log('Found:', results.data.length, 'employees');
206
+
207
+ // Execute with variables
208
+ // Query definition uses {{variableName}} syntax: { where: { status: { $eq: "{{statusFilter}}" } } }
209
+ const filteredResults = await centrali.smartQueries.execute('orders', query.data.id, {
210
+ variables: {
211
+ statusFilter: 'active',
212
+ startDate: '2024-01-01'
213
+ }
214
+ });
143
215
  ```
144
216
 
145
217
  ### Search
package/dist/index.js CHANGED
@@ -1095,17 +1095,27 @@ class SmartQueriesManager {
1095
1095
  *
1096
1096
  * @param structureSlug - The structure's record slug
1097
1097
  * @param queryId - The smart query UUID
1098
+ * @param options - Optional execution options including variables
1098
1099
  * @returns Query results
1099
1100
  *
1100
1101
  * @example
1101
1102
  * ```ts
1103
+ * // Simple execution without variables
1102
1104
  * const results = await client.smartQueries.execute('employee', 'query-uuid');
1103
1105
  * console.log('Found:', results.data.length, 'records');
1106
+ *
1107
+ * // Execution with variables
1108
+ * // Query definition: { where: { status: { $eq: "{{statusFilter}}" } } }
1109
+ * const filtered = await client.smartQueries.execute('orders', 'query-id', {
1110
+ * variables: { statusFilter: 'active' }
1111
+ * });
1104
1112
  * ```
1105
1113
  */
1106
- execute(structureSlug, queryId) {
1114
+ execute(structureSlug, queryId, options) {
1107
1115
  const path = getSmartQueryExecuteApiPath(this.workspaceId, structureSlug, queryId);
1108
- return this.requestFn('GET', path);
1116
+ // Use POST to support variables, with empty body if no options
1117
+ const body = (options === null || options === void 0 ? void 0 : options.variables) ? { variables: options.variables } : undefined;
1118
+ return this.requestFn('POST', path, body);
1109
1119
  }
1110
1120
  }
1111
1121
  exports.SmartQueriesManager = SmartQueriesManager;
@@ -1801,15 +1811,51 @@ class CentraliSDK {
1801
1811
  getToken() {
1802
1812
  return this.token;
1803
1813
  }
1804
- /** Retrieve a record by ID. */
1805
- getRecord(recordSlug, id) {
1814
+ /**
1815
+ * Retrieve a record by ID.
1816
+ *
1817
+ * @param recordSlug - The structure's record slug
1818
+ * @param id - The record ID
1819
+ * @param options - Optional parameters including expand for reference fields
1820
+ *
1821
+ * @example
1822
+ * // Basic fetch
1823
+ * const order = await centrali.getRecord('Order', 'order-123');
1824
+ *
1825
+ * // With expanded references
1826
+ * const order = await centrali.getRecord('Order', 'order-123', {
1827
+ * expand: 'customer,items'
1828
+ * });
1829
+ * // Access expanded data: order.data.data._expanded.customer
1830
+ */
1831
+ getRecord(recordSlug, id, options) {
1806
1832
  const path = getRecordApiPath(this.options.workspaceId, recordSlug, id);
1807
- return this.request('GET', path);
1833
+ return this.request('GET', path, null, options);
1808
1834
  }
1809
- /** Query records with filters, pagination, etc. */
1835
+ /**
1836
+ * Query records with filters, pagination, sorting, and reference expansion.
1837
+ *
1838
+ * @param recordSlug - The structure's record slug
1839
+ * @param queryParams - Query parameters including filter, sort, pagination, and expand
1840
+ *
1841
+ * @example
1842
+ * // Basic query with filter and sort
1843
+ * const products = await centrali.queryRecords('Product', {
1844
+ * filter: 'inStock = true AND price < 100',
1845
+ * sort: '-createdAt',
1846
+ * limit: 10
1847
+ * });
1848
+ *
1849
+ * // Query with expanded references
1850
+ * const orders = await centrali.queryRecords('Order', {
1851
+ * filter: 'status = "pending"',
1852
+ * expand: 'customer,items'
1853
+ * });
1854
+ * // Access expanded data: orders.data[0].data._expanded.customer
1855
+ */
1810
1856
  queryRecords(recordSlug, queryParams) {
1811
1857
  const path = getRecordApiPath(this.options.workspaceId, recordSlug);
1812
- return this.request('GET', path, null, Object.assign({}, queryParams));
1858
+ return this.request('GET', path, null, queryParams);
1813
1859
  }
1814
1860
  /** Get records by Ids. */
1815
1861
  getRecordsByIds(recordSlug, ids) {
package/index.ts CHANGED
@@ -539,6 +539,53 @@ export interface DeleteRecordOptions {
539
539
  hard?: boolean;
540
540
  }
541
541
 
542
+ /**
543
+ * Options for expanding reference fields when fetching records.
544
+ * Expanded data is placed in the `_expanded` object within the record's data.
545
+ */
546
+ export interface ExpandOptions {
547
+ /**
548
+ * Comma-separated list of reference fields to expand.
549
+ * Supports nested expansion using dot notation (up to 3 levels deep).
550
+ *
551
+ * @example
552
+ * // Single field
553
+ * expand: 'customer'
554
+ *
555
+ * // Multiple fields
556
+ * expand: 'customer,product'
557
+ *
558
+ * // Nested expansion
559
+ * expand: 'customer,customer.address'
560
+ */
561
+ expand?: string;
562
+ }
563
+
564
+ /**
565
+ * Options for retrieving a single record.
566
+ */
567
+ export interface GetRecordOptions extends ExpandOptions {}
568
+
569
+ /**
570
+ * Options for querying records.
571
+ */
572
+ export interface QueryRecordOptions extends ExpandOptions {
573
+ /** CFL filter expression (e.g., 'status = "active" AND price > 100') */
574
+ filter?: string;
575
+ /** Sort field with optional direction prefix (e.g., '-createdAt' for descending) */
576
+ sort?: string;
577
+ /** Maximum number of records to return */
578
+ limit?: number;
579
+ /** Number of records to skip (for pagination) */
580
+ skip?: number;
581
+ /** Page number (alternative to skip) */
582
+ page?: number;
583
+ /** Include archived (soft-deleted) records */
584
+ includeArchived?: boolean;
585
+ /** Additional query parameters */
586
+ [key: string]: any;
587
+ }
588
+
542
589
  /**
543
590
  * Response from invoking a trigger.
544
591
  * Currently the API returns the queued job ID as a string.
@@ -1128,6 +1175,39 @@ export interface ListSmartQueryOptions {
1128
1175
  sortDirection?: 'asc' | 'desc';
1129
1176
  }
1130
1177
 
1178
+ /**
1179
+ * Options for executing a smart query.
1180
+ */
1181
+ export interface ExecuteSmartQueryOptions {
1182
+ /**
1183
+ * Variables to substitute in the query.
1184
+ * Use mustache-style {{variableName}} syntax in query conditions,
1185
+ * then provide values here at execution time.
1186
+ *
1187
+ * @example
1188
+ * ```ts
1189
+ * // Query definition with variable: { where: { userId: { $eq: "{{currentUserId}}" } } }
1190
+ * const results = await client.smartQueries.execute('orders', 'query-id', {
1191
+ * variables: { currentUserId: 'user_123' }
1192
+ * });
1193
+ * ```
1194
+ */
1195
+ variables?: Record<string, string>;
1196
+ }
1197
+
1198
+ /**
1199
+ * Result from executing a smart query with metadata.
1200
+ */
1201
+ export interface SmartQueryExecuteResult<T = any> {
1202
+ /** Query results */
1203
+ result: T[];
1204
+ /** Metadata about the execution */
1205
+ meta?: {
1206
+ /** Variables that were used in the query */
1207
+ variablesUsed?: string[];
1208
+ };
1209
+ }
1210
+
1131
1211
  // =====================================================
1132
1212
  // Search Types
1133
1213
  // =====================================================
@@ -2601,20 +2681,31 @@ export class SmartQueriesManager {
2601
2681
  *
2602
2682
  * @param structureSlug - The structure's record slug
2603
2683
  * @param queryId - The smart query UUID
2684
+ * @param options - Optional execution options including variables
2604
2685
  * @returns Query results
2605
2686
  *
2606
2687
  * @example
2607
2688
  * ```ts
2689
+ * // Simple execution without variables
2608
2690
  * const results = await client.smartQueries.execute('employee', 'query-uuid');
2609
2691
  * console.log('Found:', results.data.length, 'records');
2692
+ *
2693
+ * // Execution with variables
2694
+ * // Query definition: { where: { status: { $eq: "{{statusFilter}}" } } }
2695
+ * const filtered = await client.smartQueries.execute('orders', 'query-id', {
2696
+ * variables: { statusFilter: 'active' }
2697
+ * });
2610
2698
  * ```
2611
2699
  */
2612
2700
  public execute<T = any>(
2613
2701
  structureSlug: string,
2614
- queryId: string
2702
+ queryId: string,
2703
+ options?: ExecuteSmartQueryOptions
2615
2704
  ): Promise<ApiResponse<T[]>> {
2616
2705
  const path = getSmartQueryExecuteApiPath(this.workspaceId, structureSlug, queryId);
2617
- return this.requestFn<T[]>('GET', path);
2706
+ // Use POST to support variables, with empty body if no options
2707
+ const body = options?.variables ? { variables: options.variables } : undefined;
2708
+ return this.requestFn<T[]>('POST', path, body);
2618
2709
  }
2619
2710
  }
2620
2711
 
@@ -3429,24 +3520,59 @@ export class CentraliSDK {
3429
3520
  }
3430
3521
 
3431
3522
 
3432
- /** Retrieve a record by ID. */
3523
+ /**
3524
+ * Retrieve a record by ID.
3525
+ *
3526
+ * @param recordSlug - The structure's record slug
3527
+ * @param id - The record ID
3528
+ * @param options - Optional parameters including expand for reference fields
3529
+ *
3530
+ * @example
3531
+ * // Basic fetch
3532
+ * const order = await centrali.getRecord('Order', 'order-123');
3533
+ *
3534
+ * // With expanded references
3535
+ * const order = await centrali.getRecord('Order', 'order-123', {
3536
+ * expand: 'customer,items'
3537
+ * });
3538
+ * // Access expanded data: order.data.data._expanded.customer
3539
+ */
3433
3540
  public getRecord<T = any>(
3434
3541
  recordSlug: string,
3435
- id: string
3542
+ id: string,
3543
+ options?: GetRecordOptions
3436
3544
  ): Promise<ApiResponse<T>> {
3437
3545
  const path = getRecordApiPath(this.options.workspaceId, recordSlug, id);
3438
- return this.request('GET', path);
3546
+ return this.request('GET', path, null, options);
3439
3547
  }
3440
3548
 
3441
- /** Query records with filters, pagination, etc. */
3549
+ /**
3550
+ * Query records with filters, pagination, sorting, and reference expansion.
3551
+ *
3552
+ * @param recordSlug - The structure's record slug
3553
+ * @param queryParams - Query parameters including filter, sort, pagination, and expand
3554
+ *
3555
+ * @example
3556
+ * // Basic query with filter and sort
3557
+ * const products = await centrali.queryRecords('Product', {
3558
+ * filter: 'inStock = true AND price < 100',
3559
+ * sort: '-createdAt',
3560
+ * limit: 10
3561
+ * });
3562
+ *
3563
+ * // Query with expanded references
3564
+ * const orders = await centrali.queryRecords('Order', {
3565
+ * filter: 'status = "pending"',
3566
+ * expand: 'customer,items'
3567
+ * });
3568
+ * // Access expanded data: orders.data[0].data._expanded.customer
3569
+ */
3442
3570
  public queryRecords<T = any>(
3443
3571
  recordSlug: string,
3444
- queryParams: Record<string, any>
3572
+ queryParams?: QueryRecordOptions
3445
3573
  ): Promise<ApiResponse<T>> {
3446
3574
  const path = getRecordApiPath(this.options.workspaceId, recordSlug);
3447
- return this.request('GET', path, null, {
3448
- ...queryParams,
3449
- });
3575
+ return this.request('GET', path, null, queryParams);
3450
3576
  }
3451
3577
 
3452
3578
  /** Get records by Ids. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centrali-io/centrali-sdk",
3
- "version": "2.9.5",
3
+ "version": "2.9.7",
4
4
  "description": "Centrali Node SDK",
5
5
  "main": "dist/index.js",
6
6
  "type": "commonjs",