n8n-nodes-lifespace 0.1.5 → 0.1.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 +26 -7
- package/dist/nodes/LifeSpace/LifeSpace.node.d.ts +7 -0
- package/dist/nodes/LifeSpace/LifeSpace.node.js +301 -41
- package/dist/nodes/LifeSpace/LifeSpace.node.js.map +1 -1
- package/dist/nodes/LifeSpaceTool/LifeSpaceTool.node.d.ts +13 -0
- package/dist/nodes/LifeSpaceTool/LifeSpaceTool.node.js +373 -0
- package/dist/nodes/LifeSpaceTool/LifeSpaceTool.node.js.map +1 -0
- package/dist/nodes/LifeSpaceTool/lifespace.dark.svg +14 -0
- package/dist/nodes/LifeSpaceTool/lifespace.svg +14 -0
- package/dist/nodes/LifeSpaceTrigger/LifeSpaceTrigger.node.js +2 -2
- package/dist/nodes/LifeSpaceTrigger/LifeSpaceTrigger.node.js.map +1 -1
- package/dist/nodes/agent/lifeSpaceToolFactory.d.ts +55 -0
- package/dist/nodes/agent/lifeSpaceToolFactory.js +591 -0
- package/dist/nodes/agent/lifeSpaceToolFactory.js.map +1 -0
- package/dist/nodes/lifespaceDiscovery.d.ts +78 -4
- package/dist/nodes/lifespaceDiscovery.js +41 -7
- package/dist/nodes/lifespaceDiscovery.js.map +1 -1
- package/dist/package.json +5 -5
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -70,13 +70,23 @@ Create/Update keep scalar fields in n8n Resource Mapper while using native n8n c
|
|
|
70
70
|
|
|
71
71
|
The node displays the authorized human-readable `spaceName` when present while continuing to submit the stable `spc_*` ID.
|
|
72
72
|
|
|
73
|
-
Record Type
|
|
73
|
+
Record Type is the LifeSpace `modelKey` (for example `task`). Design-time options, expressions, Trigger output and downstream Record nodes all use that plain value. CRUD calls go directly to `/spaces/{spaceId}/models/{modelKey}/records/...`, so execution adds no Discovery request and the adapter maintains no modelKey-to-route mapping. Existing `lsrt1...` workflow values are decoded only as a deprecated read-compatibility path and are never emitted or written by new configuration.
|
|
74
74
|
|
|
75
75
|
Calendar-backed models use canonical `capabilityBindings.calendar` field roles instead of Event-specific field names while the node is being configured. Date-only values are normalized to `YYYY-MM-DD`. Create/Update execution does not fetch fresh semantic Discovery solely to produce an adapter-local Calendar conflict error; the canonical mutation goes directly to LifeSpace Core, which remains authoritative for Calendar validation and current authorization.
|
|
76
76
|
|
|
77
|
+
## AI Agent Tool
|
|
78
|
+
|
|
79
|
+
`LifeSpace Tool` is the metadata-driven AI Agent sub-node. Configure one fixed Space, Record Type and semantic operation per Tool instance, then connect multiple instances to the same n8n AI Agent. The Tool name, default description and structured AI input schema are generated from LifeSpace Progressive Runtime Discovery; hand-written descriptions are optional.
|
|
80
|
+
|
|
81
|
+
- Query exposes published search/filter/comparison/local-date-window/sort/pagination semantics. Capability Query mode exposes only the capability-owned parameters and ordering that LifeSpace explicitly publishes; generic-facet composition stays narrowed until LifeSpace #228 defines it.
|
|
82
|
+
- Create/Update schemas come from writable Model fields. Required fields with LifeSpace defaults are optional AI inputs, and fields the AI omits are absent from the outgoing request rather than synthesized as empty/null placeholders.
|
|
83
|
+
- Delete and Action hide optimistic-concurrency `version` from the AI. The Adapter reads the current record version when required and Core remains the final authorization/concurrency/semantic authority.
|
|
84
|
+
- No Task/Event/Wish-specific Tool nodes or field maps are shipped. New models become available through Discovery without source changes.
|
|
85
|
+
- The ordinary `LifeSpace` workflow node remains `usableAsTool` for manually configured `$fromAI(...)` workflows, but `LifeSpace Tool` is the canonical path when the AI should receive the complete dynamic LifeSpace schema.
|
|
86
|
+
|
|
77
87
|
## LifeSpace contract compatibility
|
|
78
88
|
|
|
79
|
-
This package follows the current LifeSpace Core Kernel `0.
|
|
89
|
+
This package follows the current LifeSpace Core Kernel `0.35.0` contract family. It consumes Runtime/Discovery semantics only; Eventing configuration and webhook delivery semantics are owned independently by Integration/Eventing `0.1.0`.
|
|
80
90
|
|
|
81
91
|
The UX depends on these Kernel capabilities:
|
|
82
92
|
|
|
@@ -94,6 +104,10 @@ The UX depends on these Kernel capabilities:
|
|
|
94
104
|
- `0.29.0`: canonical ordinary-record `referenceLabel` semantics plus `record` / `record_list` lookup and resolution;
|
|
95
105
|
- `0.30.0`: explicit paginated Change History collection and Model Control Plane ownership split;
|
|
96
106
|
- `0.31.0`: Integration/Eventing wire representation moves to the independent Integration/Eventing `0.1.0` contract while Core remains the Runtime authority.
|
|
107
|
+
- `0.32.0`: `modelKey` becomes the sole Runtime address and canonical CRUD/Action paths move under `/models/{modelKey}/records`.
|
|
108
|
+
- `0.33.0`: canonical structural `timeRanges` become available in progressive semantic detail without implying an overlap query API.
|
|
109
|
+
- `0.34.0`: explicit `eq/lt/lte/gt/gte` comparison transports, first-class `createdAt` / `updatedAt` envelope comparisons and Core-owned datetime local-date-window conversion become discoverable.
|
|
110
|
+
- `0.35.0`: grouped `query.capabilityQueries` adds the preferred `calendar.window` viewing-window query with explicit IANA viewing timezone and deterministic mixed all-day/timed ordering.
|
|
97
111
|
|
|
98
112
|
The adapter prefers the `0.27+` progressive flow while configuring a node:
|
|
99
113
|
|
|
@@ -105,9 +119,9 @@ GET /me/_discovery/inventory
|
|
|
105
119
|
-> persist stable workflow configuration
|
|
106
120
|
```
|
|
107
121
|
|
|
108
|
-
Design-time callbacks prefer n8n editor-current parameters, so Fields and Actions refresh immediately after Record Type selection. A legacy 0.1.3 `modelRoute`
|
|
122
|
+
Design-time callbacks prefer n8n editor-current parameters, so Fields and Actions refresh immediately after Record Type selection. A legacy 0.1.3 `modelRoute` remains readable only for the four previously deployed baseline models; re-selecting Record Type writes the plain `modelKey`.
|
|
109
123
|
|
|
110
|
-
Execution is deliberately narrower. Get/List/Delete
|
|
124
|
+
Execution is deliberately narrower. Get/List/Create/Update/Delete call the canonical modelKey-addressed Runtime path directly without a fresh Runtime Discovery preflight. Execute Action loads only the selected model's `0.26+` static semantic detail, and reuses that detail within the same node execution for repeated items using the same Space/Record Type. No cached Discovery result is treated as authorization proof; every CRUD or Action request still goes through canonical LifeSpace Core current-state enforcement.
|
|
111
125
|
|
|
112
126
|
The legacy aggregate `GET /me/_discovery` remains an intentional design-time compatibility fallback. Neither cached Discovery nor relation lookup is treated as authorization proof; every mutation still goes through canonical LifeSpace Runtime enforcement.
|
|
113
127
|
|
|
@@ -126,7 +140,7 @@ Examples:
|
|
|
126
140
|
{{$vars.lifeSpaceRecordType}}
|
|
127
141
|
```
|
|
128
142
|
|
|
129
|
-
Discovery-backed selectors such as **Space**, **Filter Field**, **Sort Field** and **Action** support the normal n8n pattern: choose a value from the list, or switch the parameter to an expression and provide the corresponding stable ID/key. **Record Type**
|
|
143
|
+
Discovery-backed selectors such as **Space**, **Filter Field**, **Sort Field** and **Action** support the normal n8n pattern: choose a value from the list, or switch the parameter to an expression and provide the corresponding stable ID/key. **Record Type** stores the plain LifeSpace `modelKey`, so a LifeSpace Trigger can feed a Record node directly without a mapping step or an extra Discovery request.
|
|
130
144
|
|
|
131
145
|
The same applies to ordinary values such as Record ID, Search, Filter Value, Return All, Limit, Sort Direction, Cursor, explicit Version, API Method, API Path and JSON Body.
|
|
132
146
|
|
|
@@ -198,9 +212,14 @@ The normal UI supports:
|
|
|
198
212
|
|
|
199
213
|
- optional **Search**;
|
|
200
214
|
- one or more typed **Filters**;
|
|
215
|
+
- Discovery-driven explicit **Number Comparison** and **Date / Time Comparison** rows using the exact LifeSpace-published operator transport;
|
|
216
|
+
- generic **Local Date Windows** for datetime fields advertised by Time Semantics, including envelope `createdAt` / `updatedAt`, with local dates + IANA timezone sent unchanged to Core;
|
|
217
|
+
- optional grouped **Semantic Query** input generated from `query.capabilityQueries` (for example `calendar.window`) plus its published semantic ordering;
|
|
201
218
|
- **Return All** to follow `nextCursor` automatically;
|
|
202
219
|
- **Limit** when Return All is disabled.
|
|
203
220
|
|
|
221
|
+
The adapter never derives explicit comparison parameter names from field naming and never converts local calendar windows to UTC. Those transport names and timezone/DST semantics come from LifeSpace Runtime Semantic Detail. Existing `exact/from/to` filters remain available as compatibility UI and preserve the legacy inclusive `To` behavior.
|
|
222
|
+
|
|
204
223
|
Use **Sorts → Add Sort** to add zero or more sort criteria in priority order. Sortable model fields use authoritative `title` metadata from Runtime Discovery, while envelope fields such as `createdAt` / `updatedAt` are offered only when Discovery advertises them. Multiple criteria are sent as ordered repeated `sort=field:direction` query parameters.
|
|
205
224
|
|
|
206
225
|
Advanced **Options** contain manual **Cursor** as an escape hatch.
|
|
@@ -256,7 +275,7 @@ One Webhook Endpoint can therefore carry events for multiple Record Types throug
|
|
|
256
275
|
|
|
257
276
|
The Trigger verifies `X-LifeSpace-Timestamp` and `X-LifeSpace-Signature` with the LifeSpace HMAC-SHA256 contract before emitting workflow data. `endpoint.test` payloads are always accepted after signature verification.
|
|
258
277
|
|
|
259
|
-
For ordinary record events, the Trigger preserves the LifeSpace `modelKey` exactly as delivered and
|
|
278
|
+
For ordinary record events, the Trigger preserves the LifeSpace `modelKey` exactly as delivered and emits the same plain value as `recordType` for n8n composition. Pass `{{$json.recordType}}` and `{{$json.recordId}}` directly to a downstream LifeSpace Record node; it calls the canonical modelKey-addressed Runtime path with zero Discovery.
|
|
260
279
|
|
|
261
280
|
Webhook Endpoint / Event Subscription creation is intentionally not performed by the n8n Service API Token today because LifeSpace treats that configuration as a Space-management operation. The adapter does not bypass that authority boundary.
|
|
262
281
|
|
|
@@ -318,4 +337,4 @@ The adapter now consumes generic `person`, `person_list`, `record` and `record_l
|
|
|
318
337
|
|
|
319
338
|
## License
|
|
320
339
|
|
|
321
|
-
MIT
|
|
340
|
+
MIT
|
|
@@ -16,6 +16,12 @@ export declare class LifeSpace implements INodeType {
|
|
|
16
16
|
getBooleanFilterableFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
17
17
|
getNumericFilterableFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
18
18
|
getTemporalFilterableFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
19
|
+
getNumericComparisonFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
20
|
+
getTemporalComparisonFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
21
|
+
getComparisonOperatorsForCurrentField(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
22
|
+
getLocalDateWindowFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
23
|
+
getCapabilityQueries(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
24
|
+
getSemanticSorts(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
19
25
|
getPersonFilterableFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
20
26
|
getEnumValuesForCurrentFilter(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
21
27
|
getSortableFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
@@ -23,6 +29,7 @@ export declare class LifeSpace implements INodeType {
|
|
|
23
29
|
resourceMapping: {
|
|
24
30
|
getRecordFields(this: ILoadOptionsFunctions): Promise<ResourceMapperFields>;
|
|
25
31
|
getActionInputFields(this: ILoadOptionsFunctions): Promise<ResourceMapperFields>;
|
|
32
|
+
getSemanticQueryInputFields(this: ILoadOptionsFunctions): Promise<ResourceMapperFields>;
|
|
26
33
|
};
|
|
27
34
|
};
|
|
28
35
|
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
@@ -3,6 +3,81 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.LifeSpace = void 0;
|
|
4
4
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
5
|
const lifespaceDiscovery_1 = require("../lifespaceDiscovery");
|
|
6
|
+
const LEGACY_MODEL_ROUTE_TO_KEY = Object.freeze({
|
|
7
|
+
tasks: 'task',
|
|
8
|
+
wishes: 'wish',
|
|
9
|
+
'day-records': 'day_record',
|
|
10
|
+
events: 'event',
|
|
11
|
+
});
|
|
12
|
+
const LOCAL_DATE_WINDOW_SELECTOR_PREFIX = 'lsqw1.';
|
|
13
|
+
const COMPARISON_OPERATOR_LABELS = Object.freeze({
|
|
14
|
+
eq: 'Equals',
|
|
15
|
+
lt: 'Less Than',
|
|
16
|
+
lte: 'Less Than or Equal',
|
|
17
|
+
gt: 'Greater Than',
|
|
18
|
+
gte: 'Greater Than or Equal',
|
|
19
|
+
});
|
|
20
|
+
function comparisonFieldParts(value) {
|
|
21
|
+
const raw = String(value !== null && value !== void 0 ? value : '').trim();
|
|
22
|
+
const separator = raw.indexOf(':');
|
|
23
|
+
if (separator <= 0)
|
|
24
|
+
return { field: raw, valueType: '' };
|
|
25
|
+
return { valueType: raw.slice(0, separator), field: raw.slice(separator + 1) };
|
|
26
|
+
}
|
|
27
|
+
function encodeLocalDateWindowSelector(comparison) {
|
|
28
|
+
const window = comparison.localDateWindow;
|
|
29
|
+
if (!window || comparison.valueType !== 'datetime')
|
|
30
|
+
return '';
|
|
31
|
+
return `${LOCAL_DATE_WINDOW_SELECTOR_PREFIX}${Buffer.from(JSON.stringify([
|
|
32
|
+
comparison.field,
|
|
33
|
+
comparison.valueType,
|
|
34
|
+
window.dateStartParameter,
|
|
35
|
+
window.dateEndExclusiveParameter,
|
|
36
|
+
window.timezoneParameter,
|
|
37
|
+
])).toString('base64url')}`;
|
|
38
|
+
}
|
|
39
|
+
function decodeLocalDateWindowSelector(value) {
|
|
40
|
+
const raw = String(value !== null && value !== void 0 ? value : '').trim();
|
|
41
|
+
if (!raw.startsWith(LOCAL_DATE_WINDOW_SELECTOR_PREFIX))
|
|
42
|
+
return null;
|
|
43
|
+
try {
|
|
44
|
+
const decoded = JSON.parse(Buffer.from(raw.slice(LOCAL_DATE_WINDOW_SELECTOR_PREFIX.length), 'base64url').toString('utf8'));
|
|
45
|
+
if (!Array.isArray(decoded) || decoded.length !== 5 || decoded.some((entry) => typeof entry !== 'string' || !entry))
|
|
46
|
+
return null;
|
|
47
|
+
if (decoded[1] !== 'datetime')
|
|
48
|
+
return null;
|
|
49
|
+
return {
|
|
50
|
+
field: decoded[0],
|
|
51
|
+
valueType: 'datetime',
|
|
52
|
+
dateStartParameter: decoded[2],
|
|
53
|
+
dateEndExclusiveParameter: decoded[3],
|
|
54
|
+
timezoneParameter: decoded[4],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function semanticQueryMapperType(parameter) {
|
|
62
|
+
if (parameter.type === 'boolean')
|
|
63
|
+
return 'boolean';
|
|
64
|
+
if (parameter.type === 'integer' || parameter.type === 'number')
|
|
65
|
+
return 'number';
|
|
66
|
+
return 'string';
|
|
67
|
+
}
|
|
68
|
+
function semanticQueryMapperField(parameter) {
|
|
69
|
+
var _a;
|
|
70
|
+
return {
|
|
71
|
+
id: parameter.parameter,
|
|
72
|
+
displayName: (0, lifespaceDiscovery_1.humanizeKey)(((_a = parameter.role) === null || _a === void 0 ? void 0 : _a.trim()) || parameter.parameter),
|
|
73
|
+
required: parameter.required === true,
|
|
74
|
+
defaultMatch: false,
|
|
75
|
+
canBeUsedToMatch: false,
|
|
76
|
+
display: true,
|
|
77
|
+
type: semanticQueryMapperType(parameter),
|
|
78
|
+
description: `${parameter.type}${parameter.role ? ` · ${parameter.role}` : ''} · LifeSpace query parameter ${parameter.parameter}`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
6
81
|
function parseJsonObject(context, itemIndex, value, fieldName) {
|
|
7
82
|
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
|
|
8
83
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
@@ -96,14 +171,15 @@ function normalizeActionInput(context, itemIndex, value, fields) {
|
|
|
96
171
|
return result;
|
|
97
172
|
}
|
|
98
173
|
function queryParameters(context, itemIndex, limit, cursorOverride) {
|
|
99
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
|
|
174
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5;
|
|
100
175
|
const qs = {};
|
|
101
176
|
const search = String(context.getNodeParameter('search', itemIndex, '')).trim();
|
|
102
177
|
const options = context.getNodeParameter('options', itemIndex, {});
|
|
103
178
|
const configuredSorts = context.getNodeParameter('sorts.sort', itemIndex, []);
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
const
|
|
179
|
+
const semanticSort = String((_a = context.getNodeParameter('semanticSort', itemIndex, '')) !== null && _a !== void 0 ? _a : '').trim();
|
|
180
|
+
const legacySortField = String((_b = options.sortField) !== null && _b !== void 0 ? _b : '').trim();
|
|
181
|
+
const legacySortDirection = String((_c = options.sortDirection) !== null && _c !== void 0 ? _c : 'desc').trim();
|
|
182
|
+
const configuredCursor = String((_d = options.cursor) !== null && _d !== void 0 ? _d : '').trim();
|
|
107
183
|
const cursor = cursorOverride !== null && cursorOverride !== void 0 ? cursorOverride : configuredCursor;
|
|
108
184
|
const filters = context.getNodeParameter('filters.filter', itemIndex, []);
|
|
109
185
|
if (search)
|
|
@@ -111,10 +187,10 @@ function queryParameters(context, itemIndex, limit, cursorOverride) {
|
|
|
111
187
|
const orderedSorts = [];
|
|
112
188
|
const usedSortFields = new Set();
|
|
113
189
|
for (const sort of configuredSorts) {
|
|
114
|
-
const field = String((
|
|
190
|
+
const field = String((_e = sort.field) !== null && _e !== void 0 ? _e : '').trim();
|
|
115
191
|
if (!field)
|
|
116
192
|
continue;
|
|
117
|
-
const direction = String((
|
|
193
|
+
const direction = String((_f = sort.direction) !== null && _f !== void 0 ? _f : 'asc').trim();
|
|
118
194
|
if (direction !== 'asc' && direction !== 'desc') {
|
|
119
195
|
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Sort direction for ${field} must be asc or desc`, { itemIndex });
|
|
120
196
|
}
|
|
@@ -124,56 +200,64 @@ function queryParameters(context, itemIndex, limit, cursorOverride) {
|
|
|
124
200
|
usedSortFields.add(field);
|
|
125
201
|
orderedSorts.push(`${field}:${direction}`);
|
|
126
202
|
}
|
|
127
|
-
if (orderedSorts.length
|
|
203
|
+
if (semanticSort && (orderedSorts.length > 0 || legacySortField)) {
|
|
204
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Semantic Sort cannot be combined with field Sorts', { itemIndex });
|
|
205
|
+
}
|
|
206
|
+
if (semanticSort)
|
|
207
|
+
qs.sort = semanticSort;
|
|
208
|
+
if (!semanticSort && orderedSorts.length === 1)
|
|
128
209
|
qs.sort = orderedSorts[0];
|
|
129
|
-
if (orderedSorts.length > 1)
|
|
210
|
+
if (!semanticSort && orderedSorts.length > 1)
|
|
130
211
|
qs.sort = orderedSorts;
|
|
131
|
-
if (orderedSorts.length === 0 && legacySortField)
|
|
212
|
+
if (!semanticSort && orderedSorts.length === 0 && legacySortField)
|
|
132
213
|
qs.sort = `${legacySortField}:${legacySortDirection}`;
|
|
133
214
|
qs.limit = limit;
|
|
134
215
|
if (cursor)
|
|
135
216
|
qs.cursor = cursor;
|
|
136
217
|
const usedKeys = new Set();
|
|
137
|
-
const
|
|
138
|
-
const key = operator === 'from' ? `${field}From` : operator === 'to' ? `${field}To` : field;
|
|
218
|
+
const setQueryParameter = (key, value) => {
|
|
139
219
|
if (usedKeys.has(key)) {
|
|
140
|
-
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Query
|
|
220
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Query parameter ${key} may be supplied only once`, { itemIndex });
|
|
141
221
|
}
|
|
142
222
|
usedKeys.add(key);
|
|
143
223
|
qs[key] = typeof value === 'boolean' ? String(value) : value;
|
|
144
224
|
};
|
|
225
|
+
const setFilter = (field, operator, value) => {
|
|
226
|
+
const key = operator === 'from' ? `${field}From` : operator === 'to' ? `${field}To` : field;
|
|
227
|
+
setQueryParameter(key, value);
|
|
228
|
+
};
|
|
145
229
|
for (const filter of filters) {
|
|
146
|
-
const field = String((
|
|
147
|
-
const value = String((
|
|
148
|
-
const operator = (
|
|
230
|
+
const field = String((_g = filter.field) !== null && _g !== void 0 ? _g : '').trim();
|
|
231
|
+
const value = String((_h = filter.value) !== null && _h !== void 0 ? _h : '');
|
|
232
|
+
const operator = (_j = filter.operator) !== null && _j !== void 0 ? _j : 'exact';
|
|
149
233
|
if (field && value !== '')
|
|
150
234
|
setFilter(field, operator, value);
|
|
151
235
|
}
|
|
152
236
|
const typedFilters = context.getNodeParameter('filters', itemIndex, {});
|
|
153
|
-
for (const row of ((
|
|
154
|
-
const field = String((
|
|
237
|
+
for (const row of ((_k = typedFilters.text) !== null && _k !== void 0 ? _k : [])) {
|
|
238
|
+
const field = String((_l = row.field) !== null && _l !== void 0 ? _l : '').trim();
|
|
155
239
|
if (field && row.value !== undefined && row.value !== '')
|
|
156
240
|
setFilter(field, 'exact', String(row.value));
|
|
157
241
|
}
|
|
158
|
-
for (const row of ((
|
|
159
|
-
const field = String((
|
|
242
|
+
for (const row of ((_m = typedFilters.enum) !== null && _m !== void 0 ? _m : [])) {
|
|
243
|
+
const field = String((_o = row.field) !== null && _o !== void 0 ? _o : '').trim();
|
|
160
244
|
const values = Array.isArray(row.values) ? row.values.map(String).filter(Boolean) : [];
|
|
161
245
|
if (field && values.length)
|
|
162
246
|
setFilter(field, 'exact', values.join(','));
|
|
163
247
|
}
|
|
164
|
-
for (const row of ((
|
|
165
|
-
const field = String((
|
|
248
|
+
for (const row of ((_p = typedFilters.boolean) !== null && _p !== void 0 ? _p : [])) {
|
|
249
|
+
const field = String((_q = row.field) !== null && _q !== void 0 ? _q : '').trim();
|
|
166
250
|
if (field)
|
|
167
251
|
setFilter(field, 'exact', Boolean(row.value));
|
|
168
252
|
}
|
|
169
|
-
for (const row of ((
|
|
170
|
-
const field = String((
|
|
253
|
+
for (const row of ((_r = typedFilters.number) !== null && _r !== void 0 ? _r : [])) {
|
|
254
|
+
const field = String((_s = row.field) !== null && _s !== void 0 ? _s : '').trim();
|
|
171
255
|
const value = Number(row.value);
|
|
172
256
|
if (field && Number.isFinite(value))
|
|
173
|
-
setFilter(field, (
|
|
257
|
+
setFilter(field, (_t = row.operator) !== null && _t !== void 0 ? _t : 'exact', value);
|
|
174
258
|
}
|
|
175
|
-
for (const row of ((
|
|
176
|
-
const encoded = String((
|
|
259
|
+
for (const row of ((_u = typedFilters.temporal) !== null && _u !== void 0 ? _u : [])) {
|
|
260
|
+
const encoded = String((_v = row.field) !== null && _v !== void 0 ? _v : '').trim();
|
|
177
261
|
if (!encoded || row.value === undefined || row.value === '')
|
|
178
262
|
continue;
|
|
179
263
|
const separator = encoded.indexOf(':');
|
|
@@ -182,14 +266,59 @@ function queryParameters(context, itemIndex, limit, cursorOverride) {
|
|
|
182
266
|
const raw = String(row.value);
|
|
183
267
|
const value = fieldType === 'date' ? dateOnlyValue(context, itemIndex, raw, field) : raw;
|
|
184
268
|
if (value !== null)
|
|
185
|
-
setFilter(field, (
|
|
269
|
+
setFilter(field, (_w = row.operator) !== null && _w !== void 0 ? _w : 'exact', value);
|
|
186
270
|
}
|
|
187
|
-
for (const row of ((
|
|
188
|
-
const field = String((
|
|
189
|
-
const target = String((
|
|
271
|
+
for (const row of ((_x = typedFilters.person) !== null && _x !== void 0 ? _x : [])) {
|
|
272
|
+
const field = String((_y = row.field) !== null && _y !== void 0 ? _y : '').trim();
|
|
273
|
+
const target = String((_z = row.target) !== null && _z !== void 0 ? _z : '').trim();
|
|
190
274
|
if (field && target)
|
|
191
275
|
setFilter(field, 'exact', target);
|
|
192
276
|
}
|
|
277
|
+
for (const row of ((_0 = typedFilters.numberComparison) !== null && _0 !== void 0 ? _0 : [])) {
|
|
278
|
+
const field = comparisonFieldParts(row.field).field;
|
|
279
|
+
const parameter = String((_1 = row.parameter) !== null && _1 !== void 0 ? _1 : '').trim();
|
|
280
|
+
const value = Number(row.value);
|
|
281
|
+
if (field && parameter && Number.isFinite(value))
|
|
282
|
+
setQueryParameter(parameter, value);
|
|
283
|
+
}
|
|
284
|
+
for (const row of ((_2 = typedFilters.temporalComparison) !== null && _2 !== void 0 ? _2 : [])) {
|
|
285
|
+
const { field, valueType } = comparisonFieldParts(row.field);
|
|
286
|
+
const parameter = String((_3 = row.parameter) !== null && _3 !== void 0 ? _3 : '').trim();
|
|
287
|
+
if (!field || !parameter || row.value === undefined || row.value === '')
|
|
288
|
+
continue;
|
|
289
|
+
const raw = String(row.value);
|
|
290
|
+
const value = valueType === 'date' ? dateOnlyValue(context, itemIndex, raw, field) : raw;
|
|
291
|
+
if (value !== null)
|
|
292
|
+
setQueryParameter(parameter, value);
|
|
293
|
+
}
|
|
294
|
+
const localDateWindows = context.getNodeParameter('localDateWindows.window', itemIndex, []);
|
|
295
|
+
for (const row of localDateWindows) {
|
|
296
|
+
const selector = decodeLocalDateWindowSelector(row.field);
|
|
297
|
+
if (!selector) {
|
|
298
|
+
if (String((_4 = row.field) !== null && _4 !== void 0 ? _4 : '').trim()) {
|
|
299
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Local Date Window selector is invalid. Re-select the field from Runtime Discovery.', { itemIndex });
|
|
300
|
+
}
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
const dateStart = dateOnlyValue(context, itemIndex, row.dateStart, selector.field);
|
|
304
|
+
const dateEndExclusive = dateOnlyValue(context, itemIndex, row.dateEndExclusive, selector.field);
|
|
305
|
+
const timezone = String((_5 = row.timezone) !== null && _5 !== void 0 ? _5 : '').trim();
|
|
306
|
+
if (dateStart !== null)
|
|
307
|
+
setQueryParameter(selector.dateStartParameter, dateStart);
|
|
308
|
+
if (dateEndExclusive !== null)
|
|
309
|
+
setQueryParameter(selector.dateEndExclusiveParameter, dateEndExclusive);
|
|
310
|
+
if (timezone)
|
|
311
|
+
setQueryParameter(selector.timezoneParameter, timezone);
|
|
312
|
+
}
|
|
313
|
+
const semanticQueryInput = mappedValue(context, itemIndex, 'semanticQueryInput');
|
|
314
|
+
for (const [parameter, value] of Object.entries(semanticQueryInput)) {
|
|
315
|
+
if (value === null || value === undefined || value === '')
|
|
316
|
+
continue;
|
|
317
|
+
if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') {
|
|
318
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Semantic Query parameter ${parameter} must be a scalar value`, { itemIndex });
|
|
319
|
+
}
|
|
320
|
+
setQueryParameter(parameter, value);
|
|
321
|
+
}
|
|
193
322
|
return qs;
|
|
194
323
|
}
|
|
195
324
|
function queryPage(context, itemIndex, response) {
|
|
@@ -313,6 +442,7 @@ function actionOption(action) {
|
|
|
313
442
|
};
|
|
314
443
|
}
|
|
315
444
|
async function optionModel(context) {
|
|
445
|
+
var _a, _b;
|
|
316
446
|
const spaceId = (0, lifespaceDiscovery_1.loadOptionParameter)(context, 'spaceId');
|
|
317
447
|
const recordTypeValue = (0, lifespaceDiscovery_1.loadOptionParameter)(context, 'recordType');
|
|
318
448
|
const legacyModelRoute = recordTypeValue ? '' : (0, lifespaceDiscovery_1.loadOptionParameter)(context, 'modelRoute');
|
|
@@ -323,10 +453,7 @@ async function optionModel(context) {
|
|
|
323
453
|
throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'LifeSpace Record Type selector is invalid. Choose a Record Type from Discovery or pass a Trigger recordType value.');
|
|
324
454
|
}
|
|
325
455
|
const discovery = await lifespaceDiscovery_1.loadRuntimeDiscovery.call(context);
|
|
326
|
-
const
|
|
327
|
-
const model = recordType
|
|
328
|
-
? (0, lifespaceDiscovery_1.discoveryModel)(discovery, spaceId, recordType.modelKey)
|
|
329
|
-
: space === null || space === void 0 ? void 0 : space.models.find((entry) => entry.route === legacyModelRoute);
|
|
456
|
+
const model = (0, lifespaceDiscovery_1.discoveryModel)(discovery, spaceId, (_b = (_a = recordType === null || recordType === void 0 ? void 0 : recordType.modelKey) !== null && _a !== void 0 ? _a : LEGACY_MODEL_ROUTE_TO_KEY[legacyModelRoute]) !== null && _b !== void 0 ? _b : '');
|
|
330
457
|
return model ? { model, spaceId } : null;
|
|
331
458
|
}
|
|
332
459
|
async function filterFieldOptions(context, types, encodeType = false) {
|
|
@@ -345,6 +472,24 @@ async function filterFieldOptions(context, types, encodeType = false) {
|
|
|
345
472
|
});
|
|
346
473
|
});
|
|
347
474
|
}
|
|
475
|
+
async function comparisonFieldOptions(context, types) {
|
|
476
|
+
var _a;
|
|
477
|
+
const selected = await optionModel(context);
|
|
478
|
+
if (!selected)
|
|
479
|
+
return [];
|
|
480
|
+
const allowed = new Set(types);
|
|
481
|
+
return ((_a = selected.model.query.comparisons) !== null && _a !== void 0 ? _a : [])
|
|
482
|
+
.filter((comparison) => allowed.has(comparison.valueType))
|
|
483
|
+
.map((comparison) => {
|
|
484
|
+
var _a;
|
|
485
|
+
const field = selected.model.fields.find((entry) => entry.key === comparison.field);
|
|
486
|
+
return {
|
|
487
|
+
name: ((_a = field === null || field === void 0 ? void 0 : field.title) === null || _a === void 0 ? void 0 : _a.trim()) || (0, lifespaceDiscovery_1.humanizeKey)(comparison.field),
|
|
488
|
+
value: `${comparison.valueType}:${comparison.field}`,
|
|
489
|
+
description: `${comparison.source} · ${comparison.valueType} · explicit LifeSpace comparison operators`,
|
|
490
|
+
};
|
|
491
|
+
});
|
|
492
|
+
}
|
|
348
493
|
async function relationFieldOptions(context, cardinality, filterableOnly = false) {
|
|
349
494
|
const selected = await optionModel(context);
|
|
350
495
|
if (!selected)
|
|
@@ -533,6 +678,16 @@ class LifeSpace {
|
|
|
533
678
|
{ displayName: 'Operator', name: 'operator', type: 'options', options: [{ name: 'Equals', value: 'exact' }, { name: 'From / Greater Than or Equal', value: 'from' }, { name: 'To / Less Than or Equal', value: 'to' }], default: 'exact' },
|
|
534
679
|
{ displayName: 'Value', name: 'value', type: 'dateTime', default: '', required: true },
|
|
535
680
|
] },
|
|
681
|
+
{ displayName: 'Number Comparison', name: 'numberComparison', values: [
|
|
682
|
+
{ displayName: 'Field Name or ID', name: 'field', type: 'options', description: 'Fields and envelope values advertised by LifeSpace explicit comparison semantics. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.', typeOptions: { loadOptionsMethod: 'getNumericComparisonFields', loadOptionsDependsOn: ['spaceId', 'recordType'] }, options: [], default: '', required: true },
|
|
683
|
+
{ displayName: 'Operator Name or ID', name: 'parameter', type: 'options', description: 'The option value is the exact query parameter published by LifeSpace; the adapter does not derive transport names. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.', typeOptions: { loadOptionsMethod: 'getComparisonOperatorsForCurrentField', loadOptionsDependsOn: ['spaceId', 'recordType', '&field'] }, options: [], default: '', required: true },
|
|
684
|
+
{ displayName: 'Value', name: 'value', type: 'number', default: 0, required: true },
|
|
685
|
+
] },
|
|
686
|
+
{ displayName: 'Date / Time Comparison', name: 'temporalComparison', values: [
|
|
687
|
+
{ displayName: 'Field Name or ID', name: 'field', type: 'options', description: 'Includes model date/datetime fields plus LifeSpace envelope timestamps such as createdAt/updatedAt when advertised. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.', typeOptions: { loadOptionsMethod: 'getTemporalComparisonFields', loadOptionsDependsOn: ['spaceId', 'recordType'] }, options: [], default: '', required: true },
|
|
688
|
+
{ displayName: 'Operator Name or ID', name: 'parameter', type: 'options', description: 'Uses the exact explicit comparison transport advertised by LifeSpace. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.', typeOptions: { loadOptionsMethod: 'getComparisonOperatorsForCurrentField', loadOptionsDependsOn: ['spaceId', 'recordType', '&field'] }, options: [], default: '', required: true },
|
|
689
|
+
{ displayName: 'Value', name: 'value', type: 'dateTime', default: '', required: true },
|
|
690
|
+
] },
|
|
536
691
|
{ displayName: 'Person Filter', name: 'person', values: [
|
|
537
692
|
{ displayName: 'Field Name or ID', name: 'field', type: 'options', description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>', typeOptions: { loadOptionsMethod: 'getPersonFilterableFields', loadOptionsDependsOn: ['spaceId', 'recordType'] }, options: [], default: '', required: true },
|
|
538
693
|
{ displayName: 'Person Name or ID', name: 'target', type: 'options', description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>', typeOptions: { loadOptionsMethod: 'getRelationTargetsForCurrentField', loadOptionsDependsOn: ['spaceId', 'recordType', '&field'] }, options: [], default: '', required: true },
|
|
@@ -544,6 +699,45 @@ class LifeSpace {
|
|
|
544
699
|
] },
|
|
545
700
|
],
|
|
546
701
|
},
|
|
702
|
+
{
|
|
703
|
+
displayName: 'Local Date Windows', name: 'localDateWindows', type: 'fixedCollection', default: {},
|
|
704
|
+
placeholder: 'Add Local Date Window', typeOptions: { multipleValues: true },
|
|
705
|
+
displayOptions: { show: { resource: ['modelRecord'], operation: ['list'] } },
|
|
706
|
+
options: [{ displayName: 'Window', name: 'window', values: [
|
|
707
|
+
{ displayName: 'Field Name or ID', name: 'field', type: 'options', typeOptions: { loadOptionsMethod: 'getLocalDateWindowFields', loadOptionsDependsOn: ['spaceId', 'recordType'] }, options: [], default: '', required: true, description: 'Only datetime fields whose published comparison semantics include a local-date-window transport are offered. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.' },
|
|
708
|
+
{ displayName: 'Start Date', name: 'dateStart', type: 'dateTime', default: '', required: true, description: 'Inclusive local calendar start date. The adapter submits YYYY-MM-DD and does not calculate UTC boundaries.' },
|
|
709
|
+
{ displayName: 'End Date (Exclusive)', name: 'dateEndExclusive', type: 'dateTime', default: '', required: true, description: 'Exclusive local calendar end date' },
|
|
710
|
+
{ displayName: 'Viewing Timezone', name: 'timezone', type: 'string', default: '', required: true, placeholder: 'Europe/Amsterdam', description: 'IANA timezone passed unchanged to LifeSpace Core' },
|
|
711
|
+
] }],
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
displayName: 'Semantic Query Name or ID', name: 'semanticQueryKey', type: 'options',
|
|
715
|
+
typeOptions: { loadOptionsMethod: 'getCapabilityQueries', loadOptionsDependsOn: ['spaceId', 'recordType'] },
|
|
716
|
+
options: [], default: '',
|
|
717
|
+
displayOptions: { show: { resource: ['modelRecord'], operation: ['list'] } },
|
|
718
|
+
description: 'Optional grouped capability query published by LifeSpace, for example Calendar Window. The adapter does not hard-code Event fields. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
719
|
+
},
|
|
720
|
+
{
|
|
721
|
+
displayName: 'Semantic Query Input', name: 'semanticQueryInput', type: 'resourceMapper',
|
|
722
|
+
default: { mappingMode: 'defineBelow', value: null }, noDataExpression: true,
|
|
723
|
+
typeOptions: {
|
|
724
|
+
loadOptionsDependsOn: ['spaceId', 'recordType', 'semanticQueryKey'],
|
|
725
|
+
resourceMapper: {
|
|
726
|
+
resourceMapperMethod: 'getSemanticQueryInputFields', mode: 'add',
|
|
727
|
+
fieldWords: { singular: 'parameter', plural: 'parameters' }, addAllFields: true, supportAutoMap: false,
|
|
728
|
+
noFieldsError: 'Choose a Semantic Query to load its LifeSpace-published parameters.',
|
|
729
|
+
},
|
|
730
|
+
},
|
|
731
|
+
displayOptions: { show: { resource: ['modelRecord'], operation: ['list'] } },
|
|
732
|
+
description: 'Parameters are projected directly from query.capabilityQueries. Calendar local dates/timezone are sent to Core unchanged; Core owns overlap and DST semantics.',
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
displayName: 'Semantic Sort Name or ID', name: 'semanticSort', type: 'options',
|
|
736
|
+
typeOptions: { loadOptionsMethod: 'getSemanticSorts', loadOptionsDependsOn: ['spaceId', 'recordType', 'semanticQueryKey'] },
|
|
737
|
+
options: [], default: '',
|
|
738
|
+
displayOptions: { show: { resource: ['modelRecord'], operation: ['list'] } },
|
|
739
|
+
description: 'Optional capability-specific sort published with the selected Semantic Query. Do not combine with field Sorts. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
740
|
+
},
|
|
547
741
|
{
|
|
548
742
|
displayName: 'Return All', name: 'returnAll', type: 'boolean', default: false,
|
|
549
743
|
displayOptions: { show: { resource: ['modelRecord'], operation: ['list'] } },
|
|
@@ -643,7 +837,7 @@ class LifeSpace {
|
|
|
643
837
|
var _a;
|
|
644
838
|
return ({
|
|
645
839
|
name: `${model.display.plural} (${model.key})`,
|
|
646
|
-
value:
|
|
840
|
+
value: model.key,
|
|
647
841
|
description: (_a = model.description) !== null && _a !== void 0 ? _a : undefined,
|
|
648
842
|
});
|
|
649
843
|
});
|
|
@@ -698,6 +892,64 @@ class LifeSpace {
|
|
|
698
892
|
async getBooleanFilterableFields() { return filterFieldOptions(this, ['boolean']); },
|
|
699
893
|
async getNumericFilterableFields() { return filterFieldOptions(this, ['integer', 'number']); },
|
|
700
894
|
async getTemporalFilterableFields() { return filterFieldOptions(this, ['date', 'datetime'], true); },
|
|
895
|
+
async getNumericComparisonFields() { return comparisonFieldOptions(this, ['integer', 'number']); },
|
|
896
|
+
async getTemporalComparisonFields() { return comparisonFieldOptions(this, ['date', 'datetime']); },
|
|
897
|
+
async getComparisonOperatorsForCurrentField() {
|
|
898
|
+
var _a, _b;
|
|
899
|
+
const selected = await optionModel(this);
|
|
900
|
+
const { field } = comparisonFieldParts(this.getCurrentNodeParameter('&field'));
|
|
901
|
+
const comparison = (_a = selected === null || selected === void 0 ? void 0 : selected.model.query.comparisons) === null || _a === void 0 ? void 0 : _a.find((entry) => entry.field === field);
|
|
902
|
+
return ((_b = comparison === null || comparison === void 0 ? void 0 : comparison.operators) !== null && _b !== void 0 ? _b : [])
|
|
903
|
+
.filter((operator) => operator.transport === 'explicit')
|
|
904
|
+
.map((operator) => {
|
|
905
|
+
var _a;
|
|
906
|
+
return ({
|
|
907
|
+
name: (_a = COMPARISON_OPERATOR_LABELS[operator.operator]) !== null && _a !== void 0 ? _a : (0, lifespaceDiscovery_1.humanizeKey)(operator.operator),
|
|
908
|
+
value: operator.parameter,
|
|
909
|
+
description: `${operator.operator} · ${operator.transport} · ${operator.parameter}`,
|
|
910
|
+
});
|
|
911
|
+
});
|
|
912
|
+
},
|
|
913
|
+
async getLocalDateWindowFields() {
|
|
914
|
+
var _a;
|
|
915
|
+
const selected = await optionModel(this);
|
|
916
|
+
if (!selected)
|
|
917
|
+
return [];
|
|
918
|
+
return ((_a = selected.model.query.comparisons) !== null && _a !== void 0 ? _a : [])
|
|
919
|
+
.filter((comparison) => comparison.valueType === 'datetime' && comparison.localDateWindow)
|
|
920
|
+
.map((comparison) => {
|
|
921
|
+
var _a;
|
|
922
|
+
const field = selected.model.fields.find((entry) => entry.key === comparison.field);
|
|
923
|
+
return {
|
|
924
|
+
name: ((_a = field === null || field === void 0 ? void 0 : field.title) === null || _a === void 0 ? void 0 : _a.trim()) || (0, lifespaceDiscovery_1.humanizeKey)(comparison.field),
|
|
925
|
+
value: encodeLocalDateWindowSelector(comparison),
|
|
926
|
+
description: `${comparison.source} · [start,end) local calendar window · Core resolves timezone/DST`,
|
|
927
|
+
};
|
|
928
|
+
});
|
|
929
|
+
},
|
|
930
|
+
async getCapabilityQueries() {
|
|
931
|
+
var _a;
|
|
932
|
+
const selected = await optionModel(this);
|
|
933
|
+
return ((_a = selected === null || selected === void 0 ? void 0 : selected.model.query.capabilityQueries) !== null && _a !== void 0 ? _a : []).map((query) => ({
|
|
934
|
+
name: `${(0, lifespaceDiscovery_1.humanizeKey)(query.capability)} · ${(0, lifespaceDiscovery_1.humanizeKey)(query.key)}`,
|
|
935
|
+
value: query.key,
|
|
936
|
+
description: `${query.semantics}${query.recurrenceExpansion === false ? ' · recurrence not expanded' : ''}`,
|
|
937
|
+
}));
|
|
938
|
+
},
|
|
939
|
+
async getSemanticSorts() {
|
|
940
|
+
var _a, _b, _c;
|
|
941
|
+
const selected = await optionModel(this);
|
|
942
|
+
const queryKey = (0, lifespaceDiscovery_1.loadOptionParameter)(this, 'semanticQueryKey');
|
|
943
|
+
const query = (_a = selected === null || selected === void 0 ? void 0 : selected.model.query.capabilityQueries) === null || _a === void 0 ? void 0 : _a.find((entry) => entry.key === queryKey);
|
|
944
|
+
return ((_c = (_b = query === null || query === void 0 ? void 0 : query.ordering) === null || _b === void 0 ? void 0 : _b.values) !== null && _c !== void 0 ? _c : []).map((value) => {
|
|
945
|
+
var _a, _b;
|
|
946
|
+
return ({
|
|
947
|
+
name: value === ((_a = query === null || query === void 0 ? void 0 : query.ordering) === null || _a === void 0 ? void 0 : _a.default) ? `${value} (Default)` : value,
|
|
948
|
+
value,
|
|
949
|
+
description: `${(_b = query === null || query === void 0 ? void 0 : query.key) !== null && _b !== void 0 ? _b : 'semantic query'} ordering`,
|
|
950
|
+
});
|
|
951
|
+
});
|
|
952
|
+
},
|
|
701
953
|
async getPersonFilterableFields() { return relationFieldOptions(this, undefined, true); },
|
|
702
954
|
async getEnumValuesForCurrentFilter() {
|
|
703
955
|
var _a, _b;
|
|
@@ -742,10 +994,18 @@ class LifeSpace {
|
|
|
742
994
|
? { fields: action.input.fields.map((field) => mapperField(field, field.required === true)) }
|
|
743
995
|
: { fields: [] };
|
|
744
996
|
},
|
|
997
|
+
async getSemanticQueryInputFields() {
|
|
998
|
+
var _a;
|
|
999
|
+
const selected = await optionModel(this);
|
|
1000
|
+
const queryKey = (0, lifespaceDiscovery_1.loadOptionParameter)(this, 'semanticQueryKey');
|
|
1001
|
+
const query = (_a = selected === null || selected === void 0 ? void 0 : selected.model.query.capabilityQueries) === null || _a === void 0 ? void 0 : _a.find((entry) => entry.key === queryKey);
|
|
1002
|
+
return query ? { fields: query.parameters.map(semanticQueryMapperField) } : { fields: [] };
|
|
1003
|
+
},
|
|
745
1004
|
},
|
|
746
1005
|
};
|
|
747
1006
|
}
|
|
748
1007
|
async execute() {
|
|
1008
|
+
var _a, _b;
|
|
749
1009
|
const items = this.getInputData();
|
|
750
1010
|
const output = [];
|
|
751
1011
|
const credentials = await this.getCredentials('lifeSpaceApi');
|
|
@@ -757,15 +1017,15 @@ class LifeSpace {
|
|
|
757
1017
|
if (resource === 'modelRecord') {
|
|
758
1018
|
const operation = this.getNodeParameter('operation', itemIndex);
|
|
759
1019
|
const rawSpaceId = String(this.getNodeParameter('spaceId', itemIndex));
|
|
760
|
-
const recordType = (0, lifespaceDiscovery_1.decodeRecordTypeSelector)(this.getNodeParameter('recordType', itemIndex));
|
|
761
|
-
|
|
1020
|
+
const recordType = (0, lifespaceDiscovery_1.decodeRecordTypeSelector)(this.getNodeParameter('recordType', itemIndex, ''));
|
|
1021
|
+
const legacyModelRoute = String((_a = this.getNodeParameter('modelRoute', itemIndex, '')) !== null && _a !== void 0 ? _a : '').trim();
|
|
1022
|
+
const rawModelKey = (_b = recordType === null || recordType === void 0 ? void 0 : recordType.modelKey) !== null && _b !== void 0 ? _b : LEGACY_MODEL_ROUTE_TO_KEY[legacyModelRoute];
|
|
1023
|
+
if (!rawModelKey) {
|
|
762
1024
|
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'LifeSpace Record Type selector is invalid. Choose a Record Type from Discovery or pass a Trigger recordType value.', { itemIndex });
|
|
763
1025
|
}
|
|
764
|
-
const rawModelKey = recordType.modelKey;
|
|
765
|
-
const rawModelRoute = recordType.route;
|
|
766
1026
|
const spaceId = encodeURIComponent(rawSpaceId);
|
|
767
|
-
const
|
|
768
|
-
const collectionPath = `/spaces/${spaceId}/${
|
|
1027
|
+
const modelKey = encodeURIComponent(rawModelKey);
|
|
1028
|
+
const collectionPath = `/spaces/${spaceId}/models/${modelKey}/records`;
|
|
769
1029
|
if (operation === 'list') {
|
|
770
1030
|
const returnAll = this.getNodeParameter('returnAll', itemIndex, false);
|
|
771
1031
|
if (!returnAll) {
|