@warleon/n8n-nodes-payload-cms 1.4.2 → 1.4.3

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.
@@ -2,12 +2,14 @@ import { IExecuteFunctions, ILoadOptionsFunctions, INodeExecutionData, INodeProp
2
2
  import { AxiosRequestConfig } from "axios";
3
3
  import { SanitizedCollectionConfig, SanitizedGlobalConfig } from "./payload.types";
4
4
  export declare class PayloadCms implements INodeType {
5
- private static authTokenCache;
5
+ private static collectionsCache;
6
+ private static globalsCache;
6
7
  description: INodeTypeDescription;
7
8
  methods: {
8
9
  loadOptions: {
9
10
  getCollections(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
10
11
  getGlobals(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
12
+ getPayloadFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
11
13
  };
12
14
  };
13
15
  discoverCollections(this: ILoadOptionsFunctions): Promise<SanitizedCollectionConfig[]>;
@@ -41,9 +41,10 @@ const n8n_workflow_1 = require("n8n-workflow");
41
41
  const axios_1 = __importStar(require("axios"));
42
42
  const form_data_1 = __importDefault(require("form-data"));
43
43
  const qs_esm_1 = require("qs-esm");
44
+ const utils_1 = require("./utils");
44
45
  class PayloadCms {
45
- // Cache for authentication tokens
46
- static authTokenCache = new Map();
46
+ static collectionsCache = new Map();
47
+ static globalsCache = new Map();
47
48
  description = {
48
49
  displayName: "Payload CMS",
49
50
  name: "payloadCms",
@@ -215,9 +216,12 @@ class PayloadCms {
215
216
  {
216
217
  displayName: "Data",
217
218
  name: "data",
218
- type: "json",
219
+ type: "multiOptions",
219
220
  required: true,
220
- default: "{}",
221
+ default: "",
222
+ typeOptions: {
223
+ loadOptionsMethod: "getPayloadFields",
224
+ },
221
225
  displayOptions: {
222
226
  show: {
223
227
  resource: ["collection"],
@@ -313,6 +317,7 @@ class PayloadCms {
313
317
  async getCollections() {
314
318
  try {
315
319
  const collections = await PayloadCms.prototype.discoverCollections.call(this);
320
+ PayloadCms.collectionsCache.set(this.getInstanceId(), collections);
316
321
  return collections.map((collection) => ({
317
322
  name: collection.labels?.plural || collection.slug,
318
323
  value: collection.slug,
@@ -325,6 +330,7 @@ class PayloadCms {
325
330
  async getGlobals() {
326
331
  try {
327
332
  const globals = await PayloadCms.prototype.discoverGlobals.call(this);
333
+ PayloadCms.globalsCache.set(this.getInstanceId(), globals);
328
334
  return globals.map((global) => ({
329
335
  name: global.label || global.slug,
330
336
  value: global.slug,
@@ -334,6 +340,33 @@ class PayloadCms {
334
340
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load globals: ${error instanceof Error ? error.message : "Unknown error"}`);
335
341
  }
336
342
  },
343
+ async getPayloadFields() {
344
+ const resource = this.getCurrentNodeParameter("resource");
345
+ switch (resource) {
346
+ case "collection":
347
+ const collectionSlug = this.getCurrentNodeParameter("collection");
348
+ const collection = PayloadCms.collectionsCache
349
+ .get(this.getInstanceId())
350
+ ?.find((c) => c.slug === collectionSlug);
351
+ if (!collection) {
352
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load fields for collection ${collectionSlug}: collection not found`);
353
+ }
354
+ return collection.fields.flatMap((f) => (0, utils_1.payloadField2N8nOption)(f));
355
+ break;
356
+ case "global":
357
+ const globalSlug = this.getCurrentNodeParameter("collection");
358
+ const global = PayloadCms.globalsCache
359
+ .get(this.getInstanceId())
360
+ ?.find((g) => g.slug === globalSlug);
361
+ if (!global) {
362
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load fields for global ${globalSlug}: global not found`);
363
+ }
364
+ return global.fields.flatMap((f) => (0, utils_1.payloadField2N8nOption)(f));
365
+ break;
366
+ default:
367
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load fields for resource ${resource}: resource not supported`);
368
+ }
369
+ },
337
370
  },
338
371
  };
339
372
  async discoverCollections() {
@@ -513,7 +546,7 @@ class PayloadCms {
513
546
  else {
514
547
  data = {};
515
548
  }
516
- const sanitizeData = { ...data, ...metadata };
549
+ const sanitizeData = { ...metadata, ...data };
517
550
  formData.append("_payload", JSON.stringify(sanitizeData));
518
551
  requestConfig = {
519
552
  method: method,
@@ -1,11 +1,11 @@
1
1
  import type { DeepRequired } from "ts-essentials";
2
- export interface SanitizedGlobalConfig extends DeepRequired<GlobalConfig> {
3
- fields: Field[];
2
+ export interface SanitizedGlobalConfig extends GlobalConfig {
3
+ fields: PayloadField[];
4
4
  slug: GlobalSlug;
5
5
  }
6
6
  export interface SanitizedCollectionConfig extends DeepRequired<CollectionConfig> {
7
7
  auth: Auth;
8
- fields: Field[];
8
+ fields: PayloadField[];
9
9
  slug: CollectionSlug;
10
10
  }
11
11
  export type CollectionConfig<TSlug extends object = any> = {
@@ -118,12 +118,11 @@ export interface IncomingAuthType {
118
118
  */
119
119
  useSessions?: boolean;
120
120
  }
121
- export type Field = any;
122
121
  export type CollectionSlug = string;
123
122
  export type GlobalSlug = string;
124
- export type GlobalConfig<TSlug extends GlobalSlug = any> = {
123
+ export type GlobalConfig = {
125
124
  custom?: Record<string, any>;
126
- fields: Field[];
125
+ fields: PayloadField[];
127
126
  label?: StaticLabel;
128
127
  };
129
128
  export declare const validOperators: readonly [
@@ -158,3 +157,37 @@ export type Where = {
158
157
  or?: Where[];
159
158
  [key: string]: Where[] | WhereField | undefined;
160
159
  };
160
+ export type PayloadFieldType = "array" | "blocks" | "checkbox" | "code" | "collapsible" | "date" | "email" | "group" | "join" | "json" | "number" | "point" | "radio" | "relationship" | "richText" | "row" | "select" | "tabs" | "text" | "textarea" | "ui" | "upload";
161
+ export interface PayloadAdminConfig {
162
+ disableBulkEdit?: boolean;
163
+ hidden?: boolean;
164
+ disabled?: boolean;
165
+ components?: {
166
+ Field?: boolean;
167
+ };
168
+ }
169
+ export interface PayloadHooksConfig {
170
+ beforeValidate?: (null | unknown)[];
171
+ beforeChange?: (null | unknown)[];
172
+ afterRead?: (null | unknown)[];
173
+ }
174
+ export interface PayloadAccessConfig {
175
+ [key: string]: unknown;
176
+ }
177
+ export interface PayloadField {
178
+ name: string;
179
+ type: PayloadFieldType;
180
+ required?: boolean;
181
+ unique?: boolean;
182
+ hidden?: boolean;
183
+ index?: boolean;
184
+ defaultValue?: unknown;
185
+ access?: PayloadAccessConfig;
186
+ admin?: PayloadAdminConfig;
187
+ hooks?: PayloadHooksConfig;
188
+ fields?: PayloadField[];
189
+ options?: Array<string | {
190
+ label: string;
191
+ value: string | number;
192
+ }>;
193
+ }
@@ -0,0 +1,3 @@
1
+ import { INodePropertyOptions } from "n8n-workflow";
2
+ import { PayloadField } from "./payload.types";
3
+ export declare function payloadField2N8nOption(field: PayloadField, parentName?: string): INodePropertyOptions[];
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.payloadField2N8nOption = payloadField2N8nOption;
4
+ function payloadField2N8nOption(field, parentName = "") {
5
+ const prefix = parentName ? `${parentName}.` : "";
6
+ switch (field.type) {
7
+ case "select":
8
+ case "radio":
9
+ return (field.options?.map((opt) => ({
10
+ name: `${prefix}${field.name}: ${typeof opt === "string" ? opt : opt.label ?? String(opt.value)}`,
11
+ value: typeof opt === "string" ? opt : opt.value,
12
+ })) || []);
13
+ case "checkbox":
14
+ return [
15
+ { name: `${prefix}${field.name}: True`, value: true },
16
+ { name: `${prefix}${field.name}: False`, value: false },
17
+ ];
18
+ case "point":
19
+ return [
20
+ { name: `${prefix}${field.name}.lat`, value: "lat" },
21
+ { name: `${prefix}${field.name}.lng`, value: "lng" },
22
+ ];
23
+ case "array":
24
+ case "group":
25
+ case "row":
26
+ case "tabs":
27
+ case "blocks":
28
+ return (field.fields || []).flatMap((subField) => payloadField2N8nOption(subField, `${prefix}${field.name}`));
29
+ default:
30
+ return [
31
+ {
32
+ name: `${prefix}${field.name}`,
33
+ value: field.name,
34
+ },
35
+ ];
36
+ }
37
+ }
@@ -0,0 +1,2 @@
1
+ import { INodeProperties } from "n8n-workflow";
2
+ export declare function convertPayloadSchemaToN8n(schema: any[]): INodeProperties[];
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertPayloadSchemaToN8n = void 0;
4
+ function mapPayloadFieldToN8n(field) {
5
+ const base = {
6
+ displayName: field.name,
7
+ name: field.name,
8
+ required: field.required || false,
9
+ default: field.defaultValue ?? "",
10
+ };
11
+ switch (field.type) {
12
+ case "text":
13
+ case "email":
14
+ return { ...base, type: "string" };
15
+ case "textarea":
16
+ case "code":
17
+ case "json":
18
+ case "richText":
19
+ return { ...base, type: "string", typeOptions: { rows: 5 } };
20
+ case "number":
21
+ return { ...base, type: "number" };
22
+ case "checkbox":
23
+ return { ...base, type: "boolean" };
24
+ case "date":
25
+ return { ...base, type: "dateTime" };
26
+ case "select":
27
+ case "radio":
28
+ return {
29
+ ...base,
30
+ type: "options",
31
+ options: field.options?.map((opt) => ({
32
+ name: opt.label ?? opt,
33
+ value: opt.value ?? opt,
34
+ })) || [],
35
+ };
36
+ case "relationship":
37
+ case "upload":
38
+ return { ...base, type: "string" };
39
+ case "point":
40
+ return {
41
+ ...base,
42
+ type: "fixedCollection",
43
+ options: [
44
+ {
45
+ name: "point",
46
+ displayName: "Point",
47
+ values: [
48
+ { displayName: "Latitude", name: "lat", type: "number" },
49
+ { displayName: "Longitude", name: "lng", type: "number" },
50
+ ],
51
+ },
52
+ ],
53
+ };
54
+ case "array":
55
+ case "group":
56
+ case "row":
57
+ case "tabs":
58
+ case "blocks":
59
+ return {
60
+ ...base,
61
+ type: "collection",
62
+ options: (field.fields || []).map(mapPayloadFieldToN8n),
63
+ };
64
+ default:
65
+ return { ...base, type: "string" };
66
+ }
67
+ }
68
+ function convertPayloadSchemaToN8n(schema) {
69
+ return schema.map(mapPayloadFieldToN8n);
70
+ }
71
+ exports.convertPayloadSchemaToN8n = convertPayloadSchemaToN8n;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warleon/n8n-nodes-payload-cms",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "Dynamic n8n node for Payload CMS that auto-discovers collections and operations forked and extended from https://github.com/leadership-institute/n8n-payload-dynamic",
5
5
  "main": "dist/index.js",
6
6
  "author": "warleon",