n8n-nodes-base 1.96.1 → 1.97.0
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/dist/nodes/Evaluation/EvaluationTrigger/EvaluationTrigger.node.ee.js +18 -13
- package/dist/nodes/Evaluation/EvaluationTrigger/EvaluationTrigger.node.ee.js.map +1 -1
- package/dist/nodes/Form/Form.node.js +3 -3
- package/dist/nodes/Form/Form.node.js.map +1 -1
- package/dist/nodes/Form/formCompletionUtils.js.map +1 -0
- package/dist/nodes/Form/formNodeUtils.js.map +1 -0
- package/dist/nodes/Form/{utils/utils.js → utils.js} +7 -21
- package/dist/nodes/Form/utils.js.map +1 -0
- package/dist/nodes/Form/v1/FormTriggerV1.node.js +1 -1
- package/dist/nodes/Form/v1/FormTriggerV1.node.js.map +1 -1
- package/dist/nodes/Form/v2/FormTriggerV2.node.js +1 -1
- package/dist/nodes/Form/v2/FormTriggerV2.node.js.map +1 -1
- package/dist/nodes/Google/Gmail/GenericFunctions.js +1 -1
- package/dist/nodes/Google/Gmail/GenericFunctions.js.map +1 -1
- package/dist/nodes/Google/Gmail/v2/DraftDescription.js +7 -0
- package/dist/nodes/Google/Gmail/v2/DraftDescription.js.map +1 -1
- package/dist/nodes/Google/Gmail/v2/GmailV2.node.js +4 -0
- package/dist/nodes/Google/Gmail/v2/GmailV2.node.js.map +1 -1
- package/dist/nodes/Google/Gmail/v2/utils/draft.js +44 -0
- package/dist/nodes/Google/Gmail/v2/utils/draft.js.map +1 -0
- package/dist/nodes/HttpRequest/V3/HttpRequestV3.node.js +10 -4
- package/dist/nodes/HttpRequest/V3/HttpRequestV3.node.js.map +1 -1
- package/dist/nodes/HttpRequest/V3/utils/binaryData.js +37 -0
- package/dist/nodes/HttpRequest/V3/utils/binaryData.js.map +1 -0
- package/dist/nodes/HttpRequest/V3/utils/parse.js +34 -0
- package/dist/nodes/HttpRequest/V3/utils/parse.js.map +1 -0
- package/dist/nodes/Linear/CommentDescription.js +105 -0
- package/dist/nodes/Linear/CommentDescription.js.map +1 -0
- package/dist/nodes/Linear/IssueDescription.js +23 -1
- package/dist/nodes/Linear/IssueDescription.js.map +1 -1
- package/dist/nodes/Linear/Linear.node.js +37 -0
- package/dist/nodes/Linear/Linear.node.js.map +1 -1
- package/dist/nodes/Linear/Queries.js +17 -0
- package/dist/nodes/Linear/Queries.js.map +1 -1
- package/dist/nodes/Linear/test/workflow/apiRequest.js +280 -0
- package/dist/nodes/Linear/test/workflow/apiRequest.js.map +1 -0
- package/dist/nodes/Linear/test/workflow/apiResponses.js +198 -0
- package/dist/nodes/Linear/test/workflow/apiResponses.js.map +1 -0
- package/dist/nodes/Postgres/transport/index.js +55 -60
- package/dist/nodes/Postgres/transport/index.js.map +1 -1
- package/dist/nodes/Wait/Wait.node.js +1 -1
- package/dist/nodes/Wait/Wait.node.js.map +1 -1
- package/dist/types/nodes.json +4 -4
- package/dist/utils/connection-pool-manager.js +42 -30
- package/dist/utils/connection-pool-manager.js.map +1 -1
- package/dist/utils/sendAndWait/utils.js +1 -1
- package/dist/utils/sendAndWait/utils.js.map +1 -1
- package/package.json +7 -7
- package/dist/nodes/Form/utils/formCompletionUtils.js.map +0 -1
- package/dist/nodes/Form/utils/formNodeUtils.js.map +0 -1
- package/dist/nodes/Form/utils/utils.js.map +0 -1
- /package/dist/nodes/Form/{utils/formCompletionUtils.js → formCompletionUtils.js} +0 -0
- /package/dist/nodes/Form/{utils/formNodeUtils.js → formNodeUtils.js} +0 -0
|
@@ -22,6 +22,7 @@ __export(connection_pool_manager_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(connection_pool_manager_exports);
|
|
24
24
|
var import_crypto = require("crypto");
|
|
25
|
+
var import_n8n_workflow = require("n8n-workflow");
|
|
25
26
|
let instance;
|
|
26
27
|
const ttl = 5 * 60 * 1e3;
|
|
27
28
|
const cleanUpInterval = 60 * 1e3;
|
|
@@ -30,18 +31,22 @@ class ConnectionPoolManager {
|
|
|
30
31
|
* Private constructor that initializes the connection pool manager.
|
|
31
32
|
* Sets up cleanup handlers for process exit and stale connections.
|
|
32
33
|
*/
|
|
33
|
-
constructor() {
|
|
34
|
+
constructor(logger) {
|
|
35
|
+
this.logger = logger;
|
|
34
36
|
this.map = /* @__PURE__ */ new Map();
|
|
35
|
-
process.on("exit", () =>
|
|
37
|
+
process.on("exit", () => {
|
|
38
|
+
this.logger.debug("ConnectionPoolManager: Shutting down. Cleaning up all pools");
|
|
39
|
+
this.purgeConnections();
|
|
40
|
+
});
|
|
36
41
|
setInterval(() => this.cleanupStaleConnections(), cleanUpInterval);
|
|
37
42
|
}
|
|
38
43
|
/**
|
|
39
44
|
* Gets the singleton instance of the ConnectionPoolManager.
|
|
40
45
|
* Creates a new instance if one doesn't exist.
|
|
41
46
|
*/
|
|
42
|
-
static getInstance() {
|
|
47
|
+
static getInstance(logger) {
|
|
43
48
|
if (!instance) {
|
|
44
|
-
instance = new ConnectionPoolManager();
|
|
49
|
+
instance = new ConnectionPoolManager(logger);
|
|
45
50
|
}
|
|
46
51
|
return instance;
|
|
47
52
|
}
|
|
@@ -65,49 +70,56 @@ class ConnectionPoolManager {
|
|
|
65
70
|
async getConnection(options) {
|
|
66
71
|
const key = this.makeKey(options);
|
|
67
72
|
let value = this.map.get(key);
|
|
68
|
-
if (
|
|
69
|
-
value =
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
if (value) {
|
|
74
|
+
value.lastUsed = Date.now();
|
|
75
|
+
value.wasUsed(value.pool);
|
|
76
|
+
return value.pool;
|
|
77
|
+
}
|
|
78
|
+
const abortController = new AbortController();
|
|
79
|
+
value = {
|
|
80
|
+
pool: await options.fallBackHandler(abortController),
|
|
81
|
+
abortController,
|
|
82
|
+
wasUsed: options.wasUsed
|
|
83
|
+
};
|
|
84
|
+
if (abortController.signal.aborted) {
|
|
85
|
+
throw new import_n8n_workflow.OperationalError("Could not create pool. Connection attempt was aborted.", {
|
|
86
|
+
cause: abortController.signal.reason
|
|
87
|
+
});
|
|
73
88
|
}
|
|
74
89
|
this.map.set(key, { ...value, lastUsed: Date.now() });
|
|
90
|
+
abortController.signal.addEventListener("abort", async () => {
|
|
91
|
+
this.logger.debug("ConnectionPoolManager: Got abort signal, cleaning up pool.");
|
|
92
|
+
this.cleanupConnection(key);
|
|
93
|
+
});
|
|
75
94
|
return value.pool;
|
|
76
95
|
}
|
|
96
|
+
cleanupConnection(key) {
|
|
97
|
+
const registration = this.map.get(key);
|
|
98
|
+
if (registration) {
|
|
99
|
+
this.map.delete(key);
|
|
100
|
+
registration.abortController.abort();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
77
103
|
/**
|
|
78
104
|
* Removes and cleans up connection pools that haven't been used within the
|
|
79
105
|
* TTL.
|
|
80
106
|
*/
|
|
81
107
|
cleanupStaleConnections() {
|
|
82
108
|
const now = Date.now();
|
|
83
|
-
for (const [key, {
|
|
109
|
+
for (const [key, { lastUsed }] of this.map.entries()) {
|
|
84
110
|
if (now - lastUsed > ttl) {
|
|
85
|
-
|
|
86
|
-
this.
|
|
111
|
+
this.logger.debug("ConnectionPoolManager: Found stale pool. Cleaning it up.");
|
|
112
|
+
void this.cleanupConnection(key);
|
|
87
113
|
}
|
|
88
114
|
}
|
|
89
115
|
}
|
|
90
116
|
/**
|
|
91
117
|
* Removes and cleans up all existing connection pools.
|
|
118
|
+
* Connections are closed in the background.
|
|
92
119
|
*/
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
this.map.delete(key);
|
|
97
|
-
return await value.cleanUpHandler(value.pool);
|
|
98
|
-
})
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Cleans up all connection pools when the process is shutting down.
|
|
103
|
-
* Does not wait for cleanup promises to resolve also does not remove the
|
|
104
|
-
* references from the pool.
|
|
105
|
-
*
|
|
106
|
-
* Only call this on process shutdown.
|
|
107
|
-
*/
|
|
108
|
-
onShutdown() {
|
|
109
|
-
for (const { cleanUpHandler, pool } of this.map.values()) {
|
|
110
|
-
void cleanUpHandler(pool);
|
|
120
|
+
purgeConnections() {
|
|
121
|
+
for (const key of this.map.keys()) {
|
|
122
|
+
this.cleanupConnection(key);
|
|
111
123
|
}
|
|
112
124
|
}
|
|
113
125
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../utils/connection-pool-manager.ts"],"sourcesContent":["import { createHash } from 'crypto';\n\nlet instance: ConnectionPoolManager;\n\n// 5 minutes\nconst ttl = 5 * 60 * 1000;\n\n// 1 minute\nconst cleanUpInterval = 60 * 1000;\n\ntype RegistrationOptions = {\n\tcredentials: unknown;\n\tnodeType: string;\n\tnodeVersion?: string;\n};\n\ntype GetConnectionOption<Pool> = RegistrationOptions & {\n\t
|
|
1
|
+
{"version":3,"sources":["../../utils/connection-pool-manager.ts"],"sourcesContent":["import { createHash } from 'crypto';\nimport { OperationalError, type Logger } from 'n8n-workflow';\n\nlet instance: ConnectionPoolManager;\n\n// 5 minutes\nconst ttl = 5 * 60 * 1000;\n\n// 1 minute\nconst cleanUpInterval = 60 * 1000;\n\ntype RegistrationOptions = {\n\tcredentials: unknown;\n\tnodeType: string;\n\tnodeVersion?: string;\n};\n\ntype GetConnectionOption<Pool> = RegistrationOptions & {\n\t/**\n\t * When a node requests for a connection pool, but none is available, this\n\t * handler is called to create new instance of the pool, which is then cached\n\t * and re-used until it goes stale.\n\t */\n\tfallBackHandler: (abortController: AbortController) => Promise<Pool>;\n\n\twasUsed: (pool: Pool) => void;\n};\n\ntype Registration<Pool> = {\n\t/** This is an instance of a Connection Pool class, that gets reused across multiple executions */\n\tpool: Pool;\n\n\tabortController: AbortController;\n\n\twasUsed: (pool: Pool) => void;\n\n\t/** We keep this timestamp to check if a pool hasn't been used in a while, and if it needs to be closed */\n\tlastUsed: number;\n};\n\nexport class ConnectionPoolManager {\n\t/**\n\t * Gets the singleton instance of the ConnectionPoolManager.\n\t * Creates a new instance if one doesn't exist.\n\t */\n\tstatic getInstance(logger: Logger): ConnectionPoolManager {\n\t\tif (!instance) {\n\t\t\tinstance = new ConnectionPoolManager(logger);\n\t\t}\n\t\treturn instance;\n\t}\n\n\tprivate map = new Map<string, Registration<unknown>>();\n\n\t/**\n\t * Private constructor that initializes the connection pool manager.\n\t * Sets up cleanup handlers for process exit and stale connections.\n\t */\n\tprivate constructor(private readonly logger: Logger) {\n\t\t// Close all open pools when the process exits\n\t\tprocess.on('exit', () => {\n\t\t\tthis.logger.debug('ConnectionPoolManager: Shutting down. Cleaning up all pools');\n\t\t\tthis.purgeConnections();\n\t\t});\n\n\t\t// Regularly close stale pools\n\t\tsetInterval(() => this.cleanupStaleConnections(), cleanUpInterval);\n\t}\n\n\t/**\n\t * Generates a unique key for connection pool identification.\n\t * Hashes the credentials and node information for security.\n\t */\n\tprivate makeKey({ credentials, nodeType, nodeVersion }: RegistrationOptions): string {\n\t\t// The credential contains decrypted secrets, that's why we hash it.\n\t\treturn createHash('sha1')\n\t\t\t.update(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tcredentials,\n\t\t\t\t\tnodeType,\n\t\t\t\t\tnodeVersion,\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.digest('base64');\n\t}\n\n\t/**\n\t * Gets or creates a connection pool for the given options.\n\t * Updates the last used timestamp for existing connections.\n\t */\n\tasync getConnection<T>(options: GetConnectionOption<T>): Promise<T> {\n\t\tconst key = this.makeKey(options);\n\n\t\tlet value = this.map.get(key);\n\n\t\tif (value) {\n\t\t\tvalue.lastUsed = Date.now();\n\t\t\tvalue.wasUsed(value.pool);\n\t\t\treturn value.pool as T;\n\t\t}\n\n\t\tconst abortController = new AbortController();\n\t\tvalue = {\n\t\t\tpool: await options.fallBackHandler(abortController),\n\t\t\tabortController,\n\t\t\twasUsed: options.wasUsed,\n\t\t} as Registration<unknown>;\n\n\t\t// It's possible that `options.fallBackHandler` already called the abort\n\t\t// function. If that's the case let's not continue.\n\t\tif (abortController.signal.aborted) {\n\t\t\tthrow new OperationalError('Could not create pool. Connection attempt was aborted.', {\n\t\t\t\tcause: abortController.signal.reason,\n\t\t\t});\n\t\t}\n\n\t\tthis.map.set(key, { ...value, lastUsed: Date.now() });\n\t\tabortController.signal.addEventListener('abort', async () => {\n\t\t\tthis.logger.debug('ConnectionPoolManager: Got abort signal, cleaning up pool.');\n\t\t\tthis.cleanupConnection(key);\n\t\t});\n\n\t\treturn value.pool as T;\n\t}\n\n\tprivate cleanupConnection(key: string) {\n\t\tconst registration = this.map.get(key);\n\n\t\tif (registration) {\n\t\t\tthis.map.delete(key);\n\t\t\tregistration.abortController.abort();\n\t\t}\n\t}\n\n\t/**\n\t * Removes and cleans up connection pools that haven't been used within the\n\t * TTL.\n\t */\n\tprivate cleanupStaleConnections() {\n\t\tconst now = Date.now();\n\t\tfor (const [key, { lastUsed }] of this.map.entries()) {\n\t\t\tif (now - lastUsed > ttl) {\n\t\t\t\tthis.logger.debug('ConnectionPoolManager: Found stale pool. Cleaning it up.');\n\t\t\t\tvoid this.cleanupConnection(key);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Removes and cleans up all existing connection pools.\n\t * Connections are closed in the background.\n\t */\n\tpurgeConnections(): void {\n\t\tfor (const key of this.map.keys()) {\n\t\t\tthis.cleanupConnection(key);\n\t\t}\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA2B;AAC3B,0BAA8C;AAE9C,IAAI;AAGJ,MAAM,MAAM,IAAI,KAAK;AAGrB,MAAM,kBAAkB,KAAK;AA+BtB,MAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA,EAkB1B,YAA6B,QAAgB;AAAhB;AANrC,SAAQ,MAAM,oBAAI,IAAmC;AAQpD,YAAQ,GAAG,QAAQ,MAAM;AACxB,WAAK,OAAO,MAAM,6DAA6D;AAC/E,WAAK,iBAAiB;AAAA,IACvB,CAAC;AAGD,gBAAY,MAAM,KAAK,wBAAwB,GAAG,eAAe;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA,EAtBA,OAAO,YAAY,QAAuC;AACzD,QAAI,CAAC,UAAU;AACd,iBAAW,IAAI,sBAAsB,MAAM;AAAA,IAC5C;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBQ,QAAQ,EAAE,aAAa,UAAU,YAAY,GAAgC;AAEpF,eAAO,0BAAW,MAAM,EACtB;AAAA,MACA,KAAK,UAAU;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,MACD,CAAC;AAAA,IACF,EACC,OAAO,QAAQ;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAiB,SAA6C;AACnE,UAAM,MAAM,KAAK,QAAQ,OAAO;AAEhC,QAAI,QAAQ,KAAK,IAAI,IAAI,GAAG;AAE5B,QAAI,OAAO;AACV,YAAM,WAAW,KAAK,IAAI;AAC1B,YAAM,QAAQ,MAAM,IAAI;AACxB,aAAO,MAAM;AAAA,IACd;AAEA,UAAM,kBAAkB,IAAI,gBAAgB;AAC5C,YAAQ;AAAA,MACP,MAAM,MAAM,QAAQ,gBAAgB,eAAe;AAAA,MACnD;AAAA,MACA,SAAS,QAAQ;AAAA,IAClB;AAIA,QAAI,gBAAgB,OAAO,SAAS;AACnC,YAAM,IAAI,qCAAiB,0DAA0D;AAAA,QACpF,OAAO,gBAAgB,OAAO;AAAA,MAC/B,CAAC;AAAA,IACF;AAEA,SAAK,IAAI,IAAI,KAAK,EAAE,GAAG,OAAO,UAAU,KAAK,IAAI,EAAE,CAAC;AACpD,oBAAgB,OAAO,iBAAiB,SAAS,YAAY;AAC5D,WAAK,OAAO,MAAM,4DAA4D;AAC9E,WAAK,kBAAkB,GAAG;AAAA,IAC3B,CAAC;AAED,WAAO,MAAM;AAAA,EACd;AAAA,EAEQ,kBAAkB,KAAa;AACtC,UAAM,eAAe,KAAK,IAAI,IAAI,GAAG;AAErC,QAAI,cAAc;AACjB,WAAK,IAAI,OAAO,GAAG;AACnB,mBAAa,gBAAgB,MAAM;AAAA,IACpC;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,0BAA0B;AACjC,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,KAAK,EAAE,SAAS,CAAC,KAAK,KAAK,IAAI,QAAQ,GAAG;AACrD,UAAI,MAAM,WAAW,KAAK;AACzB,aAAK,OAAO,MAAM,0DAA0D;AAC5E,aAAK,KAAK,kBAAkB,GAAG;AAAA,MAChC;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBAAyB;AACxB,eAAW,OAAO,KAAK,IAAI,KAAK,GAAG;AAClC,WAAK,kBAAkB,GAAG;AAAA,IAC3B;AAAA,EACD;AACD;","names":[]}
|
|
@@ -41,7 +41,7 @@ var import_descriptions = require("./descriptions");
|
|
|
41
41
|
var import_email_templates = require("./email-templates");
|
|
42
42
|
var import_cssVariables = require("../../nodes/Form/cssVariables");
|
|
43
43
|
var import_Form = require("../../nodes/Form/Form.node");
|
|
44
|
-
var import_utils = require("../../nodes/Form/utils
|
|
44
|
+
var import_utils = require("../../nodes/Form/utils");
|
|
45
45
|
var import_utilities = require("../utilities");
|
|
46
46
|
const INPUT_FIELD_IDENTIFIER = "field-0";
|
|
47
47
|
const limitWaitTimeOption = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../utils/sendAndWait/utils.ts"],"sourcesContent":["import isbot from 'isbot';\nimport {\n\tNodeOperationError,\n\tSEND_AND_WAIT_OPERATION,\n\ttryToParseJsonToFormFields,\n\tupdateDisplayOptions,\n} from 'n8n-workflow';\nimport type {\n\tINodeProperties,\n\tIExecuteFunctions,\n\tIWebhookFunctions,\n\tIDataObject,\n\tFormFieldsParameter,\n} from 'n8n-workflow';\n\nimport { limitWaitTimeProperties } from './descriptions';\nimport {\n\tACTION_RECORDED_PAGE,\n\tBUTTON_STYLE_PRIMARY,\n\tBUTTON_STYLE_SECONDARY,\n\tcreateEmailBodyWithN8nAttribution,\n\tcreateEmailBodyWithoutN8nAttribution,\n} from './email-templates';\nimport type { IEmail } from './interfaces';\nimport { cssVariables } from '../../nodes/Form/cssVariables';\nimport { formFieldsProperties } from '../../nodes/Form/Form.node';\nimport {\n\tprepareFormData,\n\tprepareFormReturnItem,\n\tresolveRawData,\n} from '../../nodes/Form/utils/utils';\nimport { escapeHtml } from '../utilities';\n\nexport type SendAndWaitConfig = {\n\ttitle: string;\n\tmessage: string;\n\turl: string;\n\toptions: Array<{ label: string; value: string; style: string }>;\n\tappendAttribution?: boolean;\n};\n\ntype FormResponseTypeOptions = {\n\tmessageButtonLabel?: string;\n\tresponseFormTitle?: string;\n\tresponseFormDescription?: string;\n\tresponseFormButtonLabel?: string;\n\tresponseFormCustomCss?: string;\n};\n\nconst INPUT_FIELD_IDENTIFIER = 'field-0';\n\nconst limitWaitTimeOption: INodeProperties = {\n\tdisplayName: 'Limit Wait Time',\n\tname: 'limitWaitTime',\n\ttype: 'fixedCollection',\n\tdescription:\n\t\t'Whether the workflow will automatically resume execution after the specified limit type',\n\tdefault: { values: { limitType: 'afterTimeInterval', resumeAmount: 45, resumeUnit: 'minutes' } },\n\toptions: [\n\t\t{\n\t\t\tdisplayName: 'Values',\n\t\t\tname: 'values',\n\t\t\tvalues: limitWaitTimeProperties,\n\t\t},\n\t],\n};\n\nconst appendAttributionOption: INodeProperties = {\n\tdisplayName: 'Append n8n Attribution',\n\tname: 'appendAttribution',\n\ttype: 'boolean',\n\tdefault: true,\n\tdescription:\n\t\t'Whether to include the phrase \"This message was sent automatically with n8n\" to the end of the message',\n};\n\n// Operation Properties ----------------------------------------------------------\nexport function getSendAndWaitProperties(\n\ttargetProperties: INodeProperties[],\n\tresource: string = 'message',\n\tadditionalProperties: INodeProperties[] = [],\n\toptions?: {\n\t\tnoButtonStyle?: boolean;\n\t\tdefaultApproveLabel?: string;\n\t\tdefaultDisapproveLabel?: string;\n\t},\n) {\n\tconst buttonStyle: INodeProperties = {\n\t\tdisplayName: 'Button Style',\n\t\tname: 'buttonStyle',\n\t\ttype: 'options',\n\t\tdefault: 'primary',\n\t\toptions: [\n\t\t\t{\n\t\t\t\tname: 'Primary',\n\t\t\t\tvalue: 'primary',\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'Secondary',\n\t\t\t\tvalue: 'secondary',\n\t\t\t},\n\t\t],\n\t};\n\tconst approvalOptionsValues = [\n\t\t{\n\t\t\tdisplayName: 'Type of Approval',\n\t\t\tname: 'approvalType',\n\t\t\ttype: 'options',\n\t\t\tplaceholder: 'Add option',\n\t\t\tdefault: 'single',\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tname: 'Approve Only',\n\t\t\t\t\tvalue: 'single',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'Approve and Disapprove',\n\t\t\t\t\tvalue: 'double',\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\tdisplayName: 'Approve Button Label',\n\t\t\tname: 'approveLabel',\n\t\t\ttype: 'string',\n\t\t\tdefault: options?.defaultApproveLabel || 'Approve',\n\t\t\tdisplayOptions: {\n\t\t\t\tshow: {\n\t\t\t\t\tapprovalType: ['single', 'double'],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t...[\n\t\t\toptions?.noButtonStyle\n\t\t\t\t? ({} as INodeProperties)\n\t\t\t\t: {\n\t\t\t\t\t\t...buttonStyle,\n\t\t\t\t\t\tdisplayName: 'Approve Button Style',\n\t\t\t\t\t\tname: 'buttonApprovalStyle',\n\t\t\t\t\t\tdisplayOptions: {\n\t\t\t\t\t\t\tshow: {\n\t\t\t\t\t\t\t\tapprovalType: ['single', 'double'],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t],\n\t\t{\n\t\t\tdisplayName: 'Disapprove Button Label',\n\t\t\tname: 'disapproveLabel',\n\t\t\ttype: 'string',\n\t\t\tdefault: options?.defaultDisapproveLabel || 'Decline',\n\t\t\tdisplayOptions: {\n\t\t\t\tshow: {\n\t\t\t\t\tapprovalType: ['double'],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t...[\n\t\t\toptions?.noButtonStyle\n\t\t\t\t? ({} as INodeProperties)\n\t\t\t\t: {\n\t\t\t\t\t\t...buttonStyle,\n\t\t\t\t\t\tdisplayName: 'Disapprove Button Style',\n\t\t\t\t\t\tname: 'buttonDisapprovalStyle',\n\t\t\t\t\t\tdefault: 'secondary',\n\t\t\t\t\t\tdisplayOptions: {\n\t\t\t\t\t\t\tshow: {\n\t\t\t\t\t\t\t\tapprovalType: ['double'],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t],\n\t].filter((p) => Object.keys(p).length) as INodeProperties[];\n\n\tconst sendAndWait: INodeProperties[] = [\n\t\t...targetProperties,\n\t\t{\n\t\t\tdisplayName: 'Subject',\n\t\t\tname: 'subject',\n\t\t\ttype: 'string',\n\t\t\tdefault: '',\n\t\t\trequired: true,\n\t\t\tplaceholder: 'e.g. Approval required',\n\t\t},\n\t\t{\n\t\t\tdisplayName: 'Message',\n\t\t\tname: 'message',\n\t\t\ttype: 'string',\n\t\t\tdefault: '',\n\t\t\trequired: true,\n\t\t\ttypeOptions: {\n\t\t\t\trows: 4,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tdisplayName: 'Response Type',\n\t\t\tname: 'responseType',\n\t\t\ttype: 'options',\n\t\t\tdefault: 'approval',\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tname: 'Approval',\n\t\t\t\t\tvalue: 'approval',\n\t\t\t\t\tdescription: 'User can approve/disapprove from within the message',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'Free Text',\n\t\t\t\t\tvalue: 'freeText',\n\t\t\t\t\tdescription: 'User can submit a response via a form',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'Custom Form',\n\t\t\t\t\tvalue: 'customForm',\n\t\t\t\t\tdescription: 'User can submit a response via a custom form',\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\t...updateDisplayOptions(\n\t\t\t{\n\t\t\t\tshow: {\n\t\t\t\t\tresponseType: ['customForm'],\n\t\t\t\t},\n\t\t\t},\n\t\t\tformFieldsProperties,\n\t\t),\n\n\t\t{\n\t\t\tdisplayName: 'Approval Options',\n\t\t\tname: 'approvalOptions',\n\t\t\ttype: 'fixedCollection',\n\t\t\tplaceholder: 'Add option',\n\t\t\tdefault: {},\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tdisplayName: 'Values',\n\t\t\t\t\tname: 'values',\n\t\t\t\t\tvalues: approvalOptionsValues,\n\t\t\t\t},\n\t\t\t],\n\t\t\tdisplayOptions: {\n\t\t\t\tshow: {\n\t\t\t\t\tresponseType: ['approval'],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tdisplayName: 'Options',\n\t\t\tname: 'options',\n\t\t\ttype: 'collection',\n\t\t\tplaceholder: 'Add option',\n\t\t\tdefault: {},\n\t\t\toptions: [limitWaitTimeOption, appendAttributionOption],\n\t\t\tdisplayOptions: {\n\t\t\t\tshow: {\n\t\t\t\t\tresponseType: ['approval'],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tdisplayName: 'Options',\n\t\t\tname: 'options',\n\t\t\ttype: 'collection',\n\t\t\tplaceholder: 'Add option',\n\t\t\tdefault: {},\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tdisplayName: 'Message Button Label',\n\t\t\t\t\tname: 'messageButtonLabel',\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: 'Respond',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdisplayName: 'Response Form Title',\n\t\t\t\t\tname: 'responseFormTitle',\n\t\t\t\t\tdescription: 'Title of the form that the user can access to provide their response',\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: '',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdisplayName: 'Response Form Description',\n\t\t\t\t\tname: 'responseFormDescription',\n\t\t\t\t\tdescription: 'Description of the form that the user can access to provide their response',\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: '',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdisplayName: 'Response Form Button Label',\n\t\t\t\t\tname: 'responseFormButtonLabel',\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: 'Submit',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdisplayName: 'Response Form Custom Styling',\n\t\t\t\t\tname: 'responseFormCustomCss',\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\trows: 10,\n\t\t\t\t\t\teditor: 'cssEditor',\n\t\t\t\t\t},\n\t\t\t\t\tdefault: cssVariables.trim(),\n\t\t\t\t\tdescription: 'Override default styling of the response form with CSS',\n\t\t\t\t},\n\t\t\t\tlimitWaitTimeOption,\n\t\t\t\tappendAttributionOption,\n\t\t\t],\n\t\t\tdisplayOptions: {\n\t\t\t\tshow: {\n\t\t\t\t\tresponseType: ['freeText', 'customForm'],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t...additionalProperties,\n\t];\n\n\treturn updateDisplayOptions(\n\t\t{\n\t\t\tshow: {\n\t\t\t\tresource: [resource],\n\t\t\t\toperation: [SEND_AND_WAIT_OPERATION],\n\t\t\t},\n\t\t},\n\t\tsendAndWait,\n\t);\n}\n\n// Webhook Function --------------------------------------------------------------\nconst getFormResponseCustomizations = (context: IWebhookFunctions) => {\n\tconst message = context.getNodeParameter('message', '') as string;\n\tconst options = context.getNodeParameter('options', {}) as FormResponseTypeOptions;\n\n\tlet formTitle = '';\n\tif (options.responseFormTitle) {\n\t\tformTitle = options.responseFormTitle;\n\t}\n\n\tlet formDescription = message;\n\tif (options.responseFormDescription) {\n\t\tformDescription = options.responseFormDescription;\n\t}\n\tformDescription = formDescription.replace(/\\\\n/g, '\\n').replace(/<br>/g, '\\n');\n\n\tlet buttonLabel = 'Submit';\n\tif (options.responseFormButtonLabel) {\n\t\tbuttonLabel = options.responseFormButtonLabel;\n\t}\n\n\treturn {\n\t\tformTitle,\n\t\tformDescription,\n\t\tbuttonLabel,\n\t\tcustomCss: options.responseFormCustomCss,\n\t};\n};\n\nexport async function sendAndWaitWebhook(this: IWebhookFunctions) {\n\tconst method = this.getRequestObject().method;\n\tconst res = this.getResponseObject();\n\tconst req = this.getRequestObject();\n\n\tconst responseType = this.getNodeParameter('responseType', 'approval') as\n\t\t| 'approval'\n\t\t| 'freeText'\n\t\t| 'customForm';\n\n\tif (responseType === 'approval' && isbot(req.headers['user-agent'])) {\n\t\tres.send('');\n\t\treturn { noWebhookResponse: true };\n\t}\n\n\tif (responseType === 'freeText') {\n\t\tif (method === 'GET') {\n\t\t\tconst { formTitle, formDescription, buttonLabel, customCss } =\n\t\t\t\tgetFormResponseCustomizations(this);\n\n\t\t\tconst data = prepareFormData({\n\t\t\t\tformTitle,\n\t\t\t\tformDescription,\n\t\t\t\tformSubmittedHeader: 'Got it, thanks',\n\t\t\t\tformSubmittedText: 'This page can be closed now',\n\t\t\t\tbuttonLabel,\n\t\t\t\tredirectUrl: undefined,\n\t\t\t\tformFields: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfieldLabel: 'Response',\n\t\t\t\t\t\tfieldType: 'textarea',\n\t\t\t\t\t\trequiredField: true,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\ttestRun: false,\n\t\t\t\tquery: {},\n\t\t\t\tcustomCss,\n\t\t\t});\n\n\t\t\tres.render('form-trigger', data);\n\n\t\t\treturn {\n\t\t\t\tnoWebhookResponse: true,\n\t\t\t};\n\t\t}\n\t\tif (method === 'POST') {\n\t\t\tconst data = this.getBodyData().data as IDataObject;\n\n\t\t\treturn {\n\t\t\t\twebhookResponse: ACTION_RECORDED_PAGE,\n\t\t\t\tworkflowData: [[{ json: { data: { text: data[INPUT_FIELD_IDENTIFIER] } } }]],\n\t\t\t};\n\t\t}\n\t}\n\n\tif (responseType === 'customForm') {\n\t\tconst defineForm = this.getNodeParameter('defineForm', 'fields') as 'fields' | 'json';\n\t\tlet fields: FormFieldsParameter = [];\n\n\t\tif (defineForm === 'json') {\n\t\t\ttry {\n\t\t\t\tconst jsonOutput = this.getNodeParameter('jsonOutput', '', {\n\t\t\t\t\trawExpressions: true,\n\t\t\t\t}) as string;\n\n\t\t\t\tfields = tryToParseJsonToFormFields(resolveRawData(this, jsonOutput));\n\t\t\t} catch (error) {\n\t\t\t\tthrow new NodeOperationError(this.getNode(), error.message, {\n\t\t\t\t\tdescription: error.message,\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tfields = this.getNodeParameter('formFields.values', []) as FormFieldsParameter;\n\t\t}\n\n\t\tif (method === 'GET') {\n\t\t\tconst { formTitle, formDescription, buttonLabel, customCss } =\n\t\t\t\tgetFormResponseCustomizations(this);\n\n\t\t\tconst data = prepareFormData({\n\t\t\t\tformTitle,\n\t\t\t\tformDescription,\n\t\t\t\tformSubmittedHeader: 'Got it, thanks',\n\t\t\t\tformSubmittedText: 'This page can be closed now',\n\t\t\t\tbuttonLabel,\n\t\t\t\tredirectUrl: undefined,\n\t\t\t\tformFields: fields,\n\t\t\t\ttestRun: false,\n\t\t\t\tquery: {},\n\t\t\t\tcustomCss,\n\t\t\t});\n\n\t\t\tres.render('form-trigger', data);\n\n\t\t\treturn {\n\t\t\t\tnoWebhookResponse: true,\n\t\t\t};\n\t\t}\n\t\tif (method === 'POST') {\n\t\t\tconst returnItem = await prepareFormReturnItem(this, fields, 'production', true);\n\t\t\tconst json = returnItem.json;\n\n\t\t\tdelete json.submittedAt;\n\t\t\tdelete json.formMode;\n\n\t\t\treturnItem.json = { data: json };\n\n\t\t\treturn {\n\t\t\t\twebhookResponse: ACTION_RECORDED_PAGE,\n\t\t\t\tworkflowData: [[returnItem]],\n\t\t\t};\n\t\t}\n\t}\n\n\tconst query = req.query as { approved: 'false' | 'true' };\n\tconst approved = query.approved === 'true';\n\treturn {\n\t\twebhookResponse: ACTION_RECORDED_PAGE,\n\t\tworkflowData: [[{ json: { data: { approved } } }]],\n\t};\n}\n\n// Send and Wait Config -----------------------------------------------------------\nexport function getSendAndWaitConfig(context: IExecuteFunctions): SendAndWaitConfig {\n\tconst message = escapeHtml((context.getNodeParameter('message', 0, '') as string).trim())\n\t\t.replace(/\\\\n/g, '\\n')\n\t\t.replace(/<br>/g, '\\n');\n\tconst subject = escapeHtml(context.getNodeParameter('subject', 0, '') as string);\n\tconst resumeUrl = context.evaluateExpression('{{ $execution?.resumeUrl }}', 0) as string;\n\tconst nodeId = context.evaluateExpression('{{ $nodeId }}', 0) as string;\n\tconst approvalOptions = context.getNodeParameter('approvalOptions.values', 0, {}) as {\n\t\tapprovalType?: 'single' | 'double';\n\t\tapproveLabel?: string;\n\t\tbuttonApprovalStyle?: string;\n\t\tdisapproveLabel?: string;\n\t\tbuttonDisapprovalStyle?: string;\n\t};\n\n\tconst options = context.getNodeParameter('options', 0, {});\n\n\tconst config: SendAndWaitConfig = {\n\t\ttitle: subject,\n\t\tmessage,\n\t\turl: `${resumeUrl}/${nodeId}`,\n\t\toptions: [],\n\t\tappendAttribution: options?.appendAttribution as boolean,\n\t};\n\n\tconst responseType = context.getNodeParameter('responseType', 0, 'approval') as string;\n\n\tif (responseType === 'freeText' || responseType === 'customForm') {\n\t\tconst label = context.getNodeParameter('options.messageButtonLabel', 0, 'Respond') as string;\n\t\tconfig.options.push({\n\t\t\tlabel,\n\t\t\tvalue: 'true',\n\t\t\tstyle: 'primary',\n\t\t});\n\t} else if (approvalOptions.approvalType === 'double') {\n\t\tconst approveLabel = escapeHtml(approvalOptions.approveLabel || 'Approve');\n\t\tconst buttonApprovalStyle = approvalOptions.buttonApprovalStyle || 'primary';\n\t\tconst disapproveLabel = escapeHtml(approvalOptions.disapproveLabel || 'Disapprove');\n\t\tconst buttonDisapprovalStyle = approvalOptions.buttonDisapprovalStyle || 'secondary';\n\n\t\tconfig.options.push({\n\t\t\tlabel: disapproveLabel,\n\t\t\tvalue: 'false',\n\t\t\tstyle: buttonDisapprovalStyle,\n\t\t});\n\t\tconfig.options.push({\n\t\t\tlabel: approveLabel,\n\t\t\tvalue: 'true',\n\t\t\tstyle: buttonApprovalStyle,\n\t\t});\n\t} else {\n\t\tconst label = escapeHtml(approvalOptions.approveLabel || 'Approve');\n\t\tconst style = approvalOptions.buttonApprovalStyle || 'primary';\n\t\tconfig.options.push({\n\t\t\tlabel,\n\t\t\tvalue: 'true',\n\t\t\tstyle,\n\t\t});\n\t}\n\n\treturn config;\n}\n\nexport function createButton(url: string, label: string, approved: string, style: string) {\n\tlet buttonStyle = BUTTON_STYLE_PRIMARY;\n\tif (style === 'secondary') {\n\t\tbuttonStyle = BUTTON_STYLE_SECONDARY;\n\t}\n\treturn `<a href=\"${url}?approved=${approved}\" target=\"_blank\" style=\"${buttonStyle}\">${label}</a>`;\n}\n\nexport function createEmail(context: IExecuteFunctions) {\n\tconst to = (context.getNodeParameter('sendTo', 0, '') as string).trim();\n\tconst config = getSendAndWaitConfig(context);\n\n\tif (to.indexOf('@') === -1 || (to.match(/@/g) || []).length > 1) {\n\t\tconst description = `The email address '${to}' in the 'To' field isn't valid or contains multiple addresses. Please provide only a single email address.`;\n\t\tthrow new NodeOperationError(context.getNode(), 'Invalid email address', {\n\t\t\tdescription,\n\t\t\titemIndex: 0,\n\t\t});\n\t}\n\n\tconst buttons: string[] = [];\n\tfor (const option of config.options) {\n\t\tbuttons.push(createButton(config.url, option.label, option.value, option.style));\n\t}\n\tlet emailBody: string;\n\tif (config.appendAttribution !== false) {\n\t\tconst instanceId = context.getInstanceId();\n\t\temailBody = createEmailBodyWithN8nAttribution(config.message, buttons.join('\\n'), instanceId);\n\t} else {\n\t\temailBody = createEmailBodyWithoutN8nAttribution(config.message, buttons.join('\\n'));\n\t}\n\n\tconst email: IEmail = {\n\t\tto,\n\t\tsubject: config.title,\n\t\tbody: '',\n\t\thtmlBody: emailBody,\n\t};\n\n\treturn email;\n}\n"],"mappings":"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","names":["isbot"]}
|
|
1
|
+
{"version":3,"sources":["../../../utils/sendAndWait/utils.ts"],"sourcesContent":["import isbot from 'isbot';\nimport {\n\tNodeOperationError,\n\tSEND_AND_WAIT_OPERATION,\n\ttryToParseJsonToFormFields,\n\tupdateDisplayOptions,\n} from 'n8n-workflow';\nimport type {\n\tINodeProperties,\n\tIExecuteFunctions,\n\tIWebhookFunctions,\n\tIDataObject,\n\tFormFieldsParameter,\n} from 'n8n-workflow';\n\nimport { limitWaitTimeProperties } from './descriptions';\nimport {\n\tACTION_RECORDED_PAGE,\n\tBUTTON_STYLE_PRIMARY,\n\tBUTTON_STYLE_SECONDARY,\n\tcreateEmailBodyWithN8nAttribution,\n\tcreateEmailBodyWithoutN8nAttribution,\n} from './email-templates';\nimport type { IEmail } from './interfaces';\nimport { cssVariables } from '../../nodes/Form/cssVariables';\nimport { formFieldsProperties } from '../../nodes/Form/Form.node';\nimport { prepareFormData, prepareFormReturnItem, resolveRawData } from '../../nodes/Form/utils';\nimport { escapeHtml } from '../utilities';\n\nexport type SendAndWaitConfig = {\n\ttitle: string;\n\tmessage: string;\n\turl: string;\n\toptions: Array<{ label: string; value: string; style: string }>;\n\tappendAttribution?: boolean;\n};\n\ntype FormResponseTypeOptions = {\n\tmessageButtonLabel?: string;\n\tresponseFormTitle?: string;\n\tresponseFormDescription?: string;\n\tresponseFormButtonLabel?: string;\n\tresponseFormCustomCss?: string;\n};\n\nconst INPUT_FIELD_IDENTIFIER = 'field-0';\n\nconst limitWaitTimeOption: INodeProperties = {\n\tdisplayName: 'Limit Wait Time',\n\tname: 'limitWaitTime',\n\ttype: 'fixedCollection',\n\tdescription:\n\t\t'Whether the workflow will automatically resume execution after the specified limit type',\n\tdefault: { values: { limitType: 'afterTimeInterval', resumeAmount: 45, resumeUnit: 'minutes' } },\n\toptions: [\n\t\t{\n\t\t\tdisplayName: 'Values',\n\t\t\tname: 'values',\n\t\t\tvalues: limitWaitTimeProperties,\n\t\t},\n\t],\n};\n\nconst appendAttributionOption: INodeProperties = {\n\tdisplayName: 'Append n8n Attribution',\n\tname: 'appendAttribution',\n\ttype: 'boolean',\n\tdefault: true,\n\tdescription:\n\t\t'Whether to include the phrase \"This message was sent automatically with n8n\" to the end of the message',\n};\n\n// Operation Properties ----------------------------------------------------------\nexport function getSendAndWaitProperties(\n\ttargetProperties: INodeProperties[],\n\tresource: string = 'message',\n\tadditionalProperties: INodeProperties[] = [],\n\toptions?: {\n\t\tnoButtonStyle?: boolean;\n\t\tdefaultApproveLabel?: string;\n\t\tdefaultDisapproveLabel?: string;\n\t},\n) {\n\tconst buttonStyle: INodeProperties = {\n\t\tdisplayName: 'Button Style',\n\t\tname: 'buttonStyle',\n\t\ttype: 'options',\n\t\tdefault: 'primary',\n\t\toptions: [\n\t\t\t{\n\t\t\t\tname: 'Primary',\n\t\t\t\tvalue: 'primary',\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'Secondary',\n\t\t\t\tvalue: 'secondary',\n\t\t\t},\n\t\t],\n\t};\n\tconst approvalOptionsValues = [\n\t\t{\n\t\t\tdisplayName: 'Type of Approval',\n\t\t\tname: 'approvalType',\n\t\t\ttype: 'options',\n\t\t\tplaceholder: 'Add option',\n\t\t\tdefault: 'single',\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tname: 'Approve Only',\n\t\t\t\t\tvalue: 'single',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'Approve and Disapprove',\n\t\t\t\t\tvalue: 'double',\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\tdisplayName: 'Approve Button Label',\n\t\t\tname: 'approveLabel',\n\t\t\ttype: 'string',\n\t\t\tdefault: options?.defaultApproveLabel || 'Approve',\n\t\t\tdisplayOptions: {\n\t\t\t\tshow: {\n\t\t\t\t\tapprovalType: ['single', 'double'],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t...[\n\t\t\toptions?.noButtonStyle\n\t\t\t\t? ({} as INodeProperties)\n\t\t\t\t: {\n\t\t\t\t\t\t...buttonStyle,\n\t\t\t\t\t\tdisplayName: 'Approve Button Style',\n\t\t\t\t\t\tname: 'buttonApprovalStyle',\n\t\t\t\t\t\tdisplayOptions: {\n\t\t\t\t\t\t\tshow: {\n\t\t\t\t\t\t\t\tapprovalType: ['single', 'double'],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t],\n\t\t{\n\t\t\tdisplayName: 'Disapprove Button Label',\n\t\t\tname: 'disapproveLabel',\n\t\t\ttype: 'string',\n\t\t\tdefault: options?.defaultDisapproveLabel || 'Decline',\n\t\t\tdisplayOptions: {\n\t\t\t\tshow: {\n\t\t\t\t\tapprovalType: ['double'],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t...[\n\t\t\toptions?.noButtonStyle\n\t\t\t\t? ({} as INodeProperties)\n\t\t\t\t: {\n\t\t\t\t\t\t...buttonStyle,\n\t\t\t\t\t\tdisplayName: 'Disapprove Button Style',\n\t\t\t\t\t\tname: 'buttonDisapprovalStyle',\n\t\t\t\t\t\tdefault: 'secondary',\n\t\t\t\t\t\tdisplayOptions: {\n\t\t\t\t\t\t\tshow: {\n\t\t\t\t\t\t\t\tapprovalType: ['double'],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t],\n\t].filter((p) => Object.keys(p).length) as INodeProperties[];\n\n\tconst sendAndWait: INodeProperties[] = [\n\t\t...targetProperties,\n\t\t{\n\t\t\tdisplayName: 'Subject',\n\t\t\tname: 'subject',\n\t\t\ttype: 'string',\n\t\t\tdefault: '',\n\t\t\trequired: true,\n\t\t\tplaceholder: 'e.g. Approval required',\n\t\t},\n\t\t{\n\t\t\tdisplayName: 'Message',\n\t\t\tname: 'message',\n\t\t\ttype: 'string',\n\t\t\tdefault: '',\n\t\t\trequired: true,\n\t\t\ttypeOptions: {\n\t\t\t\trows: 4,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tdisplayName: 'Response Type',\n\t\t\tname: 'responseType',\n\t\t\ttype: 'options',\n\t\t\tdefault: 'approval',\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tname: 'Approval',\n\t\t\t\t\tvalue: 'approval',\n\t\t\t\t\tdescription: 'User can approve/disapprove from within the message',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'Free Text',\n\t\t\t\t\tvalue: 'freeText',\n\t\t\t\t\tdescription: 'User can submit a response via a form',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'Custom Form',\n\t\t\t\t\tvalue: 'customForm',\n\t\t\t\t\tdescription: 'User can submit a response via a custom form',\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\t...updateDisplayOptions(\n\t\t\t{\n\t\t\t\tshow: {\n\t\t\t\t\tresponseType: ['customForm'],\n\t\t\t\t},\n\t\t\t},\n\t\t\tformFieldsProperties,\n\t\t),\n\n\t\t{\n\t\t\tdisplayName: 'Approval Options',\n\t\t\tname: 'approvalOptions',\n\t\t\ttype: 'fixedCollection',\n\t\t\tplaceholder: 'Add option',\n\t\t\tdefault: {},\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tdisplayName: 'Values',\n\t\t\t\t\tname: 'values',\n\t\t\t\t\tvalues: approvalOptionsValues,\n\t\t\t\t},\n\t\t\t],\n\t\t\tdisplayOptions: {\n\t\t\t\tshow: {\n\t\t\t\t\tresponseType: ['approval'],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tdisplayName: 'Options',\n\t\t\tname: 'options',\n\t\t\ttype: 'collection',\n\t\t\tplaceholder: 'Add option',\n\t\t\tdefault: {},\n\t\t\toptions: [limitWaitTimeOption, appendAttributionOption],\n\t\t\tdisplayOptions: {\n\t\t\t\tshow: {\n\t\t\t\t\tresponseType: ['approval'],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tdisplayName: 'Options',\n\t\t\tname: 'options',\n\t\t\ttype: 'collection',\n\t\t\tplaceholder: 'Add option',\n\t\t\tdefault: {},\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tdisplayName: 'Message Button Label',\n\t\t\t\t\tname: 'messageButtonLabel',\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: 'Respond',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdisplayName: 'Response Form Title',\n\t\t\t\t\tname: 'responseFormTitle',\n\t\t\t\t\tdescription: 'Title of the form that the user can access to provide their response',\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: '',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdisplayName: 'Response Form Description',\n\t\t\t\t\tname: 'responseFormDescription',\n\t\t\t\t\tdescription: 'Description of the form that the user can access to provide their response',\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: '',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdisplayName: 'Response Form Button Label',\n\t\t\t\t\tname: 'responseFormButtonLabel',\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: 'Submit',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdisplayName: 'Response Form Custom Styling',\n\t\t\t\t\tname: 'responseFormCustomCss',\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\ttypeOptions: {\n\t\t\t\t\t\trows: 10,\n\t\t\t\t\t\teditor: 'cssEditor',\n\t\t\t\t\t},\n\t\t\t\t\tdefault: cssVariables.trim(),\n\t\t\t\t\tdescription: 'Override default styling of the response form with CSS',\n\t\t\t\t},\n\t\t\t\tlimitWaitTimeOption,\n\t\t\t\tappendAttributionOption,\n\t\t\t],\n\t\t\tdisplayOptions: {\n\t\t\t\tshow: {\n\t\t\t\t\tresponseType: ['freeText', 'customForm'],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t...additionalProperties,\n\t];\n\n\treturn updateDisplayOptions(\n\t\t{\n\t\t\tshow: {\n\t\t\t\tresource: [resource],\n\t\t\t\toperation: [SEND_AND_WAIT_OPERATION],\n\t\t\t},\n\t\t},\n\t\tsendAndWait,\n\t);\n}\n\n// Webhook Function --------------------------------------------------------------\nconst getFormResponseCustomizations = (context: IWebhookFunctions) => {\n\tconst message = context.getNodeParameter('message', '') as string;\n\tconst options = context.getNodeParameter('options', {}) as FormResponseTypeOptions;\n\n\tlet formTitle = '';\n\tif (options.responseFormTitle) {\n\t\tformTitle = options.responseFormTitle;\n\t}\n\n\tlet formDescription = message;\n\tif (options.responseFormDescription) {\n\t\tformDescription = options.responseFormDescription;\n\t}\n\tformDescription = formDescription.replace(/\\\\n/g, '\\n').replace(/<br>/g, '\\n');\n\n\tlet buttonLabel = 'Submit';\n\tif (options.responseFormButtonLabel) {\n\t\tbuttonLabel = options.responseFormButtonLabel;\n\t}\n\n\treturn {\n\t\tformTitle,\n\t\tformDescription,\n\t\tbuttonLabel,\n\t\tcustomCss: options.responseFormCustomCss,\n\t};\n};\n\nexport async function sendAndWaitWebhook(this: IWebhookFunctions) {\n\tconst method = this.getRequestObject().method;\n\tconst res = this.getResponseObject();\n\tconst req = this.getRequestObject();\n\n\tconst responseType = this.getNodeParameter('responseType', 'approval') as\n\t\t| 'approval'\n\t\t| 'freeText'\n\t\t| 'customForm';\n\n\tif (responseType === 'approval' && isbot(req.headers['user-agent'])) {\n\t\tres.send('');\n\t\treturn { noWebhookResponse: true };\n\t}\n\n\tif (responseType === 'freeText') {\n\t\tif (method === 'GET') {\n\t\t\tconst { formTitle, formDescription, buttonLabel, customCss } =\n\t\t\t\tgetFormResponseCustomizations(this);\n\n\t\t\tconst data = prepareFormData({\n\t\t\t\tformTitle,\n\t\t\t\tformDescription,\n\t\t\t\tformSubmittedHeader: 'Got it, thanks',\n\t\t\t\tformSubmittedText: 'This page can be closed now',\n\t\t\t\tbuttonLabel,\n\t\t\t\tredirectUrl: undefined,\n\t\t\t\tformFields: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfieldLabel: 'Response',\n\t\t\t\t\t\tfieldType: 'textarea',\n\t\t\t\t\t\trequiredField: true,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\ttestRun: false,\n\t\t\t\tquery: {},\n\t\t\t\tcustomCss,\n\t\t\t});\n\n\t\t\tres.render('form-trigger', data);\n\n\t\t\treturn {\n\t\t\t\tnoWebhookResponse: true,\n\t\t\t};\n\t\t}\n\t\tif (method === 'POST') {\n\t\t\tconst data = this.getBodyData().data as IDataObject;\n\n\t\t\treturn {\n\t\t\t\twebhookResponse: ACTION_RECORDED_PAGE,\n\t\t\t\tworkflowData: [[{ json: { data: { text: data[INPUT_FIELD_IDENTIFIER] } } }]],\n\t\t\t};\n\t\t}\n\t}\n\n\tif (responseType === 'customForm') {\n\t\tconst defineForm = this.getNodeParameter('defineForm', 'fields') as 'fields' | 'json';\n\t\tlet fields: FormFieldsParameter = [];\n\n\t\tif (defineForm === 'json') {\n\t\t\ttry {\n\t\t\t\tconst jsonOutput = this.getNodeParameter('jsonOutput', '', {\n\t\t\t\t\trawExpressions: true,\n\t\t\t\t}) as string;\n\n\t\t\t\tfields = tryToParseJsonToFormFields(resolveRawData(this, jsonOutput));\n\t\t\t} catch (error) {\n\t\t\t\tthrow new NodeOperationError(this.getNode(), error.message, {\n\t\t\t\t\tdescription: error.message,\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tfields = this.getNodeParameter('formFields.values', []) as FormFieldsParameter;\n\t\t}\n\n\t\tif (method === 'GET') {\n\t\t\tconst { formTitle, formDescription, buttonLabel, customCss } =\n\t\t\t\tgetFormResponseCustomizations(this);\n\n\t\t\tconst data = prepareFormData({\n\t\t\t\tformTitle,\n\t\t\t\tformDescription,\n\t\t\t\tformSubmittedHeader: 'Got it, thanks',\n\t\t\t\tformSubmittedText: 'This page can be closed now',\n\t\t\t\tbuttonLabel,\n\t\t\t\tredirectUrl: undefined,\n\t\t\t\tformFields: fields,\n\t\t\t\ttestRun: false,\n\t\t\t\tquery: {},\n\t\t\t\tcustomCss,\n\t\t\t});\n\n\t\t\tres.render('form-trigger', data);\n\n\t\t\treturn {\n\t\t\t\tnoWebhookResponse: true,\n\t\t\t};\n\t\t}\n\t\tif (method === 'POST') {\n\t\t\tconst returnItem = await prepareFormReturnItem(this, fields, 'production', true);\n\t\t\tconst json = returnItem.json;\n\n\t\t\tdelete json.submittedAt;\n\t\t\tdelete json.formMode;\n\n\t\t\treturnItem.json = { data: json };\n\n\t\t\treturn {\n\t\t\t\twebhookResponse: ACTION_RECORDED_PAGE,\n\t\t\t\tworkflowData: [[returnItem]],\n\t\t\t};\n\t\t}\n\t}\n\n\tconst query = req.query as { approved: 'false' | 'true' };\n\tconst approved = query.approved === 'true';\n\treturn {\n\t\twebhookResponse: ACTION_RECORDED_PAGE,\n\t\tworkflowData: [[{ json: { data: { approved } } }]],\n\t};\n}\n\n// Send and Wait Config -----------------------------------------------------------\nexport function getSendAndWaitConfig(context: IExecuteFunctions): SendAndWaitConfig {\n\tconst message = escapeHtml((context.getNodeParameter('message', 0, '') as string).trim())\n\t\t.replace(/\\\\n/g, '\\n')\n\t\t.replace(/<br>/g, '\\n');\n\tconst subject = escapeHtml(context.getNodeParameter('subject', 0, '') as string);\n\tconst resumeUrl = context.evaluateExpression('{{ $execution?.resumeUrl }}', 0) as string;\n\tconst nodeId = context.evaluateExpression('{{ $nodeId }}', 0) as string;\n\tconst approvalOptions = context.getNodeParameter('approvalOptions.values', 0, {}) as {\n\t\tapprovalType?: 'single' | 'double';\n\t\tapproveLabel?: string;\n\t\tbuttonApprovalStyle?: string;\n\t\tdisapproveLabel?: string;\n\t\tbuttonDisapprovalStyle?: string;\n\t};\n\n\tconst options = context.getNodeParameter('options', 0, {});\n\n\tconst config: SendAndWaitConfig = {\n\t\ttitle: subject,\n\t\tmessage,\n\t\turl: `${resumeUrl}/${nodeId}`,\n\t\toptions: [],\n\t\tappendAttribution: options?.appendAttribution as boolean,\n\t};\n\n\tconst responseType = context.getNodeParameter('responseType', 0, 'approval') as string;\n\n\tif (responseType === 'freeText' || responseType === 'customForm') {\n\t\tconst label = context.getNodeParameter('options.messageButtonLabel', 0, 'Respond') as string;\n\t\tconfig.options.push({\n\t\t\tlabel,\n\t\t\tvalue: 'true',\n\t\t\tstyle: 'primary',\n\t\t});\n\t} else if (approvalOptions.approvalType === 'double') {\n\t\tconst approveLabel = escapeHtml(approvalOptions.approveLabel || 'Approve');\n\t\tconst buttonApprovalStyle = approvalOptions.buttonApprovalStyle || 'primary';\n\t\tconst disapproveLabel = escapeHtml(approvalOptions.disapproveLabel || 'Disapprove');\n\t\tconst buttonDisapprovalStyle = approvalOptions.buttonDisapprovalStyle || 'secondary';\n\n\t\tconfig.options.push({\n\t\t\tlabel: disapproveLabel,\n\t\t\tvalue: 'false',\n\t\t\tstyle: buttonDisapprovalStyle,\n\t\t});\n\t\tconfig.options.push({\n\t\t\tlabel: approveLabel,\n\t\t\tvalue: 'true',\n\t\t\tstyle: buttonApprovalStyle,\n\t\t});\n\t} else {\n\t\tconst label = escapeHtml(approvalOptions.approveLabel || 'Approve');\n\t\tconst style = approvalOptions.buttonApprovalStyle || 'primary';\n\t\tconfig.options.push({\n\t\t\tlabel,\n\t\t\tvalue: 'true',\n\t\t\tstyle,\n\t\t});\n\t}\n\n\treturn config;\n}\n\nexport function createButton(url: string, label: string, approved: string, style: string) {\n\tlet buttonStyle = BUTTON_STYLE_PRIMARY;\n\tif (style === 'secondary') {\n\t\tbuttonStyle = BUTTON_STYLE_SECONDARY;\n\t}\n\treturn `<a href=\"${url}?approved=${approved}\" target=\"_blank\" style=\"${buttonStyle}\">${label}</a>`;\n}\n\nexport function createEmail(context: IExecuteFunctions) {\n\tconst to = (context.getNodeParameter('sendTo', 0, '') as string).trim();\n\tconst config = getSendAndWaitConfig(context);\n\n\tif (to.indexOf('@') === -1 || (to.match(/@/g) || []).length > 1) {\n\t\tconst description = `The email address '${to}' in the 'To' field isn't valid or contains multiple addresses. Please provide only a single email address.`;\n\t\tthrow new NodeOperationError(context.getNode(), 'Invalid email address', {\n\t\t\tdescription,\n\t\t\titemIndex: 0,\n\t\t});\n\t}\n\n\tconst buttons: string[] = [];\n\tfor (const option of config.options) {\n\t\tbuttons.push(createButton(config.url, option.label, option.value, option.style));\n\t}\n\tlet emailBody: string;\n\tif (config.appendAttribution !== false) {\n\t\tconst instanceId = context.getInstanceId();\n\t\temailBody = createEmailBodyWithN8nAttribution(config.message, buttons.join('\\n'), instanceId);\n\t} else {\n\t\temailBody = createEmailBodyWithoutN8nAttribution(config.message, buttons.join('\\n'));\n\t}\n\n\tconst email: IEmail = {\n\t\tto,\n\t\tsubject: config.title,\n\t\tbody: '',\n\t\thtmlBody: emailBody,\n\t};\n\n\treturn email;\n}\n"],"mappings":"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","names":["isbot"]}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-base",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.97.0",
|
|
4
4
|
"description": "Base nodes of n8n",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
8
|
+
"LICENSE.md",
|
|
9
|
+
"LICENSE_EE.md"
|
|
10
10
|
],
|
|
11
11
|
"n8n": {
|
|
12
12
|
"credentials": [
|
|
@@ -861,7 +861,7 @@
|
|
|
861
861
|
"@types/xml2js": "^0.4.14",
|
|
862
862
|
"eslint-plugin-n8n-nodes-base": "^1.16.3",
|
|
863
863
|
"@n8n/typescript-config": "1.2.0",
|
|
864
|
-
"n8n-core": "1.
|
|
864
|
+
"n8n-core": "1.98.0"
|
|
865
865
|
},
|
|
866
866
|
"dependencies": {
|
|
867
867
|
"@aws-sdk/client-sso-oidc": "3.808.0",
|
|
@@ -930,10 +930,10 @@
|
|
|
930
930
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz",
|
|
931
931
|
"xml2js": "0.6.2",
|
|
932
932
|
"xmlhttprequest-ssl": "3.1.0",
|
|
933
|
-
"@n8n/config": "1.
|
|
934
|
-
"@n8n/imap": "0.10.0",
|
|
933
|
+
"@n8n/config": "1.43.0",
|
|
935
934
|
"@n8n/di": "0.6.0",
|
|
936
|
-
"n8n
|
|
935
|
+
"@n8n/imap": "0.10.0",
|
|
936
|
+
"n8n-workflow": "1.96.0"
|
|
937
937
|
},
|
|
938
938
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
939
939
|
"homepage": "https://n8n.io",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../nodes/Form/utils/formCompletionUtils.ts"],"sourcesContent":["import { type Response } from 'express';\nimport {\n\ttype NodeTypeAndVersion,\n\ttype IWebhookFunctions,\n\ttype IWebhookResponseData,\n\ttype IBinaryData,\n\ttype IDataObject,\n\tOperationalError,\n} from 'n8n-workflow';\n\nimport { sanitizeCustomCss, sanitizeHtml } from './utils';\n\nconst getBinaryDataFromNode = (context: IWebhookFunctions, nodeName: string): IDataObject => {\n\treturn context.evaluateExpression(`{{ $('${nodeName}').first().binary }}`) as IDataObject;\n};\n\nexport const binaryResponse = async (\n\tcontext: IWebhookFunctions,\n): Promise<{ data: string | Buffer; fileName: string; type: string }> => {\n\tconst inputDataFieldName = context.getNodeParameter('inputDataFieldName', '') as string;\n\tconst parentNodes = context.getParentNodes(context.getNode().name);\n\tconst binaryNode = parentNodes\n\t\t.reverse()\n\t\t.find((node) => getBinaryDataFromNode(context, node?.name)?.hasOwnProperty(inputDataFieldName));\n\tif (!binaryNode) {\n\t\tthrow new OperationalError(`No binary data with field ${inputDataFieldName} found.`);\n\t}\n\tconst binaryData = getBinaryDataFromNode(context, binaryNode?.name)[\n\t\tinputDataFieldName\n\t] as IBinaryData;\n\n\treturn {\n\t\t// If a binaryData has an id, the following field is set:\n\t\t// N8N_DEFAULT_BINARY_DATA_MODE=filesystem\n\t\tdata: binaryData.id\n\t\t\t? await context.helpers.binaryToBuffer(await context.helpers.getBinaryStream(binaryData.id))\n\t\t\t: atob(binaryData.data),\n\t\tfileName: binaryData.fileName ?? 'file',\n\t\ttype: binaryData.mimeType,\n\t};\n};\n\nexport const renderFormCompletion = async (\n\tcontext: IWebhookFunctions,\n\tres: Response,\n\ttrigger: NodeTypeAndVersion,\n): Promise<IWebhookResponseData> => {\n\tconst completionTitle = context.getNodeParameter('completionTitle', '') as string;\n\tconst completionMessage = context.getNodeParameter('completionMessage', '') as string;\n\tconst redirectUrl = context.getNodeParameter('redirectUrl', '') as string;\n\tconst options = context.getNodeParameter('options', {}) as {\n\t\tformTitle: string;\n\t\tcustomCss?: string;\n\t};\n\tconst responseText = context.getNodeParameter('responseText', '') as string;\n\tconst binary =\n\t\tcontext.getNodeParameter('respondWith', '') === 'returnBinary'\n\t\t\t? await binaryResponse(context)\n\t\t\t: '';\n\n\tlet title = options.formTitle;\n\tif (!title) {\n\t\ttitle = context.evaluateExpression(`{{ $('${trigger?.name}').params.formTitle }}`) as string;\n\t}\n\tconst appendAttribution = context.evaluateExpression(\n\t\t`{{ $('${trigger?.name}').params.options?.appendAttribution === false ? false : true }}`,\n\t) as boolean;\n\n\tres.render('form-trigger-completion', {\n\t\ttitle: completionTitle,\n\t\tmessage: completionMessage,\n\t\tformTitle: title,\n\t\tappendAttribution,\n\t\tresponseText: sanitizeHtml(responseText),\n\t\tresponseBinary: encodeURIComponent(JSON.stringify(binary)),\n\t\tdangerousCustomCss: sanitizeCustomCss(options.customCss),\n\t\tredirectUrl,\n\t});\n\n\treturn { noWebhookResponse: true };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAOO;AAEP,mBAAgD;AAEhD,MAAM,wBAAwB,CAAC,SAA4B,aAAkC;AAC5F,SAAO,QAAQ,mBAAmB,SAAS,QAAQ,sBAAsB;AAC1E;AAEO,MAAM,iBAAiB,OAC7B,YACwE;AACxE,QAAM,qBAAqB,QAAQ,iBAAiB,sBAAsB,EAAE;AAC5E,QAAM,cAAc,QAAQ,eAAe,QAAQ,QAAQ,EAAE,IAAI;AACjE,QAAM,aAAa,YACjB,QAAQ,EACR,KAAK,CAAC,SAAS,sBAAsB,SAAS,MAAM,IAAI,GAAG,eAAe,kBAAkB,CAAC;AAC/F,MAAI,CAAC,YAAY;AAChB,UAAM,IAAI,qCAAiB,6BAA6B,kBAAkB,SAAS;AAAA,EACpF;AACA,QAAM,aAAa,sBAAsB,SAAS,YAAY,IAAI,EACjE,kBACD;AAEA,SAAO;AAAA;AAAA;AAAA,IAGN,MAAM,WAAW,KACd,MAAM,QAAQ,QAAQ,eAAe,MAAM,QAAQ,QAAQ,gBAAgB,WAAW,EAAE,CAAC,IACzF,KAAK,WAAW,IAAI;AAAA,IACvB,UAAU,WAAW,YAAY;AAAA,IACjC,MAAM,WAAW;AAAA,EAClB;AACD;AAEO,MAAM,uBAAuB,OACnC,SACA,KACA,YACmC;AACnC,QAAM,kBAAkB,QAAQ,iBAAiB,mBAAmB,EAAE;AACtE,QAAM,oBAAoB,QAAQ,iBAAiB,qBAAqB,EAAE;AAC1E,QAAM,cAAc,QAAQ,iBAAiB,eAAe,EAAE;AAC9D,QAAM,UAAU,QAAQ,iBAAiB,WAAW,CAAC,CAAC;AAItD,QAAM,eAAe,QAAQ,iBAAiB,gBAAgB,EAAE;AAChE,QAAM,SACL,QAAQ,iBAAiB,eAAe,EAAE,MAAM,iBAC7C,MAAM,eAAe,OAAO,IAC5B;AAEJ,MAAI,QAAQ,QAAQ;AACpB,MAAI,CAAC,OAAO;AACX,YAAQ,QAAQ,mBAAmB,SAAS,SAAS,IAAI,wBAAwB;AAAA,EAClF;AACA,QAAM,oBAAoB,QAAQ;AAAA,IACjC,SAAS,SAAS,IAAI;AAAA,EACvB;AAEA,MAAI,OAAO,2BAA2B;AAAA,IACrC,OAAO;AAAA,IACP,SAAS;AAAA,IACT,WAAW;AAAA,IACX;AAAA,IACA,kBAAc,2BAAa,YAAY;AAAA,IACvC,gBAAgB,mBAAmB,KAAK,UAAU,MAAM,CAAC;AAAA,IACzD,wBAAoB,gCAAkB,QAAQ,SAAS;AAAA,IACvD;AAAA,EACD,CAAC;AAED,SAAO,EAAE,mBAAmB,KAAK;AAClC;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../nodes/Form/utils/formNodeUtils.ts"],"sourcesContent":["import { type Response } from 'express';\nimport {\n\ttype NodeTypeAndVersion,\n\ttype IWebhookFunctions,\n\ttype FormFieldsParameter,\n\ttype IWebhookResponseData,\n} from 'n8n-workflow';\n\nimport { renderForm } from './utils';\n\nexport const renderFormNode = async (\n\tcontext: IWebhookFunctions,\n\tres: Response,\n\ttrigger: NodeTypeAndVersion,\n\tfields: FormFieldsParameter,\n\tmode: 'test' | 'production',\n): Promise<IWebhookResponseData> => {\n\tconst options = context.getNodeParameter('options', {}) as {\n\t\tformTitle: string;\n\t\tformDescription: string;\n\t\tbuttonLabel: string;\n\t\tcustomCss?: string;\n\t};\n\n\tlet title = options.formTitle;\n\tif (!title) {\n\t\ttitle = context.evaluateExpression(`{{ $('${trigger?.name}').params.formTitle }}`) as string;\n\t}\n\n\tlet buttonLabel = options.buttonLabel;\n\tif (!buttonLabel) {\n\t\tbuttonLabel =\n\t\t\t(context.evaluateExpression(\n\t\t\t\t`{{ $('${trigger?.name}').params.options?.buttonLabel }}`,\n\t\t\t) as string) || 'Submit';\n\t}\n\n\tconst appendAttribution = context.evaluateExpression(\n\t\t`{{ $('${trigger?.name}').params.options?.appendAttribution === false ? false : true }}`,\n\t) as boolean;\n\n\trenderForm({\n\t\tcontext,\n\t\tres,\n\t\tformTitle: title,\n\t\tformDescription: options.formDescription,\n\t\tformFields: fields,\n\t\tresponseMode: 'responseNode',\n\t\tmode,\n\t\tredirectUrl: undefined,\n\t\tappendAttribution,\n\t\tbuttonLabel,\n\t\tcustomCss: options.customCss,\n\t});\n\n\treturn {\n\t\tnoWebhookResponse: true,\n\t};\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,mBAA2B;AAEpB,MAAM,iBAAiB,OAC7B,SACA,KACA,SACA,QACA,SACmC;AACnC,QAAM,UAAU,QAAQ,iBAAiB,WAAW,CAAC,CAAC;AAOtD,MAAI,QAAQ,QAAQ;AACpB,MAAI,CAAC,OAAO;AACX,YAAQ,QAAQ,mBAAmB,SAAS,SAAS,IAAI,wBAAwB;AAAA,EAClF;AAEA,MAAI,cAAc,QAAQ;AAC1B,MAAI,CAAC,aAAa;AACjB,kBACE,QAAQ;AAAA,MACR,SAAS,SAAS,IAAI;AAAA,IACvB,KAAgB;AAAA,EAClB;AAEA,QAAM,oBAAoB,QAAQ;AAAA,IACjC,SAAS,SAAS,IAAI;AAAA,EACvB;AAEA,+BAAW;AAAA,IACV;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,iBAAiB,QAAQ;AAAA,IACzB,YAAY;AAAA,IACZ,cAAc;AAAA,IACd;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA,WAAW,QAAQ;AAAA,EACpB,CAAC;AAED,SAAO;AAAA,IACN,mBAAmB;AAAA,EACpB;AACD;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../nodes/Form/utils/utils.ts"],"sourcesContent":["import type { Response } from 'express';\nimport isbot from 'isbot';\nimport { DateTime } from 'luxon';\nimport type {\n\tINodeExecutionData,\n\tMultiPartFormData,\n\tIDataObject,\n\tIWebhookFunctions,\n\tFormFieldsParameter,\n\tNodeTypeAndVersion,\n} from 'n8n-workflow';\nimport {\n\tFORM_NODE_TYPE,\n\tFORM_TRIGGER_NODE_TYPE,\n\tNodeOperationError,\n\tWAIT_NODE_TYPE,\n\tjsonParse,\n} from 'n8n-workflow';\nimport sanitize from 'sanitize-html';\n\nimport { getResolvables } from '../../../utils/utilities';\nimport { WebhookAuthorizationError } from '../../Webhook/error';\nimport { validateWebhookAuthentication } from '../../Webhook/utils';\nimport { FORM_TRIGGER_AUTHENTICATION_PROPERTY } from '../interfaces';\nimport type { FormTriggerData, FormTriggerInput } from '../interfaces';\n\nexport function sanitizeHtml(text: string) {\n\treturn sanitize(text, {\n\t\tallowedTags: [\n\t\t\t'b',\n\t\t\t'div',\n\t\t\t'i',\n\t\t\t'iframe',\n\t\t\t'img',\n\t\t\t'video',\n\t\t\t'source',\n\t\t\t'em',\n\t\t\t'strong',\n\t\t\t'a',\n\t\t\t'h1',\n\t\t\t'h2',\n\t\t\t'h3',\n\t\t\t'h4',\n\t\t\t'h5',\n\t\t\t'h6',\n\t\t\t'u',\n\t\t\t'sub',\n\t\t\t'sup',\n\t\t\t'code',\n\t\t\t'pre',\n\t\t\t'span',\n\t\t\t'br',\n\t\t\t'ul',\n\t\t\t'ol',\n\t\t\t'li',\n\t\t\t'p',\n\t\t],\n\t\tallowedAttributes: {\n\t\t\ta: ['href', 'target', 'rel'],\n\t\t\timg: ['src', 'alt', 'width', 'height'],\n\t\t\tvideo: ['controls', 'autoplay', 'loop', 'muted', 'poster', 'width', 'height'],\n\t\t\tiframe: [\n\t\t\t\t'src',\n\t\t\t\t'width',\n\t\t\t\t'height',\n\t\t\t\t'frameborder',\n\t\t\t\t'allow',\n\t\t\t\t'allowfullscreen',\n\t\t\t\t'referrerpolicy',\n\t\t\t],\n\t\t\tsource: ['src', 'type'],\n\t\t},\n\t\tallowedSchemes: ['https', 'http'],\n\t\tallowedSchemesByTag: {\n\t\t\tsource: ['https', 'http'],\n\t\t\tiframe: ['https', 'http'],\n\t\t},\n\t\tallowProtocolRelative: false,\n\t\ttransformTags: {\n\t\t\tiframe: sanitize.simpleTransform('iframe', {\n\t\t\t\tsandbox: '',\n\t\t\t\treferrerpolicy: 'strict-origin-when-cross-origin',\n\t\t\t\tallow: 'fullscreen; autoplay; encrypted-media',\n\t\t\t}),\n\t\t},\n\t});\n}\n\nexport const prepareFormFields = (context: IWebhookFunctions, fields: FormFieldsParameter) => {\n\treturn fields.map((field) => {\n\t\tif (field.fieldType === 'html') {\n\t\t\tlet { html } = field;\n\n\t\t\tif (!html) return field;\n\n\t\t\tfor (const resolvable of getResolvables(html)) {\n\t\t\t\thtml = html.replace(resolvable, context.evaluateExpression(resolvable) as string);\n\t\t\t}\n\n\t\t\tfield.html = sanitizeHtml(html);\n\t\t}\n\n\t\tif (field.fieldType === 'hiddenField') {\n\t\t\tfield.fieldLabel = field.fieldName as string;\n\t\t}\n\n\t\treturn field;\n\t});\n};\n\nexport function sanitizeCustomCss(css: string | undefined): string | undefined {\n\tif (!css) return undefined;\n\n\t// Use sanitize-html with custom settings for CSS\n\treturn sanitize(css, {\n\t\tallowedTags: [], // No HTML tags allowed\n\t\tallowedAttributes: {}, // No attributes allowed\n\t\t// This ensures we're only keeping the text content\n\t\t// which should be the CSS, while removing any HTML/script tags\n\t});\n}\n\nexport function createDescriptionMetadata(description: string) {\n\treturn description === ''\n\t\t? 'n8n form'\n\t\t: description.replace(/^\\s*\\n+|<\\/?[^>]+(>|$)/g, '').slice(0, 150);\n}\n\nexport function prepareFormData({\n\tformTitle,\n\tformDescription,\n\tformSubmittedHeader,\n\tformSubmittedText,\n\tredirectUrl,\n\tformFields,\n\ttestRun,\n\tquery,\n\tinstanceId,\n\tuseResponseData,\n\tappendAttribution = true,\n\tbuttonLabel,\n\tcustomCss,\n}: {\n\tformTitle: string;\n\tformDescription: string;\n\tformSubmittedText: string | undefined;\n\tredirectUrl: string | undefined;\n\tformFields: FormFieldsParameter;\n\ttestRun: boolean;\n\tquery: IDataObject;\n\tinstanceId?: string;\n\tuseResponseData?: boolean;\n\tappendAttribution?: boolean;\n\tbuttonLabel?: string;\n\tformSubmittedHeader?: string;\n\tcustomCss?: string;\n}) {\n\tconst utm_campaign = instanceId ? `&utm_campaign=${instanceId}` : '';\n\tconst n8nWebsiteLink = `https://n8n.io/?utm_source=n8n-internal&utm_medium=form-trigger${utm_campaign}`;\n\n\tif (formSubmittedText === undefined) {\n\t\tformSubmittedText = 'Your response has been recorded';\n\t}\n\n\tconst formData: FormTriggerData = {\n\t\ttestRun,\n\t\tformTitle,\n\t\tformDescription,\n\t\tformDescriptionMetadata: createDescriptionMetadata(formDescription),\n\t\tformSubmittedHeader,\n\t\tformSubmittedText,\n\t\tn8nWebsiteLink,\n\t\tformFields: [],\n\t\tuseResponseData,\n\t\tappendAttribution,\n\t\tbuttonLabel,\n\t\tdangerousCustomCss: sanitizeCustomCss(customCss),\n\t};\n\n\tif (redirectUrl) {\n\t\tif (!redirectUrl.includes('://')) {\n\t\t\tredirectUrl = `http://${redirectUrl}`;\n\t\t}\n\t\tformData.redirectUrl = redirectUrl;\n\t}\n\n\tfor (const [index, field] of formFields.entries()) {\n\t\tconst { fieldType, requiredField, multiselect, placeholder } = field;\n\n\t\tconst input: IDataObject = {\n\t\t\tid: `field-${index}`,\n\t\t\terrorId: `error-field-${index}`,\n\t\t\tlabel: field.fieldLabel,\n\t\t\tinputRequired: requiredField ? 'form-required' : '',\n\t\t\tdefaultValue: query[field.fieldLabel] ?? '',\n\t\t\tplaceholder,\n\t\t};\n\n\t\tif (multiselect) {\n\t\t\tinput.isMultiSelect = true;\n\t\t\tinput.multiSelectOptions =\n\t\t\t\tfield.fieldOptions?.values.map((e, i) => ({\n\t\t\t\t\tid: `option${i}_${input.id}`,\n\t\t\t\t\tlabel: e.option,\n\t\t\t\t})) ?? [];\n\t\t} else if (fieldType === 'file') {\n\t\t\tinput.isFileInput = true;\n\t\t\tinput.acceptFileTypes = field.acceptFileTypes;\n\t\t\tinput.multipleFiles = field.multipleFiles ? 'multiple' : '';\n\t\t} else if (fieldType === 'dropdown') {\n\t\t\tinput.isSelect = true;\n\t\t\tconst fieldOptions = field.fieldOptions?.values ?? [];\n\t\t\tinput.selectOptions = fieldOptions.map((e) => e.option);\n\t\t} else if (fieldType === 'textarea') {\n\t\t\tinput.isTextarea = true;\n\t\t} else if (fieldType === 'html') {\n\t\t\tinput.isHtml = true;\n\t\t\tinput.html = field.html as string;\n\t\t} else if (fieldType === 'hiddenField') {\n\t\t\tinput.isHidden = true;\n\t\t\tinput.hiddenName = field.fieldName as string;\n\t\t\tinput.hiddenValue =\n\t\t\t\tinput.defaultValue === '' ? (field.fieldValue as string) : input.defaultValue;\n\t\t} else {\n\t\t\tinput.isInput = true;\n\t\t\tinput.type = fieldType as 'text' | 'number' | 'date' | 'email';\n\t\t}\n\n\t\tformData.formFields.push(input as FormTriggerInput);\n\t}\n\n\treturn formData;\n}\n\nexport const validateResponseModeConfiguration = (context: IWebhookFunctions) => {\n\tconst responseMode = context.getNodeParameter('responseMode', 'onReceived') as string;\n\tconst connectedNodes = context.getChildNodes(context.getNode().name);\n\tconst nodeVersion = context.getNode().typeVersion;\n\n\tconst isRespondToWebhookConnected = connectedNodes.some(\n\t\t(node) => node.type === 'n8n-nodes-base.respondToWebhook',\n\t);\n\n\tif (!isRespondToWebhookConnected && responseMode === 'responseNode') {\n\t\tthrow new NodeOperationError(\n\t\t\tcontext.getNode(),\n\t\t\tnew Error('No Respond to Webhook node found in the workflow'),\n\t\t\t{\n\t\t\t\tdescription:\n\t\t\t\t\t'Insert a Respond to Webhook node to your workflow to respond to the form submission or choose another option for the “Respond When” parameter',\n\t\t\t},\n\t\t);\n\t}\n\n\tif (isRespondToWebhookConnected && responseMode !== 'responseNode' && nodeVersion <= 2.1) {\n\t\tthrow new NodeOperationError(\n\t\t\tcontext.getNode(),\n\t\t\tnew Error(`${context.getNode().name} node not correctly configured`),\n\t\t\t{\n\t\t\t\tdescription:\n\t\t\t\t\t'Set the “Respond When” parameter to “Using Respond to Webhook Node” or remove the Respond to Webhook node',\n\t\t\t},\n\t\t);\n\t}\n\n\tif (isRespondToWebhookConnected && nodeVersion > 2.1) {\n\t\tthrow new NodeOperationError(\n\t\t\tcontext.getNode(),\n\t\t\tnew Error(\n\t\t\t\t'The \"Respond to Webhook\" node is not supported in workflows initiated by the \"n8n Form Trigger\"',\n\t\t\t),\n\t\t\t{\n\t\t\t\tdescription:\n\t\t\t\t\t'To configure your response, add an \"n8n Form\" node and set the \"Page Type\" to \"Form Ending\"',\n\t\t\t},\n\t\t);\n\t}\n};\n\nexport function addFormResponseDataToReturnItem(\n\treturnItem: INodeExecutionData,\n\tformFields: FormFieldsParameter,\n\tbodyData: IDataObject,\n) {\n\tfor (const [index, field] of formFields.entries()) {\n\t\tconst key = `field-${index}`;\n\t\tconst name = field.fieldLabel ?? field.fieldName;\n\t\tlet value = bodyData[key] ?? null;\n\n\t\tif (value === null) {\n\t\t\treturnItem.json[name] = null;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (field.fieldType === 'html') {\n\t\t\tif (field.elementName) {\n\t\t\t\treturnItem.json[field.elementName] = value;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (field.fieldType === 'number') {\n\t\t\tvalue = Number(value);\n\t\t}\n\t\tif (field.fieldType === 'text') {\n\t\t\tvalue = String(value).trim();\n\t\t}\n\t\tif (field.multiselect && typeof value === 'string') {\n\t\t\tvalue = jsonParse(value);\n\t\t}\n\t\tif (field.fieldType === 'date' && value && field.formatDate !== '') {\n\t\t\tvalue = DateTime.fromFormat(String(value), 'yyyy-mm-dd').toFormat(field.formatDate as string);\n\t\t}\n\t\tif (field.fieldType === 'file' && field.multipleFiles && !Array.isArray(value)) {\n\t\t\tvalue = [value];\n\t\t}\n\n\t\treturnItem.json[name] = value;\n\t}\n}\n\nexport async function prepareFormReturnItem(\n\tcontext: IWebhookFunctions,\n\tformFields: FormFieldsParameter,\n\tmode: 'test' | 'production',\n\tuseWorkflowTimezone: boolean = false,\n) {\n\tconst bodyData = (context.getBodyData().data as IDataObject) ?? {};\n\tconst files = (context.getBodyData().files as IDataObject) ?? {};\n\n\tconst returnItem: INodeExecutionData = {\n\t\tjson: {},\n\t};\n\tif (files && Object.keys(files).length) {\n\t\treturnItem.binary = {};\n\t}\n\n\tfor (const key of Object.keys(files)) {\n\t\tconst processFiles: MultiPartFormData.File[] = [];\n\t\tlet multiFile = false;\n\t\tconst filesInput = files[key] as MultiPartFormData.File[] | MultiPartFormData.File;\n\n\t\tif (Array.isArray(filesInput)) {\n\t\t\tbodyData[key] = filesInput.map((file) => ({\n\t\t\t\tfilename: file.originalFilename,\n\t\t\t\tmimetype: file.mimetype,\n\t\t\t\tsize: file.size,\n\t\t\t}));\n\t\t\tprocessFiles.push(...filesInput);\n\t\t\tmultiFile = true;\n\t\t} else {\n\t\t\tbodyData[key] = {\n\t\t\t\tfilename: filesInput.originalFilename,\n\t\t\t\tmimetype: filesInput.mimetype,\n\t\t\t\tsize: filesInput.size,\n\t\t\t};\n\t\t\tprocessFiles.push(filesInput);\n\t\t}\n\n\t\tconst entryIndex = Number(key.replace(/field-/g, ''));\n\t\tconst fieldLabel = isNaN(entryIndex) ? key : formFields[entryIndex].fieldLabel;\n\n\t\tlet fileCount = 0;\n\t\tfor (const file of processFiles) {\n\t\t\tlet binaryPropertyName = fieldLabel.replace(/\\W/g, '_');\n\n\t\t\tif (multiFile) {\n\t\t\t\tbinaryPropertyName += `_${fileCount++}`;\n\t\t\t}\n\n\t\t\treturnItem.binary![binaryPropertyName] = await context.nodeHelpers.copyBinaryFile(\n\t\t\t\tfile.filepath,\n\t\t\t\tfile.originalFilename ?? file.newFilename,\n\t\t\t\tfile.mimetype,\n\t\t\t);\n\t\t}\n\t}\n\n\taddFormResponseDataToReturnItem(returnItem, formFields, bodyData);\n\n\tconst timezone = useWorkflowTimezone ? context.getTimezone() : 'UTC';\n\treturnItem.json.submittedAt = DateTime.now().setZone(timezone).toISO();\n\n\treturnItem.json.formMode = mode;\n\n\tif (\n\t\tcontext.getNode().type === FORM_TRIGGER_NODE_TYPE &&\n\t\tObject.keys(context.getRequestObject().query || {}).length\n\t) {\n\t\treturnItem.json.formQueryParameters = context.getRequestObject().query;\n\t}\n\n\treturn returnItem;\n}\n\nexport function renderForm({\n\tcontext,\n\tres,\n\tformTitle,\n\tformDescription,\n\tformFields,\n\tresponseMode,\n\tmode,\n\tformSubmittedText,\n\tredirectUrl,\n\tappendAttribution,\n\tbuttonLabel,\n\tcustomCss,\n}: {\n\tcontext: IWebhookFunctions;\n\tres: Response;\n\tformTitle: string;\n\tformDescription: string;\n\tformFields: FormFieldsParameter;\n\tresponseMode: string;\n\tmode: 'test' | 'production';\n\tformSubmittedText?: string;\n\tredirectUrl?: string;\n\tappendAttribution?: boolean;\n\tbuttonLabel?: string;\n\tcustomCss?: string;\n}) {\n\tformDescription = (formDescription || '').replace(/\\\\n/g, '\\n').replace(/<br>/g, '\\n');\n\tconst instanceId = context.getInstanceId();\n\n\tconst useResponseData = responseMode === 'responseNode';\n\n\tlet query: IDataObject = {};\n\n\tif (context.getNode().type === FORM_TRIGGER_NODE_TYPE) {\n\t\tquery = context.getRequestObject().query as IDataObject;\n\t} else if (context.getNode().type === FORM_NODE_TYPE) {\n\t\tconst parentNodes = context.getParentNodes(context.getNode().name);\n\t\tconst trigger = parentNodes.find(\n\t\t\t(node) => node.type === FORM_TRIGGER_NODE_TYPE,\n\t\t) as NodeTypeAndVersion;\n\t\ttry {\n\t\t\tconst triggerQueryParameters = context.evaluateExpression(\n\t\t\t\t`{{ $('${trigger?.name}').first().json.formQueryParameters }}`,\n\t\t\t) as IDataObject;\n\n\t\t\tif (triggerQueryParameters) {\n\t\t\t\tquery = triggerQueryParameters;\n\t\t\t}\n\t\t} catch (error) {}\n\t}\n\n\tformFields = prepareFormFields(context, formFields);\n\n\tconst data = prepareFormData({\n\t\tformTitle,\n\t\tformDescription,\n\t\tformSubmittedText,\n\t\tredirectUrl,\n\t\tformFields,\n\t\ttestRun: mode === 'test',\n\t\tquery,\n\t\tinstanceId,\n\t\tuseResponseData,\n\t\tappendAttribution,\n\t\tbuttonLabel,\n\t\tcustomCss,\n\t});\n\n\tres.render('form-trigger', data);\n}\n\nexport const isFormConnected = (nodes: NodeTypeAndVersion[]) => {\n\treturn nodes.some(\n\t\t(n) =>\n\t\t\tn.type === FORM_NODE_TYPE || (n.type === WAIT_NODE_TYPE && n.parameters?.resume === 'form'),\n\t);\n};\n\nexport async function formWebhook(\n\tcontext: IWebhookFunctions,\n\tauthProperty = FORM_TRIGGER_AUTHENTICATION_PROPERTY,\n) {\n\tconst node = context.getNode();\n\tconst options = context.getNodeParameter('options', {}) as {\n\t\tignoreBots?: boolean;\n\t\trespondWithOptions?: {\n\t\t\tvalues: {\n\t\t\t\trespondWith: 'text' | 'redirect';\n\t\t\t\tformSubmittedText: string;\n\t\t\t\tredirectUrl: string;\n\t\t\t};\n\t\t};\n\t\tformSubmittedText?: string;\n\t\tuseWorkflowTimezone?: boolean;\n\t\tappendAttribution?: boolean;\n\t\tbuttonLabel?: string;\n\t\tcustomCss?: string;\n\t};\n\tconst res = context.getResponseObject();\n\tconst req = context.getRequestObject();\n\n\ttry {\n\t\tif (options.ignoreBots && isbot(req.headers['user-agent'])) {\n\t\t\tthrow new WebhookAuthorizationError(403);\n\t\t}\n\t\tif (node.typeVersion > 1) {\n\t\t\tawait validateWebhookAuthentication(context, authProperty);\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof WebhookAuthorizationError) {\n\t\t\tres.setHeader('WWW-Authenticate', 'Basic realm=\"Enter credentials\"');\n\t\t\tres.status(401).send();\n\t\t\treturn { noWebhookResponse: true };\n\t\t}\n\t\tthrow error;\n\t}\n\n\tconst mode = context.getMode() === 'manual' ? 'test' : 'production';\n\tconst formFields = context.getNodeParameter('formFields.values', []) as FormFieldsParameter;\n\n\tconst method = context.getRequestObject().method;\n\n\tvalidateResponseModeConfiguration(context);\n\n\t//Show the form on GET request\n\tif (method === 'GET') {\n\t\tconst formTitle = context.getNodeParameter('formTitle', '') as string;\n\t\tconst formDescription = sanitizeHtml(context.getNodeParameter('formDescription', '') as string);\n\t\tlet responseMode = context.getNodeParameter('responseMode', '') as string;\n\n\t\tlet formSubmittedText;\n\t\tlet redirectUrl;\n\t\tlet appendAttribution = true;\n\n\t\tif (options.respondWithOptions) {\n\t\t\tconst values = (options.respondWithOptions as IDataObject).values as IDataObject;\n\t\t\tif (values.respondWith === 'text') {\n\t\t\t\tformSubmittedText = values.formSubmittedText as string;\n\t\t\t}\n\t\t\tif (values.respondWith === 'redirect') {\n\t\t\t\tredirectUrl = values.redirectUrl as string;\n\t\t\t}\n\t\t} else {\n\t\t\tformSubmittedText = options.formSubmittedText as string;\n\t\t}\n\n\t\tif (options.appendAttribution === false) {\n\t\t\tappendAttribution = false;\n\t\t}\n\n\t\tlet buttonLabel = 'Submit';\n\n\t\tif (options.buttonLabel) {\n\t\t\tbuttonLabel = options.buttonLabel;\n\t\t}\n\n\t\tconst connectedNodes = context.getChildNodes(context.getNode().name, {\n\t\t\tincludeNodeParameters: true,\n\t\t});\n\t\tconst hasNextPage = isFormConnected(connectedNodes);\n\n\t\tif (hasNextPage) {\n\t\t\tredirectUrl = undefined;\n\t\t\tresponseMode = 'responseNode';\n\t\t}\n\n\t\trenderForm({\n\t\t\tcontext,\n\t\t\tres,\n\t\t\tformTitle,\n\t\t\tformDescription,\n\t\t\tformFields,\n\t\t\tresponseMode,\n\t\t\tmode,\n\t\t\tformSubmittedText,\n\t\t\tredirectUrl,\n\t\t\tappendAttribution,\n\t\t\tbuttonLabel,\n\t\t\tcustomCss: options.customCss,\n\t\t});\n\n\t\treturn {\n\t\t\tnoWebhookResponse: true,\n\t\t};\n\t}\n\n\tlet { useWorkflowTimezone } = options;\n\n\tif (useWorkflowTimezone === undefined && node.typeVersion > 2) {\n\t\tuseWorkflowTimezone = true;\n\t}\n\n\tconst returnItem = await prepareFormReturnItem(context, formFields, mode, useWorkflowTimezone);\n\n\treturn {\n\t\twebhookResponse: { status: 200 },\n\t\tworkflowData: [[returnItem]],\n\t};\n}\n\nexport function resolveRawData(context: IWebhookFunctions, rawData: string) {\n\tconst resolvables = getResolvables(rawData);\n\tlet returnData: string = rawData;\n\n\tif (returnData.startsWith('=')) {\n\t\treturnData = returnData.replace(/^=+/, '');\n\t} else {\n\t\treturn returnData;\n\t}\n\n\tif (resolvables.length) {\n\t\tfor (const resolvable of resolvables) {\n\t\t\tconst resolvedValue = context.evaluateExpression(`${resolvable}`);\n\n\t\t\tif (typeof resolvedValue === 'object' && resolvedValue !== null) {\n\t\t\t\treturnData = returnData.replace(resolvable, JSON.stringify(resolvedValue));\n\t\t\t} else {\n\t\t\t\treturnData = returnData.replace(resolvable, resolvedValue as string);\n\t\t\t}\n\t\t}\n\t}\n\treturn returnData;\n}\n"],"mappings":"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","names":["sanitize","isbot"]}
|
|
File without changes
|
|
File without changes
|