n8n-nodes-42min 0.1.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/LICENSE +21 -0
- package/README.md +151 -0
- package/dist/credentials/FortyTwoMinApi.credentials.d.ts +10 -0
- package/dist/credentials/FortyTwoMinApi.credentials.js +45 -0
- package/dist/credentials/FortyTwoMinApi.credentials.js.map +1 -0
- package/dist/icons/fortytwomin.dark.svg +22 -0
- package/dist/icons/fortytwomin.svg +22 -0
- package/dist/nodes/FortyTwoMin/FortyTwoMin.node.d.ts +4 -0
- package/dist/nodes/FortyTwoMin/FortyTwoMin.node.js +68 -0
- package/dist/nodes/FortyTwoMin/FortyTwoMin.node.js.map +1 -0
- package/dist/nodes/FortyTwoMin/FortyTwoMin.node.json +18 -0
- package/dist/nodes/FortyTwoMin/FortyTwoMinTrigger.node.d.ts +12 -0
- package/dist/nodes/FortyTwoMin/FortyTwoMinTrigger.node.js +185 -0
- package/dist/nodes/FortyTwoMin/FortyTwoMinTrigger.node.js.map +1 -0
- package/dist/nodes/FortyTwoMin/FortyTwoMinTrigger.node.json +18 -0
- package/dist/nodes/FortyTwoMin/GenericFunctions.d.ts +11 -0
- package/dist/nodes/FortyTwoMin/GenericFunctions.js +120 -0
- package/dist/nodes/FortyTwoMin/GenericFunctions.js.map +1 -0
- package/dist/nodes/FortyTwoMin/Routing.d.ts +10 -0
- package/dist/nodes/FortyTwoMin/Routing.js +63 -0
- package/dist/nodes/FortyTwoMin/Routing.js.map +1 -0
- package/dist/nodes/FortyTwoMin/descriptions/BookingDescription.d.ts +3 -0
- package/dist/nodes/FortyTwoMin/descriptions/BookingDescription.js +477 -0
- package/dist/nodes/FortyTwoMin/descriptions/BookingDescription.js.map +1 -0
- package/dist/nodes/FortyTwoMin/descriptions/EventTypeDescription.d.ts +3 -0
- package/dist/nodes/FortyTwoMin/descriptions/EventTypeDescription.js +143 -0
- package/dist/nodes/FortyTwoMin/descriptions/EventTypeDescription.js.map +1 -0
- package/dist/nodes/FortyTwoMin/descriptions/SlotDescription.d.ts +3 -0
- package/dist/nodes/FortyTwoMin/descriptions/SlotDescription.js +127 -0
- package/dist/nodes/FortyTwoMin/descriptions/SlotDescription.js.map +1 -0
- package/dist/nodes/FortyTwoMin/descriptions/UserDescription.d.ts +3 -0
- package/dist/nodes/FortyTwoMin/descriptions/UserDescription.js +28 -0
- package/dist/nodes/FortyTwoMin/descriptions/UserDescription.js.map +1 -0
- package/index.js +3 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 42min
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# n8n-nodes-42min
|
|
2
|
+
|
|
3
|
+
An [n8n](https://n8n.io) community node for [42min](https://42min.us), a meeting
|
|
4
|
+
scheduling platform. Create and manage bookings, look up availability, and start
|
|
5
|
+
workflows the moment something happens on a calendar.
|
|
6
|
+
|
|
7
|
+
This is a community node. It runs inside your own n8n instance and talks directly to
|
|
8
|
+
`api.42min.us`; nothing routes through a third party.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
In n8n, go to **Settings → Community Nodes → Install** and enter:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
n8n-nodes-42min
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or install it manually next to your n8n data directory:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install n8n-nodes-42min
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Requires n8n 1.x and Node.js 20.15 or newer.
|
|
25
|
+
|
|
26
|
+
## Credentials
|
|
27
|
+
|
|
28
|
+
The node authenticates with a **personal access token**.
|
|
29
|
+
|
|
30
|
+
1. In 42min, open **Settings → API** and create a token.
|
|
31
|
+
2. Give it the scopes you need. For everything this node offers:
|
|
32
|
+
`user:read`, `event_types:read`, `slots:read`, `bookings:read`, `bookings:create`,
|
|
33
|
+
`bookings:cancel`, `bookings:reschedule`, `bookings:update`, `webhooks:read`,
|
|
34
|
+
`webhooks:write`.
|
|
35
|
+
3. In n8n, create a **42min API** credential and paste the token.
|
|
36
|
+
|
|
37
|
+
Use **Test** to confirm it works. Leave **Base URL** alone unless you run a
|
|
38
|
+
self-hosted 42min.
|
|
39
|
+
|
|
40
|
+
## Operations
|
|
41
|
+
|
|
42
|
+
### 42min (action node)
|
|
43
|
+
|
|
44
|
+
| Resource | Operations |
|
|
45
|
+
|---|---|
|
|
46
|
+
| **Booking** | Create, Get, Get Many, Update, Cancel, Reschedule |
|
|
47
|
+
| **Event Type** | Get, Get Many |
|
|
48
|
+
| **Slot** | Get Many, Check |
|
|
49
|
+
| **User** | Get Current |
|
|
50
|
+
|
|
51
|
+
### 42min Trigger
|
|
52
|
+
|
|
53
|
+
Starts a workflow on any of these events:
|
|
54
|
+
|
|
55
|
+
`booking_created`, `booking_updated`, `booking_canceled`, `booking_rescheduled`,
|
|
56
|
+
`booking_no_show`, `event_type_updated`, `event_type_deleted`,
|
|
57
|
+
`routing_form_submitted`.
|
|
58
|
+
|
|
59
|
+
Activating a workflow registers a webhook subscription with 42min automatically, and
|
|
60
|
+
deactivating it removes the subscription again.
|
|
61
|
+
|
|
62
|
+
## Things worth knowing
|
|
63
|
+
|
|
64
|
+
**Trigger items and lookup items use the same field names.** 42min delivers webhooks
|
|
65
|
+
in nested camelCase (`data.booking.startTime`) while the REST API is flat snake_case
|
|
66
|
+
(`start_at`). Booking triggers reshape the delivery into the REST vocabulary so you do
|
|
67
|
+
not have to learn two names for every field. The original envelope fields survive as
|
|
68
|
+
`event_id`, `event` and `occurred_at`. Set **Raw Payload** if you want the delivery
|
|
69
|
+
untouched.
|
|
70
|
+
|
|
71
|
+
**Deliveries are verified.** Every webhook is checked against its
|
|
72
|
+
`X-42min-Webhook-Signature` HMAC, with a replay window, and anything that fails is
|
|
73
|
+
rejected with a 401 instead of starting your workflow. Turn **Verify Signature** off
|
|
74
|
+
only if something between 42min and n8n rewrites the request body.
|
|
75
|
+
|
|
76
|
+
**Dedupe on `delivery_id`, not `event_id`.** The delivery id is stable across retries.
|
|
77
|
+
Both are attached to every trigger item.
|
|
78
|
+
|
|
79
|
+
**Writes are idempotent.** Booking creates, updates, cancels and reschedules send an
|
|
80
|
+
`Idempotency-Key` derived from the execution and item, so a retry inside one execution
|
|
81
|
+
replays the original result rather than double-booking. Set **Idempotency Key**
|
|
82
|
+
yourself when the same logical operation might be attempted from more than one
|
|
83
|
+
execution, for example keyed on a CRM record id.
|
|
84
|
+
|
|
85
|
+
**Get Event Type identifies by ID or by username plus slug.** A slug alone is not
|
|
86
|
+
enough, since it is unique per user rather than per account. The node encodes the
|
|
87
|
+
`username/slug` pair into the single path segment the API expects.
|
|
88
|
+
|
|
89
|
+
**Check the slot before you book.** Use **Slot: Check** first. A slot that was free a
|
|
90
|
+
moment ago may not be, and Create Booking sends real email and writes to a real
|
|
91
|
+
calendar.
|
|
92
|
+
|
|
93
|
+
**Updating a booking reads it first.** 42min requires the `If-Match` version token on
|
|
94
|
+
a PATCH, so the node fetches the booking, takes its ETag and sends it back. A
|
|
95
|
+
concurrent edit fails with a 409 rather than being silently overwritten. Only
|
|
96
|
+
`metadata`, `responses` and `attendee_name` are writable: to move a booking use
|
|
97
|
+
**Reschedule**, to cancel it use **Cancel**.
|
|
98
|
+
|
|
99
|
+
## Trigger requirements
|
|
100
|
+
|
|
101
|
+
42min delivers over HTTPS to public addresses only. Your n8n must be:
|
|
102
|
+
|
|
103
|
+
- reachable at an `https://` URL, and
|
|
104
|
+
- resolvable to a public IP. Deliveries to private ranges are refused.
|
|
105
|
+
|
|
106
|
+
If n8n advertises a non-HTTPS address the trigger will say so when you activate the
|
|
107
|
+
workflow. Set `WEBHOOK_URL` (or `N8N_PROTOCOL` and `N8N_HOST`) accordingly.
|
|
108
|
+
|
|
109
|
+
The action node has no such requirement: it only makes outbound calls, so it works
|
|
110
|
+
behind a firewall.
|
|
111
|
+
|
|
112
|
+
## Local development
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npm install
|
|
116
|
+
npm run lint
|
|
117
|
+
npm test
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
To run n8n with the node loaded and rebuilt on every change:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm run dev
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
For the trigger you need a publicly reachable n8n, so use a tunnel during
|
|
127
|
+
development.
|
|
128
|
+
|
|
129
|
+
## Releasing
|
|
130
|
+
|
|
131
|
+
Publishing happens in GitHub Actions, which attaches an npm provenance
|
|
132
|
+
statement. n8n requires this: nodes published from a local machine are not
|
|
133
|
+
accepted for verification.
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npm version minor
|
|
137
|
+
git push --follow-tags
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Pushing the tag runs `.github/workflows/publish.yml`, which lints, builds and
|
|
141
|
+
publishes. Update `CHANGELOG.md` in the same commit as the version bump.
|
|
142
|
+
|
|
143
|
+
## Resources
|
|
144
|
+
|
|
145
|
+
- [42min API reference](https://42min.us/help/api)
|
|
146
|
+
- [OpenAPI specification](https://api.42min.us/openapi.yaml)
|
|
147
|
+
- [n8n community nodes documentation](https://docs.n8n.io/integrations/community-nodes/)
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, Icon, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class FortyTwoMinApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
icon: Icon;
|
|
6
|
+
documentationUrl: string;
|
|
7
|
+
properties: INodeProperties[];
|
|
8
|
+
authenticate: IAuthenticateGeneric;
|
|
9
|
+
test: ICredentialTestRequest;
|
|
10
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FortyTwoMinApi = void 0;
|
|
4
|
+
class FortyTwoMinApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'fortyTwoMinApi';
|
|
7
|
+
this.displayName = '42min API';
|
|
8
|
+
this.icon = { light: 'file:../icons/fortytwomin.svg', dark: 'file:../icons/fortytwomin.dark.svg' };
|
|
9
|
+
this.documentationUrl = 'https://42min.us/help/api';
|
|
10
|
+
this.properties = [
|
|
11
|
+
{
|
|
12
|
+
displayName: 'Access Token',
|
|
13
|
+
name: 'accessToken',
|
|
14
|
+
type: 'string',
|
|
15
|
+
typeOptions: { password: true },
|
|
16
|
+
default: '',
|
|
17
|
+
required: true,
|
|
18
|
+
description: 'Personal access token from 42min. Create one under Settings > API in your 42min account.',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
displayName: 'Base URL',
|
|
22
|
+
name: 'baseUrl',
|
|
23
|
+
type: 'string',
|
|
24
|
+
default: 'https://api.42min.us',
|
|
25
|
+
description: 'Change this only if you run a self-hosted 42min instance. Do not include a trailing slash or the /v1 path.',
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
this.authenticate = {
|
|
29
|
+
type: 'generic',
|
|
30
|
+
properties: {
|
|
31
|
+
headers: {
|
|
32
|
+
Authorization: '=Bearer {{$credentials.accessToken}}',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
this.test = {
|
|
37
|
+
request: {
|
|
38
|
+
baseURL: '={{$credentials.baseUrl}}',
|
|
39
|
+
url: '/v1/me',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.FortyTwoMinApi = FortyTwoMinApi;
|
|
45
|
+
//# sourceMappingURL=FortyTwoMinApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FortyTwoMinApi.credentials.js","sourceRoot":"","sources":["../../credentials/FortyTwoMinApi.credentials.ts"],"names":[],"mappings":";;;AAQA,MAAa,cAAc;IAA3B;QACC,SAAI,GAAG,gBAAgB,CAAC;QAExB,gBAAW,GAAG,WAAW,CAAC;QAE1B,SAAI,GAAS,EAAE,KAAK,EAAE,+BAA+B,EAAE,IAAI,EAAE,oCAAoC,EAAE,CAAC;QAEpG,qBAAgB,GAAG,2BAA2B,CAAC;QAE/C,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,cAAc;gBAC3B,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EACV,6FAA6F;aAC9F;YACD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,sBAAsB;gBAC/B,WAAW,EACV,4GAA4G;aAC7G;SACD,CAAC;QAEF,iBAAY,GAAyB;YACpC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE;gBACX,OAAO,EAAE;oBACR,aAAa,EAAE,sCAAsC;iBACrD;aACD;SACD,CAAC;QAEF,SAAI,GAA2B;YAC9B,OAAO,EAAE;gBACR,OAAO,EAAE,2BAA2B;gBACpC,GAAG,EAAE,QAAQ;aACb;SACD,CAAC;IACH,CAAC;CAAA;AA7CD,wCA6CC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
|
2
|
+
<defs>
|
|
3
|
+
<clipPath id="fortytwomin-clip-dark">
|
|
4
|
+
<rect x="2" y="5" width="28" height="26" rx="3"></rect>
|
|
5
|
+
</clipPath>
|
|
6
|
+
</defs>
|
|
7
|
+
|
|
8
|
+
<rect x="8" y="1" width="2.5" height="5" rx="1.2" fill="#fdf6ec"></rect>
|
|
9
|
+
<rect x="21.5" y="1" width="2.5" height="5" rx="1.2" fill="#fdf6ec"></rect>
|
|
10
|
+
|
|
11
|
+
<rect x="2" y="5" width="28" height="26" rx="3" fill="#1a1625"></rect>
|
|
12
|
+
|
|
13
|
+
<g clip-path="url(#fortytwomin-clip-dark)">
|
|
14
|
+
<rect x="2" y="5" width="28" height="9" fill="#f25c2c"></rect>
|
|
15
|
+
</g>
|
|
16
|
+
|
|
17
|
+
<line x1="2" y1="14" x2="30" y2="14" stroke="#fdf6ec" stroke-width="1.6"></line>
|
|
18
|
+
|
|
19
|
+
<text x="16" y="27" text-anchor="middle" fill="#fdf6ec" font-family="Outfit, 'Trebuchet MS', sans-serif" font-size="14" font-weight="900" letter-spacing="-0.5">42</text>
|
|
20
|
+
|
|
21
|
+
<rect x="2" y="5" width="28" height="26" rx="3" fill="none" stroke="#fdf6ec" stroke-width="2"></rect>
|
|
22
|
+
</svg>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
|
2
|
+
<defs>
|
|
3
|
+
<clipPath id="fortytwomin-clip">
|
|
4
|
+
<rect x="2" y="5" width="28" height="26" rx="3"></rect>
|
|
5
|
+
</clipPath>
|
|
6
|
+
</defs>
|
|
7
|
+
|
|
8
|
+
<rect x="8" y="1" width="2.5" height="5" rx="1.2" fill="#1a1625"></rect>
|
|
9
|
+
<rect x="21.5" y="1" width="2.5" height="5" rx="1.2" fill="#1a1625"></rect>
|
|
10
|
+
|
|
11
|
+
<rect x="2" y="5" width="28" height="26" rx="3" fill="#fdf6ec"></rect>
|
|
12
|
+
|
|
13
|
+
<g clip-path="url(#fortytwomin-clip)">
|
|
14
|
+
<rect x="2" y="5" width="28" height="9" fill="#f25c2c"></rect>
|
|
15
|
+
</g>
|
|
16
|
+
|
|
17
|
+
<line x1="2" y1="14" x2="30" y2="14" stroke="#1a1625" stroke-width="1.6"></line>
|
|
18
|
+
|
|
19
|
+
<text x="16" y="27" text-anchor="middle" fill="#1a1625" font-family="Outfit, 'Trebuchet MS', sans-serif" font-size="14" font-weight="900" letter-spacing="-0.5">42</text>
|
|
20
|
+
|
|
21
|
+
<rect x="2" y="5" width="28" height="26" rx="3" fill="none" stroke="#1a1625" stroke-width="2"></rect>
|
|
22
|
+
</svg>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FortyTwoMin = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const BookingDescription_1 = require("./descriptions/BookingDescription");
|
|
6
|
+
const EventTypeDescription_1 = require("./descriptions/EventTypeDescription");
|
|
7
|
+
const SlotDescription_1 = require("./descriptions/SlotDescription");
|
|
8
|
+
const UserDescription_1 = require("./descriptions/UserDescription");
|
|
9
|
+
class FortyTwoMin {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.description = {
|
|
12
|
+
displayName: '42min',
|
|
13
|
+
name: 'fortyTwoMin',
|
|
14
|
+
icon: { light: 'file:../../icons/fortytwomin.svg', dark: 'file:../../icons/fortytwomin.dark.svg' },
|
|
15
|
+
group: ['transform'],
|
|
16
|
+
version: 1,
|
|
17
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
18
|
+
description: 'Read and write bookings, event types and availability in 42min',
|
|
19
|
+
defaults: { name: '42min' },
|
|
20
|
+
inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
21
|
+
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
22
|
+
usableAsTool: true,
|
|
23
|
+
credentials: [{ name: 'fortyTwoMinApi', required: true }],
|
|
24
|
+
requestDefaults: {
|
|
25
|
+
baseURL: '={{$credentials.baseUrl.replace(/\\/+$/, "")}}/v1',
|
|
26
|
+
headers: {
|
|
27
|
+
Accept: 'application/json',
|
|
28
|
+
'Content-Type': 'application/json',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
properties: [
|
|
32
|
+
{
|
|
33
|
+
displayName: 'Resource',
|
|
34
|
+
name: 'resource',
|
|
35
|
+
type: 'options',
|
|
36
|
+
noDataExpression: true,
|
|
37
|
+
options: [
|
|
38
|
+
{ name: 'Booking', value: 'booking' },
|
|
39
|
+
{ name: 'Event Type', value: 'eventType' },
|
|
40
|
+
{ name: 'Slot', value: 'slot' },
|
|
41
|
+
{ name: 'User', value: 'user' },
|
|
42
|
+
],
|
|
43
|
+
default: 'booking',
|
|
44
|
+
},
|
|
45
|
+
...BookingDescription_1.bookingOperations,
|
|
46
|
+
...BookingDescription_1.bookingFields,
|
|
47
|
+
...EventTypeDescription_1.eventTypeOperations,
|
|
48
|
+
...EventTypeDescription_1.eventTypeFields,
|
|
49
|
+
...SlotDescription_1.slotOperations,
|
|
50
|
+
...SlotDescription_1.slotFields,
|
|
51
|
+
...UserDescription_1.userOperations,
|
|
52
|
+
...UserDescription_1.userFields,
|
|
53
|
+
{
|
|
54
|
+
displayName: 'Idempotency Key',
|
|
55
|
+
name: 'idempotencyKey',
|
|
56
|
+
type: 'string',
|
|
57
|
+
default: '',
|
|
58
|
+
displayOptions: {
|
|
59
|
+
show: { resource: ['booking'], operation: ['create', 'update', 'cancel', 'reschedule'] },
|
|
60
|
+
},
|
|
61
|
+
description: 'Leave empty to derive one from the execution and item. Set it to a stable value of your own, such as a CRM record ID, when the same logical operation may be attempted from more than one execution.',
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.FortyTwoMin = FortyTwoMin;
|
|
68
|
+
//# sourceMappingURL=FortyTwoMin.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FortyTwoMin.node.js","sourceRoot":"","sources":["../../../nodes/FortyTwoMin/FortyTwoMin.node.ts"],"names":[],"mappings":";;;AACA,+CAAmD;AAEnD,0EAAqF;AACrF,8EAA2F;AAC3F,oEAA4E;AAC5E,oEAA4E;AAE5E,MAAa,WAAW;IAAxB;QACC,gBAAW,GAAyB;YACnC,WAAW,EAAE,OAAO;YACpB,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,EAAE,KAAK,EAAE,kCAAkC,EAAE,IAAI,EAAE,uCAAuC,EAAE;YAClG,KAAK,EAAE,CAAC,WAAW,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,QAAQ,EAAE,8DAA8D;YACxE,WAAW,EAAE,gEAAgE;YAC7E,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;YAC3B,MAAM,EAAE,CAAC,kCAAmB,CAAC,IAAI,CAAC;YAClC,OAAO,EAAE,CAAC,kCAAmB,CAAC,IAAI,CAAC;YACnC,YAAY,EAAE,IAAI;YAClB,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACzD,eAAe,EAAE;gBAChB,OAAO,EAAE,mDAAmD;gBAC5D,OAAO,EAAE;oBACR,MAAM,EAAE,kBAAkB;oBAC1B,cAAc,EAAE,kBAAkB;iBAClC;aACD;YACD,UAAU,EAAE;gBACX;oBACC,WAAW,EAAE,UAAU;oBACvB,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,SAAS;oBACf,gBAAgB,EAAE,IAAI;oBACtB,OAAO,EAAE;wBACR,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;wBACrC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE;wBAC1C,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;wBAC/B,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;qBAC/B;oBACD,OAAO,EAAE,SAAS;iBAClB;gBAED,GAAG,sCAAiB;gBACpB,GAAG,kCAAa;gBAChB,GAAG,0CAAmB;gBACtB,GAAG,sCAAe;gBAClB,GAAG,gCAAc;gBACjB,GAAG,4BAAU;gBACb,GAAG,gCAAc;gBACjB,GAAG,4BAAU;gBAEb;oBACC,WAAW,EAAE,iBAAiB;oBAC9B,IAAI,EAAE,gBAAgB;oBACtB,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,EAAE;oBACX,cAAc,EAAE;wBACf,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE;qBACxF;oBACD,WAAW,EACV,sMAAsM;iBACvM;aACD;SACD,CAAC;IACH,CAAC;CAAA;AA1DD,kCA0DC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"node": "n8n-nodes-42min.fortyTwoMin",
|
|
3
|
+
"nodeVersion": "1.0",
|
|
4
|
+
"codexVersion": "1.0",
|
|
5
|
+
"categories": ["Productivity", "Sales"],
|
|
6
|
+
"resources": {
|
|
7
|
+
"credentialDocumentation": [
|
|
8
|
+
{
|
|
9
|
+
"url": "https://42min.us/help/integrations/n8n"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"primaryDocumentation": [
|
|
13
|
+
{
|
|
14
|
+
"url": "https://42min.us/help/api/overview"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IHookFunctions, INodeType, INodeTypeDescription, IWebhookFunctions, IWebhookResponseData } from 'n8n-workflow';
|
|
2
|
+
export declare class FortyTwoMinTrigger implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
webhookMethods: {
|
|
5
|
+
default: {
|
|
6
|
+
checkExists(this: IHookFunctions): Promise<boolean>;
|
|
7
|
+
create(this: IHookFunctions): Promise<boolean>;
|
|
8
|
+
delete(this: IHookFunctions): Promise<boolean>;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FortyTwoMinTrigger = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const GenericFunctions_1 = require("./GenericFunctions");
|
|
6
|
+
class FortyTwoMinTrigger {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.description = {
|
|
9
|
+
displayName: '42min Trigger',
|
|
10
|
+
name: 'fortyTwoMinTrigger',
|
|
11
|
+
icon: { light: 'file:../../icons/fortytwomin.svg', dark: 'file:../../icons/fortytwomin.dark.svg' },
|
|
12
|
+
group: ['trigger'],
|
|
13
|
+
version: 1,
|
|
14
|
+
subtitle: '={{$parameter["events"].join(", ")}}',
|
|
15
|
+
description: 'Starts a workflow when something happens in 42min',
|
|
16
|
+
defaults: { name: '42min Trigger' },
|
|
17
|
+
inputs: [],
|
|
18
|
+
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
19
|
+
credentials: [{ name: 'fortyTwoMinApi', required: true }],
|
|
20
|
+
webhooks: [
|
|
21
|
+
{
|
|
22
|
+
name: 'default',
|
|
23
|
+
httpMethod: 'POST',
|
|
24
|
+
responseMode: 'onReceived',
|
|
25
|
+
path: 'webhook',
|
|
26
|
+
rawBody: true,
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
properties: [
|
|
30
|
+
{
|
|
31
|
+
displayName: 'Events',
|
|
32
|
+
name: 'events',
|
|
33
|
+
type: 'multiOptions',
|
|
34
|
+
required: true,
|
|
35
|
+
default: ['booking_created'],
|
|
36
|
+
description: 'The events to subscribe to',
|
|
37
|
+
options: [
|
|
38
|
+
{ name: 'Booking Canceled', value: 'booking_canceled' },
|
|
39
|
+
{ name: 'Booking Created', value: 'booking_created' },
|
|
40
|
+
{ name: 'Booking Marked No-Show', value: 'booking_no_show' },
|
|
41
|
+
{ name: 'Booking Rescheduled', value: 'booking_rescheduled' },
|
|
42
|
+
{ name: 'Booking Updated', value: 'booking_updated' },
|
|
43
|
+
{ name: 'Event Type Deleted', value: 'event_type_deleted' },
|
|
44
|
+
{ name: 'Event Type Updated', value: 'event_type_updated' },
|
|
45
|
+
{ name: 'Routing Form Submitted', value: 'routing_form_submitted' },
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
displayName: 'Options',
|
|
50
|
+
name: 'options',
|
|
51
|
+
type: 'collection',
|
|
52
|
+
placeholder: 'Add Option',
|
|
53
|
+
default: {},
|
|
54
|
+
options: [
|
|
55
|
+
{
|
|
56
|
+
displayName: 'Raw Payload',
|
|
57
|
+
name: 'rawPayload',
|
|
58
|
+
type: 'boolean',
|
|
59
|
+
default: false,
|
|
60
|
+
description: 'Whether to emit the delivery exactly as 42min sent it. By default booking events are reshaped into the same flat, snake_case field names the REST API uses, so a trigger item and a lookup item can be read the same way.',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
displayName: 'Timestamp Tolerance (Seconds)',
|
|
64
|
+
name: 'tolerance',
|
|
65
|
+
type: 'number',
|
|
66
|
+
default: 300,
|
|
67
|
+
typeOptions: { minValue: 0 },
|
|
68
|
+
description: 'Reject deliveries whose signature timestamp is older than this. Guards against a captured delivery being replayed.',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
displayName: 'Verify Signature',
|
|
72
|
+
name: 'verifySignature',
|
|
73
|
+
type: 'boolean',
|
|
74
|
+
default: true,
|
|
75
|
+
description: 'Whether to check the X-42min-Webhook-Signature header and reject anything that fails. Turn this off only if your reverse proxy rewrites the request body.',
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
this.webhookMethods = {
|
|
82
|
+
default: {
|
|
83
|
+
async checkExists() {
|
|
84
|
+
const staticData = this.getWorkflowStaticData('node');
|
|
85
|
+
const webhookUrl = this.getNodeWebhookUrl('default');
|
|
86
|
+
const response = await GenericFunctions_1.fortyTwoMinApiRequest.call(this, 'GET', '/v1/webhooks');
|
|
87
|
+
const existing = (response.data ?? []).find((hook) => hook.url === webhookUrl);
|
|
88
|
+
if (!existing) {
|
|
89
|
+
delete staticData.webhookId;
|
|
90
|
+
delete staticData.signingSecret;
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
if (!staticData.signingSecret) {
|
|
94
|
+
await GenericFunctions_1.fortyTwoMinApiRequest
|
|
95
|
+
.call(this, 'DELETE', `/v1/webhooks/${existing.id}`)
|
|
96
|
+
.catch(() => undefined);
|
|
97
|
+
delete staticData.webhookId;
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
staticData.webhookId = existing.id;
|
|
101
|
+
return true;
|
|
102
|
+
},
|
|
103
|
+
async create() {
|
|
104
|
+
const staticData = this.getWorkflowStaticData('node');
|
|
105
|
+
const webhookUrl = this.getNodeWebhookUrl('default');
|
|
106
|
+
const events = this.getNodeParameter('events');
|
|
107
|
+
if (!webhookUrl?.startsWith('https://')) {
|
|
108
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), '42min delivers webhooks over HTTPS only, and this n8n instance is reachable at a non-HTTPS URL', {
|
|
109
|
+
description: 'Set WEBHOOK_URL (or N8N_PROTOCOL/N8N_HOST) so n8n advertises a public https:// address, then activate the workflow again. The address must also resolve to a public IP: 42min refuses to deliver to private ranges.',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const response = await GenericFunctions_1.fortyTwoMinApiRequest.call(this, 'POST', '/v1/webhooks', {
|
|
113
|
+
url: webhookUrl,
|
|
114
|
+
events,
|
|
115
|
+
description: `n8n: ${this.getWorkflow().name ?? 'workflow'}`,
|
|
116
|
+
});
|
|
117
|
+
const created = (response.data ?? {});
|
|
118
|
+
if (!created.id || !created.signing_secret) {
|
|
119
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), '42min did not return a subscription ID and signing secret');
|
|
120
|
+
}
|
|
121
|
+
staticData.webhookId = created.id;
|
|
122
|
+
staticData.signingSecret = created.signing_secret;
|
|
123
|
+
return true;
|
|
124
|
+
},
|
|
125
|
+
async delete() {
|
|
126
|
+
const staticData = this.getWorkflowStaticData('node');
|
|
127
|
+
if (!staticData.webhookId)
|
|
128
|
+
return true;
|
|
129
|
+
try {
|
|
130
|
+
await GenericFunctions_1.fortyTwoMinApiRequest.call(this, 'DELETE', `/v1/webhooks/${staticData.webhookId}`);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
const status = error?.httpCode ?? error?.statusCode;
|
|
134
|
+
if (String(status) !== '404')
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
delete staticData.webhookId;
|
|
138
|
+
delete staticData.signingSecret;
|
|
139
|
+
return true;
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
async webhook() {
|
|
145
|
+
const staticData = this.getWorkflowStaticData('node');
|
|
146
|
+
const options = this.getNodeParameter('options', {});
|
|
147
|
+
const headers = this.getHeaderData();
|
|
148
|
+
const request = this.getRequestObject();
|
|
149
|
+
const verify = options.verifySignature !== false;
|
|
150
|
+
const rawBody = request.rawBody;
|
|
151
|
+
if (verify) {
|
|
152
|
+
if (!rawBody) {
|
|
153
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'The raw request body was not available, so the webhook signature could not be verified', {
|
|
154
|
+
description: 'Something between 42min and n8n is re-serializing the request. Fix the proxy, or turn off Verify Signature if you accept unauthenticated deliveries.',
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
const result = (0, GenericFunctions_1.verifyWebhookSignature)(rawBody, headers['x-42min-webhook-signature'], staticData.signingSecret ?? '', options.tolerance ?? 300);
|
|
158
|
+
if (!result.ok) {
|
|
159
|
+
const response = this.getResponseObject();
|
|
160
|
+
response.status(401).send(`Webhook signature rejected: ${result.reason}`);
|
|
161
|
+
return { noWebhookResponse: true };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
let envelope;
|
|
165
|
+
if (rawBody) {
|
|
166
|
+
try {
|
|
167
|
+
envelope = JSON.parse(rawBody.toString('utf8'));
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
envelope = this.getBodyData();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
envelope = this.getBodyData();
|
|
175
|
+
}
|
|
176
|
+
const isBookingEvent = String(envelope.event ?? '').startsWith('booking.');
|
|
177
|
+
const emitRaw = options.rawPayload === true || !isBookingEvent;
|
|
178
|
+
const item = emitRaw ? envelope : (0, GenericFunctions_1.normalizeBookingEvent)(envelope);
|
|
179
|
+
item.delivery_id = headers['x-42min-webhook-id'] ?? null;
|
|
180
|
+
item.delivery_attempt = headers['x-42min-webhook-attempt'] ?? null;
|
|
181
|
+
return { workflowData: [this.helpers.returnJsonArray([item])] };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
exports.FortyTwoMinTrigger = FortyTwoMinTrigger;
|
|
185
|
+
//# sourceMappingURL=FortyTwoMinTrigger.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FortyTwoMinTrigger.node.js","sourceRoot":"","sources":["../../../nodes/FortyTwoMin/FortyTwoMinTrigger.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"node": "n8n-nodes-42min.fortyTwoMinTrigger",
|
|
3
|
+
"nodeVersion": "1.0",
|
|
4
|
+
"codexVersion": "1.0",
|
|
5
|
+
"categories": ["Productivity", "Sales"],
|
|
6
|
+
"resources": {
|
|
7
|
+
"credentialDocumentation": [
|
|
8
|
+
{
|
|
9
|
+
"url": "https://42min.us/help/integrations/n8n"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"primaryDocumentation": [
|
|
13
|
+
{
|
|
14
|
+
"url": "https://42min.us/help/api/webhooks"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IDataObject, IExecuteFunctions, IHookFunctions, IHttpRequestMethods, ILoadOptionsFunctions, IWebhookFunctions } from 'n8n-workflow';
|
|
2
|
+
type RequestContext = IExecuteFunctions | IHookFunctions | ILoadOptionsFunctions | IWebhookFunctions;
|
|
3
|
+
export declare function fortyTwoMinApiRequest(this: RequestContext, method: IHttpRequestMethods, resource: string, body?: IDataObject, qs?: IDataObject): Promise<IDataObject>;
|
|
4
|
+
export declare function verifyWebhookSignature(rawBody: Buffer | string, signatureHeader: string | undefined, secret: string, toleranceSeconds?: number): {
|
|
5
|
+
ok: true;
|
|
6
|
+
} | {
|
|
7
|
+
ok: false;
|
|
8
|
+
reason: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function normalizeBookingEvent(envelope: IDataObject): IDataObject;
|
|
11
|
+
export {};
|