1-
2-
31import {
4- INodeType ,
5- INodeTypeDescription ,
2+ INodeType ,
3+ INodeTypeDescription ,
64ILoadOptionsFunctions ,
75INodeListSearchResult ,
86IExecuteFunctions ,
@@ -17,22 +15,22 @@ import { apiRequest } from './GenericFunctions';
1715import isbot from 'isbot' ;
1816
1917interface LowcoderAppType {
20- applicationId :string ;
21- name :string ;
18+ applicationId :string ;
19+ name :string ;
2220applicationType :number
2321}
2422
2523const WAIT_TIME_UNLIMITED = '3000-01-01T00:00:00.000Z' ;
2624
2725export class Lowcoder implements INodeType {
28- description :INodeTypeDescription = {
26+ description :INodeTypeDescription = {
2927displayName :'Lowcoder' ,
3028name :'lowcoder' ,
3129// eslint-disable-next-line n8n-nodes-base/node-class-description-icon-not-svg
3230icon :'file:lowcoder.png' ,
3331group :[ 'transform' ] ,
3432version :1 ,
35- subtitle :'=app:{{ $parameter["appId"]' ,
33+ subtitle :'=app:{{ $parameter["appId"]' ,
3634description :'Consume Lowcoder API' ,
3735defaults :{
3836name :'Lowcoder' ,
@@ -50,100 +48,121 @@ export class Lowcoder implements INodeType {
5048name :'default' ,
5149httpMethod :'={{$parameter["httpMethod"]}}' ,
5250isFullPath :true ,
53- responseCode :'200' ,
5451responseMode :'onReceived' ,
55- responseData :'allEntries ' ,
56- responseContentType :'={{$parameter["options"]["responseContentType"]}}' ,
52+ responseData :'={{$parameter["options"]["responseData"] || "Workflow Resumed!"}} ' ,
53+ responseContentType :'={{$parameter["options"]["responseContentType"] || "application/json" }}' ,
5754responsePropertyName :'={{$parameter["options"]["responsePropertyName"]}}' ,
5855responseHeaders :'={{$parameter["options"]["responseHeaders"]}}' ,
5956path :'={{$parameter["appId"] || ""}}' ,
60- restartWebhook :true ,
57+ restartWebhook :true ,
6158} ,
62- ] ,
59+ ] ,
6360properties :[
6461 ...appFields ,
6562{
66- displayName :'Resume the workflow by calling this Webhook: http(s)://{n8n-url}/webhook-waiting/{Workflow-Execution-ID}/{Lowcoder-App-ID}' ,
67- name :'webhookNotice' ,
68- type :'notice' ,
69- default :'' ,
70- } ,
71- {
72- displayName :'The Workflow-Execution-ID is available via the n8n Rest API' ,
73- name :'webhookNotice' ,
74- type :'notice' ,
75- default :'' ,
76- } ,
63+ displayName :'Resume the workflow by calling this Webhook: http(s)://{n8n-url}/webhook-waiting/{Workflow-Execution-ID}/{Lowcoder-App-ID}' ,
64+ name :'webhookNotice' ,
65+ type :'notice' ,
66+ default :'' ,
67+ } ,
68+ {
69+ displayName :'The Workflow-Execution-ID is available via the n8n Rest API' ,
70+ name :'webhookNotice' ,
71+ type :'notice' ,
72+ default :'' ,
73+ } ,
7774httpMethodsProperty ,
78- optionsProperty
75+ optionsProperty ,
76+ {
77+ displayName :'Response Code' ,
78+ name :'responseCode' ,
79+ type :'number' ,
80+ default :200 ,
81+ description :'The HTTP response code to return' ,
82+ } ,
7983] ,
80- } ;
84+ } ;
8185
8286methods = {
83- listSearch :{
84- async searchApps (
85- this :ILoadOptionsFunctions ,
86- query ?:string ,
87- ) :Promise < INodeListSearchResult > {
88-
89- const searchResults = await apiRequest . call (
90- this ,
91- 'GET' ,
92- 'applications/list' ,
93- { } ,
94- {
95- query,
87+ listSearch :{
88+ async searchApps (
89+ this :ILoadOptionsFunctions ,
90+ query ?:string ,
91+ ) :Promise < INodeListSearchResult > {
92+ const searchResults = await apiRequest . call (
93+ this ,
94+ 'GET' ,
95+ 'applications/list' ,
96+ { } ,
97+ {
98+ query,
9699withContainerSize :false
97- } ,
98- ) ;
99- console . log ( searchResults ) ;
100- return {
101- results :searchResults . data . map ( ( b :LowcoderAppType ) => ( {
102- name :`${ b . name } (${ b . applicationType == 2 ?"Module" :"App" } )` ,
103- value :b . applicationId ,
104- } ) ) ,
105- } ;
106- } ,
107- } ,
108- } ;
100+ } ,
101+ ) ;
102+ console . log ( searchResults ) ;
103+ return {
104+ results :searchResults . data . map ( ( b :LowcoderAppType ) => ( {
105+ name :`${ b . name } (${ b . applicationType == 2 ?"Module" :"App" } )` ,
106+ value :b . applicationId ,
107+ } ) ) ,
108+ } ;
109+ } ,
110+ } ,
111+ } ;
109112
110113async webhook ( this :IWebhookFunctions ) :Promise < IWebhookResponseData > {
111- const options = this . getNodeParameter ( 'options' , { } ) as {
112- binaryData :boolean ;
113- ignoreBots :boolean ;
114- rawBody :Buffer ;
115- responseData ?:string ;
116- } ;
117- const req = this . getRequestObject ( ) ;
118- const resp = this . getResponseObject ( ) ;
114+ const options = this . getNodeParameter ( 'options' , { } ) as {
115+ binaryData :boolean ;
116+ ignoreBots :boolean ;
117+ rawBody :Buffer ;
118+ responseData ?:string ;
119+ responseCode ?:number ;
120+ } ;
121+ const req = this . getRequestObject ( ) ;
122+ const resp = this . getResponseObject ( ) ;
119123
120- try {
121- if ( options . ignoreBots && isbot ( req . headers [ 'user-agent' ] ) ) {
122- throw new NodeApiError ( this . getNode ( ) , { } , { message :'Authorization data is wrong!' } ) ;
124+ try {
125+ if ( options . ignoreBots && isbot ( req . headers [ 'user-agent' ] ) ) {
126+ throw new NodeApiError ( this . getNode ( ) , { } , { message :'Authorization data is wrong!' } ) ;
123127}
124- } catch ( error ) {
125- resp . writeHead ( error . responseCode , { 'WWW-Authenticate' :'Basic realm="Webhook"' } ) ;
128+ } catch ( error ) {
129+ resp . writeHead ( error . responseCode || 401 , { 'WWW-Authenticate' :'Basic realm="Webhook"' } ) ;
126130resp . end ( error . message ) ;
127131return { noWebhookResponse :true } ;
128- }
129- const body = typeof req . body != 'undefined' ?req . body :{ } ;
130- const returnItem :INodeExecutionData = {
131- binary :{ } ,
132- json :{
133- headers :req . headers ,
134- params :req . params ,
135- query :req . query ,
136- body :body ,
137- } ,
138- } ;
139- return { workflowData :[ [ returnItem ] ] } ;
140- }
132+ }
141133
142- async execute ( this :IExecuteFunctions ) :Promise < INodeExecutionData [ ] [ ] > {
134+ const type = req . query . type ;
135+ if ( type === 'resume' ) {
136+ // Resume workflow as before
137+ const body = typeof req . body != 'undefined' ?req . body :{ } ;
138+ const returnItem :INodeExecutionData = {
139+ binary :{ } ,
140+ json :{
141+ headers :req . headers ,
142+ params :req . params ,
143+ query :req . query ,
144+ body :body ,
145+ } ,
146+ } ;
147+ const responseCode = options . responseCode || 200 ;
148+ resp . statusCode = responseCode ;
149+ return { workflowData :[ [ returnItem ] ] } ;
150+ } else {
151+ // Return input data, and don't resume
152+ const staticData = this . getWorkflowStaticData ( 'node' ) ;
153+ const previousData = staticData . previousNodeData || [ ] ;
154+ resp . statusCode = 200 ;
155+ resp . setHeader ( 'Content-Type' , 'application/json' ) ;
156+ resp . end ( JSON . stringify ( { message :'Static response: workflow not resumed' , type, previousData} ) ) ;
157+ return { noWebhookResponse :true } ;
158+ }
159+ }
143160
161+ async execute ( this :IExecuteFunctions ) :Promise < INodeExecutionData [ ] [ ] > {
144162let waitTill = new Date ( WAIT_TIME_UNLIMITED ) ;
145-
163+ const staticData = this . getWorkflowStaticData ( 'node' ) ;
164+ staticData . previousNodeData = this . getInputData ( ) . map ( item => item . json ) ;
146165await this . putExecutionToWait ( waitTill ) ;
147- return [ this . getInputData ( ) ] ;
148- }
166+ return [ this . getInputData ( ) ] ;
167+ }
149168}