@loopthink/n8n-nodes-loopthink 0.10.0 → 0.13.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 +33 -52
- package/dist/nodes/Loopthink/Loopthink.node.js +0 -33
- package/dist/nodes/Loopthink/Loopthink.node.js.map +1 -1
- package/dist/nodes/Loopthink/result.operation.js +4 -2
- package/dist/nodes/Loopthink/result.operation.js.map +1 -1
- package/dist/nodes/LoopthinkRunner/LoopthinkRunner.node.js +4 -4
- package/dist/nodes/LoopthinkRunner/LoopthinkRunner.node.js.map +1 -1
- package/dist/nodes/LoopthinkRunner/workflowTools.d.ts +1 -0
- package/dist/nodes/LoopthinkRunner/workflowTools.js +1 -0
- package/dist/nodes/LoopthinkRunner/workflowTools.js.map +1 -1
- package/package.json +2 -3
- package/dist/credentials/LoopthinkTargetApi.credentials.d.ts +0 -7
- package/dist/credentials/LoopthinkTargetApi.credentials.js +0 -46
- package/dist/credentials/LoopthinkTargetApi.credentials.js.map +0 -1
- package/dist/nodes/Loopthink/execute.operation.d.ts +0 -3
- package/dist/nodes/Loopthink/execute.operation.js +0 -89
- package/dist/nodes/Loopthink/execute.operation.js.map +0 -1
- package/dist/nodes/Loopthink/prepare.operation.d.ts +0 -3
- package/dist/nodes/Loopthink/prepare.operation.js +0 -144
- package/dist/nodes/Loopthink/prepare.operation.js.map +0 -1
- package/dist/nodes/Loopthink/query.d.ts +0 -29
- package/dist/nodes/Loopthink/query.js +0 -63
- package/dist/nodes/Loopthink/query.js.map +0 -1
- package/dist/nodes/LoopthinkRunner/secrets.d.ts +0 -7
- package/dist/nodes/LoopthinkRunner/secrets.js +0 -63
- package/dist/nodes/LoopthinkRunner/secrets.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Run [loopthink](https://www.loopthink.ai) MCP tools from inside your own network.
|
|
4
4
|
|
|
5
|
-
The node reaches out to loopthink, claims tool calls,
|
|
6
|
-
|
|
5
|
+
The node reaches out to loopthink, claims tool calls, hands them to your
|
|
6
|
+
workflow, masks whatever it answers with and sends that back. **Nothing has
|
|
7
7
|
to reach your n8n from the internet**, which is the whole point: it exists for
|
|
8
8
|
environments where the Docker runner cannot be deployed because inbound traffic
|
|
9
9
|
is not an option.
|
|
@@ -24,15 +24,16 @@ Claude ──► loopthink ──► queue ──┐
|
|
|
24
24
|
(an n8n Data Table, a Sheet, a database, any node-only integration), so it sends
|
|
25
25
|
the validated arguments instead.
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
a branch with **loopthink → Execute Request**, and every branch ends in
|
|
27
|
+
Every call leaves the Runner on the same output. A Switch on `{{$json.tool}}`
|
|
28
|
+
sends each tool to the branch that answers it, and every branch ends in
|
|
30
29
|
**loopthink → Send Result**. Give the Switch a fallback, or a tool nobody answers
|
|
31
30
|
leaves the caller waiting out its timeout.
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
What a branch does is your decision, because a tool carries what it needs. A
|
|
33
|
+
parameter the author pinned down arrives alongside the ones the model filled: a
|
|
34
|
+
table name, a statement, a path. So a Postgres branch reads
|
|
35
|
+
`{{ $json.params.statement }}`, and an HTTP branch reads
|
|
36
|
+
`{{ $json.params.path }}` and issues the call with an n8n credential.
|
|
36
37
|
|
|
37
38
|
See [examples/](examples) for three working workflows: over an n8n Data Table,
|
|
38
39
|
over Postgres, and over an HTTP API.
|
|
@@ -79,30 +80,16 @@ That last step matters: while you are only running *Test workflow* in the editor
|
|
|
79
80
|
the node listens for a short window and then stops. It polls continuously only
|
|
80
81
|
once the workflow is active.
|
|
81
82
|
|
|
82
|
-
###
|
|
83
|
+
### Credentials for your own systems
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
They stay in n8n, on whichever node makes the call, and loopthink never holds
|
|
86
|
+
them. A tool says what to reach, never what to reach it with: the path or the
|
|
87
|
+
statement travels as a fixed parameter, and the API key or database password is
|
|
88
|
+
picked from n8n's own credential store by the node that needs it.
|
|
86
89
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
Then add a **loopthink Target Secrets** credential in n8n (the node's **Secrets**
|
|
92
|
-
slot) with a `CRM_API_KEY` entry. The runner fills the placeholder in on the way out. loopthink sends the
|
|
93
|
-
request to make, never the key to make it with. The secret is never stored there
|
|
94
|
-
and never travels.
|
|
95
|
-
|
|
96
|
-
Two behaviours worth knowing:
|
|
97
|
-
|
|
98
|
-
- **A missing secret refuses the call.** The literal placeholder is never sent;
|
|
99
|
-
it would earn a 401 and leave `{{secret.CRM_API_KEY}}` in the target's access
|
|
100
|
-
log. The error names what is missing.
|
|
101
|
-
- **Execution records show the unresolved form.** A substituted URL can contain a
|
|
102
|
-
secret, and n8n stores execution data.
|
|
103
|
-
|
|
104
|
-
A placeholder in a **URL** ends up in the target's access log and in any proxy in
|
|
105
|
-
between. Sometimes an API leaves no choice, but prefer a header where you have one.
|
|
90
|
+
The node used to substitute `{{secret.NAME}}` into a resolved request, and that
|
|
91
|
+
went with the HTTP kind. n8n's credentials do the same job better, because they
|
|
92
|
+
were never anywhere near us to begin with.
|
|
106
93
|
|
|
107
94
|
## How it behaves
|
|
108
95
|
|
|
@@ -138,38 +125,32 @@ past the last id it was given by passing `id_after`. Both are ordinary filters i
|
|
|
138
125
|
already understands, so nothing opaque travels back and forth and the model can
|
|
139
126
|
also bisect a large range instead of only walking forward.
|
|
140
127
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
**Prepare Query** is only for the Data Table node, and only because that node
|
|
147
|
-
cannot take its conditions from an expression. A SQL statement or a URL is one
|
|
148
|
-
string, so a call that left a filter out simply produces a shorter query. A Data
|
|
149
|
-
Table node's conditions are rows in the editor, fixed when the workflow is built,
|
|
150
|
-
and the list as a whole cannot be computed: handed a string, n8n walks it
|
|
128
|
+
**`$json.q`** is what fills a Data Table node's condition rows, and it arrives
|
|
129
|
+
ready to use. That node cannot take its conditions from an expression: they are
|
|
130
|
+
rows in the editor, fixed when the workflow is built, and the list as a whole
|
|
131
|
+
cannot be computed, because n8n walks a string handed to a multi-value collection
|
|
151
132
|
character by character and quietly produces one empty condition per character.
|
|
152
133
|
|
|
153
|
-
So every row has to hold a value on every call
|
|
154
|
-
|
|
155
|
-
|
|
134
|
+
So every row has to hold a value on every call, including the ones the model left
|
|
135
|
+
empty. The platform sends them, keyed by the tool's parameter name: a bound so
|
|
136
|
+
far outside the data that the comparison is free, and a wildcard for an optional
|
|
137
|
+
match. One key, one plain value:
|
|
156
138
|
|
|
157
|
-
| | Column | Comparison | Value |
|
|
139
|
+
| Tool parameter | Column | Comparison | Value |
|
|
158
140
|
|---|---|---|---|
|
|
159
|
-
|
|
|
160
|
-
|
|
|
161
|
-
|
|
|
162
|
-
|
|
|
141
|
+
| `created_after` | `createdAt` | Or Later | `{{ $json.q.created_after }}` |
|
|
142
|
+
| `created_before` | `createdAt` | Or Earlier | `{{ $json.q.created_before }}` |
|
|
143
|
+
| `status` | `status` | Contains | `{{ $json.q.status }}` |
|
|
144
|
+
| `id_after` | `id` | Greater Than | `{{ $json.q.id_after }}` |
|
|
163
145
|
|
|
164
146
|
The comparison is chosen once from the dropdown and never changes, so it is not
|
|
165
147
|
in the data. Set **Limit** to `{{ $json.q.fetch }}`, which is one more than the
|
|
166
148
|
limit, and **Order** to `{{ $json.q.order }}`.
|
|
167
149
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
150
|
+
`id_after` is what lets a model read on, and it is an ordinary parameter like any
|
|
151
|
+
other. Compare it with **Greater Than** rather than Or Later, so that it means
|
|
152
|
+
what it says and the boundary row is not returned twice.
|
|
171
153
|
|
|
172
|
-

|
|
173
154
|

|
|
174
155
|
|
|
175
156
|
Paging is by **cursor**, not offset, so the source does the work: `id < c` with a
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Loopthink = void 0;
|
|
4
|
-
const execute_operation_1 = require("./execute.operation");
|
|
5
|
-
const prepare_operation_1 = require("./prepare.operation");
|
|
6
4
|
const result_operation_1 = require("./result.operation");
|
|
7
5
|
class Loopthink {
|
|
8
6
|
constructor() {
|
|
@@ -24,12 +22,6 @@ class Loopthink {
|
|
|
24
22
|
displayName: 'Authentication',
|
|
25
23
|
displayOptions: { show: { operation: ['result'] } },
|
|
26
24
|
},
|
|
27
|
-
{
|
|
28
|
-
name: 'loopthinkTargetApi',
|
|
29
|
-
required: false,
|
|
30
|
-
displayName: 'Secrets',
|
|
31
|
-
displayOptions: { show: { operation: ['execute'] } },
|
|
32
|
-
},
|
|
33
25
|
],
|
|
34
26
|
properties: [
|
|
35
27
|
{
|
|
@@ -45,41 +37,16 @@ class Loopthink {
|
|
|
45
37
|
description: 'Mask the answer and send it back to loopthink',
|
|
46
38
|
action: 'Send the result back to loopthink',
|
|
47
39
|
},
|
|
48
|
-
{
|
|
49
|
-
name: 'Execute Request',
|
|
50
|
-
value: 'execute',
|
|
51
|
-
description: 'Issue the HTTP call loopthink resolved, filling in your secrets',
|
|
52
|
-
action: 'Execute the resolved HTTP request',
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
name: 'Prepare Query',
|
|
56
|
-
value: 'prepare',
|
|
57
|
-
description: "Turn the model's optional parameters into values a Data Table node can filter on",
|
|
58
|
-
action: 'Prepare a data table query',
|
|
59
|
-
},
|
|
60
40
|
],
|
|
61
41
|
},
|
|
62
42
|
...result_operation_1.resultFields.map((field) => ({
|
|
63
43
|
...field,
|
|
64
44
|
displayOptions: { ...field.displayOptions, show: { ...field.displayOptions?.show, operation: ['result'] } },
|
|
65
45
|
})),
|
|
66
|
-
...execute_operation_1.executeFields.map((field) => ({
|
|
67
|
-
...field,
|
|
68
|
-
displayOptions: { ...field.displayOptions, show: { ...field.displayOptions?.show, operation: ['execute'] } },
|
|
69
|
-
})),
|
|
70
|
-
...prepare_operation_1.prepareFields.map((field) => ({
|
|
71
|
-
...field,
|
|
72
|
-
displayOptions: { ...field.displayOptions, show: { ...field.displayOptions?.show, operation: ['prepare'] } },
|
|
73
|
-
})),
|
|
74
46
|
],
|
|
75
47
|
};
|
|
76
48
|
}
|
|
77
49
|
async execute() {
|
|
78
|
-
const operation = this.getNodeParameter('operation', 0);
|
|
79
|
-
if (operation === 'execute')
|
|
80
|
-
return execute_operation_1.executeRequest.call(this);
|
|
81
|
-
if (operation === 'prepare')
|
|
82
|
-
return prepare_operation_1.executePrepare.call(this);
|
|
83
50
|
return result_operation_1.executeResult.call(this);
|
|
84
51
|
}
|
|
85
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Loopthink.node.js","sourceRoot":"","sources":["../../../nodes/Loopthink/Loopthink.node.ts"],"names":[],"mappings":";;;AAOA,
|
|
1
|
+
{"version":3,"file":"Loopthink.node.js","sourceRoot":"","sources":["../../../nodes/Loopthink/Loopthink.node.ts"],"names":[],"mappings":";;;AAOA,yDAAiE;AAmBjE,MAAa,SAAS;IAAtB;QACC,gBAAW,GAAyB;YACnC,WAAW,EAAE,WAAW;YACxB,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,yBAAyB;YAC/B,KAAK,EAAE,CAAC,WAAW,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,QAAQ,EAAE,8BAA8B;YACxC,WAAW,EAAE,wCAAwC;YACrD,QAAQ,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;YAC/B,MAAM,EAAE,CAAC,MAAM,CAAC;YAChB,OAAO,EAAE,CAAC,MAAM,CAAC;YACjB,WAAW,EAAE;gBACZ;oBACC,IAAI,EAAE,oBAAoB;oBAC1B,QAAQ,EAAE,IAAI;oBACd,WAAW,EAAE,gBAAgB;oBAC7B,cAAc,EAAE,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE;iBACnD;aACD;YACD,UAAU,EAAE;gBACX;oBACC,WAAW,EAAE,WAAW;oBACxB,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,SAAS;oBACf,gBAAgB,EAAE,IAAI;oBACtB,OAAO,EAAE,QAAQ;oBACjB,OAAO,EAAE;wBACR;4BACC,IAAI,EAAE,aAAa;4BACnB,KAAK,EAAE,QAAQ;4BACf,WAAW,EAAE,+CAA+C;4BAC5D,MAAM,EAAE,mCAAmC;yBAC3C;qBACD;iBACD;gBACD,GAAG,+BAAY,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;oBAC/B,GAAG,KAAK;oBACR,cAAc,EAAE,EAAE,GAAG,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,EAAE,GAAG,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE;iBAC3G,CAAC,CAAC;aACH;SACD,CAAC;IAKH,CAAC;IAHA,KAAK,CAAC,OAAO;QACZ,OAAO,gCAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;CACD;AA9CD,8BA8CC"}
|
|
@@ -7,7 +7,9 @@ const masking_1 = require("../LoopthinkRunner/masking");
|
|
|
7
7
|
function pagePayload(ctx, respondWith, items) {
|
|
8
8
|
if (respondWith === 'object')
|
|
9
9
|
return (items[0]?.json ?? {});
|
|
10
|
-
const rows = items
|
|
10
|
+
const rows = items
|
|
11
|
+
.map((item) => item.json)
|
|
12
|
+
.filter((row) => row && Object.keys(row).length > 0);
|
|
11
13
|
if (respondWith === 'list')
|
|
12
14
|
return rows;
|
|
13
15
|
const limit = Number(ctx.getNodeParameter('pageSize', 0));
|
|
@@ -65,7 +67,7 @@ exports.resultFields = [
|
|
|
65
67
|
displayName: 'Limit',
|
|
66
68
|
name: 'pageSize',
|
|
67
69
|
type: 'number',
|
|
68
|
-
default: "={{ $('
|
|
70
|
+
default: "={{ $('loopthink Runner').first().json.q.limit }}",
|
|
69
71
|
displayOptions: { show: { respondWith: ['page'] } },
|
|
70
72
|
description: 'How many rows to answer with. Read one more than this in the branch: if the extra row arrives, the answer is marked truncated.',
|
|
71
73
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result.operation.js","sourceRoot":"","sources":["../../../nodes/Loopthink/result.operation.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"result.operation.js","sourceRoot":"","sources":["../../../nodes/Loopthink/result.operation.ts"],"names":[],"mappings":"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"}
|
|
@@ -45,9 +45,9 @@ class LoopthinkRunner {
|
|
|
45
45
|
displayOptions: { show: { transport: ['polling'] } },
|
|
46
46
|
name: 'pollInterval',
|
|
47
47
|
type: 'number',
|
|
48
|
-
typeOptions: { minValue:
|
|
49
|
-
default:
|
|
50
|
-
description: 'How often to check for work. This is the latency added to every tool call,
|
|
48
|
+
typeOptions: { minValue: 10, maxValue: 300 },
|
|
49
|
+
default: 10,
|
|
50
|
+
description: 'How often to check for work. This is the latency added to every tool call, and every poll is a request you pay for. Ten seconds is the floor; use WebSocket if the wait matters, because a pushed call has none of it.',
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
displayName: 'Every claimed call leaves here. Route it with a Switch on <code>{{$json.tool}}</code>: a workflow tool goes to the branch that answers it, an HTTP tool to a branch with <b>loopthink → Execute Request</b>. Every branch ends in <b>loopthink → Send Result</b>. Give the Switch a fallback, or a tool nobody answers leaves the caller waiting out its timeout.',
|
|
@@ -60,7 +60,7 @@ class LoopthinkRunner {
|
|
|
60
60
|
}
|
|
61
61
|
async trigger() {
|
|
62
62
|
const credentials = await this.getCredentials('loopthinkRunnerApi');
|
|
63
|
-
const pollInterval = this.getNodeParameter('pollInterval',
|
|
63
|
+
const pollInterval = Math.max(10, this.getNodeParameter('pollInterval', 10)) * 1000;
|
|
64
64
|
const transport = this.getNodeParameter('transport', 'polling');
|
|
65
65
|
const queueUrl = String(credentials.queueUrl || '').replace(/\/+$/, '');
|
|
66
66
|
const workspaceId = String(credentials.workspaceId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoopthinkRunner.node.js","sourceRoot":"","sources":["../../../nodes/LoopthinkRunner/LoopthinkRunner.node.ts"],"names":[],"mappings":";;;AAOA,+CAAgE;AAEhE,qCAAuC;AACvC,mDAA8E;AAyB9E,MAAa,eAAe;IAA5B;QACC,gBAAW,GAAyB;YACnC,WAAW,EAAE,kBAAkB;YAC/B,IAAI,EAAE,iBAAiB;YAKvB,IAAI,EAAE,yBAAyB;YAC/B,KAAK,EAAE,CAAC,SAAS,CAAC;YAClB,OAAO,EAAE,CAAC;YACV,QAAQ,EAAE,iGAAiG;YAC3G,WAAW,EAAE,gFAAgF;YAC7F,QAAQ,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE;YAKtC,MAAM,EAAE,CAAC,MAAM,CAAC;YAGhB,OAAO,EAAE,8BAAc;YACvB,WAAW,EAAE;gBACZ,EAAE,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,gBAAgB,EAAE;aAC7E;YACD,UAAU,EAAE;gBACX;oBAIC,WAAW,EAAE,WAAW;oBACxB,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,SAAS;oBACf,gBAAgB,EAAE,IAAI;oBACtB,OAAO,EAAE,SAAS;oBAClB,OAAO,EAAE;wBACR;4BACC,IAAI,EAAE,SAAS;4BACf,KAAK,EAAE,SAAS;4BAChB,WAAW,EAAE,0DAA0D;yBACvE;wBACD;4BACC,IAAI,EAAE,WAAW;4BACjB,KAAK,EAAE,WAAW;4BAClB,WAAW,EACV,0JAA0J;yBAC3J;qBACD;iBACD;gBACD;oBACC,WAAW,EAAE,yBAAyB;oBACtC,cAAc,EAAE,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE;oBACpD,IAAI,EAAE,cAAc;oBACpB,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"LoopthinkRunner.node.js","sourceRoot":"","sources":["../../../nodes/LoopthinkRunner/LoopthinkRunner.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,7 @@ function emitJob(ctx, job) {
|
|
|
24
24
|
? job.request.params
|
|
25
25
|
: {},
|
|
26
26
|
statement: isStatementRequest(job.request) ? job.request.statement : null,
|
|
27
|
+
q: isParamsRequest(job.request) ? (job.request.q ?? {}) : {},
|
|
27
28
|
masking: job.masking ?? [],
|
|
28
29
|
scope: job.scope ?? null,
|
|
29
30
|
leaseUntil: job.leaseUntil,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflowTools.js","sourceRoot":"","sources":["../../../nodes/LoopthinkRunner/workflowTools.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"workflowTools.js","sourceRoot":"","sources":["../../../nodes/LoopthinkRunner/workflowTools.ts"],"names":[],"mappings":";;;AAiFA,0CAEC;AAED,gDAIC;AAyBD,0BAqBC;AAtDD,SAAgB,eAAe,CAAC,OAAiC;IAChE,OAAQ,OAAyB,EAAE,IAAI,KAAK,QAAQ,CAAC;AACtD,CAAC;AAED,SAAgB,kBAAkB,CACjC,OAAiC;IAEjC,OAAQ,OAA4B,EAAE,IAAI,KAAK,WAAW,CAAC;AAC5D,CAAC;AAWY,QAAA,cAAc,GAA+B;IAGzD,EAAE,IAAI,EAAE,MAA0C,EAAE;CACpD,CAAC;AAUF,SAAgB,OAAO,CAAC,GAAsB,EAAE,GAAkB;IACjE,GAAG,CAAC,IAAI,CAAC;QACR,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC;YAC3B;gBACC,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,OAAO,EAAE,GAAG,CAAC,OAAiC;gBAI9C,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC;oBACtE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM;oBACpB,CAAC,CAAC,EAAE;gBACL,SAAS,EAAE,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;gBACzE,CAAC,EAAE,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;gBAC5D,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,EAAE;gBAC1B,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,IAAI;gBACxB,UAAU,EAAE,GAAG,CAAC,UAAU;aAC1B;SACD,CAAC;KACF,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loopthink/n8n-nodes-loopthink",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Run loopthink MCP tools from inside your own network. The node reaches out to loopthink, claims tool calls, executes them against your internal HTTP APIs and returns masked results \u2014 no inbound connection required.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"n8n-community-node-package",
|
|
@@ -42,8 +42,7 @@
|
|
|
42
42
|
"n8n": {
|
|
43
43
|
"n8nNodesApiVersion": 1,
|
|
44
44
|
"credentials": [
|
|
45
|
-
"dist/credentials/LoopthinkRunnerApi.credentials.js"
|
|
46
|
-
"dist/credentials/LoopthinkTargetApi.credentials.js"
|
|
45
|
+
"dist/credentials/LoopthinkRunnerApi.credentials.js"
|
|
47
46
|
],
|
|
48
47
|
"nodes": [
|
|
49
48
|
"dist/nodes/LoopthinkRunner/LoopthinkRunner.node.js",
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LoopthinkTargetApi = void 0;
|
|
4
|
-
class LoopthinkTargetApi {
|
|
5
|
-
constructor() {
|
|
6
|
-
this.name = 'loopthinkTargetApi';
|
|
7
|
-
this.displayName = 'Loopthink Target Secrets API';
|
|
8
|
-
this.documentationUrl = 'https://www.loopthink.ai/docs/n8n';
|
|
9
|
-
this.properties = [
|
|
10
|
-
{
|
|
11
|
-
displayName: 'Secrets',
|
|
12
|
-
name: 'secrets',
|
|
13
|
-
placeholder: 'Add secret',
|
|
14
|
-
type: 'fixedCollection',
|
|
15
|
-
typeOptions: { multipleValues: true },
|
|
16
|
-
default: {},
|
|
17
|
-
description: 'Each entry matches a {{secret.NAME}} placeholder configured in loopthink. A call whose placeholder is missing here is refused rather than sent, because an unresolved placeholder would reach the target system and end up in its logs.',
|
|
18
|
-
options: [
|
|
19
|
-
{
|
|
20
|
-
name: 'secret',
|
|
21
|
-
displayName: 'Secret',
|
|
22
|
-
values: [
|
|
23
|
-
{
|
|
24
|
-
displayName: 'Name',
|
|
25
|
-
name: 'name',
|
|
26
|
-
type: 'string',
|
|
27
|
-
default: '',
|
|
28
|
-
placeholder: 'CRM_API_KEY',
|
|
29
|
-
description: 'The NAME in {{secret.NAME}}, exactly as written in loopthink',
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
displayName: 'Value',
|
|
33
|
-
name: 'value',
|
|
34
|
-
type: 'string',
|
|
35
|
-
typeOptions: { password: true },
|
|
36
|
-
default: '',
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
},
|
|
40
|
-
],
|
|
41
|
-
},
|
|
42
|
-
];
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
exports.LoopthinkTargetApi = LoopthinkTargetApi;
|
|
46
|
-
//# sourceMappingURL=LoopthinkTargetApi.credentials.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"LoopthinkTargetApi.credentials.js","sourceRoot":"","sources":["../../credentials/LoopthinkTargetApi.credentials.ts"],"names":[],"mappings":";;;AAaA,MAAa,kBAAkB;IAA/B;QACC,SAAI,GAAG,oBAAoB,CAAC;QAE5B,gBAAW,GAAG,8BAA8B,CAAC;QAM7C,qBAAgB,GAAG,mCAAmC,CAAC;QAEvD,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,SAAS;gBACtB,IAAI,EAAE,SAAS;gBACf,WAAW,EAAE,YAAY;gBACzB,IAAI,EAAE,iBAAiB;gBACvB,WAAW,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE;gBACrC,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,yOAAyO;gBAC1O,OAAO,EAAE;oBACR;wBACC,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,QAAQ;wBACrB,MAAM,EAAE;4BACP;gCACC,WAAW,EAAE,MAAM;gCACnB,IAAI,EAAE,MAAM;gCACZ,IAAI,EAAE,QAAQ;gCACd,OAAO,EAAE,EAAE;gCACX,WAAW,EAAE,aAAa;gCAC1B,WAAW,EAAE,8DAA8D;6BAC3E;4BACD;gCACC,WAAW,EAAE,OAAO;gCACpB,IAAI,EAAE,OAAO;gCACb,IAAI,EAAE,QAAQ;gCACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gCAC/B,OAAO,EAAE,EAAE;6BACX;yBACD;qBACD;iBACD;aACD;SACD,CAAC;IACH,CAAC;CAAA;AA9CD,gDA8CC"}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.executeFields = void 0;
|
|
4
|
-
exports.executeRequest = executeRequest;
|
|
5
|
-
const n8n_workflow_1 = require("n8n-workflow");
|
|
6
|
-
const secrets_1 = require("../LoopthinkRunner/secrets");
|
|
7
|
-
exports.executeFields = [
|
|
8
|
-
{
|
|
9
|
-
displayName: 'Request',
|
|
10
|
-
name: 'httpRequest',
|
|
11
|
-
type: 'json',
|
|
12
|
-
default: "={{ $json.request }}",
|
|
13
|
-
description: 'The resolved call from the Runner. Leave this as it is unless the branch reshapes the item first.',
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
displayName: 'Timeout (Seconds)',
|
|
17
|
-
name: 'requestTimeout',
|
|
18
|
-
type: 'number',
|
|
19
|
-
typeOptions: { minValue: 1, maxValue: 120 },
|
|
20
|
-
default: 30,
|
|
21
|
-
description: 'How long to wait for the internal API before giving up',
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
displayName: 'Keys for your own systems stay in this n8n. Write <code>{{secret.NAME}}</code> in loopthink where a value belongs and add a matching entry under <b>Secrets</b>. A call whose placeholder has no entry is refused rather than sent, because the literal placeholder would reach the target and sit in its log.',
|
|
25
|
-
name: 'executeNotice',
|
|
26
|
-
type: 'notice',
|
|
27
|
-
default: '',
|
|
28
|
-
},
|
|
29
|
-
];
|
|
30
|
-
function parseRequest(value) {
|
|
31
|
-
if (typeof value === 'string') {
|
|
32
|
-
try {
|
|
33
|
-
return JSON.parse(value);
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
return {};
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return (value ?? {});
|
|
40
|
-
}
|
|
41
|
-
async function executeRequest() {
|
|
42
|
-
const timeout = this.getNodeParameter('requestTimeout', 0, 30) * 1000;
|
|
43
|
-
let secrets = {};
|
|
44
|
-
try {
|
|
45
|
-
secrets = (0, secrets_1.secretsFromCredential)(await this.getCredentials('loopthinkTargetApi'));
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
}
|
|
49
|
-
const out = [];
|
|
50
|
-
for (let i = 0; i < this.getInputData().length; i += 1) {
|
|
51
|
-
const request = parseRequest(this.getNodeParameter('httpRequest', i));
|
|
52
|
-
if (!request.url) {
|
|
53
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No url in the Request parameter', {
|
|
54
|
-
description: 'This operation runs the HTTP call loopthink resolved. A workflow tool has no url, so route those to their own branch instead.',
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
try {
|
|
58
|
-
const resolved = (0, secrets_1.substituteSecrets)(request, secrets);
|
|
59
|
-
const url = new URL(resolved.url);
|
|
60
|
-
Object.entries(resolved.query || {}).forEach(([key, value]) => url.searchParams.set(key, String(value)));
|
|
61
|
-
const response = await this.helpers.httpRequest({
|
|
62
|
-
method: (resolved.method || 'GET'),
|
|
63
|
-
url: url.toString(),
|
|
64
|
-
headers: resolved.headers || {},
|
|
65
|
-
body: resolved.body ?? undefined,
|
|
66
|
-
json: true,
|
|
67
|
-
timeout,
|
|
68
|
-
returnFullResponse: true,
|
|
69
|
-
ignoreHttpStatusErrors: true,
|
|
70
|
-
});
|
|
71
|
-
out.push({
|
|
72
|
-
json: {
|
|
73
|
-
status: response.statusCode,
|
|
74
|
-
data: response.body,
|
|
75
|
-
url: request.url,
|
|
76
|
-
method: request.method ?? 'GET',
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
catch (error) {
|
|
81
|
-
if (error instanceof secrets_1.MissingSecretError) {
|
|
82
|
-
this.logger.warn(`loopthink: ${error.message}`);
|
|
83
|
-
}
|
|
84
|
-
out.push({ json: { error: error.message, url: request.url } });
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return [out];
|
|
88
|
-
}
|
|
89
|
-
//# sourceMappingURL=execute.operation.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"execute.operation.js","sourceRoot":"","sources":["../../../nodes/Loopthink/execute.operation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.prepareFields = void 0;
|
|
4
|
-
exports.executePrepare = executePrepare;
|
|
5
|
-
const query_1 = require("./query");
|
|
6
|
-
exports.prepareFields = [
|
|
7
|
-
{
|
|
8
|
-
displayName: 'Parameters',
|
|
9
|
-
name: 'params',
|
|
10
|
-
type: 'json',
|
|
11
|
-
default: '={{ $json.params }}',
|
|
12
|
-
description: 'What the model sent. Leave this as it is unless the branch reshapes the item first.',
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
displayName: 'Rows per Answer',
|
|
16
|
-
name: 'defaultLimit',
|
|
17
|
-
type: 'number',
|
|
18
|
-
typeOptions: { minValue: 1, maxValue: 500 },
|
|
19
|
-
default: 20,
|
|
20
|
-
description: 'The most rows a single answer carries. Used when the call sends no limit, and a larger limit is capped to it.',
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
displayName: 'Order',
|
|
24
|
-
name: 'order',
|
|
25
|
-
type: 'options',
|
|
26
|
-
default: 'DESC',
|
|
27
|
-
options: [
|
|
28
|
-
{ name: 'Newest First', value: 'DESC' },
|
|
29
|
-
{ name: 'Oldest First', value: 'ASC' },
|
|
30
|
-
],
|
|
31
|
-
description: 'Used unless the call sends a sort parameter of "oldest" or "newest". Ascending by id is also what lets a model read a long list in order.',
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
displayName: 'Optional Ranges',
|
|
35
|
-
name: 'ranges',
|
|
36
|
-
placeholder: 'Add range',
|
|
37
|
-
type: 'fixedCollection',
|
|
38
|
-
typeOptions: { multipleValues: true },
|
|
39
|
-
default: {},
|
|
40
|
-
description: 'One entry per column the tool can narrow down. Each yields a min and a max, filled from the call or opened all the way up. A range on id is what lets a model continue past the last row it saw.',
|
|
41
|
-
options: [
|
|
42
|
-
{
|
|
43
|
-
name: 'range',
|
|
44
|
-
displayName: 'Range',
|
|
45
|
-
values: [
|
|
46
|
-
{
|
|
47
|
-
displayName: 'Column',
|
|
48
|
-
name: 'column',
|
|
49
|
-
type: 'string',
|
|
50
|
-
default: '',
|
|
51
|
-
placeholder: 'createdAt',
|
|
52
|
-
description: 'Also the stem of the two keys it appears under, as q.createdAt_min and q.createdAt_max',
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
displayName: 'Type',
|
|
56
|
-
name: 'type',
|
|
57
|
-
type: 'options',
|
|
58
|
-
default: 'date',
|
|
59
|
-
options: [
|
|
60
|
-
{ name: 'Date', value: 'date' },
|
|
61
|
-
{ name: 'Number', value: 'number' },
|
|
62
|
-
],
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
displayName: 'Parameter Prefix',
|
|
66
|
-
name: 'parameter',
|
|
67
|
-
type: 'string',
|
|
68
|
-
default: '',
|
|
69
|
-
placeholder: 'created',
|
|
70
|
-
description: 'Only when the parameters are not named after the column. Empty means the column name is the prefix, so a column "check_in" reads check_in_after and check_in_before.',
|
|
71
|
-
},
|
|
72
|
-
],
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
displayName: 'Optional Exact Matches',
|
|
78
|
-
name: 'matches',
|
|
79
|
-
placeholder: 'Add match',
|
|
80
|
-
type: 'fixedCollection',
|
|
81
|
-
typeOptions: { multipleValues: true },
|
|
82
|
-
default: {},
|
|
83
|
-
description: 'One entry per column the tool can pin to a value. Compare the row with "contains": an equals row has no value that means "no filter", a wildcard does.',
|
|
84
|
-
options: [
|
|
85
|
-
{
|
|
86
|
-
name: 'match',
|
|
87
|
-
displayName: 'Match',
|
|
88
|
-
values: [
|
|
89
|
-
{
|
|
90
|
-
displayName: 'Column',
|
|
91
|
-
name: 'column',
|
|
92
|
-
type: 'string',
|
|
93
|
-
default: '',
|
|
94
|
-
placeholder: 'status',
|
|
95
|
-
description: 'Also the key it appears under, as q.status',
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
displayName: 'Parameter',
|
|
99
|
-
name: 'parameter',
|
|
100
|
-
type: 'string',
|
|
101
|
-
default: '',
|
|
102
|
-
description: 'Only when the parameter is not named after the column',
|
|
103
|
-
},
|
|
104
|
-
],
|
|
105
|
-
},
|
|
106
|
-
],
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
displayName: 'Each key holds one value, so a condition row is <b>column</b>, a comparison you pick once, and <code>{{ $json.q.<key> }}</code> in <b>Value</b>. A range yields two keys, <code>q.<column>_min</code> and <code>q.<column>_max</code>; a match yields one, <code>q.<column></code>, compared with <b>contains</b>. Set <b>Limit</b> to <code>q.fetch</code> and <b>Order</b> to <code>q.order</code>. Every key holds a value on every call, so no row has to be removed for a parameter the model left out, and <code>q.unused</code> names any the tool offers that no row reads.',
|
|
110
|
-
name: 'prepareNotice',
|
|
111
|
-
type: 'notice',
|
|
112
|
-
default: '',
|
|
113
|
-
},
|
|
114
|
-
];
|
|
115
|
-
function parseParams(value) {
|
|
116
|
-
if (typeof value === 'string') {
|
|
117
|
-
try {
|
|
118
|
-
return JSON.parse(value);
|
|
119
|
-
}
|
|
120
|
-
catch {
|
|
121
|
-
return {};
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return (value ?? {});
|
|
125
|
-
}
|
|
126
|
-
async function executePrepare() {
|
|
127
|
-
const out = [];
|
|
128
|
-
for (let i = 0; i < this.getInputData().length; i += 1) {
|
|
129
|
-
const params = parseParams(this.getNodeParameter('params', i));
|
|
130
|
-
const ranges = (this.getNodeParameter('ranges', i, {}).range ??
|
|
131
|
-
[]);
|
|
132
|
-
const matches = (this.getNodeParameter('matches', i, {}).match ??
|
|
133
|
-
[]);
|
|
134
|
-
const q = (0, query_1.prepareQuery)(params, {
|
|
135
|
-
defaultLimit: this.getNodeParameter('defaultLimit', i),
|
|
136
|
-
order: this.getNodeParameter('order', i),
|
|
137
|
-
ranges,
|
|
138
|
-
matches,
|
|
139
|
-
});
|
|
140
|
-
out.push({ json: { ...this.getInputData()[i].json, q } });
|
|
141
|
-
}
|
|
142
|
-
return [out];
|
|
143
|
-
}
|
|
144
|
-
//# sourceMappingURL=prepare.operation.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prepare.operation.js","sourceRoot":"","sources":["../../../nodes/Loopthink/prepare.operation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
export declare const DATE_MIN = "0001-01-01T00:00:00.000Z";
|
|
2
|
-
export declare const DATE_MAX = "9999-12-31T23:59:59.999Z";
|
|
3
|
-
export declare const NUMBER_MIN = -9007199254740991;
|
|
4
|
-
export declare const NUMBER_MAX = 9007199254740991;
|
|
5
|
-
export type RangeType = 'date' | 'number';
|
|
6
|
-
export interface RangeSpec {
|
|
7
|
-
column: string;
|
|
8
|
-
parameter?: string;
|
|
9
|
-
type: RangeType;
|
|
10
|
-
}
|
|
11
|
-
export interface MatchSpec {
|
|
12
|
-
column: string;
|
|
13
|
-
parameter?: string;
|
|
14
|
-
}
|
|
15
|
-
export interface PreparedQuery {
|
|
16
|
-
limit: number;
|
|
17
|
-
fetch: number;
|
|
18
|
-
order: 'ASC' | 'DESC';
|
|
19
|
-
unused: string[];
|
|
20
|
-
[key: string]: number | string | string[];
|
|
21
|
-
}
|
|
22
|
-
export declare function sortDirection(value: unknown, configured: 'ASC' | 'DESC'): 'ASC' | 'DESC';
|
|
23
|
-
export declare function likeValue(value: unknown): string;
|
|
24
|
-
export declare function prepareQuery(params: Record<string, unknown>, options: {
|
|
25
|
-
defaultLimit: number;
|
|
26
|
-
order: 'ASC' | 'DESC';
|
|
27
|
-
ranges?: RangeSpec[];
|
|
28
|
-
matches?: MatchSpec[];
|
|
29
|
-
}): PreparedQuery;
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NUMBER_MAX = exports.NUMBER_MIN = exports.DATE_MAX = exports.DATE_MIN = void 0;
|
|
4
|
-
exports.sortDirection = sortDirection;
|
|
5
|
-
exports.likeValue = likeValue;
|
|
6
|
-
exports.prepareQuery = prepareQuery;
|
|
7
|
-
exports.DATE_MIN = '0001-01-01T00:00:00.000Z';
|
|
8
|
-
exports.DATE_MAX = '9999-12-31T23:59:59.999Z';
|
|
9
|
-
exports.NUMBER_MIN = -9007199254740991;
|
|
10
|
-
exports.NUMBER_MAX = 9007199254740991;
|
|
11
|
-
const RESERVED = ['limit', 'sort'];
|
|
12
|
-
const RANGE_SUFFIXES = { min: ['_after', '_from', '_min'], max: ['_before', '_to', '_max'] };
|
|
13
|
-
function firstDefined(params, names) {
|
|
14
|
-
for (const name of names) {
|
|
15
|
-
const value = params[name];
|
|
16
|
-
if (value !== undefined && value !== null && value !== '')
|
|
17
|
-
return value;
|
|
18
|
-
}
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
|
21
|
-
function sortDirection(value, configured) {
|
|
22
|
-
const asked = String(value ?? '').toLowerCase();
|
|
23
|
-
if (['oldest', 'asc', 'ascending'].includes(asked))
|
|
24
|
-
return 'ASC';
|
|
25
|
-
if (['newest', 'desc', 'descending'].includes(asked))
|
|
26
|
-
return 'DESC';
|
|
27
|
-
return configured;
|
|
28
|
-
}
|
|
29
|
-
function likeValue(value) {
|
|
30
|
-
if (value === undefined || value === null || value === '')
|
|
31
|
-
return '%';
|
|
32
|
-
return String(value).replace(/([%_\\])/g, '\\$1');
|
|
33
|
-
}
|
|
34
|
-
function prepareQuery(params, options) {
|
|
35
|
-
const asked = Number(params.limit);
|
|
36
|
-
const limit = Number.isFinite(asked) && asked > 0
|
|
37
|
-
? Math.min(asked, options.defaultLimit)
|
|
38
|
-
: options.defaultLimit;
|
|
39
|
-
const consumed = new Set(RESERVED);
|
|
40
|
-
const query = {
|
|
41
|
-
limit,
|
|
42
|
-
fetch: limit + 1,
|
|
43
|
-
order: sortDirection(params.sort, options.order),
|
|
44
|
-
unused: [],
|
|
45
|
-
};
|
|
46
|
-
for (const range of options.ranges ?? []) {
|
|
47
|
-
const prefix = range.parameter || range.column;
|
|
48
|
-
[...RANGE_SUFFIXES.min, ...RANGE_SUFFIXES.max].forEach((s) => consumed.add(prefix + s));
|
|
49
|
-
const min = firstDefined(params, RANGE_SUFFIXES.min.map((s) => prefix + s));
|
|
50
|
-
const max = firstDefined(params, RANGE_SUFFIXES.max.map((s) => prefix + s));
|
|
51
|
-
const wide = range.type === 'date' ? [exports.DATE_MIN, exports.DATE_MAX] : [exports.NUMBER_MIN, exports.NUMBER_MAX];
|
|
52
|
-
query[`${range.column}_min`] = (min ?? wide[0]);
|
|
53
|
-
query[`${range.column}_max`] = (max ?? wide[1]);
|
|
54
|
-
}
|
|
55
|
-
for (const match of options.matches ?? []) {
|
|
56
|
-
const name = match.parameter || match.column;
|
|
57
|
-
consumed.add(name);
|
|
58
|
-
query[match.column] = likeValue(params[name]);
|
|
59
|
-
}
|
|
60
|
-
query.unused = Object.keys(params).filter((name) => !consumed.has(name));
|
|
61
|
-
return query;
|
|
62
|
-
}
|
|
63
|
-
//# sourceMappingURL=query.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../../nodes/Loopthink/query.ts"],"names":[],"mappings":";;;AA8EA,sCAKC;AASD,8BAGC;AAED,oCA2CC;AApHY,QAAA,QAAQ,GAAG,0BAA0B,CAAC;AACtC,QAAA,QAAQ,GAAG,0BAA0B,CAAC;AAEtC,QAAA,UAAU,GAAG,CAAC,gBAAgB,CAAC;AAC/B,QAAA,UAAU,GAAG,gBAAgB,CAAC;AAG3C,MAAM,QAAQ,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAiCnC,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;AAE7F,SAAS,YAAY,CAAC,MAA+B,EAAE,KAAe;IACrE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE;YAAE,OAAO,KAAK,CAAC;IACzE,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAMD,SAAgB,aAAa,CAAC,KAAc,EAAE,UAA0B;IACvE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAChD,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACjE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACpE,OAAO,UAAU,CAAC;AACnB,CAAC;AASD,SAAgB,SAAS,CAAC,KAAc;IACvC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,GAAG,CAAC;IACtE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AACnD,CAAC;AAED,SAAgB,YAAY,CAC3B,MAA+B,EAC/B,OAKC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,KAAK,GACV,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;QAClC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC;QACvC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;IAGzB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IAEnC,MAAM,KAAK,GAAkB;QAC5B,KAAK;QACL,KAAK,EAAE,KAAK,GAAG,CAAC;QAChB,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC;QAChD,MAAM,EAAE,EAAE;KACV,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC;QAC/C,CAAC,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACxF,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5E,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5E,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,gBAAQ,EAAE,gBAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAU,EAAE,kBAAU,CAAC,CAAC;QACrF,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAoB,CAAC;QACnE,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAoB,CAAC;IACpE,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC;QAC7C,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnB,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IACzE,OAAO,KAAK,CAAC;AACd,CAAC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export declare class MissingSecretError extends Error {
|
|
2
|
-
readonly names: string[];
|
|
3
|
-
constructor(names: string[]);
|
|
4
|
-
}
|
|
5
|
-
export declare function collectPlaceholders(value: unknown, found?: Set<string>): Set<string>;
|
|
6
|
-
export declare function substituteSecrets<T>(value: T, secrets: Record<string, string>): T;
|
|
7
|
-
export declare function secretsFromCredential(credential: unknown): Record<string, string>;
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MissingSecretError = void 0;
|
|
4
|
-
exports.collectPlaceholders = collectPlaceholders;
|
|
5
|
-
exports.substituteSecrets = substituteSecrets;
|
|
6
|
-
exports.secretsFromCredential = secretsFromCredential;
|
|
7
|
-
const PLACEHOLDER = /\{\{\s*secret\.([A-Za-z_][A-Za-z0-9_]*)\s*\}\}/g;
|
|
8
|
-
class MissingSecretError extends Error {
|
|
9
|
-
constructor(names) {
|
|
10
|
-
super(`Missing secret${names.length > 1 ? 's' : ''} in the runner credential: ${names.join(', ')}. ` +
|
|
11
|
-
'Add them under "loopthink Target Secrets".');
|
|
12
|
-
this.names = names;
|
|
13
|
-
this.name = 'MissingSecretError';
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
exports.MissingSecretError = MissingSecretError;
|
|
17
|
-
function collectPlaceholders(value, found = new Set()) {
|
|
18
|
-
if (typeof value === 'string') {
|
|
19
|
-
for (const match of value.matchAll(PLACEHOLDER))
|
|
20
|
-
found.add(match[1]);
|
|
21
|
-
return found;
|
|
22
|
-
}
|
|
23
|
-
if (Array.isArray(value)) {
|
|
24
|
-
value.forEach((v) => collectPlaceholders(v, found));
|
|
25
|
-
return found;
|
|
26
|
-
}
|
|
27
|
-
if (value && typeof value === 'object') {
|
|
28
|
-
Object.values(value).forEach((v) => collectPlaceholders(v, found));
|
|
29
|
-
}
|
|
30
|
-
return found;
|
|
31
|
-
}
|
|
32
|
-
function substituteString(value, secrets) {
|
|
33
|
-
return value.replace(PLACEHOLDER, (_full, name) => secrets[name]);
|
|
34
|
-
}
|
|
35
|
-
function substituteSecrets(value, secrets) {
|
|
36
|
-
const missing = [...collectPlaceholders(value)].filter((name) => !secrets[name]);
|
|
37
|
-
if (missing.length)
|
|
38
|
-
throw new MissingSecretError(missing);
|
|
39
|
-
const walk = (v) => {
|
|
40
|
-
if (typeof v === 'string')
|
|
41
|
-
return substituteString(v, secrets);
|
|
42
|
-
if (Array.isArray(v))
|
|
43
|
-
return v.map(walk);
|
|
44
|
-
if (v && typeof v === 'object') {
|
|
45
|
-
return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x)]));
|
|
46
|
-
}
|
|
47
|
-
return v;
|
|
48
|
-
};
|
|
49
|
-
return walk(value);
|
|
50
|
-
}
|
|
51
|
-
function secretsFromCredential(credential) {
|
|
52
|
-
const entries = credential?.secrets?.secret;
|
|
53
|
-
if (!Array.isArray(entries))
|
|
54
|
-
return {};
|
|
55
|
-
const out = {};
|
|
56
|
-
for (const entry of entries) {
|
|
57
|
-
const name = String(entry?.name || '').trim();
|
|
58
|
-
if (name && entry?.value)
|
|
59
|
-
out[name] = String(entry.value);
|
|
60
|
-
}
|
|
61
|
-
return out;
|
|
62
|
-
}
|
|
63
|
-
//# sourceMappingURL=secrets.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../../nodes/LoopthinkRunner/secrets.ts"],"names":[],"mappings":"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"}
|