@halix/action-sdk 1.0.21 → 1.0.22

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/lib/esm/lists.js CHANGED
@@ -8,7 +8,7 @@
8
8
  // Full license terms available in the LICENSE file.
9
9
  /**
10
10
  * @module @halix/action-sdk/lists
11
- * @description List data retrieval functions. Use this to efficiently retrieve objects
11
+ * @description List data retrieval and bulk operations. Use this to efficiently retrieve objects
12
12
  * from the database for display in list-like user interfaces. This is preferred over
13
13
  * the `data-crud` module when showing one page of data at a time.
14
14
  *
@@ -18,6 +18,8 @@
18
18
  * - Sorting
19
19
  * - Filtering
20
20
  * - Search
21
+ * - Mass edit operations (bulk update multiple records)
22
+ * - Mass delete operations (bulk delete multiple records)
21
23
  */
22
24
  import axios from 'axios';
23
25
  import { from, lastValueFrom } from 'rxjs';
@@ -154,4 +156,173 @@ export async function getListData(request, options) {
154
156
  export function getListDataAsObservable(request, options) {
155
157
  return from(getListData(request, options));
156
158
  }
159
+ // ================================================================================
160
+ // MASS EDIT AND DELETE FUNCTIONS
161
+ // ================================================================================
162
+ /**
163
+ * massEdit performs a bulk update operation on multiple records. This function allows you to
164
+ * update a specific property on multiple objects in a single request.
165
+ *
166
+ * **Security Scoping**: The dataRequest serves as a security boundary. Only records that would
167
+ * be returned by the dataRequest can be updated. The keys array must reference records within
168
+ * this scope. This allows efficient security validation without checking each record individually.
169
+ *
170
+ * The value can be set in two ways based on valueType:
171
+ * - 'literal': Set the property to a literal value
172
+ * - 'property': Copy the value from another property on the same object
173
+ *
174
+ * @param request - The mass edit request specifying what to update and how
175
+ *
176
+ * @returns Promise resolving to statistics about the operation
177
+ *
178
+ * @example
179
+ * // Update the status of multiple orders to 'shipped'
180
+ * const result = await massEdit({
181
+ * keys: ['order-123', 'order-456', 'order-789'],
182
+ * dataRequest: {
183
+ * dataElementId: 'order',
184
+ * parentDataElementId: 'company',
185
+ * parentKey: orgProxyKey
186
+ * },
187
+ * dataElementId: 'order',
188
+ * property: 'status',
189
+ * valueType: 'literal',
190
+ * value: 'shipped'
191
+ * });
192
+ * console.log(`Updated ${result.succeeded} of ${result.tried} orders`);
193
+ *
194
+ * @example
195
+ * // Copy shipping address to billing address for multiple customers
196
+ * const result = await massEdit({
197
+ * keys: selectedCustomerKeys,
198
+ * dataRequest: {
199
+ * dataElementId: 'customer',
200
+ * parentDataElementId: 'company',
201
+ * parentKey: orgProxyKey
202
+ * },
203
+ * dataElementId: 'customer',
204
+ * property: 'billingAddress',
205
+ * valueType: 'property',
206
+ * value: 'shippingAddress'
207
+ * });
208
+ */
209
+ export async function massEdit(request) {
210
+ const url = `${serviceAddress}/list/sandboxes/${sandboxKey}/massedit`;
211
+ // Build headers with authentication token
212
+ let authToken = await lastValueFrom(getAuthToken());
213
+ let headers = {
214
+ Authorization: `Bearer ${authToken}`
215
+ };
216
+ console.log("Sending POST request to " + url + " with token " + authToken);
217
+ // Make the API request
218
+ let response = await axios.post(url, request, { headers });
219
+ return response.data;
220
+ }
221
+ /**
222
+ * massEditAsObservable performs a bulk update operation on multiple records, returning an Observable.
223
+ * See massEdit for detailed documentation.
224
+ *
225
+ * @param request - The mass edit request specifying what to update and how
226
+ *
227
+ * @returns Observable resolving to statistics about the operation
228
+ *
229
+ * @example
230
+ * massEditAsObservable({
231
+ * keys: ['order-123', 'order-456'],
232
+ * dataRequest: {
233
+ * dataElementId: 'order',
234
+ * parentDataElementId: 'company',
235
+ * parentKey: orgProxyKey
236
+ * },
237
+ * dataElementId: 'order',
238
+ * property: 'status',
239
+ * valueType: 'literal',
240
+ * value: 'shipped'
241
+ * }).subscribe(result => {
242
+ * console.log(`Updated ${result.succeeded} of ${result.tried} orders`);
243
+ * });
244
+ */
245
+ export function massEditAsObservable(request) {
246
+ return from(massEdit(request));
247
+ }
248
+ /**
249
+ * massDelete performs a bulk delete operation on multiple records. This function allows you to
250
+ * soft-delete multiple objects in a single request.
251
+ *
252
+ * **Security Scoping**: The dataRequest serves as a security boundary. Only records that would
253
+ * be returned by the dataRequest can be deleted. The keys array must reference records within
254
+ * this scope. This allows efficient security validation without checking each record individually.
255
+ *
256
+ * If emptyList is set to true, all records returned by the dataRequest will be deleted,
257
+ * ignoring the keys array.
258
+ *
259
+ * @param request - The mass delete request specifying what to delete
260
+ *
261
+ * @returns Promise resolving to statistics about the operation
262
+ *
263
+ * @example
264
+ * // Delete specific orders
265
+ * const result = await massDelete({
266
+ * keys: ['order-123', 'order-456', 'order-789'],
267
+ * dataRequest: {
268
+ * dataElementId: 'order',
269
+ * parentDataElementId: 'company',
270
+ * parentKey: orgProxyKey,
271
+ * filter: { field: 'status', operator: '==', value: 'cancelled' }
272
+ * },
273
+ * dataElementId: 'order'
274
+ * });
275
+ * console.log(`Deleted ${result.succeeded} of ${result.tried} orders`);
276
+ *
277
+ * @example
278
+ * // Delete all records matching the filter
279
+ * const result = await massDelete({
280
+ * keys: [],
281
+ * dataRequest: {
282
+ * dataElementId: 'tempRecord',
283
+ * parentDataElementId: 'company',
284
+ * parentKey: orgProxyKey,
285
+ * filter: { field: 'createdDate', operator: '<', value: '2023-01-01' }
286
+ * },
287
+ * dataElementId: 'tempRecord',
288
+ * emptyList: true
289
+ * });
290
+ * console.log(`Deleted ${result.succeeded} old records`);
291
+ */
292
+ export async function massDelete(request) {
293
+ const url = `${serviceAddress}/list/sandboxes/${sandboxKey}/massdelete`;
294
+ // Build headers with authentication token
295
+ let authToken = await lastValueFrom(getAuthToken());
296
+ let headers = {
297
+ Authorization: `Bearer ${authToken}`
298
+ };
299
+ console.log("Sending POST request to " + url + " with token " + authToken);
300
+ // Make the API request
301
+ let response = await axios.post(url, request, { headers });
302
+ return response.data;
303
+ }
304
+ /**
305
+ * massDeleteAsObservable performs a bulk delete operation on multiple records, returning an Observable.
306
+ * See massDelete for detailed documentation.
307
+ *
308
+ * @param request - The mass delete request specifying what to delete
309
+ *
310
+ * @returns Observable resolving to statistics about the operation
311
+ *
312
+ * @example
313
+ * massDeleteAsObservable({
314
+ * keys: ['order-123', 'order-456'],
315
+ * dataRequest: {
316
+ * dataElementId: 'order',
317
+ * parentDataElementId: 'company',
318
+ * parentKey: orgProxyKey
319
+ * },
320
+ * dataElementId: 'order'
321
+ * }).subscribe(result => {
322
+ * console.log(`Deleted ${result.succeeded} of ${result.tried} orders`);
323
+ * });
324
+ */
325
+ export function massDeleteAsObservable(request) {
326
+ return from(massDelete(request));
327
+ }
157
328
  //# sourceMappingURL=lists.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lists.js","sourceRoot":"","sources":["../../src/lists.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lists.js","sourceRoot":"","sources":["../../src/lists.ts"],"names":[],"mappings":"AAAA,yBAAyB;AACzB,mCAAmC;AACnC,EAAE;AACF,oEAAoE;AACpE,0EAA0E;AAC1E,EAAE;AACF,6DAA6D;AAC7D,oDAAoD;AAEpD;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,IAAI,EAAc,aAAa,EAAE,MAAM,MAAM,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAsOzE,mFAAmF;AACnF,gCAAgC;AAChC,mFAAmF;AAEnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA6B,EAAE,OAAyB;IAEtF,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,KAAK,CAAC;IAC5C,MAAM,SAAS,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC;IAEpC,iFAAiF;IACjF,IAAI,GAAW,CAAC;IAChB,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;QACxB,GAAG,GAAG,GAAG,cAAc,mBAAmB,UAAU,wBAAwB,CAAC;IACjF,CAAC;SAAM,IAAI,SAAS,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChC,GAAG,GAAG,GAAG,cAAc,mBAAmB,UAAU,iBAAiB,CAAC;IAC1E,CAAC;SAAM,IAAI,CAAC,SAAS,IAAI,QAAQ,EAAE,CAAC;QAChC,GAAG,GAAG,GAAG,cAAc,mBAAmB,UAAU,kBAAkB,CAAC;IAC3E,CAAC;SAAM,CAAC;QACJ,GAAG,GAAG,GAAG,cAAc,mBAAmB,UAAU,WAAW,CAAC;IACpE,CAAC;IAED,yBAAyB;IACzB,IAAI,MAAM,GAAQ,EAAE,CAAC;IAErB,yCAAyC;IACzC,IAAI,OAAO,EAAE,WAAW,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAC7C,CAAC;IAED,6CAA6C;IAC7C,IAAI,SAAS,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;QAC/B,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC;QAChD,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QACpC,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;IACnD,CAAC;IAED,mEAAmE;IACnE,IAAI,OAAO,GAAQ,EAAE,CAAC;IACtB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,IAAI,SAAS,GAAG,MAAM,aAAa,CAAC,YAAY,EAAE,CAAC,CAAC;QACpD,OAAO,CAAC,aAAa,GAAG,UAAU,SAAS,EAAE,CAAC;QAE9C,OAAO,CAAC,GAAG,CAAC,0BAA0B,GAAG,GAAG,GAAG,cAAc,GAAG,SAAS,CAAC,CAAC;IAC/E,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,GAAG,CAAC,0BAA0B,GAAG,GAAG,GAAG,oBAAoB,CAAC,CAAC;IACzE,CAAC;IAED,uBAAuB;IACvB,IAAI,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE;QAC1C,OAAO;QACP,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;KAC9D,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,IAAI,CAAC;AACzB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAA6B,EAAE,OAAyB;IAC5F,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,mFAAmF;AACnF,iCAAiC;AACjC,mFAAmF;AAEnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAwB;IACnD,MAAM,GAAG,GAAG,GAAG,cAAc,mBAAmB,UAAU,WAAW,CAAC;IAEtE,0CAA0C;IAC1C,IAAI,SAAS,GAAG,MAAM,aAAa,CAAC,YAAY,EAAE,CAAC,CAAC;IACpD,IAAI,OAAO,GAAQ;QACf,aAAa,EAAE,UAAU,SAAS,EAAE;KACvC,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,0BAA0B,GAAG,GAAG,GAAG,cAAc,GAAG,SAAS,CAAC,CAAC;IAE3E,uBAAuB;IACvB,IAAI,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAE3D,OAAO,QAAQ,CAAC,IAAI,CAAC;AACzB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAwB;IACzD,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAA0B;IACvD,MAAM,GAAG,GAAG,GAAG,cAAc,mBAAmB,UAAU,aAAa,CAAC;IAExE,0CAA0C;IAC1C,IAAI,SAAS,GAAG,MAAM,aAAa,CAAC,YAAY,EAAE,CAAC,CAAC;IACpD,IAAI,OAAO,GAAQ;QACf,aAAa,EAAE,UAAU,SAAS,EAAE;KACvC,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,0BAA0B,GAAG,GAAG,GAAG,cAAc,GAAG,SAAS,CAAC,CAAC;IAE3E,uBAAuB;IACvB,IAAI,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAE3D,OAAO,QAAQ,CAAC,IAAI,CAAC;AACzB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAA0B;IAC7D,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,133 @@
1
+ // Halix SDK License v1.0
2
+ // Copyright (c) 2025 halix.io LLC.
3
+ //
4
+ // This source code is licensed for use **only** within applications
5
+ // running on the Halix platform, in accordance with Halix SDK guidelines.
6
+ //
7
+ // Unauthorized use outside the Halix platform is prohibited.
8
+ // Full license terms available in the LICENSE file.
9
+ /**
10
+ * @module @halix/action-sdk/messaging
11
+ * @description Messaging and notification functions for the Halix Platform action SDK. This module
12
+ * provides functions for sending messages (email, text) through the Halix notification service.
13
+ */
14
+ import axios from 'axios';
15
+ import { from, lastValueFrom } from 'rxjs';
16
+ import { sandboxKey, serviceAddress, getAuthToken } from './sdk-general';
17
+ // ================================================================================
18
+ // ENUMS & CONSTANTS
19
+ // ================================================================================
20
+ /**
21
+ * MessageMethod represents the delivery method for a message.
22
+ */
23
+ export var MessageMethod;
24
+ (function (MessageMethod) {
25
+ /** Send as email */
26
+ MessageMethod["Email"] = "email";
27
+ /** Send as text/SMS */
28
+ MessageMethod["Text"] = "text";
29
+ /** Send as both email and text */
30
+ MessageMethod["EmailAndText"] = "email,text";
31
+ })(MessageMethod || (MessageMethod = {}));
32
+ // ================================================================================
33
+ // MESSAGING FUNCTIONS
34
+ // ================================================================================
35
+ /**
36
+ * sendMessage sends a message (email and/or text) to recipients through the Halix notification
37
+ * service. The message is sent asynchronously - this function returns immediately after the
38
+ * message is queued for sending.
39
+ *
40
+ * @param orgProxyElementId - The ID of the organization proxy element (e.g., "business", "school")
41
+ * @param orgProxyKey - The key of the organization proxy object
42
+ * @param message - The message request object containing recipients, content, and delivery options
43
+ *
44
+ * @returns Promise that resolves when the message has been queued for sending
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * // Send an email to customers (sentAs defaults to email)
49
+ * await sendMessage('business', businessKey, {
50
+ * userProxyKeys: [customerKey1, customerKey2, customerKey3],
51
+ * subject: 'Important Announcement',
52
+ * body: '<p>This is an important announcement.</p>',
53
+ * replyToEmail: 'sender@example.com'
54
+ * });
55
+ * ```
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * // Send to user proxies and direct email addresses
60
+ * await sendMessage('business', businessKey, {
61
+ * userProxyKeys: [clientKey1, clientKey2],
62
+ * directEmailAddresses: ['manager@example.com'],
63
+ * sentAs: MessageMethod.EmailAndText,
64
+ * subject: 'Project Reminder',
65
+ * body: '<p>Don\'t forget about the deadline.</p>',
66
+ * resourceKeys: [attachmentKey]
67
+ * });
68
+ * ```
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * // Send email to direct addresses only (no user proxies)
73
+ * await sendMessage('business', businessKey, {
74
+ * directEmailAddresses: ['partner@example.com', 'vendor@example.com'],
75
+ * subject: 'External Notification',
76
+ * body: '<p>Important information for external stakeholders.</p>'
77
+ * });
78
+ * ```
79
+ */
80
+ export async function sendMessage(orgProxyElementId, orgProxyKey, message) {
81
+ // Build the server request from the simplified client request
82
+ const serverRequest = {
83
+ recipientGroups: message.userProxyKeys && message.userProxyKeys.length > 0 ? [
84
+ {
85
+ type: "",
86
+ recipientKeys: message.userProxyKeys
87
+ }
88
+ ] : [],
89
+ sentAs: message.sentAs?.toString() || MessageMethod.Email,
90
+ type: "direct",
91
+ subject: message.subject,
92
+ body: message.body,
93
+ replyToEmail: message.replyToEmail,
94
+ resourceKeys: message.resourceKeys,
95
+ additionalEmails: message.directEmailAddresses
96
+ };
97
+ let url = `${serviceAddress}/notification/sandboxes/${sandboxKey}/${orgProxyElementId}/${orgProxyKey}/sendMessage`;
98
+ let authToken = await lastValueFrom(getAuthToken());
99
+ console.log("Sending POST request to " + url + " with token " + authToken);
100
+ await axios.post(url, serverRequest, {
101
+ headers: { "Authorization": `Bearer ${authToken}` },
102
+ });
103
+ // Note: The message is sent asynchronously by the notification service
104
+ // This function returns once the message has been queued, not when delivery is complete
105
+ }
106
+ /**
107
+ * sendMessageAsObservable sends a message (email and/or text) to recipients through the Halix
108
+ * notification service. The message is sent asynchronously - this observable completes immediately
109
+ * after the message is queued for sending.
110
+ *
111
+ * @param orgProxyElementId - The ID of the organization proxy element (e.g., "business", "school")
112
+ * @param orgProxyKey - The key of the organization proxy object
113
+ * @param message - The message request object containing recipients, content, and delivery options
114
+ *
115
+ * @returns Observable that completes when the message has been queued for sending
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * sendMessageAsObservable('business', businessKey, {
120
+ * userProxyKeys: [customerKey1, customerKey2],
121
+ * directEmailAddresses: ['admin@example.com'],
122
+ * subject: 'Monthly Newsletter',
123
+ * body: '<p>Newsletter content here...</p>'
124
+ * }).subscribe({
125
+ * next: () => console.log('Message queued for sending'),
126
+ * error: (err) => console.error('Failed to send message:', err)
127
+ * });
128
+ * ```
129
+ */
130
+ export function sendMessageAsObservable(orgProxyElementId, orgProxyKey, message) {
131
+ return from(sendMessage(orgProxyElementId, orgProxyKey, message));
132
+ }
133
+ //# sourceMappingURL=messaging.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messaging.js","sourceRoot":"","sources":["../../src/messaging.ts"],"names":[],"mappings":"AAAA,yBAAyB;AACzB,mCAAmC;AACnC,EAAE;AACF,oEAAoE;AACpE,0EAA0E;AAC1E,EAAE;AACF,6DAA6D;AAC7D,oDAAoD;AAEpD;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,IAAI,EAAc,aAAa,EAAE,MAAM,MAAM,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEzE,mFAAmF;AACnF,oBAAoB;AACpB,mFAAmF;AAEnF;;GAEG;AACH,MAAM,CAAN,IAAY,aAOX;AAPD,WAAY,aAAa;IACrB,oBAAoB;IACpB,gCAAe,CAAA;IACf,uBAAuB;IACvB,8BAAa,CAAA;IACb,kCAAkC;IAClC,4CAA2B,CAAA;AAC/B,CAAC,EAPW,aAAa,KAAb,aAAa,QAOxB;AAgED,mFAAmF;AACnF,sBAAsB;AACtB,mFAAmF;AAEnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,iBAAyB,EAAE,WAAmB,EAAE,OAAuB;IAErG,8DAA8D;IAC9D,MAAM,aAAa,GAAyB;QACxC,eAAe,EAAE,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YACzE;gBACI,IAAI,EAAE,EAAE;gBACR,aAAa,EAAE,OAAO,CAAC,aAAa;aACvC;SACJ,CAAC,CAAC,CAAC,EAAE;QACN,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,aAAa,CAAC,KAAK;QACzD,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,gBAAgB,EAAE,OAAO,CAAC,oBAAoB;KACjD,CAAC;IAEF,IAAI,GAAG,GAAG,GAAG,cAAc,2BAA2B,UAAU,IAAI,iBAAiB,IAAI,WAAW,cAAc,CAAC;IAEnH,IAAI,SAAS,GAAG,MAAM,aAAa,CAAC,YAAY,EAAE,CAAC,CAAC;IAEpD,OAAO,CAAC,GAAG,CAAC,0BAA0B,GAAG,GAAG,GAAG,cAAc,GAAG,SAAS,CAAC,CAAC;IAE3E,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,EAAE;QACjC,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,SAAS,EAAE,EAAE;KACtD,CAAC,CAAC;IAEH,uEAAuE;IACvE,wFAAwF;AAC5F,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,uBAAuB,CAAC,iBAAyB,EAAE,WAAmB,EAAE,OAAuB;IAC3G,OAAO,IAAI,CAAC,WAAW,CAAC,iBAAiB,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;AACtE,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { Observable } from 'rxjs';
2
+ import { FilterExpression } from './filter-expressions';
2
3
  /**
3
4
  * SaveOptions is an interface for specifying save operation options.
4
5
  */
@@ -49,8 +50,10 @@ export declare function getObjectAsObservable(dataElementId: string, key: string
49
50
  * objects will include the specified related objects as nested objects
50
51
  *
51
52
  * @returns Promise resolving to an array of objects
53
+ *
54
+ * @see {@link FilterExpression} for filter syntax and examples
52
55
  */
53
- export declare function getRelatedObjects(parentElementId: string, parentKey: string, elementId: string, filter?: string, fetchedRelationships?: string[]): Promise<any[]>;
56
+ export declare function getRelatedObjects(parentElementId: string, parentKey: string, elementId: string, filter?: FilterExpression, fetchedRelationships?: string[]): Promise<any[]>;
54
57
  /**
55
58
  * getRelatedObjectsAsObservable retrieves an array of objects from the the database. The objects
56
59
  * returned are related to a parent through a defined relationship in the schema. In a typical
@@ -73,8 +76,10 @@ export declare function getRelatedObjects(parentElementId: string, parentKey: st
73
76
  * objects will include the specified related objects as nested objects
74
77
  *
75
78
  * @returns Observable resolving to an array of objects
79
+ *
80
+ * @see {@link FilterExpression} for filter syntax and examples
76
81
  */
77
- export declare function getRelatedObjectsAsObservable(parentElementId: string, parentKey: string, elementId: string, filter?: string, fetchedRelationships?: string[]): Observable<any[]>;
82
+ export declare function getRelatedObjectsAsObservable(parentElementId: string, parentKey: string, elementId: string, filter?: FilterExpression, fetchedRelationships?: string[]): Observable<any[]>;
78
83
  /**
79
84
  * saveRelatedObject saves a related object to the database. The objectToSave is saved, and its
80
85
  * relationship to the parent object is established based on the relationship specified in the
@@ -0,0 +1,153 @@
1
+ /**
2
+ * @module @halix/action-sdk/filter-expressions
3
+ * @description Filter expression language (dataexpr format) used throughout the SDK for filtering
4
+ * data in queries.
5
+ */
6
+ /**
7
+ * FilterExpression represents a filter expression string in the Halix dataexpr format.
8
+ *
9
+ * Filter expressions are used to filter data based on logical comparisons and boolean conditions.
10
+ * They support a wide range of operators, boolean logic, arrays, and special variables.
11
+ *
12
+ * ## Expression Structure
13
+ *
14
+ * An expression consists of:
15
+ * - One or more comparisons
16
+ * - Optionally combined using boolean operators (`AND`, `OR`)
17
+ * - Grouped using parentheses `(...)` for logical grouping and precedence
18
+ *
19
+ * ### Basic Forms
20
+ * ```
21
+ * <left> <operator> <right>
22
+ * (<expression1>) AND (<expression2>)
23
+ * (<expression1>) OR (<expression2>)
24
+ * ```
25
+ *
26
+ * ## Supported Operators
27
+ *
28
+ * | Operator | Description | Example |
29
+ * |----------|-------------|---------|
30
+ * | `=` | Equals | `status = 'active'` |
31
+ * | `!=` | Not equals | `status != 'closed'` |
32
+ * | `~` | Equals (case-insensitive) | `name ~ 'ADMIN'` |
33
+ * | `!~` | Not equals (case-insensitive) | `role !~ 'ADMIN'` |
34
+ * | `<` | Less than | `score < '80'` |
35
+ * | `>` | Greater than | `score > '90'` |
36
+ * | `<=` | Less than or equal to | `score <= '90'` |
37
+ * | `>=` | Greater than or equal to | `score >= '70'` |
38
+ * | `!>` | Begins with | `name !> 'Jo'` |
39
+ * | `<!` | Ends with | `email <! '@example.com'` |
40
+ * | `<>` | Contains (string or array) | `tags <> 'urgent'` |
41
+ * | `!<>` | Does not contain | `tags !<> 'archived'` |
42
+ * | `<empty> $void` | Value is empty | `notes <empty> $void` |
43
+ * | `!<empty> $void` | Value is not empty | `notes !<empty> $void` |
44
+ *
45
+ * ## Value Types
46
+ *
47
+ * Values in expressions can be:
48
+ * - **String literals**: Must be wrapped in single quotes - `'value'`
49
+ * - **Attribute references**: Must not be quoted - `status`, `score`
50
+ * - **Arrays**: Literal arrays - `['A', 'B', 'C']`
51
+ * - **Variables**: Special variables - `$today`, `$daysAgo:5`
52
+ * - **Page/group variables**: Must be quoted - `'@{page.fieldName}'`, `'@{group.fieldName}'`
53
+ *
54
+ * ## Boolean Logic
55
+ *
56
+ * Combine comparisons using:
57
+ * - `AND` – all subexpressions must be true
58
+ * - `OR` – at least one subexpression must be true
59
+ *
60
+ * **Important**: Each operand of `AND`/`OR` must be enclosed in parentheses.
61
+ *
62
+ * ### Examples
63
+ * ```
64
+ * (status = 'active') AND (priority = 'high')
65
+ * (status = 'active') AND ((priority = 'high') OR (escalated = 'true'))
66
+ * ```
67
+ *
68
+ * ## Expression Variables
69
+ *
70
+ * Use special `$variables` for dynamic time-based filtering:
71
+ *
72
+ * | Variable | Meaning |
73
+ * |----------|---------|
74
+ * | `$today` | Current date (e.g. `2023-06-25`) |
75
+ * | `$todayTimestamp` | Timestamp for midnight today |
76
+ * | `$todayUnixTimestamp` | Unix timestamp (ms) for today |
77
+ * | `$startOfMonth` | First day of the current month |
78
+ * | `$endOfMonth` | Last day of the current month |
79
+ * | `$yearsAgo:N` | Timestamp N years ago |
80
+ * | `$monthsAgo:N` | Timestamp N months ago |
81
+ * | `$weeksAgo:N` | Timestamp N weeks ago |
82
+ * | `$daysAgo:N` | Timestamp N days ago |
83
+ * | `$hoursAgo:N` | Timestamp N hours ago |
84
+ * | `$minutesAgo:N` | Timestamp N minutes ago |
85
+ * | `$secondsAgo:N` | Timestamp N seconds ago |
86
+ * | `$yearsAhead:N` | Timestamp N years in the future |
87
+ * | `$monthsAhead:N` | Timestamp N months in the future |
88
+ * | `$weeksAhead:N` | Timestamp N weeks in the future |
89
+ * | `$daysAhead:N` | Timestamp N days in the future |
90
+ * | `$hoursAhead:N` | Timestamp N hours in the future |
91
+ * | `$minutesAhead:N` | Timestamp N minutes in the future |
92
+ * | `$secondsAhead:N` | Timestamp N seconds in the future |
93
+ *
94
+ * ## Common Examples
95
+ *
96
+ * ### Simple Comparison
97
+ * ```typescript
98
+ * const filter = "status = 'active'";
99
+ * ```
100
+ *
101
+ * ### Case-Insensitive Match
102
+ * ```typescript
103
+ * const filter = "role ~ 'ADMIN'";
104
+ * ```
105
+ *
106
+ * ### Contains Check
107
+ * ```typescript
108
+ * const filter = "notes <> 'important'";
109
+ * ```
110
+ *
111
+ * ### Array Contains
112
+ * ```typescript
113
+ * const filter = "['pending', 'active', 'review'] <> status";
114
+ * ```
115
+ *
116
+ * ### Empty/Not Empty
117
+ * ```typescript
118
+ * const filter = "notes !<empty> $void"; // Has notes
119
+ * ```
120
+ *
121
+ * ### Compound Expression
122
+ * ```typescript
123
+ * const filter = "(status = 'active') AND (priority = 'high')";
124
+ * ```
125
+ *
126
+ * ### Nested Logic
127
+ * ```typescript
128
+ * const filter = "(status = 'active') AND ((score > '90') OR (grade = 'A'))";
129
+ * ```
130
+ *
131
+ * ### Time-Based Filtering
132
+ * ```typescript
133
+ * const filter = "createdAt > $daysAgo:30"; // Created in last 30 days
134
+ * ```
135
+ *
136
+ * ### Boolean Values
137
+ * ```typescript
138
+ * const filter = "enabled = boolean:true";
139
+ * ```
140
+ *
141
+ * ### Using Page Variables
142
+ * ```typescript
143
+ * const filter = "category = '@{page.selectedCategory.value}'";
144
+ * ```
145
+ *
146
+ * ### Complex Multi-Condition Filter
147
+ * ```typescript
148
+ * const filter = "(status = 'active') AND " +
149
+ * "((priority = 'high') OR (dueDate < $today)) AND " +
150
+ * "(assignedTo !<empty> $void)";
151
+ * ```
152
+ */
153
+ export type FilterExpression = string;
@@ -6,5 +6,7 @@
6
6
  export { getAuthToken, sandboxKey, serviceAddress, actionSubject, userContext, params, useBody, initialize, type UserContext, type IncomingEventBody, type BaseActionResponse, type ActionResponse, type NotificationConfig, type ListActionResponse, type FormTemplateActionResponse, type PageTemplateActionResponse, type ObjectSaveActionResponse, type CalculatedFieldActionResponse, type SingleValueActionResponse, type ErrorResponse, prepareSuccessResponse, prepareErrorResponse } from './sdk-general';
7
7
  export { type SaveOptions, getObject, getObjectAsObservable, getRelatedObjects, getRelatedObjectsAsObservable, saveRelatedObject, saveRelatedObjectAsObservable, deleteRelatedObject, deleteRelatedObjectAsObservable, deleteRelatedObjects, deleteRelatedObjectsAsObservable } from './data-crud';
8
8
  export { type ContentResource, getOrCreateResource, getOrCreateResourceAsObservable, saveResource, saveResourceAsObservable, sendFileContents, sendFileContentsAsObservable, createOrUpdateResource, createOrUpdateResourceAsObservable } from './content';
9
- export { type SortField, type DataSortField, type ListDataRequest, type ListDataResponse, type ListDataOptions, type ListDataSearchOptions, getListData, getListDataAsObservable } from './lists';
9
+ export { MessageMethod, type MessageRequest, sendMessage, sendMessageAsObservable } from './messaging';
10
+ export { type FilterExpression } from './filter-expressions';
11
+ export { type SortField, type DataSortField, type BaseListDataRequest, type PagedListDataRequest, type ListDataResponse, type ListDataOptions, type ListDataSearchOptions, type MassEditValueType, type MassEditRequest, type MassDeleteRequest, type MassChangeResponse, getListData, getListDataAsObservable, massEdit, massEditAsObservable, massDelete, massDeleteAsObservable } from './lists';
10
12
  export { sortObjectArray, compareValues, getValueFromObject, debounceFn } from './utilities';