@learningsuite/n8n-nodes-learningsuite 1.2.5 → 1.3.4

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 (33) hide show
  1. package/README.md +41 -12
  2. package/dist/nodes/LearningSuite/LearningSuite.node.d.ts +7 -1
  3. package/dist/nodes/LearningSuite/LearningSuite.node.js +2 -4
  4. package/dist/nodes/LearningSuite/LearningSuiteTrigger.node.d.ts +7 -1
  5. package/dist/nodes/LearningSuite/LearningSuiteTrigger.node.js +15 -1
  6. package/dist/nodes/LearningSuite/descriptions/ai.properties.js +86 -0
  7. package/dist/nodes/LearningSuite/descriptions/customFields.properties.js +138 -17
  8. package/dist/nodes/LearningSuite/descriptions/member.properties.js +1 -1
  9. package/dist/nodes/LearningSuite/descriptions/module.properties.js +1 -1
  10. package/dist/nodes/LearningSuite/descriptions/trigger.instant.properties.js +35 -3
  11. package/dist/nodes/LearningSuite/descriptions/webhook.properties.js +37 -2
  12. package/dist/nodes/LearningSuite/descriptions/webhook.sampleData.properties.js +26 -0
  13. package/dist/nodes/LearningSuite/exec.types.d.ts +2 -2
  14. package/dist/nodes/LearningSuite/execute/ai.handlers.d.ts +3 -0
  15. package/dist/nodes/LearningSuite/execute/ai.handlers.js +44 -0
  16. package/dist/nodes/LearningSuite/execute/customFields.handlers.d.ts +1 -0
  17. package/dist/nodes/LearningSuite/execute/customFields.handlers.js +273 -22
  18. package/dist/nodes/LearningSuite/execute/user.handlers.js +1 -1
  19. package/dist/nodes/LearningSuite/execute/webhook.handlers.js +17 -1
  20. package/dist/nodes/LearningSuite/methods/loadOptions/ai.loadOptions.d.ts +3 -0
  21. package/dist/nodes/LearningSuite/methods/loadOptions/ai.loadOptions.js +11 -0
  22. package/dist/nodes/LearningSuite/methods/loadOptions/common.d.ts +1 -0
  23. package/dist/nodes/LearningSuite/methods/loadOptions/common.js +5 -0
  24. package/dist/nodes/LearningSuite/methods/loadOptions/customFields.loadOptions.d.ts +8 -4
  25. package/dist/nodes/LearningSuite/methods/loadOptions/customFields.loadOptions.js +76 -3
  26. package/dist/nodes/LearningSuite/methods/loadOptions/teamMember.loadOptions.js +1 -1
  27. package/dist/nodes/LearningSuite/shared/customFields.helpers.js +1 -4
  28. package/dist/nodes/LearningSuite/shared/customFields.shared.d.ts +1 -0
  29. package/dist/nodes/LearningSuite/shared/customFields.upload.d.ts +1 -1
  30. package/dist/nodes/LearningSuite/shared/customFields.upload.js +11 -10
  31. package/dist/nodes/LearningSuite/shared/request.d.ts +3 -0
  32. package/dist/nodes/LearningSuite/shared/request.js +18 -0
  33. package/package.json +1 -1
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.toOptions = toOptions;
4
4
  exports.ensureArray = ensureArray;
5
5
  exports.fetchOptions = fetchOptions;
6
+ exports.fetchOptionsAll = fetchOptionsAll;
6
7
  const shared_1 = require("../../shared");
7
8
  function toOptions(rows, labelKeys = ['name', 'title', 'email'], valueKeys = ['id', 'sid', 'slug']) {
8
9
  return rows.map((r) => {
@@ -20,3 +21,7 @@ async function fetchOptions(endpoint, qs, labelKeys, valueKeys) {
20
21
  const rows = ensureArray(res);
21
22
  return toOptions(rows, labelKeys, valueKeys);
22
23
  }
24
+ async function fetchOptionsAll(endpoint, qs, labelKeys, valueKeys) {
25
+ const rows = await shared_1.lsRequestAll.call(this, endpoint, { qs });
26
+ return toOptions(rows, labelKeys, valueKeys);
27
+ }
@@ -1,7 +1,11 @@
1
- import type { ILoadOptionsFunctions } from 'n8n-workflow';
2
- export declare function customFields_getCards(this: ILoadOptionsFunctions): Promise<import("n8n-workflow").INodePropertyOptions[]>;
3
- export declare function customFields_getDefinitions(this: ILoadOptionsFunctions): Promise<import("n8n-workflow").INodePropertyOptions[]>;
4
- export declare function customFields_getCategories(this: ILoadOptionsFunctions): Promise<import("n8n-workflow").INodePropertyOptions[]>;
1
+ import type { ILoadOptionsFunctions, INodePropertyOptions } from 'n8n-workflow';
2
+ export declare function customFields_getCards(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
3
+ export declare function customFields_getDefinitions(this: ILoadOptionsFunctions): Promise<{
4
+ name: string;
5
+ value: string;
6
+ }[]>;
7
+ export declare function customFields_getMediaDefinitions(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
8
+ export declare function customFields_getCategories(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
5
9
  export declare function customFields_getFieldType(this: ILoadOptionsFunctions): Promise<{
6
10
  name: string;
7
11
  value: string;
@@ -2,23 +2,96 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.customFields_getCards = customFields_getCards;
4
4
  exports.customFields_getDefinitions = customFields_getDefinitions;
5
+ exports.customFields_getMediaDefinitions = customFields_getMediaDefinitions;
5
6
  exports.customFields_getCategories = customFields_getCategories;
6
7
  exports.customFields_getFieldType = customFields_getFieldType;
7
8
  exports.customFields_getFieldOptions = customFields_getFieldOptions;
8
9
  const common_1 = require("./common");
10
+ const shared_1 = require("../../shared");
9
11
  const customFields_helpers_1 = require("../../shared/customFields.helpers");
12
+ const MEDIA_FIELD_TYPES = new Set(['files', 'images', 'videos', 'audios']);
13
+ function getMediaFieldMaxInfo(fieldType, typeDefinition) {
14
+ const maxByType = {
15
+ files: typeDefinition === null || typeDefinition === void 0 ? void 0 : typeDefinition.maxFiles,
16
+ images: typeDefinition === null || typeDefinition === void 0 ? void 0 : typeDefinition.maxImages,
17
+ videos: typeDefinition === null || typeDefinition === void 0 ? void 0 : typeDefinition.maxVideos,
18
+ audios: typeDefinition === null || typeDefinition === void 0 ? void 0 : typeDefinition.maxAudios,
19
+ };
20
+ const max = maxByType[fieldType];
21
+ if (typeof max === 'number' && Number.isFinite(max)) {
22
+ return `max. ${max}`;
23
+ }
24
+ if (typeof max === 'string' && max.trim() !== '') {
25
+ return `max. ${max.trim()}`;
26
+ }
27
+ return undefined;
28
+ }
29
+ function getMediaFieldDetails(fieldType, typeDefinition, cardName) {
30
+ const typeLabel = fieldType.charAt(0).toUpperCase() + fieldType.slice(1);
31
+ return [typeLabel, getMediaFieldMaxInfo(fieldType, typeDefinition), cardName].filter(Boolean).join(', ');
32
+ }
10
33
  async function customFields_getCards() {
11
- return common_1.fetchOptions.call(this, '/custom-fields/cards', undefined, ['name', 'title'], ['id']);
34
+ return common_1.fetchOptionsAll.call(this, '/custom-fields/cards', undefined, ['name', 'title'], ['id']);
12
35
  }
13
36
  async function customFields_getDefinitions() {
14
37
  const cardId = this.getCurrentNodeParameter('cardId');
15
38
  const customFieldCardId = this.getCurrentNodeParameter('customFieldCardId');
16
39
  const filterCardId = cardId || customFieldCardId;
17
- return common_1.fetchOptions.call(this, '/custom-fields/definitions', filterCardId ? { customFieldCardId: filterCardId } : undefined, ['label', 'name', 'key'], ['key']);
40
+ const definitions = await shared_1.lsRequestAll.call(this, '/custom-fields/definitions', {
41
+ qs: filterCardId ? { customFieldCardId: filterCardId } : undefined,
42
+ });
43
+ return definitions
44
+ .filter((definition) => typeof definition === 'object' && definition !== null)
45
+ .map((definition) => {
46
+ var _a, _b, _c, _d;
47
+ const definitionRecord = definition;
48
+ const key = definitionRecord.key;
49
+ const typeDefinition = definitionRecord.typeDefinition;
50
+ const fieldType = String((_a = typeDefinition === null || typeDefinition === void 0 ? void 0 : typeDefinition.type) !== null && _a !== void 0 ? _a : '').toLowerCase();
51
+ const fieldName = String((_d = (_c = (_b = definitionRecord.label) !== null && _b !== void 0 ? _b : definitionRecord.name) !== null && _c !== void 0 ? _c : key) !== null && _d !== void 0 ? _d : 'Unknown');
52
+ const value = String(key !== null && key !== void 0 ? key : fieldName);
53
+ if (!MEDIA_FIELD_TYPES.has(fieldType)) {
54
+ return { name: fieldName, value };
55
+ }
56
+ return {
57
+ name: `${fieldName} (${getMediaFieldDetails(fieldType, typeDefinition)})`,
58
+ value,
59
+ };
60
+ });
61
+ }
62
+ async function customFields_getMediaDefinitions() {
63
+ var _a, _b, _c, _d, _e;
64
+ const cards = await shared_1.lsRequestAll.call(this, '/custom-fields/cards/expanded');
65
+ const options = [];
66
+ for (const card of cards) {
67
+ if (typeof card !== 'object' || card === null)
68
+ continue;
69
+ const cardRecord = card;
70
+ const definitions = cardRecord.definitions;
71
+ if (!Array.isArray(definitions))
72
+ continue;
73
+ const cardName = String((_b = (_a = cardRecord.name) !== null && _a !== void 0 ? _a : cardRecord.title) !== null && _b !== void 0 ? _b : '').trim();
74
+ for (const definition of definitions) {
75
+ if (typeof definition !== 'object' || definition === null)
76
+ continue;
77
+ const definitionRecord = definition;
78
+ const key = definitionRecord.key;
79
+ const typeDefinition = definitionRecord.typeDefinition;
80
+ const fieldType = String((_c = typeDefinition === null || typeDefinition === void 0 ? void 0 : typeDefinition.type) !== null && _c !== void 0 ? _c : '').toLowerCase();
81
+ if (typeof key !== 'string' || !MEDIA_FIELD_TYPES.has(fieldType)) {
82
+ continue;
83
+ }
84
+ const fieldName = String((_e = (_d = definitionRecord.label) !== null && _d !== void 0 ? _d : definitionRecord.name) !== null && _e !== void 0 ? _e : key);
85
+ const details = getMediaFieldDetails(fieldType, typeDefinition, cardName);
86
+ const name = `${fieldName} (${details})`;
87
+ options.push({ name, value: key });
88
+ }
89
+ }
90
+ return options.sort((a, b) => String(a.name).localeCompare(String(b.name)));
18
91
  }
19
92
  async function customFields_getCategories() {
20
93
  const customFieldCardId = this.getCurrentNodeParameter('customFieldCardId');
21
- return common_1.fetchOptions.call(this, '/custom-fields/categories', customFieldCardId ? { customFieldCardId } : undefined, ['name', 'title'], ['id']);
94
+ return common_1.fetchOptionsAll.call(this, '/custom-fields/categories', customFieldCardId ? { customFieldCardId } : undefined, ['name', 'title'], ['id']);
22
95
  }
23
96
  async function customFields_getFieldType() {
24
97
  const fieldKey = this.getCurrentNodeParameter('fieldKey');
@@ -6,7 +6,7 @@ const shared_1 = require("../../shared");
6
6
  const common_1 = require("./common");
7
7
  function buildLabel(m) {
8
8
  var _a, _b;
9
- const fullName = (m === null || m === void 0 ? void 0 : m.fullName) || [m === null || m === void 0 ? void 0 : m.firstName, m === null || m === void 0 ? void 0 : m.lastName].filter(Boolean).join(' ') || 'Unbekannt';
9
+ const fullName = (m === null || m === void 0 ? void 0 : m.fullName) || [m === null || m === void 0 ? void 0 : m.firstName, m === null || m === void 0 ? void 0 : m.lastName].filter(Boolean).join(' ') || 'Unknown';
10
10
  const role = (_a = m === null || m === void 0 ? void 0 : m.roleId) !== null && _a !== void 0 ? _a : '—';
11
11
  const email = (_b = m === null || m === void 0 ? void 0 : m.email) !== null && _b !== void 0 ? _b : '';
12
12
  return [fullName, role, email].filter(Boolean).join(' - ');
@@ -6,10 +6,7 @@ exports.getLsSimpleType = getLsSimpleType;
6
6
  const request_1 = require("./request");
7
7
  const customFields_shared_1 = require("./customFields.shared");
8
8
  async function fetchFieldDefinition(ctx, fieldKey) {
9
- const cards = await request_1.lsRequest.call(ctx, 'GET', '/custom-fields/cards/expanded');
10
- if (!Array.isArray(cards)) {
11
- return undefined;
12
- }
9
+ const cards = await request_1.lsRequestAll.call(ctx, '/custom-fields/cards/expanded');
13
10
  for (const card of cards) {
14
11
  if (!(0, customFields_shared_1.isLsCard)(card) || !Array.isArray(card.definitions)) {
15
12
  continue;
@@ -15,6 +15,7 @@ export interface LsTypeDefinition {
15
15
  export interface LsFieldDefinition {
16
16
  key: string;
17
17
  name: string;
18
+ customFieldCardId?: string;
18
19
  typeDefinition?: LsTypeDefinition;
19
20
  }
20
21
  export interface LsCard {
@@ -9,5 +9,5 @@ interface UploadedFileValue {
9
9
  * Uploads one or more binary properties and returns the array of file value objects.
10
10
  * The binaryPropertyNames parameter can be a comma-separated list (e.g. "data,file1,file2").
11
11
  */
12
- export declare function uploadFilesFromBinaryProperties(ctx: IExecuteFunctions, itemIndex: number, userId: string, binaryPropertyNames: string, fieldType: string, fileNameOverride?: string): Promise<UploadedFileValue[]>;
12
+ export declare function uploadFilesFromBinaryProperties(ctx: IExecuteFunctions, itemIndex: number, userId: string, customFieldKey: string, binaryPropertyNames: string, fieldType: string, fileNameOverride?: string): Promise<UploadedFileValue[]>;
13
13
  export {};
@@ -10,9 +10,13 @@ function resolveFileType(fieldType) {
10
10
  * Creates a file slot in the LearningSuite custom-field store for a given user.
11
11
  * Returns the fileId and the uploadSpec describing how/where to upload.
12
12
  */
13
- async function createFileSlot(ctx, userId, isVideo) {
13
+ async function createFileSlot(ctx, userId, customFieldKey, fileName) {
14
+ const body = { customFieldKey };
15
+ if (fileName) {
16
+ body.fileName = fileName;
17
+ }
14
18
  const response = (await request_1.lsRequest.call(ctx, 'POST', `/custom-fields/store/${userId}/files`, {
15
- body: { isVideo },
19
+ body,
16
20
  }));
17
21
  const fileId = response.fileId;
18
22
  const uploadSpec = response.uploadSpec;
@@ -68,9 +72,7 @@ async function uploadViaTus(ctx, uploadSpec, buffer, fileName, contentType) {
68
72
  if (!location) {
69
73
  throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'tus creation response missing Location header');
70
74
  }
71
- const uploadUrl = location.startsWith('http')
72
- ? location
73
- : new URL(location, uploadSpec.uploadUrl).toString();
75
+ const uploadUrl = location.startsWith('http') ? location : new URL(location, uploadSpec.uploadUrl).toString();
74
76
  let offset = 0;
75
77
  while (offset < buffer.length) {
76
78
  const chunk = buffer.subarray(offset, Math.min(offset + TUS_CHUNK_SIZE, buffer.length));
@@ -157,14 +159,13 @@ function createUploadedFileValue(fileType, fileId, file) {
157
159
  * 2. Upload the binary data via HTTP PUT
158
160
  * 3. Return the file value object to store on the custom field
159
161
  */
160
- async function uploadSingleFile(ctx, itemIndex, userId, binaryPropertyName, fieldType, fileNameOverride) {
162
+ async function uploadSingleFile(ctx, itemIndex, userId, customFieldKey, binaryPropertyName, fieldType, fileNameOverride) {
161
163
  const binaryData = ctx.helpers.assertBinaryData(itemIndex, binaryPropertyName);
162
164
  const buffer = await ctx.helpers.getBinaryDataBuffer(itemIndex, binaryPropertyName);
163
165
  const fileType = resolveFileType(fieldType);
164
- const isVideo = fileType === 'videos';
165
166
  const mimeType = binaryData.mimeType || 'application/octet-stream';
166
167
  const fileName = fileNameOverride || binaryData.fileName || 'upload';
167
- const { fileId, uploadSpec } = await createFileSlot(ctx, userId, isVideo);
168
+ const { fileId, uploadSpec } = await createFileSlot(ctx, userId, customFieldKey, fileName);
168
169
  if (uploadSpec.type === 'storage') {
169
170
  await uploadViaStorage(ctx, uploadSpec, buffer, mimeType);
170
171
  }
@@ -181,7 +182,7 @@ async function uploadSingleFile(ctx, itemIndex, userId, binaryPropertyName, fiel
181
182
  * Uploads one or more binary properties and returns the array of file value objects.
182
183
  * The binaryPropertyNames parameter can be a comma-separated list (e.g. "data,file1,file2").
183
184
  */
184
- async function uploadFilesFromBinaryProperties(ctx, itemIndex, userId, binaryPropertyNames, fieldType, fileNameOverride) {
185
+ async function uploadFilesFromBinaryProperties(ctx, itemIndex, userId, customFieldKey, binaryPropertyNames, fieldType, fileNameOverride) {
185
186
  const names = binaryPropertyNames
186
187
  .split(',')
187
188
  .map((n) => n.trim())
@@ -191,7 +192,7 @@ async function uploadFilesFromBinaryProperties(ctx, itemIndex, userId, binaryPro
191
192
  }
192
193
  const results = [];
193
194
  for (const name of names) {
194
- const value = await uploadSingleFile(ctx, itemIndex, userId, name, fieldType, fileNameOverride);
195
+ const value = await uploadSingleFile(ctx, itemIndex, userId, customFieldKey, name, fieldType, fileNameOverride);
195
196
  results.push(value);
196
197
  }
197
198
  return results;
@@ -11,3 +11,6 @@ export declare function apiRequest(this: ApiThis, { method, path, qs, body, }: {
11
11
  qs?: IDataObject;
12
12
  body?: IDataObject;
13
13
  }): Promise<IDataObject | IDataObject[]>;
14
+ export declare function lsRequestAll(this: ApiThis, endpoint: string, { qs }?: {
15
+ qs?: IDataObject;
16
+ }): Promise<IDataObject[]>;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.normalizeEndpoint = normalizeEndpoint;
4
4
  exports.lsRequest = lsRequest;
5
5
  exports.apiRequest = apiRequest;
6
+ exports.lsRequestAll = lsRequestAll;
6
7
  const n8n_workflow_1 = require("n8n-workflow");
7
8
  function hasRequestWithAuthentication(value) {
8
9
  var _a;
@@ -51,3 +52,20 @@ async function lsRequest(method, endpoint, { qs, body } = {}) {
51
52
  async function apiRequest({ method, path, qs, body, }) {
52
53
  return requestCore.call(this, { method, endpoint: path, qs, body });
53
54
  }
55
+ async function lsRequestAll(endpoint, { qs } = {}) {
56
+ const pageSize = 100;
57
+ const maxPages = 500;
58
+ const all = [];
59
+ let offset = 0;
60
+ for (let page = 0; page < maxPages; page++) {
61
+ const res = await lsRequest.call(this, 'GET', endpoint, {
62
+ qs: { ...(qs !== null && qs !== void 0 ? qs : {}), limit: pageSize, offset },
63
+ });
64
+ const rows = Array.isArray(res) ? res : res ? [res] : [];
65
+ all.push(...rows);
66
+ if (rows.length < pageSize)
67
+ break;
68
+ offset += pageSize;
69
+ }
70
+ return all;
71
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@learningsuite/n8n-nodes-learningsuite",
3
- "version": "1.2.5",
3
+ "version": "1.3.4",
4
4
  "description": "n8n node for LearningSuite API",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",