@centrali-io/centrali-sdk 4.4.9 → 4.5.1

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 (3) hide show
  1. package/README.md +123 -2
  2. package/index.ts +69 -16
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -143,12 +143,126 @@ const archived = await centrali.queryRecords('StructureName', {
143
143
  includeArchived: true
144
144
  });
145
145
 
146
- // Query records
146
+ // Query records with top-level filters
147
147
  const products = await centrali.queryRecords('Product', {
148
- filter: 'inStock = true AND price < 100',
148
+ 'data.inStock': true,
149
+ 'data.price[lte]': 100,
149
150
  sort: '-createdAt',
150
151
  limit: 10
151
152
  });
153
+
154
+ // Same query using nested filter object (compute function style)
155
+ const products2 = await centrali.queryRecords('Product', {
156
+ filter: { 'data.inStock': true, 'data.price': { lte: 100 } },
157
+ sort: '-createdAt',
158
+ limit: 10
159
+ });
160
+ ```
161
+
162
+ ### Filter Syntax
163
+
164
+ The SDK supports **two filter styles** — use whichever you prefer:
165
+
166
+ **Style 1 — Top-level filters** (SDK-native):
167
+ ```typescript
168
+ const results = await centrali.queryRecords('Order', {
169
+ 'data.status': 'active', // Exact match
170
+ 'data.total[gte]': 100, // Operator with bracket notation
171
+ 'data.tags[hasAny]': 'vip,premium', // Comma-separated for array ops
172
+ sort: '-createdAt',
173
+ pageSize: 25
174
+ });
175
+ ```
176
+
177
+ **Style 2 — Nested `filter` object** (same syntax as compute functions):
178
+ ```typescript
179
+ const results = await centrali.queryRecords('Order', {
180
+ filter: {
181
+ 'data.status': 'active',
182
+ 'data.total': { gte: 100 },
183
+ 'data.tags': { hasAny: ['vip', 'premium'] }
184
+ },
185
+ sort: '-createdAt',
186
+ pageSize: 25
187
+ });
188
+ ```
189
+
190
+ Both styles work because the data service merges them. Use `data.` prefix for custom fields. System fields (`id`, `createdAt`, `updatedAt`, `status`) don't need the prefix.
191
+
192
+ > **Compute functions** use `api.queryRecords()` which has a slightly different interface — sort is an array of objects `[{ field, direction }]` instead of a string, and `searchFields` is an array instead of comma-separated. See the [compute function docs](https://docs.centrali.io/platform/writing-functions) for details.
193
+
194
+ ### Filter Operators
195
+
196
+ | Operator | SDK (top-level) | SDK (nested) / Compute |
197
+ |----------|----------------|----------------------|
198
+ | Equal | `'data.status': 'active'` | `'data.status': 'active'` or `{ eq: 'active' }` |
199
+ | Not equal | `'data.status[ne]': 'deleted'` | `'data.status': { ne: 'deleted' }` |
200
+ | Greater than | `'data.age[gt]': 18` | `'data.age': { gt: 18 }` |
201
+ | Greater/equal | `'data.age[gte]': 18` | `'data.age': { gte: 18 }` |
202
+ | Less than | `'data.age[lt]': 65` | `'data.age': { lt: 65 }` |
203
+ | Less/equal | `'data.age[lte]': 65` | `'data.age': { lte: 65 }` |
204
+ | In list | `'data.status[in]': 'a,b,c'` | `'data.status': { in: ['a', 'b', 'c'] }` |
205
+ | Not in list | `'data.status[nin]': 'a,b'` | `'data.status': { nin: ['a', 'b'] }` |
206
+ | Contains | `'data.email[contains]': '@gmail'` | `'data.email': { contains: '@gmail' }` |
207
+ | Starts with | `'data.name[startswith]': 'John'` | `'data.name': { startswith: 'John' }` |
208
+ | Ends with | `'data.email[endswith]': '.com'` | `'data.email': { endswith: '.com' }` |
209
+ | Has any (array) | `'data.tags[hasAny]': 'a,b'` | `'data.tags': { hasAny: ['a', 'b'] }` |
210
+ | Has all (array) | `'data.tags[hasAll]': 'a,b'` | `'data.tags': { hasAll: ['a', 'b'] }` |
211
+
212
+ ### Date Range Filtering
213
+
214
+ Use `dateWindow` to filter records by a date field:
215
+
216
+ ```typescript
217
+ // Records created in the last 30 days
218
+ const recent = await centrali.queryRecords('Order', {
219
+ dateWindow: {
220
+ field: 'createdAt',
221
+ from: new Date(Date.now() - 30 * 86400000).toISOString()
222
+ }
223
+ });
224
+
225
+ // Records updated in a specific range
226
+ const q1 = await centrali.queryRecords('Order', {
227
+ dateWindow: {
228
+ field: 'updatedAt',
229
+ from: '2024-01-01T00:00:00Z',
230
+ to: '2024-03-31T23:59:59Z'
231
+ }
232
+ });
233
+ ```
234
+
235
+ The `dateWindow` object has three properties:
236
+
237
+ | Property | Type | Description |
238
+ |----------|------|-------------|
239
+ | `field` | string | Date field to filter on (e.g., `'createdAt'`, `'updatedAt'`, or a custom date field) |
240
+ | `from` | string? | ISO 8601 lower bound (inclusive) |
241
+ | `to` | string? | ISO 8601 upper bound (inclusive) |
242
+
243
+ ### Reserved Query Parameters
244
+
245
+ When using `queryRecords`, the following parameter names are reserved and cannot be used as filter field names. Any other key you pass is treated as a record data filter.
246
+
247
+ | Parameter | Purpose |
248
+ |-----------|---------|
249
+ | `page`, `pageSize`, `limit` | Pagination |
250
+ | `sort` | Sorting (string with optional `-` prefix for descending) |
251
+ | `search`, `searchField`, `searchFields` | Full-text search |
252
+ | `filter` | Structured filter object (alternative to top-level filters) |
253
+ | `fields`, `select` | Field selection |
254
+ | `expand` | Reference expansion |
255
+ | `includeDeleted`, `includeArchived`, `all` | Include soft-deleted records |
256
+ | `includeTotal` | Include total count in response |
257
+ | `dateWindow` | Date range filtering (see above) |
258
+
259
+ To filter by a record field that shares a name with a reserved parameter, use the `data.` prefix:
260
+
261
+ ```typescript
262
+ // Filter by a field called "sort" in your record data
263
+ const results = await centrali.queryRecords('MyStructure', {
264
+ 'data.sort': 'alphabetical'
265
+ });
152
266
  ```
153
267
 
154
268
  ### Expanding References
@@ -541,6 +655,13 @@ const thumbnailUrl = centrali.getFileRenderUrl(renderId, {
541
655
  });
542
656
  ```
543
657
 
658
+ **Audio & video files** are supported up to 500 MB. The storage service supports HTTP range requests (`Accept-Ranges: bytes`), so render URLs work with standard `<audio>` and `<video>` elements — seeking and progressive playback work out of the box:
659
+
660
+ ```html
661
+ <video src={centrali.getFileRenderUrl(renderId)} controls />
662
+ <audio src={centrali.getFileRenderUrl(renderId)} controls />
663
+ ```
664
+
544
665
  ### Data Validation
545
666
 
546
667
  AI-powered data quality validation to detect typos, format issues, duplicates, and semantic errors:
package/index.ts CHANGED
@@ -845,29 +845,64 @@ export interface FilterOperators {
845
845
  */
846
846
  export type FilterValue = string | number | boolean | null | FilterOperators;
847
847
 
848
+ /**
849
+ * Date range filter for restricting results to a time window.
850
+ *
851
+ * @example
852
+ * // Records created in the last 30 days
853
+ * { field: 'createdAt', from: '2024-01-01T00:00:00Z' }
854
+ *
855
+ * // Records updated in a specific range
856
+ * { field: 'updatedAt', from: '2024-01-01T00:00:00Z', to: '2024-03-31T23:59:59Z' }
857
+ */
858
+ export interface DateWindowOption {
859
+ /** The date field to filter on (e.g., 'createdAt', 'updatedAt', or a custom date field) */
860
+ field: string;
861
+ /** ISO 8601 date string — lower bound (inclusive, gte) */
862
+ from?: string;
863
+ /** ISO 8601 date string — upper bound (inclusive, lte) */
864
+ to?: string;
865
+ }
866
+
848
867
  /**
849
868
  * Options for querying records.
850
869
  *
851
- * IMPORTANT: Filters are passed at the TOP LEVEL, not nested under a 'filter' key.
852
- * Use 'data.' prefix for custom fields, and bracket notation for operators.
870
+ * Supports two filter styles:
853
871
  *
854
- * @example
855
- * // Simple equality filter
856
- * { 'data.status': 'active', pageSize: 10 }
872
+ * **Style 1 — Top-level filters (recommended for SDK):**
873
+ * Pass filter fields directly as top-level keys with `data.` prefix and bracket notation.
874
+ * ```ts
875
+ * { 'data.status': 'active', 'data.price[lte]': 100, pageSize: 10 }
876
+ * ```
857
877
  *
858
- * // Filter with operators (bracket notation)
859
- * { 'data.price[lte]': 100, 'data.status[ne]': 'discontinued' }
878
+ * **Style 2 Nested filter object (same syntax as compute functions):**
879
+ * Wrap filters in a `filter` object. Useful if you prefer the same syntax as `api.queryRecords` in compute functions.
880
+ * ```ts
881
+ * { filter: { 'data.status': 'active', 'data.price': { lte: 100 } }, pageSize: 10 }
882
+ * ```
860
883
  *
861
- * // Multiple values with 'in' operator (comma-separated string)
862
- * { 'data.status[in]': 'pending,processing', pageSize: 50 }
884
+ * Both styles are supported and can be mixed. Use `data.` prefix for custom fields.
885
+ * System fields (`id`, `createdAt`, `updatedAt`, `status`) don't need the prefix.
863
886
  *
864
- * // Range filters
865
- * { 'data.age[gte]': 18, 'data.age[lte]': 65 }
887
+ * @example
888
+ * // Top-level filters with bracket notation
889
+ * { 'data.status': 'active', 'data.age[gte]': 18, sort: '-createdAt' }
890
+ *
891
+ * // Nested filter object
892
+ * { filter: { 'data.status': 'active', 'data.age': { gte: 18 } }, sort: '-createdAt' }
866
893
  *
867
- * // Filter on top-level record fields (no 'data.' prefix)
868
- * { 'createdAt[gte]': '2024-01-01', sort: '-createdAt' }
894
+ * // Date window
895
+ * { dateWindow: { field: 'createdAt', from: '2024-01-01T00:00:00Z' }, sort: '-createdAt' }
869
896
  */
870
897
  export interface QueryRecordOptions extends ExpandOptions {
898
+ /**
899
+ * Structured filter object. Wrap your field filters here as an alternative to top-level keys.
900
+ * Uses the same syntax as compute function `api.queryRecords`.
901
+ *
902
+ * @example
903
+ * { filter: { 'data.status': 'active', 'data.age': { gte: 18 } } }
904
+ */
905
+ filter?: Record<string, any>;
871
906
  /** Sort field with optional direction prefix (e.g., '-createdAt' for descending) */
872
907
  sort?: string;
873
908
  /** Page number (1-indexed, default: 1) */
@@ -876,16 +911,34 @@ export interface QueryRecordOptions extends ExpandOptions {
876
911
  pageSize?: number;
877
912
  /** Alias for pageSize */
878
913
  limit?: number;
879
- /** Include archived (soft-deleted) records */
914
+ /** Include soft-deleted records */
915
+ includeDeleted?: boolean;
916
+ /** Include archived (soft-deleted) records. Alias for includeDeleted. */
880
917
  includeArchived?: boolean;
881
- /** Include total count in response */
918
+ /** Shorthand for includeDeleted (from HTTP query params) */
919
+ all?: boolean;
920
+ /** Include total count in response metadata */
882
921
  includeTotal?: boolean;
883
922
  /** Search query string */
884
923
  search?: string;
885
924
  /** Field(s) to search in (comma-separated or single field) */
886
925
  searchField?: string;
926
+ /** Fields to search in (array format) */
927
+ searchFields?: string[];
928
+ /**
929
+ * Date range filter. Restricts results to records where the specified date field
930
+ * falls within the given range.
931
+ *
932
+ * @example
933
+ * { dateWindow: { field: 'createdAt', from: '2024-01-01T00:00:00Z', to: '2024-12-31T23:59:59Z' } }
934
+ */
935
+ dateWindow?: DateWindowOption;
936
+ /** Comma-separated fields to return (field selection) */
937
+ fields?: string;
938
+ /** Field selection (alias for fields) */
939
+ select?: string[];
887
940
  /**
888
- * Filter fields - pass at TOP LEVEL with 'data.' prefix for custom fields.
941
+ * Additional filter fields pass at TOP LEVEL with 'data.' prefix for custom fields.
889
942
  * Use bracket notation for operators: 'data.field[operator]': value
890
943
  *
891
944
  * Supported operators: eq, ne, gt, gte, lt, lte, in, nin, contains, startswith, endswith, hasAny, hasAll
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centrali-io/centrali-sdk",
3
- "version": "4.4.9",
3
+ "version": "4.5.1",
4
4
  "description": "Centrali Node SDK",
5
5
  "main": "dist/index.js",
6
6
  "type": "commonjs",