@crystalknows/n8n-nodes-crystal 0.1.1
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 +95 -0
- package/dist/credentials/CrystalApi.credentials.d.ts +10 -0
- package/dist/credentials/CrystalApi.credentials.js +40 -0
- package/dist/credentials/CrystalApi.credentials.js.map +1 -0
- package/dist/credentials/crystal.dark.svg +11 -0
- package/dist/credentials/crystal.svg +11 -0
- package/dist/nodes/Crystal/Crystal.node.d.ts +4 -0
- package/dist/nodes/Crystal/Crystal.node.js +73 -0
- package/dist/nodes/Crystal/Crystal.node.js.map +1 -0
- package/dist/nodes/Crystal/Crystal.node.json +18 -0
- package/dist/nodes/Crystal/crystal.dark.svg +11 -0
- package/dist/nodes/Crystal/crystal.svg +11 -0
- package/dist/nodes/Crystal/resources/content/index.d.ts +3 -0
- package/dist/nodes/Crystal/resources/content/index.js +215 -0
- package/dist/nodes/Crystal/resources/content/index.js.map +1 -0
- package/dist/nodes/Crystal/resources/prediction/index.d.ts +3 -0
- package/dist/nodes/Crystal/resources/prediction/index.js +102 -0
- package/dist/nodes/Crystal/resources/prediction/index.js.map +1 -0
- package/dist/nodes/Crystal/resources/profile/index.d.ts +3 -0
- package/dist/nodes/Crystal/resources/profile/index.js +53 -0
- package/dist/nodes/Crystal/resources/profile/index.js.map +1 -0
- package/dist/nodes/Crystal/shared/personQuery.d.ts +5 -0
- package/dist/nodes/Crystal/shared/personQuery.js +99 -0
- package/dist/nodes/Crystal/shared/personQuery.js.map +1 -0
- package/dist/nodes/Crystal/shared/pollPrediction.d.ts +2 -0
- package/dist/nodes/Crystal/shared/pollPrediction.js +37 -0
- package/dist/nodes/Crystal/shared/pollPrediction.js.map +1 -0
- package/dist/package.json +67 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Crystal Project, Inc.
|
|
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,95 @@
|
|
|
1
|
+
# @crystalknows/n8n-nodes-crystal
|
|
2
|
+
|
|
3
|
+
This is an n8n community node. It lets you use the [Crystal](https://www.crystalknows.com/) Data API in your n8n workflows.
|
|
4
|
+
|
|
5
|
+
Crystal predicts anyone's DISC personality type and turns it into practical guidance — how to email them, sell to them, run a meeting with them — from a name, email, or LinkedIn URL.
|
|
6
|
+
|
|
7
|
+
[n8n](https://n8n.io/) is a [fair-code licensed](https://docs.n8n.io/sustainable-use-license/) workflow automation platform.
|
|
8
|
+
|
|
9
|
+
[Installation](#installation)
|
|
10
|
+
[Operations](#operations)
|
|
11
|
+
[Credentials](#credentials)
|
|
12
|
+
[Compatibility](#compatibility)
|
|
13
|
+
[Usage](#usage)
|
|
14
|
+
[Resources](#resources)
|
|
15
|
+
[Version history](#version-history)
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
Follow the [installation guide](https://docs.n8n.io/integrations/community-nodes/installation/) in the n8n community nodes documentation.
|
|
20
|
+
|
|
21
|
+
In n8n: **Settings → Community Nodes → Install**, then enter `@crystalknows/n8n-nodes-crystal`.
|
|
22
|
+
|
|
23
|
+
## Operations
|
|
24
|
+
|
|
25
|
+
### Profile
|
|
26
|
+
|
|
27
|
+
| Operation | Description | Cost |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| **Get** | Real-time lookup of a profile Crystal already knows. Does not create new profiles — returns nothing if the person is not already known; use a Prediction for that. | 1 credit on a hit; re-fetches of the same profile are free |
|
|
30
|
+
|
|
31
|
+
Identify the person with any combination of full name, email, LinkedIn URL, job title, company name, or phone.
|
|
32
|
+
|
|
33
|
+
### Prediction
|
|
34
|
+
|
|
35
|
+
| Operation | Description | Cost |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| **Create** | Submit an async lookup and return immediately with a job ID. | 1 credit only if the job completes with a profile found |
|
|
38
|
+
| **Get** | Poll for the result of a submitted job by job ID. | — |
|
|
39
|
+
| **Create and Wait** | Submit a lookup, then poll until the job finishes (or the timeout is hit) and return the final result. | 1 credit only if a profile is found |
|
|
40
|
+
|
|
41
|
+
`Create` and `Create and Wait` accept an optional **Record ID** — a client-supplied idempotency key. Resubmitting the same Record ID will not double-charge.
|
|
42
|
+
|
|
43
|
+
### Content
|
|
44
|
+
|
|
45
|
+
All content operations take a Crystal profile ID (from a Profile or Prediction step) unless noted.
|
|
46
|
+
|
|
47
|
+
| Operation | Description | Cost |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| **Get Personality Content** | Full personality content for a profile. | Free |
|
|
50
|
+
| **Get Selling-To Playbook** | A "selling to this person" playbook. | Free |
|
|
51
|
+
| **Get Communication Advice** | Communication advice for each of one or more profiles. | Free |
|
|
52
|
+
| **Get Relationship Matrix** | A relationship matrix across several profiles. | Free |
|
|
53
|
+
| **Generate Prompt** | A ready-to-inject, DISC-tuned prompt you paste into your own AI workflow. Identify the recipient by profile ID or a raw DISC type (e.g. `D`, `Di`, `Sc`). | Free — deterministic, no model call |
|
|
54
|
+
| **Revise Email** | Rewrite a draft email so it lands well with the recipient, adapting tone, structure, and directness to their DISC type. | 1 credit per successful revision (not deduplicated) |
|
|
55
|
+
|
|
56
|
+
## Credentials
|
|
57
|
+
|
|
58
|
+
You need a Crystal Data API key.
|
|
59
|
+
|
|
60
|
+
1. Sign up at [crystalknows.com](https://www.crystalknows.com/) and verify your email.
|
|
61
|
+
2. Generate a key at [data.crystalknows.com/api-keys](https://data.crystalknows.com/api-keys).
|
|
62
|
+
3. In n8n, create a new **Crystal API** credential and paste the key.
|
|
63
|
+
|
|
64
|
+
The key is sent as a bearer token (`Authorization: Bearer <key>`). Treat it like a password — anyone with it can call the API as you. The credential test calls `POST /v4/content/generate_prompt`, which is free and spends no credit.
|
|
65
|
+
|
|
66
|
+
API credits are a single pool per organization. See the [API reference](https://data.crystalknows.com/llms-full.txt) for exactly when a credit is spent.
|
|
67
|
+
|
|
68
|
+
## Compatibility
|
|
69
|
+
|
|
70
|
+
- Requires n8n 1.60.0 or later (for `usableAsTool` support).
|
|
71
|
+
- Tested against n8n 1.7x and Node.js 20 / 22.
|
|
72
|
+
|
|
73
|
+
## Usage
|
|
74
|
+
|
|
75
|
+
- **Enrich a lead the moment it arrives.** Trigger on a new CRM contact → **Prediction: Create and Wait** with their email → branch on `result.state` (`found` / `not_found`).
|
|
76
|
+
- **Draft on-brand outreach.** **Content: Generate Prompt** with the profile ID and an objective, then feed the returned `prompt` into an AI Agent / LLM node — or use **Content: Revise Email** to have Crystal rewrite an existing draft directly.
|
|
77
|
+
- **As an AI Agent tool.** Attach this node to an AI Agent; the agent can look up a person and pull communication advice on its own.
|
|
78
|
+
|
|
79
|
+
`Prediction: Create and Wait` blocks the workflow while it polls (default: every 5s, up to 300s). Jobs usually finish within a minute or two but can take longer when Crystal's queue is busy. For large batches, prefer **Create** + a later **Get** (e.g. via a Wait node), or raise the timeout.
|
|
80
|
+
|
|
81
|
+
## Security
|
|
82
|
+
|
|
83
|
+
The published package has **no runtime dependencies** — `npm audit --omit=dev` reports 0 vulnerabilities. `n8n-workflow` is a peer dependency supplied by the n8n host.
|
|
84
|
+
|
|
85
|
+
A full `npm audit` reports advisories inside `@n8n/node-cli` and `release-it` (the build/lint/release toolchain, `devDependencies` only — never installed by users of this node). They cannot be resolved without breaking the release tooling or downgrading `@n8n/node-cli` below the version n8n requires for verification (n8n community packages may not use an `overrides` field), so they are tracked for upstream.
|
|
86
|
+
|
|
87
|
+
## Resources
|
|
88
|
+
|
|
89
|
+
* [n8n community nodes documentation](https://docs.n8n.io/integrations/#community-nodes)
|
|
90
|
+
* [Crystal Data API reference](https://data.crystalknows.com/llms-full.txt)
|
|
91
|
+
* [Crystal API (Swagger)](https://api.crystalknows.com/v4/swagger)
|
|
92
|
+
|
|
93
|
+
## Version history
|
|
94
|
+
|
|
95
|
+
See [CHANGELOG.md](./CHANGELOG.md).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IAuthenticateGeneric, Icon, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class CrystalApi 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,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CrystalApi = void 0;
|
|
4
|
+
class CrystalApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'crystalApi';
|
|
7
|
+
this.displayName = 'Crystal API';
|
|
8
|
+
this.icon = { light: 'file:crystal.svg', dark: 'file:crystal.dark.svg' };
|
|
9
|
+
this.documentationUrl = 'https://github.com/crystal-project-inc/n8n-nodes-crystal?tab=readme-ov-file#credentials';
|
|
10
|
+
this.properties = [
|
|
11
|
+
{
|
|
12
|
+
displayName: 'API Key',
|
|
13
|
+
name: 'apiKey',
|
|
14
|
+
type: 'string',
|
|
15
|
+
typeOptions: { password: true },
|
|
16
|
+
required: true,
|
|
17
|
+
default: '',
|
|
18
|
+
description: 'Generate a key at data.crystalknows.com/api-keys (requires a verified email). Treat it like a password — anyone with it can call the API as you.',
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
this.authenticate = {
|
|
22
|
+
type: 'generic',
|
|
23
|
+
properties: {
|
|
24
|
+
headers: {
|
|
25
|
+
Authorization: '=Bearer {{$credentials.apiKey}}',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
this.test = {
|
|
30
|
+
request: {
|
|
31
|
+
baseURL: 'https://api.crystalknows.com',
|
|
32
|
+
url: '/v4/content/generate_prompt',
|
|
33
|
+
method: 'POST',
|
|
34
|
+
body: { disc_type: 'D' },
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.CrystalApi = CrystalApi;
|
|
40
|
+
//# sourceMappingURL=CrystalApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CrystalApi.credentials.js","sourceRoot":"","sources":["../../credentials/CrystalApi.credentials.ts"],"names":[],"mappings":";;;AAQA,MAAa,UAAU;IAAvB;QACC,SAAI,GAAG,YAAY,CAAC;QAEpB,gBAAW,GAAG,aAAa,CAAC;QAE5B,SAAI,GAAS,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC;QAE1E,qBAAgB,GACf,yFAAyF,CAAC;QAE3F,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,SAAS;gBACtB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,QAAQ,EAAE,IAAI;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,kJAAkJ;aACnJ;SACD,CAAC;QAEF,iBAAY,GAAyB;YACpC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE;gBACX,OAAO,EAAE;oBACR,aAAa,EAAE,iCAAiC;iBAChD;aACD;SACD,CAAC;QAIF,SAAI,GAA2B;YAC9B,OAAO,EAAE;gBACR,OAAO,EAAE,8BAA8B;gBACvC,GAAG,EAAE,6BAA6B;gBAClC,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE;aACxB;SACD,CAAC;IACH,CAAC;CAAA;AA1CD,gCA0CC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg width="29" height="32" viewBox="0 0 29 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<g id="Crystal Shape">
|
|
3
|
+
<path id="Vector" d="M13.3681 19.6734L14.5238 21.2338L15.6782 19.6734L16.0898 19.1282L16.7655 18.9416L18.6398 18.4265L18.1679 16.6271L18.0405 16.1567L18.1679 15.6937L18.6398 13.887L16.7655 13.3793L16.0898 13.1926L15.6782 12.6401L14.5238 11.087L13.3681 12.6401L12.9565 13.1926L12.2808 13.3793L10.4065 13.887L10.8798 15.6937L11.0071 16.1567L10.8798 16.6271L10.4065 18.4265L12.2808 18.9416L12.9565 19.1282L13.3681 19.6734Z" fill="#2CA7E4"/>
|
|
4
|
+
<path id="Vector_2" d="M10.3999 20.4278L7.98527 19.7632L8.62345 17.3441H3.089L0 24.0041L7.3337 25.6318L10.3999 20.4278Z" fill="#7FD8F5"/>
|
|
5
|
+
<path id="Vector_3" d="M21.7436 6.38342L18.5205 11.8637L21.0612 12.5506L20.4243 14.9771H25.763L28.9941 8.00367L21.7436 6.38342Z" fill="#1FC3EA"/>
|
|
6
|
+
<path id="Vector_4" d="M25.9049 17.3441H20.4241L21.0609 19.7632L18.6021 20.4352L21.6683 25.6318L28.9939 24.0041L25.9049 17.3441Z" fill="#7FD8F5"/>
|
|
7
|
+
<path id="Vector_5" d="M16.5711 21.8009L14.5238 24.5561L12.4538 21.7637L9.45459 26.8482L14.501 32L19.5475 26.8482L16.5711 21.8009Z" fill="#7FD8F5"/>
|
|
8
|
+
<path id="Vector_6" d="M8.62345 14.9771L7.98527 12.5506L10.483 11.8712L7.25058 6.38342L0 8.00367L3.23112 14.9771H8.62345Z" fill="#1FC3EA"/>
|
|
9
|
+
<path id="Vector_7" d="M12.5058 10.4901L14.5223 7.76502L16.5172 10.4454L19.5982 5.2115L14.4995 0L9.39404 5.2115L12.5058 10.4901Z" fill="#1FC3EA"/>
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg width="29" height="32" viewBox="0 0 29 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<g id="Crystal Shape">
|
|
3
|
+
<path id="Vector" d="M13.3681 19.6734L14.5238 21.2338L15.6782 19.6734L16.0898 19.1282L16.7655 18.9416L18.6398 18.4265L18.1679 16.6271L18.0405 16.1567L18.1679 15.6937L18.6398 13.887L16.7655 13.3793L16.0898 13.1926L15.6782 12.6401L14.5238 11.087L13.3681 12.6401L12.9565 13.1926L12.2808 13.3793L10.4065 13.887L10.8798 15.6937L11.0071 16.1567L10.8798 16.6271L10.4065 18.4265L12.2808 18.9416L12.9565 19.1282L13.3681 19.6734Z" fill="#2CA7E4"/>
|
|
4
|
+
<path id="Vector_2" d="M10.3999 20.4278L7.98527 19.7632L8.62345 17.3441H3.089L0 24.0041L7.3337 25.6318L10.3999 20.4278Z" fill="#0283AA"/>
|
|
5
|
+
<path id="Vector_3" d="M21.7436 6.38342L18.5205 11.8637L21.0612 12.5506L20.4243 14.9771H25.763L28.9941 8.00367L21.7436 6.38342Z" fill="#1FC3EA"/>
|
|
6
|
+
<path id="Vector_4" d="M25.9049 17.3441H20.4241L21.0609 19.7632L18.6021 20.4352L21.6683 25.6318L28.9939 24.0041L25.9049 17.3441Z" fill="#0283AA"/>
|
|
7
|
+
<path id="Vector_5" d="M16.5711 21.8009L14.5238 24.5561L12.4538 21.7637L9.45459 26.8482L14.501 32L19.5475 26.8482L16.5711 21.8009Z" fill="#0283AA"/>
|
|
8
|
+
<path id="Vector_6" d="M8.62345 14.9771L7.98527 12.5506L10.483 11.8712L7.25058 6.38342L0 8.00367L3.23112 14.9771H8.62345Z" fill="#1FC3EA"/>
|
|
9
|
+
<path id="Vector_7" d="M12.5058 10.4901L14.5223 7.76502L16.5172 10.4454L19.5982 5.2115L14.4995 0L9.39404 5.2115L12.5058 10.4901Z" fill="#1FC3EA"/>
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Crystal = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const content_1 = require("./resources/content");
|
|
6
|
+
const prediction_1 = require("./resources/prediction");
|
|
7
|
+
const profile_1 = require("./resources/profile");
|
|
8
|
+
class Crystal {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.description = {
|
|
11
|
+
displayName: 'Crystal',
|
|
12
|
+
name: 'crystal',
|
|
13
|
+
icon: { light: 'file:crystal.svg', dark: 'file:crystal.dark.svg' },
|
|
14
|
+
group: ['transform'],
|
|
15
|
+
version: 1,
|
|
16
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
17
|
+
description: 'Enrich profiles and get DISC personality insights from the Crystal Data API',
|
|
18
|
+
defaults: {
|
|
19
|
+
name: 'Crystal',
|
|
20
|
+
},
|
|
21
|
+
usableAsTool: true,
|
|
22
|
+
inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
23
|
+
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
24
|
+
credentials: [
|
|
25
|
+
{
|
|
26
|
+
name: 'crystalApi',
|
|
27
|
+
required: true,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
requestDefaults: {
|
|
31
|
+
baseURL: 'https://api.crystalknows.com',
|
|
32
|
+
headers: {
|
|
33
|
+
Accept: 'application/json',
|
|
34
|
+
'Content-Type': 'application/json',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
properties: [
|
|
38
|
+
{
|
|
39
|
+
displayName: 'Resource',
|
|
40
|
+
name: 'resource',
|
|
41
|
+
type: 'options',
|
|
42
|
+
noDataExpression: true,
|
|
43
|
+
options: [
|
|
44
|
+
{
|
|
45
|
+
name: 'Profile',
|
|
46
|
+
value: 'profile',
|
|
47
|
+
description: 'Look up a profile Crystal already knows',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'Prediction',
|
|
51
|
+
value: 'prediction',
|
|
52
|
+
description: 'Search for and create a profile Crystal does not have yet',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'Content',
|
|
56
|
+
value: 'content',
|
|
57
|
+
description: 'Personality content, playbooks, prompts, and email revision',
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
default: 'profile',
|
|
61
|
+
},
|
|
62
|
+
...profile_1.profileOperations,
|
|
63
|
+
...profile_1.profileFields,
|
|
64
|
+
...prediction_1.predictionOperations,
|
|
65
|
+
...prediction_1.predictionFields,
|
|
66
|
+
...content_1.contentOperations,
|
|
67
|
+
...content_1.contentFields,
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.Crystal = Crystal;
|
|
73
|
+
//# sourceMappingURL=Crystal.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Crystal.node.js","sourceRoot":"","sources":["../../../nodes/Crystal/Crystal.node.ts"],"names":[],"mappings":";;;AAAA,+CAA8F;AAE9F,iDAAuE;AACvE,uDAAgF;AAChF,iDAAuE;AAEvE,MAAa,OAAO;IAApB;QACC,gBAAW,GAAyB;YACnC,WAAW,EAAE,SAAS;YACtB,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,uBAAuB,EAAE;YAClE,KAAK,EAAE,CAAC,WAAW,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,QAAQ,EAAE,8DAA8D;YACxE,WAAW,EAAE,6EAA6E;YAC1F,QAAQ,EAAE;gBACT,IAAI,EAAE,SAAS;aACf;YACD,YAAY,EAAE,IAAI;YAClB,MAAM,EAAE,CAAC,kCAAmB,CAAC,IAAI,CAAC;YAClC,OAAO,EAAE,CAAC,kCAAmB,CAAC,IAAI,CAAC;YACnC,WAAW,EAAE;gBACZ;oBACC,IAAI,EAAE,YAAY;oBAClB,QAAQ,EAAE,IAAI;iBACd;aACD;YACD,eAAe,EAAE;gBAChB,OAAO,EAAE,8BAA8B;gBACvC,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;4BACC,IAAI,EAAE,SAAS;4BACf,KAAK,EAAE,SAAS;4BAChB,WAAW,EAAE,yCAAyC;yBACtD;wBACD;4BACC,IAAI,EAAE,YAAY;4BAClB,KAAK,EAAE,YAAY;4BACnB,WAAW,EAAE,2DAA2D;yBACxE;wBACD;4BACC,IAAI,EAAE,SAAS;4BACf,KAAK,EAAE,SAAS;4BAChB,WAAW,EAAE,6DAA6D;yBAC1E;qBACD;oBACD,OAAO,EAAE,SAAS;iBAClB;gBACD,GAAG,2BAAiB;gBACpB,GAAG,uBAAa;gBAChB,GAAG,iCAAoB;gBACvB,GAAG,6BAAgB;gBACnB,GAAG,2BAAiB;gBACpB,GAAG,uBAAa;aAChB;SACD,CAAC;IACH,CAAC;CAAA;AA7DD,0BA6DC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"node": "@crystalknows/n8n-nodes-crystal.crystal",
|
|
3
|
+
"nodeVersion": "1.0",
|
|
4
|
+
"codexVersion": "1.0",
|
|
5
|
+
"categories": ["Sales", "Marketing", "Data & Storage", "Developer Tools"],
|
|
6
|
+
"resources": {
|
|
7
|
+
"credentialDocumentation": [
|
|
8
|
+
{
|
|
9
|
+
"url": "https://github.com/crystal-project-inc/n8n-nodes-crystal?tab=readme-ov-file#credentials"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"primaryDocumentation": [
|
|
13
|
+
{
|
|
14
|
+
"url": "https://github.com/crystal-project-inc/n8n-nodes-crystal?tab=readme-ov-file"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg width="29" height="32" viewBox="0 0 29 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<g id="Crystal Shape">
|
|
3
|
+
<path id="Vector" d="M13.3681 19.6734L14.5238 21.2338L15.6782 19.6734L16.0898 19.1282L16.7655 18.9416L18.6398 18.4265L18.1679 16.6271L18.0405 16.1567L18.1679 15.6937L18.6398 13.887L16.7655 13.3793L16.0898 13.1926L15.6782 12.6401L14.5238 11.087L13.3681 12.6401L12.9565 13.1926L12.2808 13.3793L10.4065 13.887L10.8798 15.6937L11.0071 16.1567L10.8798 16.6271L10.4065 18.4265L12.2808 18.9416L12.9565 19.1282L13.3681 19.6734Z" fill="#2CA7E4"/>
|
|
4
|
+
<path id="Vector_2" d="M10.3999 20.4278L7.98527 19.7632L8.62345 17.3441H3.089L0 24.0041L7.3337 25.6318L10.3999 20.4278Z" fill="#7FD8F5"/>
|
|
5
|
+
<path id="Vector_3" d="M21.7436 6.38342L18.5205 11.8637L21.0612 12.5506L20.4243 14.9771H25.763L28.9941 8.00367L21.7436 6.38342Z" fill="#1FC3EA"/>
|
|
6
|
+
<path id="Vector_4" d="M25.9049 17.3441H20.4241L21.0609 19.7632L18.6021 20.4352L21.6683 25.6318L28.9939 24.0041L25.9049 17.3441Z" fill="#7FD8F5"/>
|
|
7
|
+
<path id="Vector_5" d="M16.5711 21.8009L14.5238 24.5561L12.4538 21.7637L9.45459 26.8482L14.501 32L19.5475 26.8482L16.5711 21.8009Z" fill="#7FD8F5"/>
|
|
8
|
+
<path id="Vector_6" d="M8.62345 14.9771L7.98527 12.5506L10.483 11.8712L7.25058 6.38342L0 8.00367L3.23112 14.9771H8.62345Z" fill="#1FC3EA"/>
|
|
9
|
+
<path id="Vector_7" d="M12.5058 10.4901L14.5223 7.76502L16.5172 10.4454L19.5982 5.2115L14.4995 0L9.39404 5.2115L12.5058 10.4901Z" fill="#1FC3EA"/>
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg width="29" height="32" viewBox="0 0 29 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<g id="Crystal Shape">
|
|
3
|
+
<path id="Vector" d="M13.3681 19.6734L14.5238 21.2338L15.6782 19.6734L16.0898 19.1282L16.7655 18.9416L18.6398 18.4265L18.1679 16.6271L18.0405 16.1567L18.1679 15.6937L18.6398 13.887L16.7655 13.3793L16.0898 13.1926L15.6782 12.6401L14.5238 11.087L13.3681 12.6401L12.9565 13.1926L12.2808 13.3793L10.4065 13.887L10.8798 15.6937L11.0071 16.1567L10.8798 16.6271L10.4065 18.4265L12.2808 18.9416L12.9565 19.1282L13.3681 19.6734Z" fill="#2CA7E4"/>
|
|
4
|
+
<path id="Vector_2" d="M10.3999 20.4278L7.98527 19.7632L8.62345 17.3441H3.089L0 24.0041L7.3337 25.6318L10.3999 20.4278Z" fill="#0283AA"/>
|
|
5
|
+
<path id="Vector_3" d="M21.7436 6.38342L18.5205 11.8637L21.0612 12.5506L20.4243 14.9771H25.763L28.9941 8.00367L21.7436 6.38342Z" fill="#1FC3EA"/>
|
|
6
|
+
<path id="Vector_4" d="M25.9049 17.3441H20.4241L21.0609 19.7632L18.6021 20.4352L21.6683 25.6318L28.9939 24.0041L25.9049 17.3441Z" fill="#0283AA"/>
|
|
7
|
+
<path id="Vector_5" d="M16.5711 21.8009L14.5238 24.5561L12.4538 21.7637L9.45459 26.8482L14.501 32L19.5475 26.8482L16.5711 21.8009Z" fill="#0283AA"/>
|
|
8
|
+
<path id="Vector_6" d="M8.62345 14.9771L7.98527 12.5506L10.483 11.8712L7.25058 6.38342L0 8.00367L3.23112 14.9771H8.62345Z" fill="#1FC3EA"/>
|
|
9
|
+
<path id="Vector_7" d="M12.5058 10.4901L14.5223 7.76502L16.5172 10.4454L19.5982 5.2115L14.4995 0L9.39404 5.2115L12.5058 10.4901Z" fill="#1FC3EA"/>
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.contentFields = exports.contentOperations = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const showForContent = { resource: ['content'] };
|
|
6
|
+
const showFor = (operation) => ({ resource: ['content'], operation: [operation] });
|
|
7
|
+
function parseProfileIds(context) {
|
|
8
|
+
const raw = context.getNodeParameter('profileIds', '');
|
|
9
|
+
const ids = raw
|
|
10
|
+
.split(/[\s,]+/)
|
|
11
|
+
.map((id) => id.trim())
|
|
12
|
+
.filter((id) => id !== '');
|
|
13
|
+
if (ids.length === 0) {
|
|
14
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Provide at least one profile ID.', {
|
|
15
|
+
itemIndex: context.getItemIndex(),
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return ids;
|
|
19
|
+
}
|
|
20
|
+
async function attachProfileIdsBody(requestOptions) {
|
|
21
|
+
requestOptions.body = { profile_ids: parseProfileIds(this) };
|
|
22
|
+
return requestOptions;
|
|
23
|
+
}
|
|
24
|
+
function attachRecipientBody(extra) {
|
|
25
|
+
return async function (requestOptions) {
|
|
26
|
+
const identifyBy = this.getNodeParameter('identifyBy');
|
|
27
|
+
const recipient = identifyBy === 'discType'
|
|
28
|
+
? { disc_type: this.getNodeParameter('discType', '').trim() }
|
|
29
|
+
: { id: this.getNodeParameter('profileId', '').trim() };
|
|
30
|
+
const recipientValue = Object.values(recipient)[0];
|
|
31
|
+
if (!recipientValue) {
|
|
32
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), identifyBy === 'discType' ? 'Provide a DISC type.' : 'Provide a profile ID.', { itemIndex: this.getItemIndex() });
|
|
33
|
+
}
|
|
34
|
+
requestOptions.body = { ...recipient, ...extra(this) };
|
|
35
|
+
return requestOptions;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
exports.contentOperations = [
|
|
39
|
+
{
|
|
40
|
+
displayName: 'Operation',
|
|
41
|
+
name: 'operation',
|
|
42
|
+
type: 'options',
|
|
43
|
+
noDataExpression: true,
|
|
44
|
+
displayOptions: { show: showForContent },
|
|
45
|
+
options: [
|
|
46
|
+
{
|
|
47
|
+
name: 'Get Personality Content',
|
|
48
|
+
value: 'getProfileContent',
|
|
49
|
+
action: 'Get full personality content for a profile',
|
|
50
|
+
description: 'Full personality content for a profile you already have an ID for. Free.',
|
|
51
|
+
routing: {
|
|
52
|
+
request: {
|
|
53
|
+
method: 'GET',
|
|
54
|
+
url: '=/v4/content/profile/{{ encodeURIComponent($parameter.profileId) }}',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'Get Selling-To Playbook',
|
|
60
|
+
value: 'getSellingTo',
|
|
61
|
+
action: 'Get a selling to this person playbook',
|
|
62
|
+
description: 'A "selling to this person" playbook for a profile. Free.',
|
|
63
|
+
routing: {
|
|
64
|
+
request: {
|
|
65
|
+
method: 'GET',
|
|
66
|
+
url: '=/v4/content/profile/{{ encodeURIComponent($parameter.profileId) }}/selling_to',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'Get Communication Advice',
|
|
72
|
+
value: 'communicationAdvice',
|
|
73
|
+
action: 'Get communication advice for one or more profiles',
|
|
74
|
+
description: 'Communication advice for each of the given profiles. Free.',
|
|
75
|
+
routing: {
|
|
76
|
+
request: { method: 'POST', url: '/v4/content/profiles/communication_advice' },
|
|
77
|
+
send: { preSend: [attachProfileIdsBody] },
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'Get Relationship Matrix',
|
|
82
|
+
value: 'relationshipMatrix',
|
|
83
|
+
action: 'Get a relationship matrix across profiles',
|
|
84
|
+
description: 'A relationship matrix across the given profiles. Free.',
|
|
85
|
+
routing: {
|
|
86
|
+
request: { method: 'POST', url: '/v4/content/profiles/relationship_matrix' },
|
|
87
|
+
send: { preSend: [attachProfileIdsBody] },
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'Generate Prompt',
|
|
92
|
+
value: 'generatePrompt',
|
|
93
|
+
action: 'Generate a DISC tuned prompt for communicating with a person',
|
|
94
|
+
description: 'A ready-to-inject, DISC-tuned prompt you paste into your own AI workflow. Deterministic and free — use this if you bring your own LLM.',
|
|
95
|
+
routing: {
|
|
96
|
+
request: { method: 'POST', url: '/v4/content/generate_prompt' },
|
|
97
|
+
send: {
|
|
98
|
+
preSend: [
|
|
99
|
+
attachRecipientBody((context) => {
|
|
100
|
+
const objective = context.getNodeParameter('objective', '').trim();
|
|
101
|
+
return objective ? { objective } : {};
|
|
102
|
+
}),
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'Revise Email',
|
|
109
|
+
value: 'reviseEmail',
|
|
110
|
+
action: 'Revise a draft email for the recipients DISC type',
|
|
111
|
+
description: 'Rewrite a draft email so it lands well with the recipient, adapting tone, structure, and directness to their DISC type. Runs a real model call — costs 1 API credit per successful revision.',
|
|
112
|
+
routing: {
|
|
113
|
+
request: { method: 'POST', url: '/v4/content/revise_email' },
|
|
114
|
+
send: {
|
|
115
|
+
preSend: [
|
|
116
|
+
attachRecipientBody((context) => ({
|
|
117
|
+
email: context.getNodeParameter('emailDraft', ''),
|
|
118
|
+
})),
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
default: 'getProfileContent',
|
|
125
|
+
},
|
|
126
|
+
];
|
|
127
|
+
exports.contentFields = [
|
|
128
|
+
{
|
|
129
|
+
displayName: 'Profile ID',
|
|
130
|
+
name: 'profileId',
|
|
131
|
+
type: 'string',
|
|
132
|
+
required: true,
|
|
133
|
+
default: '',
|
|
134
|
+
displayOptions: {
|
|
135
|
+
show: { resource: ['content'], operation: ['getProfileContent', 'getSellingTo'] },
|
|
136
|
+
},
|
|
137
|
+
description: 'A Crystal profile ID, e.g. from a Profile or Prediction step',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
displayName: 'Profile IDs',
|
|
141
|
+
name: 'profileIds',
|
|
142
|
+
type: 'string',
|
|
143
|
+
required: true,
|
|
144
|
+
default: '',
|
|
145
|
+
placeholder: 'id1, id2, id3',
|
|
146
|
+
displayOptions: {
|
|
147
|
+
show: { resource: ['content'], operation: ['communicationAdvice', 'relationshipMatrix'] },
|
|
148
|
+
},
|
|
149
|
+
description: 'Crystal profile IDs, separated by commas or new lines',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
displayName: 'Identify Recipient By',
|
|
153
|
+
name: 'identifyBy',
|
|
154
|
+
type: 'options',
|
|
155
|
+
noDataExpression: true,
|
|
156
|
+
displayOptions: {
|
|
157
|
+
show: { resource: ['content'], operation: ['generatePrompt', 'reviseEmail'] },
|
|
158
|
+
},
|
|
159
|
+
options: [
|
|
160
|
+
{ name: 'Profile ID', value: 'id' },
|
|
161
|
+
{ name: 'DISC Type', value: 'discType' },
|
|
162
|
+
],
|
|
163
|
+
default: 'id',
|
|
164
|
+
description: 'Use a Crystal profile ID when one exists, otherwise a raw DISC type',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
displayName: 'Profile ID',
|
|
168
|
+
name: 'profileId',
|
|
169
|
+
type: 'string',
|
|
170
|
+
required: true,
|
|
171
|
+
default: '',
|
|
172
|
+
displayOptions: {
|
|
173
|
+
show: {
|
|
174
|
+
resource: ['content'],
|
|
175
|
+
operation: ['generatePrompt', 'reviseEmail'],
|
|
176
|
+
identifyBy: ['id'],
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
displayName: 'DISC Type',
|
|
182
|
+
name: 'discType',
|
|
183
|
+
type: 'string',
|
|
184
|
+
required: true,
|
|
185
|
+
default: '',
|
|
186
|
+
placeholder: 'D, Di, Sc …',
|
|
187
|
+
displayOptions: {
|
|
188
|
+
show: {
|
|
189
|
+
resource: ['content'],
|
|
190
|
+
operation: ['generatePrompt', 'reviseEmail'],
|
|
191
|
+
identifyBy: ['discType'],
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
displayName: 'Objective',
|
|
197
|
+
name: 'objective',
|
|
198
|
+
type: 'string',
|
|
199
|
+
default: '',
|
|
200
|
+
placeholder: 'write a follow-up email after a demo',
|
|
201
|
+
displayOptions: { show: showFor('generatePrompt') },
|
|
202
|
+
description: 'Optional — a task to focus the prompt on',
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
displayName: 'Email Draft',
|
|
206
|
+
name: 'emailDraft',
|
|
207
|
+
type: 'string',
|
|
208
|
+
required: true,
|
|
209
|
+
typeOptions: { rows: 6 },
|
|
210
|
+
default: '',
|
|
211
|
+
displayOptions: { show: showFor('reviseEmail') },
|
|
212
|
+
description: 'The draft email to revise',
|
|
213
|
+
},
|
|
214
|
+
];
|
|
215
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../nodes/Crystal/resources/content/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.predictionFields = exports.predictionOperations = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const personQuery_1 = require("../../shared/personQuery");
|
|
6
|
+
const pollPrediction_1 = require("../../shared/pollPrediction");
|
|
7
|
+
const showForPrediction = { resource: ['prediction'] };
|
|
8
|
+
const showForCreate = { resource: ['prediction'], operation: ['create', 'createAndWait'] };
|
|
9
|
+
const showForCreateAndWait = { resource: ['prediction'], operation: ['createAndWait'] };
|
|
10
|
+
const showForGet = { resource: ['prediction'], operation: ['get'] };
|
|
11
|
+
async function attachPredictionBody(requestOptions) {
|
|
12
|
+
const recordId = this.getNodeParameter('recordId', '').trim() || (0, node_crypto_1.randomUUID)();
|
|
13
|
+
requestOptions.body = {
|
|
14
|
+
query: (0, personQuery_1.buildPredictionQuery)(this),
|
|
15
|
+
record_id: recordId,
|
|
16
|
+
};
|
|
17
|
+
return requestOptions;
|
|
18
|
+
}
|
|
19
|
+
exports.predictionOperations = [
|
|
20
|
+
{
|
|
21
|
+
displayName: 'Operation',
|
|
22
|
+
name: 'operation',
|
|
23
|
+
type: 'options',
|
|
24
|
+
noDataExpression: true,
|
|
25
|
+
displayOptions: { show: showForPrediction },
|
|
26
|
+
options: [
|
|
27
|
+
{
|
|
28
|
+
name: 'Create',
|
|
29
|
+
value: 'create',
|
|
30
|
+
action: 'Submit a prediction job',
|
|
31
|
+
description: 'Submit an async lookup and return immediately with a job ID. Poll it later with "Get". A credit is spent only if the job completes with a profile found.',
|
|
32
|
+
routing: {
|
|
33
|
+
request: { method: 'POST', url: '/v4/predictions' },
|
|
34
|
+
send: { preSend: [attachPredictionBody] },
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'Create and Wait',
|
|
39
|
+
value: 'createAndWait',
|
|
40
|
+
action: 'Submit a prediction job and wait for the result',
|
|
41
|
+
description: 'Submit an async lookup, then poll until the job finishes (or the timeout is hit) and return the final result. A credit is spent only if a profile is found.',
|
|
42
|
+
routing: {
|
|
43
|
+
request: { method: 'POST', url: '/v4/predictions' },
|
|
44
|
+
send: { preSend: [attachPredictionBody] },
|
|
45
|
+
output: { postReceive: [pollPrediction_1.pollPrediction] },
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'Get',
|
|
50
|
+
value: 'get',
|
|
51
|
+
action: 'Get a prediction job result',
|
|
52
|
+
description: 'Poll for the result of a previously submitted prediction job',
|
|
53
|
+
routing: {
|
|
54
|
+
request: {
|
|
55
|
+
method: 'GET',
|
|
56
|
+
url: '=/v4/predictions/{{ encodeURIComponent($parameter.jobId) }}',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
default: 'createAndWait',
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
exports.predictionFields = [
|
|
65
|
+
...(0, personQuery_1.personQueryFields)({ show: showForCreate }),
|
|
66
|
+
{
|
|
67
|
+
displayName: 'Record ID',
|
|
68
|
+
name: 'recordId',
|
|
69
|
+
type: 'string',
|
|
70
|
+
default: '',
|
|
71
|
+
displayOptions: { show: showForCreate },
|
|
72
|
+
description: 'Optional idempotency key. Leave blank to generate a unique one per execution. Set it explicitly to make re-runs idempotent — Crystal will not double-charge for the same Record ID.',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
displayName: 'Poll Interval (Seconds)',
|
|
76
|
+
name: 'pollInterval',
|
|
77
|
+
type: 'number',
|
|
78
|
+
typeOptions: { minValue: 1 },
|
|
79
|
+
default: 5,
|
|
80
|
+
displayOptions: { show: showForCreateAndWait },
|
|
81
|
+
description: 'How long to wait between poll attempts. Jobs usually finish within a minute or two, but can take longer when Crystal’s queue is busy.',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
displayName: 'Timeout (Seconds)',
|
|
85
|
+
name: 'timeout',
|
|
86
|
+
type: 'number',
|
|
87
|
+
typeOptions: { minValue: 1 },
|
|
88
|
+
default: 300,
|
|
89
|
+
displayOptions: { show: showForCreateAndWait },
|
|
90
|
+
description: 'Give up waiting after this many seconds. The job keeps running on Crystal’s side — retrieve it later with "Get".',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
displayName: 'Job ID',
|
|
94
|
+
name: 'jobId',
|
|
95
|
+
type: 'string',
|
|
96
|
+
required: true,
|
|
97
|
+
default: '',
|
|
98
|
+
displayOptions: { show: showForGet },
|
|
99
|
+
description: 'The job ID returned by "Create"',
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../nodes/Crystal/resources/prediction/index.ts"],"names":[],"mappings":";;;AAAA,6CAAyC;AAEzC,0DAAmF;AACnF,gEAA6D;AAE7D,MAAM,iBAAiB,GAAG,EAAE,QAAQ,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC;AACvD,MAAM,aAAa,GAAG,EAAE,QAAQ,EAAE,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC,QAAQ,EAAE,eAAe,CAAC,EAAE,CAAC;AAC3F,MAAM,oBAAoB,GAAG,EAAE,QAAQ,EAAE,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;AACxF,MAAM,UAAU,GAAG,EAAE,QAAQ,EAAE,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;AAEpE,KAAK,UAAU,oBAAoB,CAElC,cAAmC;IAKnC,MAAM,QAAQ,GAAI,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,EAAE,CAAY,CAAC,IAAI,EAAE,IAAI,IAAA,wBAAU,GAAE,CAAC;IAE1F,cAAc,CAAC,IAAI,GAAG;QACrB,KAAK,EAAE,IAAA,kCAAoB,EAAC,IAAI,CAAC;QACjC,SAAS,EAAE,QAAQ;KACnB,CAAC;IAEF,OAAO,cAAc,CAAC;AACvB,CAAC;AAEY,QAAA,oBAAoB,GAAsB;IACtD;QACC,WAAW,EAAE,WAAW;QACxB,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,SAAS;QACf,gBAAgB,EAAE,IAAI;QACtB,cAAc,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE;QAC3C,OAAO,EAAE;YACR;gBACC,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,QAAQ;gBACf,MAAM,EAAE,yBAAyB;gBACjC,WAAW,EACV,0JAA0J;gBAC3J,OAAO,EAAE;oBACR,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,iBAAiB,EAAE;oBACnD,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,oBAAoB,CAAC,EAAE;iBACzC;aACD;YACD;gBACC,IAAI,EAAE,iBAAiB;gBACvB,KAAK,EAAE,eAAe;gBACtB,MAAM,EAAE,iDAAiD;gBACzD,WAAW,EACV,6JAA6J;gBAC9J,OAAO,EAAE;oBACR,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,iBAAiB,EAAE;oBACnD,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,oBAAoB,CAAC,EAAE;oBACzC,MAAM,EAAE,EAAE,WAAW,EAAE,CAAC,+BAAc,CAAC,EAAE;iBACzC;aACD;YACD;gBACC,IAAI,EAAE,KAAK;gBACX,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,6BAA6B;gBACrC,WAAW,EAAE,8DAA8D;gBAC3E,OAAO,EAAE;oBACR,OAAO,EAAE;wBACR,MAAM,EAAE,KAAK;wBACb,GAAG,EAAE,6DAA6D;qBAClE;iBACD;aACD;SACD;QACD,OAAO,EAAE,eAAe;KACxB;CACD,CAAC;AAEW,QAAA,gBAAgB,GAAsB;IAClD,GAAG,IAAA,+BAAiB,EAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;IAC7C;QACC,WAAW,EAAE,WAAW;QACxB,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,EAAE;QACX,cAAc,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE;QACvC,WAAW,EACV,qLAAqL;KACtL;IACD;QACC,WAAW,EAAE,yBAAyB;QACtC,IAAI,EAAE,cAAc;QACpB,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE;QAC5B,OAAO,EAAE,CAAC;QACV,cAAc,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE;QAC9C,WAAW,EACV,uIAAuI;KACxI;IACD;QACC,WAAW,EAAE,mBAAmB;QAChC,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE;QAC5B,OAAO,EAAE,GAAG;QACZ,cAAc,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE;QAC9C,WAAW,EACV,kHAAkH;KACnH;IACD;QACC,WAAW,EAAE,QAAQ;QACrB,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE,EAAE;QACX,cAAc,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;QACpC,WAAW,EAAE,iCAAiC;KAC9C;CACD,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.profileFields = exports.profileOperations = void 0;
|
|
4
|
+
const personQuery_1 = require("../../shared/personQuery");
|
|
5
|
+
const showForProfile = { resource: ['profile'] };
|
|
6
|
+
const showForProfileGet = { resource: ['profile'], operation: ['get'] };
|
|
7
|
+
exports.profileOperations = [
|
|
8
|
+
{
|
|
9
|
+
displayName: 'Operation',
|
|
10
|
+
name: 'operation',
|
|
11
|
+
type: 'options',
|
|
12
|
+
noDataExpression: true,
|
|
13
|
+
displayOptions: { show: showForProfile },
|
|
14
|
+
options: [
|
|
15
|
+
{
|
|
16
|
+
name: 'Get',
|
|
17
|
+
value: 'get',
|
|
18
|
+
action: 'Get a profile',
|
|
19
|
+
description: 'Real-time lookup of a profile Crystal already knows. Does not create new profiles — returns nothing found if the person is not already known. Spends 1 credit on a hit (re-fetches of the same profile are free).',
|
|
20
|
+
routing: {
|
|
21
|
+
request: {
|
|
22
|
+
method: 'GET',
|
|
23
|
+
url: '/v4/profile',
|
|
24
|
+
},
|
|
25
|
+
send: {
|
|
26
|
+
preSend: [
|
|
27
|
+
async function (requestOptions) {
|
|
28
|
+
requestOptions.qs = {
|
|
29
|
+
...requestOptions.qs,
|
|
30
|
+
...(0, personQuery_1.buildProfileQuery)(this),
|
|
31
|
+
};
|
|
32
|
+
return requestOptions;
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
output: {
|
|
37
|
+
postReceive: [
|
|
38
|
+
{
|
|
39
|
+
type: 'rootProperty',
|
|
40
|
+
properties: { property: 'data' },
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
default: 'get',
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
exports.profileFields = [
|
|
51
|
+
...(0, personQuery_1.personQueryFields)({ show: showForProfileGet }),
|
|
52
|
+
];
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../nodes/Crystal/resources/profile/index.ts"],"names":[],"mappings":";;;AACA,0DAAgF;AAEhF,MAAM,cAAc,GAAG,EAAE,QAAQ,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC;AACjD,MAAM,iBAAiB,GAAG,EAAE,QAAQ,EAAE,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;AAE3D,QAAA,iBAAiB,GAAsB;IACnD;QACC,WAAW,EAAE,WAAW;QACxB,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,SAAS;QACf,gBAAgB,EAAE,IAAI;QACtB,cAAc,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE;QACxC,OAAO,EAAE;YACR;gBACC,IAAI,EAAE,KAAK;gBACX,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,eAAe;gBACvB,WAAW,EACV,mNAAmN;gBACpN,OAAO,EAAE;oBACR,OAAO,EAAE;wBACR,MAAM,EAAE,KAAK;wBACb,GAAG,EAAE,aAAa;qBAClB;oBACD,IAAI,EAAE;wBACL,OAAO,EAAE;4BACR,KAAK,WAEJ,cAAmC;gCAEnC,cAAc,CAAC,EAAE,GAAG;oCACnB,GAAG,cAAc,CAAC,EAAE;oCACpB,GAAG,IAAA,+BAAiB,EAAC,IAAI,CAAC;iCAC1B,CAAC;gCACF,OAAO,cAAc,CAAC;4BACvB,CAAC;yBACD;qBACD;oBACD,MAAM,EAAE;wBACP,WAAW,EAAE;4BACZ;gCACC,IAAI,EAAE,cAAc;gCACpB,UAAU,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;6BAChC;yBACD;qBACD;iBACD;aACD;SACD;QACD,OAAO,EAAE,KAAK;KACd;CACD,CAAC;AAEW,QAAA,aAAa,GAAsB;IAC/C,GAAG,IAAA,+BAAiB,EAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;CACjD,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IDataObject, IDisplayOptions, IExecuteSingleFunctions, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare const PERSON_QUERY_PARAMETERS: readonly ["fullName", "email", "linkedinUrl", "jobTitle", "companyName", "phone"];
|
|
3
|
+
export declare function personQueryFields(displayOptions: IDisplayOptions): INodeProperties[];
|
|
4
|
+
export declare function buildProfileQuery(context: IExecuteSingleFunctions): IDataObject;
|
|
5
|
+
export declare function buildPredictionQuery(context: IExecuteSingleFunctions): IDataObject;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PERSON_QUERY_PARAMETERS = void 0;
|
|
4
|
+
exports.personQueryFields = personQueryFields;
|
|
5
|
+
exports.buildProfileQuery = buildProfileQuery;
|
|
6
|
+
exports.buildPredictionQuery = buildPredictionQuery;
|
|
7
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
8
|
+
exports.PERSON_QUERY_PARAMETERS = [
|
|
9
|
+
'fullName',
|
|
10
|
+
'email',
|
|
11
|
+
'linkedinUrl',
|
|
12
|
+
'jobTitle',
|
|
13
|
+
'companyName',
|
|
14
|
+
'phone',
|
|
15
|
+
];
|
|
16
|
+
const PROFILE_WIRE_NAMES = {
|
|
17
|
+
fullName: 'full_name',
|
|
18
|
+
email: 'email',
|
|
19
|
+
linkedinUrl: 'linkedin_url',
|
|
20
|
+
jobTitle: 'job_title',
|
|
21
|
+
companyName: 'company_name',
|
|
22
|
+
phone: 'phone',
|
|
23
|
+
};
|
|
24
|
+
const PREDICTION_WIRE_NAMES = {
|
|
25
|
+
fullName: 'name',
|
|
26
|
+
email: 'email',
|
|
27
|
+
linkedinUrl: 'linkedin_url',
|
|
28
|
+
jobTitle: 'job_title',
|
|
29
|
+
companyName: 'company_name',
|
|
30
|
+
phone: 'phone',
|
|
31
|
+
};
|
|
32
|
+
function personQueryFields(displayOptions) {
|
|
33
|
+
return [
|
|
34
|
+
{
|
|
35
|
+
displayName: 'Full Name',
|
|
36
|
+
name: 'fullName',
|
|
37
|
+
type: 'string',
|
|
38
|
+
default: '',
|
|
39
|
+
displayOptions,
|
|
40
|
+
description: 'For predictions this is combined with job title and company name; for a profile lookup it is matched on its own',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
displayName: 'Email',
|
|
44
|
+
name: 'email',
|
|
45
|
+
type: 'string',
|
|
46
|
+
placeholder: 'name@email.com',
|
|
47
|
+
default: '',
|
|
48
|
+
displayOptions,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
displayName: 'LinkedIn URL',
|
|
52
|
+
name: 'linkedinUrl',
|
|
53
|
+
type: 'string',
|
|
54
|
+
default: '',
|
|
55
|
+
displayOptions,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
displayName: 'Job Title',
|
|
59
|
+
name: 'jobTitle',
|
|
60
|
+
type: 'string',
|
|
61
|
+
default: '',
|
|
62
|
+
displayOptions,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
displayName: 'Company Name',
|
|
66
|
+
name: 'companyName',
|
|
67
|
+
type: 'string',
|
|
68
|
+
default: '',
|
|
69
|
+
displayOptions,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
displayName: 'Phone',
|
|
73
|
+
name: 'phone',
|
|
74
|
+
type: 'string',
|
|
75
|
+
default: '',
|
|
76
|
+
displayOptions,
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
function collectPersonQuery(context, wireNames) {
|
|
81
|
+
const query = {};
|
|
82
|
+
for (const parameter of exports.PERSON_QUERY_PARAMETERS) {
|
|
83
|
+
const value = context.getNodeParameter(parameter, '');
|
|
84
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
85
|
+
query[wireNames[parameter]] = value.trim();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (Object.keys(query).length === 0) {
|
|
89
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Provide at least one identifier (full name, email, LinkedIn URL, job title, company name, or phone).', { itemIndex: context.getItemIndex() });
|
|
90
|
+
}
|
|
91
|
+
return query;
|
|
92
|
+
}
|
|
93
|
+
function buildProfileQuery(context) {
|
|
94
|
+
return collectPersonQuery(context, PROFILE_WIRE_NAMES);
|
|
95
|
+
}
|
|
96
|
+
function buildPredictionQuery(context) {
|
|
97
|
+
return collectPersonQuery(context, PREDICTION_WIRE_NAMES);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=personQuery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"personQuery.js","sourceRoot":"","sources":["../../../../nodes/Crystal/shared/personQuery.ts"],"names":[],"mappings":";;;AAuCA,8CAgDC;AA2BD,8CAEC;AAGD,oDAEC;AAxHD,+CAAkD;AAOrC,QAAA,uBAAuB,GAAG;IACtC,UAAU;IACV,OAAO;IACP,aAAa;IACb,UAAU;IACV,aAAa;IACb,OAAO;CACE,CAAC;AAKX,MAAM,kBAAkB,GAAiB;IACxC,QAAQ,EAAE,WAAW;IACrB,KAAK,EAAE,OAAO;IACd,WAAW,EAAE,cAAc;IAC3B,QAAQ,EAAE,WAAW;IACrB,WAAW,EAAE,cAAc;IAC3B,KAAK,EAAE,OAAO;CACd,CAAC;AAGF,MAAM,qBAAqB,GAAiB;IAC3C,QAAQ,EAAE,MAAM;IAChB,KAAK,EAAE,OAAO;IACd,WAAW,EAAE,cAAc;IAC3B,QAAQ,EAAE,WAAW;IACrB,WAAW,EAAE,cAAc;IAC3B,KAAK,EAAE,OAAO;CACd,CAAC;AAEF,SAAgB,iBAAiB,CAAC,cAA+B;IAChE,OAAO;QACN;YACC,WAAW,EAAE,WAAW;YACxB,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,cAAc;YACd,WAAW,EACV,iHAAiH;SAClH;QACD;YACC,WAAW,EAAE,OAAO;YACpB,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,gBAAgB;YAC7B,OAAO,EAAE,EAAE;YACX,cAAc;SACd;QACD;YACC,WAAW,EAAE,cAAc;YAC3B,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,cAAc;SACd;QACD;YACC,WAAW,EAAE,WAAW;YACxB,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,cAAc;SACd;QACD;YACC,WAAW,EAAE,cAAc;YAC3B,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,cAAc;SACd;QACD;YACC,WAAW,EAAE,OAAO;YACpB,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,cAAc;SACd;KACD,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB,CAC1B,OAAgC,EAChC,SAAuB;IAEvB,MAAM,KAAK,GAAgB,EAAE,CAAC;IAE9B,KAAK,MAAM,SAAS,IAAI,+BAAuB,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAE,EAAE,CAAW,CAAC;QAChE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACtD,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC5C,CAAC;IACF,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,iCAAkB,CAC3B,OAAO,CAAC,OAAO,EAAE,EACjB,sGAAsG,EACtG,EAAE,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,EAAE,CACrC,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAGD,SAAgB,iBAAiB,CAAC,OAAgC;IACjE,OAAO,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AACxD,CAAC;AAGD,SAAgB,oBAAoB,CAAC,OAAgC;IACpE,OAAO,kBAAkB,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pollPrediction = pollPrediction;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const BASE_URL = 'https://api.crystalknows.com';
|
|
6
|
+
const TERMINAL_STATUSES = ['completed', 'failed'];
|
|
7
|
+
async function pollPrediction(_items, response) {
|
|
8
|
+
var _a;
|
|
9
|
+
const itemIndex = this.getItemIndex();
|
|
10
|
+
const submission = ((_a = response.body) !== null && _a !== void 0 ? _a : {});
|
|
11
|
+
const jobId = submission.job_id;
|
|
12
|
+
if (!jobId) {
|
|
13
|
+
throw new n8n_workflow_1.NodeApiError(this.getNode(), submission, {
|
|
14
|
+
message: 'Crystal did not return a job_id for the submitted prediction.',
|
|
15
|
+
itemIndex,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
const pollIntervalMs = Math.max(1, this.getNodeParameter('pollInterval', 5)) * 1000;
|
|
19
|
+
const timeoutMs = Math.max(1, this.getNodeParameter('timeout', 300)) * 1000;
|
|
20
|
+
const deadline = Date.now() + timeoutMs;
|
|
21
|
+
let job = { ...submission };
|
|
22
|
+
while (!TERMINAL_STATUSES.includes(job.status)) {
|
|
23
|
+
if (Date.now() >= deadline) {
|
|
24
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Prediction ${jobId} did not finish within ${timeoutMs / 1000}s. Use "Prediction: Get" to retrieve it later.`, { itemIndex });
|
|
25
|
+
}
|
|
26
|
+
await (0, n8n_workflow_1.sleep)(pollIntervalMs);
|
|
27
|
+
const requestOptions = {
|
|
28
|
+
baseURL: BASE_URL,
|
|
29
|
+
url: `/v4/predictions/${encodeURIComponent(jobId)}`,
|
|
30
|
+
method: 'GET',
|
|
31
|
+
json: true,
|
|
32
|
+
};
|
|
33
|
+
job = (await this.helpers.httpRequestWithAuthentication.call(this, 'crystalApi', requestOptions));
|
|
34
|
+
}
|
|
35
|
+
return [{ json: job, pairedItem: { item: itemIndex } }];
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=pollPrediction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pollPrediction.js","sourceRoot":"","sources":["../../../../nodes/Crystal/shared/pollPrediction.ts"],"names":[],"mappings":";;AAyBA,wCAiDC;AAlED,+CAAuE;AAEvE,MAAM,QAAQ,GAAG,8BAA8B,CAAC;AAChD,MAAM,iBAAiB,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AAc3C,KAAK,UAAU,cAAc,CAEnC,MAA4B,EAC5B,QAA8B;;IAE9B,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;IACtC,MAAM,UAAU,GAAG,CAAC,MAAA,QAAQ,CAAC,IAAI,mCAAI,EAAE,CAAgB,CAAC;IACxD,MAAM,KAAK,GAAG,UAAU,CAAC,MAA4B,CAAC;IAEtD,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,IAAI,2BAAY,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,UAAwB,EAAE;YAChE,OAAO,EAAE,+DAA+D;YACxE,SAAS;SACT,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GACnB,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,cAAc,EAAE,CAAC,CAAW,CAAC,GAAG,IAAI,CAAC;IACxE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,GAAG,CAAW,CAAC,GAAG,IAAI,CAAC;IACtF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IAExC,IAAI,GAAG,GAAgB,EAAE,GAAG,UAAU,EAAE,CAAC;IAEzC,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAgB,CAAC,EAAE,CAAC;QAC1D,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC5B,MAAM,IAAI,iCAAkB,CAC3B,IAAI,CAAC,OAAO,EAAE,EACd,cAAc,KAAK,0BAA0B,SAAS,GAAG,IAAI,gDAAgD,EAC7G,EAAE,SAAS,EAAE,CACb,CAAC;QACH,CAAC;QAED,MAAM,IAAA,oBAAK,EAAC,cAAc,CAAC,CAAC;QAE5B,MAAM,cAAc,GAAwB;YAC3C,OAAO,EAAE,QAAQ;YACjB,GAAG,EAAE,mBAAmB,kBAAkB,CAAC,KAAK,CAAC,EAAE;YACnD,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,IAAI;SACV,CAAC;QAEF,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,6BAA6B,CAAC,IAAI,CAC3D,IAAI,EACJ,YAAY,EACZ,cAAc,CACd,CAAgB,CAAC;IACnB,CAAC;IAED,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@crystalknows/n8n-nodes-crystal",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "n8n community node for the Crystal Data API — enrich profiles and get DISC personality insights",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://github.com/crystal-project-inc/n8n-nodes-crystal#readme",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"n8n-community-node-package",
|
|
9
|
+
"n8n",
|
|
10
|
+
"crystal",
|
|
11
|
+
"crystalknows",
|
|
12
|
+
"disc",
|
|
13
|
+
"personality",
|
|
14
|
+
"sales-intelligence",
|
|
15
|
+
"enrichment"
|
|
16
|
+
],
|
|
17
|
+
"author": {
|
|
18
|
+
"name": "Crystal",
|
|
19
|
+
"email": "support@crystalknows.com"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/crystal-project-inc/n8n-nodes-crystal.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/crystal-project-inc/n8n-nodes-crystal/issues"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20.15"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "n8n-node build",
|
|
33
|
+
"build:watch": "tsc --watch",
|
|
34
|
+
"dev": "n8n-node dev",
|
|
35
|
+
"lint": "n8n-node lint",
|
|
36
|
+
"lint:fix": "n8n-node lint --fix",
|
|
37
|
+
"release": "n8n-node release",
|
|
38
|
+
"prepublishOnly": "n8n-node prerelease"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"!dist/tsconfig.tsbuildinfo"
|
|
43
|
+
],
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"n8n": {
|
|
48
|
+
"n8nNodesApiVersion": 1,
|
|
49
|
+
"strict": true,
|
|
50
|
+
"credentials": [
|
|
51
|
+
"dist/credentials/CrystalApi.credentials.js"
|
|
52
|
+
],
|
|
53
|
+
"nodes": [
|
|
54
|
+
"dist/nodes/Crystal/Crystal.node.js"
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@n8n/node-cli": "^0.47.2",
|
|
59
|
+
"eslint": "9.32.0",
|
|
60
|
+
"prettier": "3.6.2",
|
|
61
|
+
"release-it": "^20.2.1",
|
|
62
|
+
"typescript": "5.9.2"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"n8n-workflow": "*"
|
|
66
|
+
}
|
|
67
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@crystalknows/n8n-nodes-crystal",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "n8n community node for the Crystal Data API — enrich profiles and get DISC personality insights",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://github.com/crystal-project-inc/n8n-nodes-crystal#readme",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"n8n-community-node-package",
|
|
9
|
+
"n8n",
|
|
10
|
+
"crystal",
|
|
11
|
+
"crystalknows",
|
|
12
|
+
"disc",
|
|
13
|
+
"personality",
|
|
14
|
+
"sales-intelligence",
|
|
15
|
+
"enrichment"
|
|
16
|
+
],
|
|
17
|
+
"author": {
|
|
18
|
+
"name": "Crystal",
|
|
19
|
+
"email": "support@crystalknows.com"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/crystal-project-inc/n8n-nodes-crystal.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/crystal-project-inc/n8n-nodes-crystal/issues"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20.15"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "n8n-node build",
|
|
33
|
+
"build:watch": "tsc --watch",
|
|
34
|
+
"dev": "n8n-node dev",
|
|
35
|
+
"lint": "n8n-node lint",
|
|
36
|
+
"lint:fix": "n8n-node lint --fix",
|
|
37
|
+
"release": "n8n-node release",
|
|
38
|
+
"prepublishOnly": "n8n-node prerelease"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"!dist/tsconfig.tsbuildinfo"
|
|
43
|
+
],
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"n8n": {
|
|
48
|
+
"n8nNodesApiVersion": 1,
|
|
49
|
+
"strict": true,
|
|
50
|
+
"credentials": [
|
|
51
|
+
"dist/credentials/CrystalApi.credentials.js"
|
|
52
|
+
],
|
|
53
|
+
"nodes": [
|
|
54
|
+
"dist/nodes/Crystal/Crystal.node.js"
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@n8n/node-cli": "^0.47.2",
|
|
59
|
+
"eslint": "9.32.0",
|
|
60
|
+
"prettier": "3.6.2",
|
|
61
|
+
"release-it": "^20.2.1",
|
|
62
|
+
"typescript": "5.9.2"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"n8n-workflow": "*"
|
|
66
|
+
}
|
|
67
|
+
}
|