n8n-nodes-formbase 0.2.1 → 0.3.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/README.md CHANGED
@@ -8,6 +8,7 @@ Community node for [n8n](https://n8n.io) that starts workflows when a [formbase]
8
8
  - Trigger on abandoned submissions when partial submission tracking is enabled.
9
9
  - Load forms dynamically from every workspace available to the credential.
10
10
  - Register and remove formbase webhook subscriptions with the n8n workflow lifecycle.
11
+ - Verify every webhook with HMAC-SHA256 and reject stale or forged requests.
11
12
  - Connect through workspace-scoped OAuth 2.1 with PKCE and automatic refresh-token rotation.
12
13
 
13
14
  ## Install
@@ -42,6 +43,12 @@ Self-hosted n8n must use configured HTTPS public URL for OAuth callback. Loopbac
42
43
 
43
44
  n8n webhook URL must be publicly reachable over HTTPS. For reverse-proxy or tunnel deployments, configure n8n's `WEBHOOK_URL` so generated webhook URLs use public origin.
44
45
 
46
+ n8n generates a separate 256-bit signing secret for each registration. Incoming requests must contain a valid `X-formbase-Signature` header with a timestamp no more than five minutes old. Missing, stale, or invalid signatures receive `401 Unauthorized` and do not start the workflow.
47
+
48
+ ## Example workflow
49
+
50
+ Import [`examples/formbase-submission.json`](examples/formbase-submission.json), connect formbase credential, select form, then activate workflow. Example maps event ID, submission ID, respondent email, and form name into stable output fields.
51
+
45
52
  ## Output
46
53
 
47
54
  Each webhook produces one n8n item containing formbase payload:
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FormbaseTrigger = void 0;
4
4
  const n8n_workflow_1 = require("n8n-workflow");
5
5
  const constants_1 = require("./constants");
6
+ const FormbaseWebhookSignature_1 = require("./FormbaseWebhookSignature");
6
7
  const GenericFunctions_1 = require("./GenericFunctions");
7
8
  const FORMS_PAGE_SIZE = 100;
8
9
  async function listWorkspaceForms(context, workspace) {
@@ -27,6 +28,10 @@ async function listWorkspaceForms(context, workspace) {
27
28
  function findWebhookSubscription(subscriptions, targetUrl, eventType) {
28
29
  return subscriptions.find((subscription) => subscription.targetUrl === targetUrl && subscription.provider === 'n8n' && subscription.eventType === eventType);
29
30
  }
31
+ function clearWebhookRegistration(webhookData) {
32
+ delete webhookData.subscriptionId;
33
+ delete webhookData.webhookSecret;
34
+ }
30
35
  class FormbaseTrigger {
31
36
  constructor() {
32
37
  this.description = {
@@ -37,7 +42,6 @@ class FormbaseTrigger {
37
42
  version: 1,
38
43
  subtitle: '={{ $parameter["event"] === "submission_created" ? "On submission created" : "On submission abandoned" }}',
39
44
  description: 'Starts the workflow when a formbase form receives a submission',
40
- usableAsTool: true,
41
45
  defaults: {
42
46
  name: 'formbase Trigger',
43
47
  },
@@ -131,10 +135,17 @@ class FormbaseTrigger {
131
135
  formId,
132
136
  }));
133
137
  const match = findWebhookSubscription(result.items, webhookUrl, eventType);
134
- if (match) {
135
- webhookData.subscriptionId = match.subscriptionId;
136
- return true;
138
+ if (!match) {
139
+ clearWebhookRegistration(webhookData);
140
+ return false;
137
141
  }
142
+ const registrationMatchesStaticData = webhookData.subscriptionId === match.subscriptionId && typeof webhookData.webhookSecret === 'string';
143
+ if (registrationMatchesStaticData)
144
+ return true;
145
+ await GenericFunctions_1.formbaseApiRequest.call(this, 'webhooks.delete', {
146
+ subscriptionId: match.subscriptionId,
147
+ });
148
+ clearWebhookRegistration(webhookData);
138
149
  return false;
139
150
  },
140
151
  async create() {
@@ -143,21 +154,26 @@ class FormbaseTrigger {
143
154
  return false;
144
155
  const formId = this.getNodeParameter('formId');
145
156
  const eventType = this.getNodeParameter('event');
157
+ const webhookSecret = (0, FormbaseWebhookSignature_1.createFormbaseWebhookSecret)();
146
158
  const created = (await GenericFunctions_1.formbaseApiRequest.call(this, 'webhooks.create', {
147
159
  formId,
148
160
  targetUrl: webhookUrl,
149
161
  provider: 'n8n',
150
162
  eventType,
163
+ signingSecret: webhookSecret,
151
164
  }));
152
165
  const webhookData = this.getWorkflowStaticData('node');
153
166
  webhookData.subscriptionId = created.subscriptionId;
167
+ webhookData.webhookSecret = webhookSecret;
154
168
  return true;
155
169
  },
156
170
  async delete() {
157
171
  const webhookData = this.getWorkflowStaticData('node');
158
172
  const subscriptionId = webhookData.subscriptionId;
159
- if (typeof subscriptionId !== 'string')
173
+ if (typeof subscriptionId !== 'string') {
174
+ clearWebhookRegistration(webhookData);
160
175
  return true;
176
+ }
161
177
  try {
162
178
  await GenericFunctions_1.formbaseApiRequest.call(this, 'webhooks.delete', {
163
179
  subscriptionId,
@@ -168,13 +184,17 @@ class FormbaseTrigger {
168
184
  return false;
169
185
  }
170
186
  }
171
- delete webhookData.subscriptionId;
187
+ clearWebhookRegistration(webhookData);
172
188
  return true;
173
189
  },
174
190
  },
175
191
  };
176
192
  }
177
193
  async webhook() {
194
+ if (!(0, FormbaseWebhookSignature_1.verifyFormbaseWebhookSignature)(this)) {
195
+ this.getResponseObject().status(401).send('Unauthorized').end();
196
+ return { noWebhookResponse: true };
197
+ }
178
198
  const body = this.getBodyData();
179
199
  return {
180
200
  workflowData: [this.helpers.returnJsonArray(body)],
@@ -1 +1 @@
1
- {"version":3,"file":"FormbaseTrigger.node.js","sourceRoot":"","sources":["../../../nodes/Formbase/FormbaseTrigger.node.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FormbaseTrigger.node.js","sourceRoot":"","sources":["../../../nodes/Formbase/FormbaseTrigger.node.ts"],"names":[],"mappings":";;;AAUA,+CAAgE;AAEhE,2CAAiH;AACjH,yEAAwG;AACxG,yDAAuD;AA8BvD,MAAM,eAAe,GAAG,GAAG,CAAA;AAE3B,KAAK,UAAU,kBAAkB,CAAC,OAA8B,EAAE,SAA2B;IAC3F,MAAM,KAAK,GAAkB,EAAE,CAAA;IAC/B,IAAI,MAA0B,CAAA;IAE9B,GAAG,CAAC;QACF,MAAM,MAAM,GAAG,CAAC,MAAM,qCAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE;YACnE,WAAW,EAAE,SAAS,CAAC,EAAE;YACzB,KAAK,EAAE,eAAe;YACtB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9B,CAAC,CAA8B,CAAA;QAEhC,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;QAC3B,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,MAAK;QAC1B,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YACvB,MAAM,IAAI,2BAAY,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,4CAA4C,EAAE,CAAC,CAAA;QACtG,CAAC;QACD,MAAM,GAAG,MAAM,CAAC,UAAU,CAAA;IAC5B,CAAC,QAAQ,MAAM,EAAC;IAEhB,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,uBAAuB,CAC9B,aAAoC,EACpC,SAAiB,EACjB,SAA+B;IAE/B,OAAO,aAAa,CAAC,IAAI,CACvB,CAAC,YAAY,EAAE,EAAE,CACf,YAAY,CAAC,SAAS,KAAK,SAAS,IAAI,YAAY,CAAC,QAAQ,KAAK,KAAK,IAAI,YAAY,CAAC,SAAS,KAAK,SAAS,CAClH,CAAA;AACH,CAAC;AAED,SAAS,wBAAwB,CAAC,WAAwB;IACxD,OAAO,WAAW,CAAC,cAAc,CAAA;IACjC,OAAO,WAAW,CAAC,aAAa,CAAA;AAClC,CAAC;AAGD,MAAa,eAAe;IAA5B;QACE,gBAAW,GAAyB;YAClC,WAAW,EAAE,kBAAkB;YAC/B,IAAI,EAAE,iBAAiB;YACvB,IAAI,EAAE,EAAE,KAAK,EAAE,wBAAwB,EAAE,IAAI,EAAE,6BAA6B,EAAE;YAC9E,KAAK,EAAE,CAAC,SAAS,CAAC;YAClB,OAAO,EAAE,CAAC;YACV,QAAQ,EACN,2GAA2G;YAC7G,WAAW,EAAE,gEAAgE;YAC7E,QAAQ,EAAE;gBACR,IAAI,EAAE,kBAAkB;aACzB;YACD,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,CAAC,kCAAmB,CAAC,IAAI,CAAC;YACnC,WAAW,EAAE;gBACX;oBACE,IAAI,EAAE,2CAA+B;oBACrC,QAAQ,EAAE,IAAI;iBACf;aACF;YACD,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,SAAS;oBACf,UAAU,EAAE,MAAM;oBAClB,YAAY,EAAE,YAAY;oBAC1B,IAAI,EAAE,UAAU;iBACjB;aACF;YACD,YAAY,EAAE;gBACZ,MAAM,EAAE,oCAAoC;gBAC5C,cAAc,EAAE;oBACd,QAAQ,EACN,kKAAkK;oBACpK,MAAM,EACJ,0HAA0H;iBAC7H;gBACD,cAAc,EAAE,uFAAuF;aACxG;YACD,UAAU,EAAE;gBACV;oBACE,WAAW,EAAE,iBAAiB;oBAC9B,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE;wBACX,iBAAiB,EAAE,UAAU;qBAC9B;oBACD,OAAO,EAAE,EAAE;oBACX,QAAQ,EAAE,IAAI;oBACd,WAAW,EAAE,gHAAgH;iBAC9H;gBACD;oBACE,WAAW,EAAE,OAAO;oBACpB,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,SAAS;oBACf,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,sBAAsB;4BAC5B,KAAK,EAAE,mCAAuB,CAAC,mBAAmB;4BAClD,MAAM,EAAE,yBAAyB;4BACjC,WAAW,EACT,4GAA4G;yBAC/G;wBACD;4BACE,IAAI,EAAE,oBAAoB;4BAC1B,KAAK,EAAE,mCAAuB,CAAC,iBAAiB;4BAChD,MAAM,EAAE,uBAAuB;4BAC/B,WAAW,EAAE,kDAAkD;yBAChE;qBACF;oBACD,OAAO,EAAE,oBAAoB;oBAC7B,WAAW,EAAE,mFAAmF;iBACjG;aACF;SACF,CAAA;QAED,YAAO,GAAG;YACR,WAAW,EAAE;gBACX,KAAK,CAAC,QAAQ;oBACZ,MAAM,eAAe,GAAG,CAAC,MAAM,qCAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAmC,CAAA;oBACtH,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,GAAG,CACxC,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;wBAC9C,SAAS;wBACT,KAAK,EAAE,MAAM,kBAAkB,CAAC,IAAI,EAAE,SAAS,CAAC;qBACjD,CAAC,CAAC,CACJ,CAAA;oBACD,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAA;oBAErD,OAAO,gBAAgB,CAAC,OAAO,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,CACvD,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;wBACnB,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;wBACxE,KAAK,EAAE,IAAI,CAAC,EAAE;qBACf,CAAC,CAAC,CACJ,CAAA;gBACH,CAAC;aACF;SACF,CAAA;QAED,mBAAc,GAAG;YACf,OAAO,EAAE;gBACP,KAAK,CAAC,WAAW;oBACf,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAA;oBACpD,IAAI,CAAC,UAAU;wBAAE,OAAO,KAAK,CAAA;oBAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAW,CAAA;oBACxD,IAAI,CAAC,MAAM;wBAAE,OAAO,KAAK,CAAA;oBACzB,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAyB,CAAA;oBAExE,MAAM,WAAW,GAAG,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAA;oBACtD,MAAM,MAAM,GAAG,CAAC,MAAM,qCAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,EAAE;wBACnE,MAAM;qBACP,CAAC,CAAsC,CAAA;oBAExC,MAAM,KAAK,GAAG,uBAAuB,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,CAAA;oBAC1E,IAAI,CAAC,KAAK,EAAE,CAAC;wBACX,wBAAwB,CAAC,WAAW,CAAC,CAAA;wBACrC,OAAO,KAAK,CAAA;oBACd,CAAC;oBAED,MAAM,6BAA6B,GACjC,WAAW,CAAC,cAAc,KAAK,KAAK,CAAC,cAAc,IAAI,OAAO,WAAW,CAAC,aAAa,KAAK,QAAQ,CAAA;oBACtG,IAAI,6BAA6B;wBAAE,OAAO,IAAI,CAAA;oBAI9C,MAAM,qCAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,iBAAiB,EAAE;wBACrD,cAAc,EAAE,KAAK,CAAC,cAAc;qBACrC,CAAC,CAAA;oBACF,wBAAwB,CAAC,WAAW,CAAC,CAAA;oBACrC,OAAO,KAAK,CAAA;gBACd,CAAC;gBAED,KAAK,CAAC,MAAM;oBACV,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAA;oBACpD,IAAI,CAAC,UAAU;wBAAE,OAAO,KAAK,CAAA;oBAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAW,CAAA;oBACxD,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAyB,CAAA;oBACxE,MAAM,aAAa,GAAG,IAAA,sDAA2B,GAAE,CAAA;oBAEnD,MAAM,OAAO,GAAG,CAAC,MAAM,qCAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,iBAAiB,EAAE;wBACtE,MAAM;wBACN,SAAS,EAAE,UAAU;wBACrB,QAAQ,EAAE,KAAK;wBACf,SAAS;wBACT,aAAa,EAAE,aAAa;qBAC7B,CAAC,CAA0B,CAAA;oBAE5B,MAAM,WAAW,GAAG,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAA;oBACtD,WAAW,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,CAAA;oBACnD,WAAW,CAAC,aAAa,GAAG,aAAa,CAAA;oBACzC,OAAO,IAAI,CAAA;gBACb,CAAC;gBAED,KAAK,CAAC,MAAM;oBACV,MAAM,WAAW,GAAG,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAA;oBACtD,MAAM,cAAc,GAAG,WAAW,CAAC,cAAc,CAAA;oBACjD,IAAI,OAAO,cAAc,KAAK,QAAQ,EAAE,CAAC;wBACvC,wBAAwB,CAAC,WAAW,CAAC,CAAA;wBACrC,OAAO,IAAI,CAAA;oBACb,CAAC;oBAED,IAAI,CAAC;wBACH,MAAM,qCAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,iBAAiB,EAAE;4BACrD,cAAc;yBACf,CAAC,CAAA;oBACJ,CAAC;oBAAC,OAAO,KAAc,EAAE,CAAC;wBACxB,IAAI,CAAC,CAAC,KAAK,YAAY,2BAAY,CAAC,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;4BACjE,OAAO,KAAK,CAAA;wBACd,CAAC;oBACH,CAAC;oBACD,wBAAwB,CAAC,WAAW,CAAC,CAAA;oBACrC,OAAO,IAAI,CAAA;gBACb,CAAC;aACF;SACF,CAAA;IAaH,CAAC;IAXC,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,IAAA,yDAA8B,EAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,IAAI,CAAC,iBAAiB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,GAAG,EAAE,CAAA;YAC/D,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAA;QACpC,CAAC;QAED,MAAM,IAAI,GAAgB,IAAI,CAAC,WAAW,EAAE,CAAA;QAC5C,OAAO;YACL,YAAY,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;SACnD,CAAA;IACH,CAAC;CACF;AA1LD,0CA0LC"}
@@ -0,0 +1,3 @@
1
+ import type { IWebhookFunctions } from 'n8n-workflow';
2
+ export declare function createFormbaseWebhookSecret(): string;
3
+ export declare function verifyFormbaseWebhookSignature(context: IWebhookFunctions): boolean;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createFormbaseWebhookSecret = createFormbaseWebhookSecret;
4
+ exports.verifyFormbaseWebhookSignature = verifyFormbaseWebhookSignature;
5
+ const node_crypto_1 = require("node:crypto");
6
+ const SIGNATURE_HEADER_PATTERN = /^t=(\d+),sha256=([a-f0-9]{64})$/;
7
+ const SIGNATURE_MAX_AGE_SECONDS = 5 * 60;
8
+ function getRawBody(request) {
9
+ if (!('rawBody' in request))
10
+ return undefined;
11
+ const rawBody = request.rawBody;
12
+ if (Buffer.isBuffer(rawBody))
13
+ return rawBody;
14
+ if (typeof rawBody === 'string')
15
+ return Buffer.from(rawBody);
16
+ return undefined;
17
+ }
18
+ function createFormbaseWebhookSecret() {
19
+ return `whsec_${(0, node_crypto_1.randomBytes)(32).toString('hex')}`;
20
+ }
21
+ function verifyFormbaseWebhookSignature(context) {
22
+ const webhookData = context.getWorkflowStaticData('node');
23
+ const secret = webhookData.webhookSecret;
24
+ if (typeof secret !== 'string' || secret.length === 0)
25
+ return false;
26
+ const signatureHeader = context.getHeaderData()['x-formbase-signature'];
27
+ if (typeof signatureHeader !== 'string')
28
+ return false;
29
+ const match = SIGNATURE_HEADER_PATTERN.exec(signatureHeader);
30
+ if (!match)
31
+ return false;
32
+ const [, timestamp, signatureHex] = match;
33
+ const timestampSeconds = Number(timestamp);
34
+ if (!Number.isSafeInteger(timestampSeconds))
35
+ return false;
36
+ const currentTimestampSeconds = Math.floor(Date.now() / 1000);
37
+ if (Math.abs(currentTimestampSeconds - timestampSeconds) > SIGNATURE_MAX_AGE_SECONDS)
38
+ return false;
39
+ const rawBody = getRawBody(context.getRequestObject());
40
+ if (!rawBody)
41
+ return false;
42
+ const expectedSignature = (0, node_crypto_1.createHmac)('sha256', secret).update(timestamp).update('.').update(rawBody).digest();
43
+ const receivedSignature = Buffer.from(signatureHex, 'hex');
44
+ return expectedSignature.length === receivedSignature.length && (0, node_crypto_1.timingSafeEqual)(expectedSignature, receivedSignature);
45
+ }
46
+ //# sourceMappingURL=FormbaseWebhookSignature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormbaseWebhookSignature.js","sourceRoot":"","sources":["../../../nodes/Formbase/FormbaseWebhookSignature.ts"],"names":[],"mappings":";;AAgBA,kEAEC;AAED,wEAyBC;AA7CD,6CAAsE;AAItE,MAAM,wBAAwB,GAAG,iCAAiC,CAAA;AAClE,MAAM,yBAAyB,GAAG,CAAC,GAAG,EAAE,CAAA;AAExC,SAAS,UAAU,CAAC,OAA0D;IAC5E,IAAI,CAAC,CAAC,SAAS,IAAI,OAAO,CAAC;QAAE,OAAO,SAAS,CAAA;IAE7C,MAAM,OAAO,GAAY,OAAO,CAAC,OAAO,CAAA;IACxC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAA;IAC5C,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC5D,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAgB,2BAA2B;IACzC,OAAO,SAAS,IAAA,yBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAA;AACnD,CAAC;AAED,SAAgB,8BAA8B,CAAC,OAA0B;IACvE,MAAM,WAAW,GAAG,OAAO,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAA;IACzD,MAAM,MAAM,GAAG,WAAW,CAAC,aAAa,CAAA;IACxC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAEnE,MAAM,eAAe,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,sBAAsB,CAAC,CAAA;IACvE,IAAI,OAAO,eAAe,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAErD,MAAM,KAAK,GAAG,wBAAwB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;IAC5D,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IAExB,MAAM,CAAC,EAAE,SAAS,EAAE,YAAY,CAAC,GAAG,KAAK,CAAA;IACzC,MAAM,gBAAgB,GAAG,MAAM,CAAC,SAAS,CAAC,CAAA;IAC1C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC;QAAE,OAAO,KAAK,CAAA;IAEzD,MAAM,uBAAuB,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;IAC7D,IAAI,IAAI,CAAC,GAAG,CAAC,uBAAuB,GAAG,gBAAgB,CAAC,GAAG,yBAAyB;QAAE,OAAO,KAAK,CAAA;IAElG,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAA;IACtD,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAA;IAE1B,MAAM,iBAAiB,GAAG,IAAA,wBAAU,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAA;IAC7G,MAAM,iBAAiB,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;IAE1D,OAAO,iBAAiB,CAAC,MAAM,KAAK,iBAAiB,CAAC,MAAM,IAAI,IAAA,6BAAe,EAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAAA;AACvH,CAAC"}
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-formbase",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "n8n community node for formbase — trigger workflows from form submissions.",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",
@@ -32,7 +32,8 @@
32
32
  "prepublishOnly": "npm test && npm run build && npm run lint"
33
33
  },
34
34
  "files": [
35
- "dist"
35
+ "dist",
36
+ "examples"
36
37
  ],
37
38
  "engines": {
38
39
  "node": ">=22"
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "Handle formbase submission",
3
+ "nodes": [
4
+ {
5
+ "parameters": {
6
+ "formId": "",
7
+ "event": "submission_created"
8
+ },
9
+ "type": "n8n-nodes-formbase.formbaseTrigger",
10
+ "typeVersion": 1,
11
+ "position": [0, 0],
12
+ "id": "16e911f0-6385-4acc-8286-1afb15eb035c",
13
+ "name": "formbase Trigger"
14
+ },
15
+ {
16
+ "parameters": {
17
+ "assignments": {
18
+ "assignments": [
19
+ {
20
+ "id": "cdcb57d7-377e-45e2-8da9-63e52f4690b4",
21
+ "name": "eventId",
22
+ "value": "={{ $json.eventId }}",
23
+ "type": "string"
24
+ },
25
+ {
26
+ "id": "b27b42be-fc5d-491f-a93b-02a7fa4e63f8",
27
+ "name": "submissionId",
28
+ "value": "={{ $json.submission.id }}",
29
+ "type": "string"
30
+ },
31
+ {
32
+ "id": "2b171786-cb32-4e73-96e5-d60f39060fe1",
33
+ "name": "respondentEmail",
34
+ "value": "={{ $json.submission.respondentEmail }}",
35
+ "type": "string"
36
+ },
37
+ {
38
+ "id": "a6366cdf-c3b9-4bdc-be3c-723d2bfab7a4",
39
+ "name": "formName",
40
+ "value": "={{ $json.form.name }}",
41
+ "type": "string"
42
+ }
43
+ ]
44
+ },
45
+ "options": {}
46
+ },
47
+ "type": "n8n-nodes-base.set",
48
+ "typeVersion": 3.4,
49
+ "position": [240, 0],
50
+ "id": "27abc7e3-21e9-4654-9078-b12b60420f6d",
51
+ "name": "Prepare submission"
52
+ }
53
+ ],
54
+ "pinData": {},
55
+ "connections": {
56
+ "formbase Trigger": {
57
+ "main": [
58
+ [
59
+ {
60
+ "node": "Prepare submission",
61
+ "type": "main",
62
+ "index": 0
63
+ }
64
+ ]
65
+ ]
66
+ }
67
+ },
68
+ "active": false,
69
+ "settings": {
70
+ "executionOrder": "v1"
71
+ },
72
+ "versionId": "0f0cc0ea-543e-43ac-bf55-9256b1ee5f85",
73
+ "meta": {
74
+ "templateCredsSetupCompleted": false
75
+ },
76
+ "tags": []
77
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-formbase",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "n8n community node for formbase — trigger workflows from form submissions.",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",
@@ -32,7 +32,8 @@
32
32
  "prepublishOnly": "npm test && npm run build && npm run lint"
33
33
  },
34
34
  "files": [
35
- "dist"
35
+ "dist",
36
+ "examples"
36
37
  ],
37
38
  "engines": {
38
39
  "node": ">=22"