@hostwebhook/node-types 1.69.0 → 1.71.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/dist/bucket-operations.d.ts +88 -0
- package/dist/bucket-operations.js +140 -0
- package/dist/calendar-toolkit.d.ts +1 -1
- package/dist/connections.d.ts +1 -1
- package/dist/connections.js +1 -0
- package/dist/discord-operations.d.ts +1 -1
- package/dist/discord-operations.js +4 -4
- package/dist/discord-toolkit.d.ts +1 -1
- package/dist/discord-toolkit.js +3 -3
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +1 -0
- package/dist/docs-toolkit.d.ts +1 -1
- package/dist/drive-toolkit.d.ts +1 -1
- package/dist/esm/bucket-operations.d.ts +88 -0
- package/dist/esm/bucket-operations.js +136 -0
- package/dist/esm/calendar-operations.d.ts +67 -0
- package/dist/esm/calendar-operations.js +176 -0
- package/dist/esm/calendar-toolkit.d.ts +50 -0
- package/dist/esm/calendar-toolkit.js +152 -0
- package/dist/esm/capacidad-de-credencial.d.ts +75 -0
- package/dist/esm/capacidad-de-credencial.js +68 -0
- package/dist/esm/connections.d.ts +17 -0
- package/dist/esm/connections.js +107 -0
- package/dist/esm/credentials.d.ts +144 -0
- package/dist/esm/credentials.js +199 -0
- package/dist/esm/discord-operations.d.ts +104 -0
- package/dist/esm/discord-operations.js +407 -0
- package/dist/esm/discord-toolkit.d.ts +64 -0
- package/dist/esm/discord-toolkit.js +260 -0
- package/dist/esm/dispatch.d.ts +16 -0
- package/dist/esm/dispatch.js +77 -0
- package/dist/esm/docs-operations.d.ts +99 -0
- package/dist/esm/docs-operations.js +127 -0
- package/dist/esm/docs-toolkit.d.ts +42 -0
- package/dist/esm/docs-toolkit.js +97 -0
- package/dist/esm/drive-operations.d.ts +103 -0
- package/dist/esm/drive-operations.js +319 -0
- package/dist/esm/drive-toolkit.d.ts +54 -0
- package/dist/esm/drive-toolkit.js +177 -0
- package/dist/esm/github-operations.d.ts +147 -0
- package/dist/esm/github-operations.js +551 -0
- package/dist/esm/gmail-operations.d.ts +190 -0
- package/dist/esm/gmail-operations.js +560 -0
- package/dist/esm/google-analytics-operations.d.ts +99 -0
- package/dist/esm/google-analytics-operations.js +222 -0
- package/dist/esm/google-contacts-operations.d.ts +93 -0
- package/dist/esm/google-contacts-operations.js +363 -0
- package/dist/esm/index.d.ts +68 -0
- package/dist/esm/index.js +51 -0
- package/dist/esm/jira-operations.d.ts +164 -0
- package/dist/esm/jira-operations.js +470 -0
- package/dist/esm/llm-models.d.ts +101 -0
- package/dist/esm/llm-models.js +230 -0
- package/dist/esm/mailchimp-operations.d.ts +56 -0
- package/dist/esm/mailchimp-operations.js +155 -0
- package/dist/esm/mongo-operations.d.ts +61 -0
- package/dist/esm/mongo-operations.js +120 -0
- package/dist/esm/notion-operations.d.ts +125 -0
- package/dist/esm/notion-operations.js +511 -0
- package/dist/esm/openrouter.d.ts +142 -0
- package/dist/esm/openrouter.js +99 -0
- package/dist/esm/package.json +4 -0
- package/dist/esm/postgres-operations.d.ts +60 -0
- package/dist/esm/postgres-operations.js +75 -0
- package/dist/esm/registry.d.ts +160 -0
- package/dist/esm/registry.js +885 -0
- package/dist/esm/sheets-operations.d.ts +78 -0
- package/dist/esm/sheets-operations.js +150 -0
- package/dist/esm/sheets-toolkit.d.ts +49 -0
- package/dist/esm/sheets-toolkit.js +127 -0
- package/dist/esm/shopify-operations.d.ts +95 -0
- package/dist/esm/shopify-operations.js +259 -0
- package/dist/esm/slack-operations.d.ts +81 -0
- package/dist/esm/slack-operations.js +244 -0
- package/dist/esm/slack-toolkit.d.ts +60 -0
- package/dist/esm/slack-toolkit.js +235 -0
- package/dist/esm/telegram-operations.d.ts +104 -0
- package/dist/esm/telegram-operations.js +351 -0
- package/dist/esm/telegram-toolkit.d.ts +52 -0
- package/dist/esm/telegram-toolkit.js +183 -0
- package/dist/esm/types.d.ts +149 -0
- package/dist/esm/types.js +8 -0
- package/dist/esm/ui.d.ts +13 -0
- package/dist/esm/ui.js +152 -0
- package/dist/esm/whatsapp-operations.d.ts +23 -0
- package/dist/esm/whatsapp-operations.js +36 -0
- package/dist/index.d.ts +68 -66
- package/dist/index.js +193 -187
- package/dist/openrouter.d.ts +1 -1
- package/dist/registry.d.ts +4 -4
- package/dist/registry.js +540 -210
- package/dist/sheets-toolkit.d.ts +1 -1
- package/dist/slack-operations.d.ts +1 -1
- package/dist/slack-operations.js +4 -4
- package/dist/slack-toolkit.d.ts +1 -1
- package/dist/slack-toolkit.js +3 -3
- package/dist/telegram-toolkit.d.ts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +2 -0
- package/package.json +21 -3
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gmail operation enum — single source of truth across the API, Dashboard,
|
|
3
|
+
* and Message Broker. Used by:
|
|
4
|
+
* - emailAction entity / DTO (api): operation field + validation
|
|
5
|
+
* - dashboard EmailActionGmailOperation type
|
|
6
|
+
* - broker hostwebhook types + tool schemas
|
|
7
|
+
* - trigger / future Gmail-related nodes
|
|
8
|
+
*
|
|
9
|
+
* Adding a new Gmail operation = add it here, bump this package's
|
|
10
|
+
* version, publish to npm, and re-install in the consuming repos.
|
|
11
|
+
* Each consumer still owns its operation-specific config schema (the
|
|
12
|
+
* dashboard owns the UI form schema, the api owns the dispatch logic),
|
|
13
|
+
* but the canonical list of valid operation strings lives here.
|
|
14
|
+
*/
|
|
15
|
+
export const GMAIL_OPERATIONS = [
|
|
16
|
+
'send',
|
|
17
|
+
// Pause-the-pipeline op — sends an email with Approve / (optional)
|
|
18
|
+
// Disapprove buttons and waits for the recipient to click before
|
|
19
|
+
// dispatching downstream. Backed by the shared send-and-wait infra in
|
|
20
|
+
// api/src/nodes/approval-nodes (PendingApproval + 1-click controller).
|
|
21
|
+
// Output of the node carries `payload._waitResponse = { approved,
|
|
22
|
+
// decidedAt, ipAddress, comment }` for downstream Conditional Nodes.
|
|
23
|
+
'sendAndWaitForResponse',
|
|
24
|
+
'createDraft',
|
|
25
|
+
'sendDraft',
|
|
26
|
+
'replyToThread',
|
|
27
|
+
'getMessage',
|
|
28
|
+
'listMessages',
|
|
29
|
+
'deleteMessage',
|
|
30
|
+
'markRead',
|
|
31
|
+
'markUnread',
|
|
32
|
+
'addLabel',
|
|
33
|
+
'removeLabel',
|
|
34
|
+
'listLabels',
|
|
35
|
+
'createLabel',
|
|
36
|
+
'getThread',
|
|
37
|
+
'trashThread',
|
|
38
|
+
'untrashThread',
|
|
39
|
+
];
|
|
40
|
+
/** Type guard — useful when validating untrusted input (DTOs, tool calls). */
|
|
41
|
+
export function isGmailOperation(value) {
|
|
42
|
+
return typeof value === 'string' && GMAIL_OPERATIONS.includes(value);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Esquema de formulario, grupos del desplegable y toolkits de Gmail.
|
|
46
|
+
*
|
|
47
|
+
* El enum de arriba ya estaba aquí y ya lo importaban la api (DTO + entidad) y
|
|
48
|
+
* el dashboard. Lo que baja ahora es todo lo demás, que vivía escrito a mano en
|
|
49
|
+
* cuatro sitios:
|
|
50
|
+
*
|
|
51
|
+
* - `OP_SCHEMA` de `OperationFieldsRenderer.tsx` — 17 ops, 53 campos
|
|
52
|
+
* - `OPERATION_GROUPS` de `OperationSelector.tsx` — 16 ops con etiqueta,
|
|
53
|
+
* descripción y grupo
|
|
54
|
+
* - `GMAIL_OPERATION_SPECS` del dashboard y **la misma lista otra vez** en
|
|
55
|
+
* `api/src/mcp-servers/toolkit-specs.ts` — 16 herramientas cada una
|
|
56
|
+
* - `NATIVE_EMAIL_OPERATION_SPECS`, igual, por duplicado
|
|
57
|
+
*
|
|
58
|
+
* Las dos copias del toolkit estaban idénticas el día de la mudanza (0
|
|
59
|
+
* divergencias medidas), lo cual es suerte y no diseño: viven en repos
|
|
60
|
+
* distintos, así que **ningún test podía compararlas**. Por eso bajan.
|
|
61
|
+
*
|
|
62
|
+
* OJO CON EL NOMBRE. En el dashboard `GMAIL_OPERATION_SPECS` eran las specs del
|
|
63
|
+
* *toolkit*, al revés que en los otros diez nodos. Aquí se respeta la convención
|
|
64
|
+
* del paquete: `*_OPERATION_SPECS` es el **formulario** y `*_TOOLKIT_SPECS` son
|
|
65
|
+
* las **herramientas**.
|
|
66
|
+
*/
|
|
67
|
+
/** Encabezados del desplegable, en orden de aparición. */
|
|
68
|
+
export const GMAIL_OPERATION_GROUPS = ['Messages', 'Drafts', 'Labels', 'Threads'];
|
|
69
|
+
/**
|
|
70
|
+
* El orden de las claves dentro de cada grupo **es** el orden del desplegable,
|
|
71
|
+
* igual que en Contacts: mover una clave mueve la pantalla.
|
|
72
|
+
*
|
|
73
|
+
* `send` ya no lleva `cc` ni `bcc`. Estaban declaradas y no se pintaban nunca —el
|
|
74
|
+
* renderizador se invocaba tras `operation !== "send"`— y la ruta determinista no
|
|
75
|
+
* las sabe mandar: `emailSender.send` recibe to/subject/html y nada más. Darles
|
|
76
|
+
* soporte es una función nueva, no una mudanza.
|
|
77
|
+
*/
|
|
78
|
+
export const GMAIL_OPERATION_SPECS = {
|
|
79
|
+
send: {
|
|
80
|
+
label: 'Send message',
|
|
81
|
+
labelShort: 'SEND',
|
|
82
|
+
description: 'Send a new email',
|
|
83
|
+
group: 'Messages',
|
|
84
|
+
params: [
|
|
85
|
+
{ name: 'to', label: 'To', type: 'emails', required: true, placeholder: '{{payload.email}}' },
|
|
86
|
+
{ name: 'subject', label: 'Subject', type: 'string', required: true, placeholder: 'Order #{{payload.id}}' },
|
|
87
|
+
{ name: 'body', label: 'Body (HTML)', type: 'htmlTemplate', required: true, placeholder: '<p>Hi {{payload.name}}...</p>', language: 'html' },
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
sendAndWaitForResponse: {
|
|
91
|
+
label: 'Send and wait for response',
|
|
92
|
+
labelShort: 'SEND & WAIT',
|
|
93
|
+
description: 'Send with Approve / Disapprove buttons; pause workflow until clicked',
|
|
94
|
+
group: 'Messages',
|
|
95
|
+
params: [
|
|
96
|
+
{ name: 'to', label: 'To', type: 'emails', required: true, placeholder: '{{payload.email}}', description: 'Recipient(s) who will see the Approve / Disapprove buttons.' },
|
|
97
|
+
{ name: 'subject', label: 'Subject', type: 'string', required: true, placeholder: 'Approve order #{{payload.id}}?' },
|
|
98
|
+
{ name: 'body', label: 'Body (HTML)', type: 'htmlTemplate', required: true, placeholder: '<p>Please review and approve...</p>', language: 'html', description: 'Approve / Disapprove buttons are appended automatically below your content.' },
|
|
99
|
+
{ name: 'approveLabel', label: 'Approve button label', type: 'string', placeholder: 'Approve', description: 'Default: Approve' },
|
|
100
|
+
{ name: 'includeDisapprove', label: 'Include Disapprove button', type: 'boolean', description: 'Off = approve-only confirmation. Default: on.' },
|
|
101
|
+
{ name: 'disapproveLabel', label: 'Disapprove button label', type: 'string', placeholder: 'Disapprove', description: 'Only used when Disapprove button is enabled.' },
|
|
102
|
+
{ name: 'requireDisapproveComment', label: 'Require comment on disapprove', type: 'boolean', description: 'Off = 1-click decline. On = recipient sees a feedback form before submitting; the comment lands in payload._waitResponse.comment for downstream AI/Conditional nodes to read.' },
|
|
103
|
+
{ name: 'disapproveCommentLabel', label: 'Comment form label', type: 'string', placeholder: 'Why are you disapproving?', description: "Heading shown above the textarea. Only used when 'Require comment' is on." },
|
|
104
|
+
{ name: 'disapproveCommentPlaceholder', label: 'Comment placeholder', type: 'string', placeholder: 'Tell the sender why — this helps them improve the next attempt.', description: "Hint shown inside the empty textarea. Only used when 'Require comment' is on." },
|
|
105
|
+
{ name: 'timeoutMinutes', label: 'Timeout (minutes)', type: 'number', placeholder: '1440', description: 'Auto-resolve as approved=false after this many minutes. Default 1440 (24h).' },
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
createDraft: {
|
|
109
|
+
label: 'Create draft',
|
|
110
|
+
labelShort: 'DRAFT',
|
|
111
|
+
description: 'Save a draft without sending',
|
|
112
|
+
group: 'Drafts',
|
|
113
|
+
params: [
|
|
114
|
+
{ name: 'to', label: 'To', type: 'emails', required: true, placeholder: '{{payload.email}}', description: 'Recipients the draft will be addressed to' },
|
|
115
|
+
{ name: 'subject', label: 'Subject', type: 'string', placeholder: 'Draft: {{payload.topic}}' },
|
|
116
|
+
{ name: 'body', label: 'Body (HTML)', type: 'htmlTemplate', language: 'html' },
|
|
117
|
+
{ name: 'cc', label: 'CC', type: 'emails' },
|
|
118
|
+
{ name: 'bcc', label: 'BCC', type: 'emails' },
|
|
119
|
+
{ name: 'threadId', label: 'Thread ID', type: 'string', description: 'Optional — attach draft to an existing thread' },
|
|
120
|
+
{ name: 'inReplyTo', label: 'In-Reply-To', type: 'string', description: 'Optional Message-ID header' },
|
|
121
|
+
{ name: 'references', label: 'References', type: 'string', description: 'Optional References chain' },
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
sendDraft: {
|
|
125
|
+
label: 'Send draft',
|
|
126
|
+
labelShort: 'SEND DRAFT',
|
|
127
|
+
description: 'Send a draft that createDraft already saved, in one shot',
|
|
128
|
+
params: [
|
|
129
|
+
{ name: 'draftId', label: 'Draft ID', type: 'string', required: true, placeholder: '{{payload.draftId}}', description: 'Id returned by createDraft. The draft moves from Drafts/ to Sent/ in one shot — no orphans.' },
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
replyToThread: {
|
|
133
|
+
label: 'Reply to thread',
|
|
134
|
+
labelShort: 'REPLY',
|
|
135
|
+
description: 'Reply preserving thread headers',
|
|
136
|
+
group: 'Messages',
|
|
137
|
+
params: [
|
|
138
|
+
{ name: 'threadId', label: 'Thread ID', type: 'string', required: true, placeholder: '{{payload.threadId}}' },
|
|
139
|
+
{ name: 'body', label: 'Body (HTML)', type: 'htmlTemplate', required: true, language: 'html' },
|
|
140
|
+
{ name: 'subject', label: 'Subject', type: 'string', description: 'Optional — defaults to "Re: <original>"' },
|
|
141
|
+
{ name: 'to', label: 'To', type: 'emails', description: 'Optional — defaults to last sender in thread' },
|
|
142
|
+
{ name: 'cc', label: 'CC', type: 'emails' },
|
|
143
|
+
{ name: 'bcc', label: 'BCC', type: 'emails' },
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
getMessage: {
|
|
147
|
+
label: 'Get message',
|
|
148
|
+
labelShort: 'GET',
|
|
149
|
+
description: 'Fetch a single message by id',
|
|
150
|
+
group: 'Messages',
|
|
151
|
+
params: [
|
|
152
|
+
{ name: 'messageId', label: 'Message ID', type: 'string', required: true, placeholder: '{{payload.messageId}}' },
|
|
153
|
+
{ name: 'format', label: 'Format', type: 'select', options: [{ value: 'full', label: 'full' }, { value: 'metadata', label: 'metadata' }, { value: 'minimal', label: 'minimal' }] },
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
listMessages: {
|
|
157
|
+
label: 'List messages',
|
|
158
|
+
labelShort: 'LIST',
|
|
159
|
+
description: 'Search inbox (Gmail query syntax)',
|
|
160
|
+
group: 'Messages',
|
|
161
|
+
params: [
|
|
162
|
+
{ name: 'query', label: 'Query', type: 'string', placeholder: 'from:alice@example.com is:unread', description: 'Gmail search query — supports operators like from:, is:, has:, newer_than:' },
|
|
163
|
+
{ name: 'labelIds', label: 'Label IDs', type: 'csvList', placeholder: 'INBOX,UNREAD', description: 'Comma-separated label IDs (use Gmail listLabels op to discover)' },
|
|
164
|
+
{ name: 'maxResults', label: 'Max results', type: 'number', placeholder: '25' },
|
|
165
|
+
{ name: 'includeSpamTrash', label: 'Include spam + trash', type: 'boolean' },
|
|
166
|
+
{ name: 'expand', label: 'Expand each result (≤20)', type: 'boolean', description: 'Fetch headers + snippet per message. Off = id+threadId stubs only.' },
|
|
167
|
+
{ name: 'expandFormat', label: 'Expand format', type: 'select', options: [{ value: 'metadata', label: 'Metadata (headers + snippet)' }, { value: 'full', label: 'Full body (expensive)' }], description: 'metadata = ~150-char snippet (default, cheap). full = entire body (expensive on tokens).' },
|
|
168
|
+
],
|
|
169
|
+
},
|
|
170
|
+
deleteMessage: {
|
|
171
|
+
label: 'Delete message',
|
|
172
|
+
labelShort: 'DELETE',
|
|
173
|
+
description: 'Trash (default) or hard delete',
|
|
174
|
+
group: 'Messages',
|
|
175
|
+
params: [
|
|
176
|
+
{ name: 'messageId', label: 'Message ID', type: 'string', required: true },
|
|
177
|
+
{ name: 'permanent', label: 'Permanent delete (otherwise moves to trash)', type: 'boolean' },
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
markRead: {
|
|
181
|
+
label: 'Mark as read',
|
|
182
|
+
labelShort: 'MARK READ',
|
|
183
|
+
description: 'Remove UNREAD label',
|
|
184
|
+
group: 'Messages',
|
|
185
|
+
params: [
|
|
186
|
+
{ name: 'messageId', label: 'Message ID', type: 'string', required: true },
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
markUnread: {
|
|
190
|
+
label: 'Mark as unread',
|
|
191
|
+
labelShort: 'MARK UNREAD',
|
|
192
|
+
description: 'Add UNREAD label',
|
|
193
|
+
group: 'Messages',
|
|
194
|
+
params: [
|
|
195
|
+
{ name: 'messageId', label: 'Message ID', type: 'string', required: true },
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
addLabel: {
|
|
199
|
+
label: 'Add label',
|
|
200
|
+
labelShort: 'ADD LABEL',
|
|
201
|
+
description: 'Attach label IDs to a message',
|
|
202
|
+
group: 'Messages',
|
|
203
|
+
params: [
|
|
204
|
+
{ name: 'messageId', label: 'Message ID', type: 'string', required: true },
|
|
205
|
+
{ name: 'labelIds', label: 'Label IDs to add', type: 'csvList', required: true, placeholder: 'Label_12345', description: 'Comma-separated' },
|
|
206
|
+
],
|
|
207
|
+
},
|
|
208
|
+
removeLabel: {
|
|
209
|
+
label: 'Remove label',
|
|
210
|
+
labelShort: 'REMOVE LABEL',
|
|
211
|
+
description: 'Detach label IDs from a message',
|
|
212
|
+
group: 'Messages',
|
|
213
|
+
params: [
|
|
214
|
+
{ name: 'messageId', label: 'Message ID', type: 'string', required: true },
|
|
215
|
+
{ name: 'labelIds', label: 'Label IDs to remove', type: 'csvList', required: true, placeholder: 'Label_12345' },
|
|
216
|
+
],
|
|
217
|
+
},
|
|
218
|
+
listLabels: {
|
|
219
|
+
label: 'List labels',
|
|
220
|
+
labelShort: 'LABELS',
|
|
221
|
+
description: 'All user + system labels',
|
|
222
|
+
group: 'Labels',
|
|
223
|
+
params: [],
|
|
224
|
+
},
|
|
225
|
+
createLabel: {
|
|
226
|
+
label: 'Create label',
|
|
227
|
+
labelShort: 'NEW LABEL',
|
|
228
|
+
description: 'New user label (supports / for nesting)',
|
|
229
|
+
group: 'Labels',
|
|
230
|
+
params: [
|
|
231
|
+
{ name: 'name', label: 'Label name', type: 'string', required: true, placeholder: 'Clients/Active', description: 'Use / for nested labels' },
|
|
232
|
+
{ name: 'messageListVisibility', label: 'Message list visibility', type: 'select', options: [{ value: 'show', label: 'show' }, { value: 'hide', label: 'hide' }] },
|
|
233
|
+
{ name: 'labelListVisibility', label: 'Label list visibility', type: 'select', options: [{ value: 'labelShow', label: 'labelShow' }, { value: 'labelShowIfUnread', label: 'labelShowIfUnread' }, { value: 'labelHide', label: 'labelHide' }] },
|
|
234
|
+
],
|
|
235
|
+
},
|
|
236
|
+
getThread: {
|
|
237
|
+
label: 'Get thread',
|
|
238
|
+
labelShort: 'THREAD',
|
|
239
|
+
description: 'Fetch an entire conversation',
|
|
240
|
+
group: 'Threads',
|
|
241
|
+
params: [
|
|
242
|
+
{ name: 'threadId', label: 'Thread ID', type: 'string', required: true },
|
|
243
|
+
{ name: 'format', label: 'Format', type: 'select', options: [{ value: 'full', label: 'full' }, { value: 'metadata', label: 'metadata' }, { value: 'minimal', label: 'minimal' }] },
|
|
244
|
+
],
|
|
245
|
+
},
|
|
246
|
+
trashThread: {
|
|
247
|
+
label: 'Trash thread',
|
|
248
|
+
labelShort: 'TRASH',
|
|
249
|
+
description: 'Move all thread messages to trash',
|
|
250
|
+
group: 'Threads',
|
|
251
|
+
params: [
|
|
252
|
+
{ name: 'threadId', label: 'Thread ID', type: 'string', required: true },
|
|
253
|
+
],
|
|
254
|
+
},
|
|
255
|
+
untrashThread: {
|
|
256
|
+
label: 'Untrash thread',
|
|
257
|
+
labelShort: 'UNTRASH',
|
|
258
|
+
description: 'Restore a thread from trash',
|
|
259
|
+
group: 'Threads',
|
|
260
|
+
params: [
|
|
261
|
+
{ name: 'threadId', label: 'Thread ID', type: 'string', required: true },
|
|
262
|
+
],
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
/*
|
|
266
|
+
* Los dos subconjuntos de las 17, **declarados**. Antes había que deducirlos de
|
|
267
|
+
* qué lista se dejaba a quién fuera, y las dos ausencias son decisiones tomadas:
|
|
268
|
+
*
|
|
269
|
+
* - `sendDraft` no se ofrece en el desplegable porque sólo tiene sentido
|
|
270
|
+
* detrás de un `createDraft` de la misma conversación. Sí es herramienta.
|
|
271
|
+
* - `sendAndWaitForResponse` no es herramienta porque por esa vía no espera:
|
|
272
|
+
* el modelo recibe algo inmediato y acaba diciendo que ya se aprobó. Sí se
|
|
273
|
+
* ofrece en el desplegable, con un Conditional detrás leyendo
|
|
274
|
+
* `_waitResponse.approved`.
|
|
275
|
+
*
|
|
276
|
+
* Que cada una siga teniendo 16 lo fija un test. No las "arregles".
|
|
277
|
+
*/
|
|
278
|
+
export const GMAIL_DROPDOWN_OPERATIONS = GMAIL_OPERATIONS.filter((op) => GMAIL_OPERATION_SPECS[op].group !== undefined);
|
|
279
|
+
export const GMAIL_TOOLKIT_OPERATIONS = GMAIL_OPERATIONS.filter((op) => op !== 'sendAndWaitForResponse');
|
|
280
|
+
const p = (name, description, required = true, type = 'string') => ({ name, type, description, required });
|
|
281
|
+
export const GMAIL_TOOLKIT_SPECS = [
|
|
282
|
+
{
|
|
283
|
+
operation: 'send',
|
|
284
|
+
label: 'Send message',
|
|
285
|
+
toolName: 'send_email',
|
|
286
|
+
description: 'Send a fresh Gmail message that you compose from scratch right now. USAGE RULES: (1) ' +
|
|
287
|
+
'Only use this when the user asks for a brand-new email and there is NO recent draft to ' +
|
|
288
|
+
'confirm. (2) If you previously called createDraft in this conversation and the user just ' +
|
|
289
|
+
'confirmed it, do NOT call send — call sendDraft with that draftId instead. Calling send ' +
|
|
290
|
+
're-composes the message from your memory and risks sending stale content from an earlier ' +
|
|
291
|
+
"conversation. (3) Compose the body fresh from the user's CURRENT request. Never reuse " +
|
|
292
|
+
'content recalled from memory unless the user explicitly references it. (4) Not for ' +
|
|
293
|
+
'replies inside an existing thread — use replyToThread for that.',
|
|
294
|
+
parameters: [
|
|
295
|
+
p('to', 'Recipient email address(es). Single string or comma-separated list.'),
|
|
296
|
+
p('subject', 'Email subject line.'),
|
|
297
|
+
p('body', 'HTML-formatted email body.'),
|
|
298
|
+
p('cc', 'Optional CC recipients.', false),
|
|
299
|
+
p('bcc', 'Optional BCC recipients.', false),
|
|
300
|
+
],
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
operation: 'createDraft',
|
|
304
|
+
label: 'Create draft',
|
|
305
|
+
toolName: 'draft_email',
|
|
306
|
+
description: "Save a draft in the user's Gmail drafts folder. Does NOT send. Use when asked to draft, " +
|
|
307
|
+
'prepare, or compose without sending. USAGE RULES: (1) Compose the body fresh from the ' +
|
|
308
|
+
"user's CURRENT request. Never reuse content recalled from memory unless the user " +
|
|
309
|
+
"explicitly says 'use the same content as before' or similar. (2) Always return the " +
|
|
310
|
+
'draftId in your response so the user (and you, on the next turn) can reference it. (3) ' +
|
|
311
|
+
'After creating, ask the user to confirm. If they confirm, call sendDraft with the ' +
|
|
312
|
+
'returned draftId — never re-call this tool or send.',
|
|
313
|
+
parameters: [
|
|
314
|
+
p('to', 'Recipient email address(es).'),
|
|
315
|
+
p('subject', 'Email subject line.', false),
|
|
316
|
+
p('body', 'HTML-formatted email body.', false),
|
|
317
|
+
p('cc', 'Optional CC recipients.', false),
|
|
318
|
+
p('bcc', 'Optional BCC recipients.', false),
|
|
319
|
+
p('threadId', 'Optional — attach draft to an existing thread.', false),
|
|
320
|
+
p('inReplyTo', 'Optional Message-ID header to reply to.', false),
|
|
321
|
+
p('references', 'Optional References header chain.', false),
|
|
322
|
+
],
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
operation: 'sendDraft',
|
|
326
|
+
label: 'Send draft',
|
|
327
|
+
toolName: 'send_draft',
|
|
328
|
+
description: 'Send an existing draft (it gets removed from Drafts and a copy appears in Sent). USAGE ' +
|
|
329
|
+
'RULES: (1) Only call this with a draftId returned by a createDraft tool call earlier in ' +
|
|
330
|
+
'THE CURRENT conversation. (2) Never use a draftId you remember from past conversations ' +
|
|
331
|
+
'or memory recall — those drafts may have been already sent, deleted, or belonged to a ' +
|
|
332
|
+
'different topic; sending the wrong one will silently deliver the wrong message to the ' +
|
|
333
|
+
"user's contacts. (3) If the user confirms a draft, immediately call sendDraft with the " +
|
|
334
|
+
"draftId from your latest createDraft response in this conversation. (4) If you're not " +
|
|
335
|
+
'sure which draftId is current, call createDraft again with the latest content the user ' +
|
|
336
|
+
'agreed to instead of guessing.',
|
|
337
|
+
parameters: [
|
|
338
|
+
p('draftId', 'Draft id returned by the MOST RECENT createDraft call in this conversation. Do NOT pull this id from memory or a past conversation — it will send the wrong content.'),
|
|
339
|
+
],
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
operation: 'replyToThread',
|
|
343
|
+
label: 'Reply to thread',
|
|
344
|
+
toolName: 'reply_email',
|
|
345
|
+
description: 'Reply to an existing Gmail thread preserving thread integrity (In-Reply-To / References ' +
|
|
346
|
+
'chain). Recipient defaults to the last sender if not provided. USAGE RULES: (1) Compose ' +
|
|
347
|
+
"the reply body fresh from the user's CURRENT request. Never reuse content recalled from " +
|
|
348
|
+
'memory of past replies unless the user explicitly references it. (2) Use the threadId ' +
|
|
349
|
+
'from a getThread / listMessages tool call EARLIER IN THIS CONVERSATION, not from memory ' +
|
|
350
|
+
'of past conversations.',
|
|
351
|
+
parameters: [
|
|
352
|
+
p('threadId', 'Thread to reply to.'),
|
|
353
|
+
p('body', 'HTML-formatted reply body.'),
|
|
354
|
+
p('to', 'Optional — defaults to last sender in thread.', false),
|
|
355
|
+
p('subject', 'Optional — defaults to "Re: <original>".', false),
|
|
356
|
+
p('cc', 'Optional CC recipients.', false),
|
|
357
|
+
p('bcc', 'Optional BCC recipients.', false),
|
|
358
|
+
],
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
operation: 'getMessage',
|
|
362
|
+
label: 'Get message',
|
|
363
|
+
toolName: 'get_email',
|
|
364
|
+
description: 'Fetch a single Gmail message by id. Returns headers, snippet, and decoded plain+HTML ' +
|
|
365
|
+
'body.',
|
|
366
|
+
parameters: [
|
|
367
|
+
p('messageId', 'Gmail message id.'),
|
|
368
|
+
p('format', 'full | metadata | minimal.', false),
|
|
369
|
+
],
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
operation: 'listMessages',
|
|
373
|
+
label: 'List messages',
|
|
374
|
+
toolName: 'list_emails',
|
|
375
|
+
description: 'Search the inbox. Supports Gmail search syntax (e.g. "from:boss is:unread"). Returns ' +
|
|
376
|
+
'headers + a ~150-char snippet per message by default — enough to identify which messages ' +
|
|
377
|
+
'match without flooding context with full bodies. If the user needs the full content of a ' +
|
|
378
|
+
'SPECIFIC message, call getMessage with that id afterwards (cheaper than expanding all ' +
|
|
379
|
+
'results to full).',
|
|
380
|
+
parameters: [
|
|
381
|
+
p('query', 'Gmail search query. Examples: "from:alice@x.com", "is:unread", "has:attachment newer_than:7d".', false),
|
|
382
|
+
p('labelIds', 'Filter by label id(s), comma-separated.', false),
|
|
383
|
+
p('maxResults', 'Default 25, max 500.', false, 'number'),
|
|
384
|
+
p('includeSpamTrash', 'Include spam + trash (default false).', false, 'boolean'),
|
|
385
|
+
p('expand', 'Fetch headers+snippet for each result (default true). Set false to return only id+threadId stubs.', false, 'boolean'),
|
|
386
|
+
p('expandFormat', "When expanding: 'metadata' (default — headers + snippet) or 'full' (entire body, expensive on context).", false),
|
|
387
|
+
],
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
operation: 'deleteMessage',
|
|
391
|
+
label: 'Delete message',
|
|
392
|
+
toolName: 'delete_email',
|
|
393
|
+
description: 'Move a message to trash (default) or permanently delete it. Trash is safer — users can ' +
|
|
394
|
+
'restore.',
|
|
395
|
+
parameters: [
|
|
396
|
+
p('messageId', 'Gmail message id.'),
|
|
397
|
+
p('permanent', 'true = permanent delete, false/default = trash.', false, 'boolean'),
|
|
398
|
+
],
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
operation: 'markRead',
|
|
402
|
+
label: 'Mark as read',
|
|
403
|
+
toolName: 'mark_email_read',
|
|
404
|
+
description: 'Mark a message as read (removes the UNREAD label).',
|
|
405
|
+
parameters: [
|
|
406
|
+
p('messageId', 'Gmail message id.'),
|
|
407
|
+
],
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
operation: 'markUnread',
|
|
411
|
+
label: 'Mark as unread',
|
|
412
|
+
toolName: 'mark_email_unread',
|
|
413
|
+
description: 'Mark a message as unread (adds the UNREAD label).',
|
|
414
|
+
parameters: [
|
|
415
|
+
p('messageId', 'Gmail message id.'),
|
|
416
|
+
],
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
operation: 'addLabel',
|
|
420
|
+
label: 'Add label to message',
|
|
421
|
+
toolName: 'add_email_label',
|
|
422
|
+
description: 'Add one or more labels to a message. Use label IDs from listLabels (e.g. "Label_123") ' +
|
|
423
|
+
'not label names.',
|
|
424
|
+
parameters: [
|
|
425
|
+
p('messageId', 'Gmail message id.'),
|
|
426
|
+
p('labelIds', 'Label id(s) to add, comma-separated.'),
|
|
427
|
+
],
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
operation: 'removeLabel',
|
|
431
|
+
label: 'Remove label from message',
|
|
432
|
+
toolName: 'remove_email_label',
|
|
433
|
+
description: 'Remove one or more labels from a message.',
|
|
434
|
+
parameters: [
|
|
435
|
+
p('messageId', 'Gmail message id.'),
|
|
436
|
+
p('labelIds', 'Label id(s) to remove, comma-separated.'),
|
|
437
|
+
],
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
operation: 'listLabels',
|
|
441
|
+
label: 'List labels',
|
|
442
|
+
toolName: 'list_email_labels',
|
|
443
|
+
description: "List all labels in the user's Gmail account (system + user labels). Use to discover " +
|
|
444
|
+
'label ids before calling addLabel / removeLabel.',
|
|
445
|
+
parameters: [],
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
operation: 'createLabel',
|
|
449
|
+
label: 'Create label',
|
|
450
|
+
toolName: 'create_email_label',
|
|
451
|
+
description: "Create a new user label in the user's Gmail account.",
|
|
452
|
+
parameters: [
|
|
453
|
+
p('name', 'Label name (can use / for nested labels, e.g. "Clients/Active").'),
|
|
454
|
+
p('messageListVisibility', 'show | hide.', false),
|
|
455
|
+
p('labelListVisibility', 'labelShow | labelShowIfUnread | labelHide.', false),
|
|
456
|
+
],
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
operation: 'getThread',
|
|
460
|
+
label: 'Get thread',
|
|
461
|
+
toolName: 'get_email_thread',
|
|
462
|
+
description: 'Fetch an entire Gmail thread with all its messages. Use for summarizing or deeply ' +
|
|
463
|
+
'analyzing a conversation.',
|
|
464
|
+
parameters: [
|
|
465
|
+
p('threadId', 'Gmail thread id.'),
|
|
466
|
+
p('format', 'full | metadata | minimal.', false),
|
|
467
|
+
],
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
operation: 'trashThread',
|
|
471
|
+
label: 'Trash thread',
|
|
472
|
+
toolName: 'trash_email_thread',
|
|
473
|
+
description: 'Move an entire thread to trash.',
|
|
474
|
+
parameters: [
|
|
475
|
+
p('threadId', 'Gmail thread id.'),
|
|
476
|
+
],
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
operation: 'untrashThread',
|
|
480
|
+
label: 'Untrash thread',
|
|
481
|
+
toolName: 'untrash_email_thread',
|
|
482
|
+
description: 'Restore a thread from trash.',
|
|
483
|
+
parameters: [
|
|
484
|
+
p('threadId', 'Gmail thread id.'),
|
|
485
|
+
],
|
|
486
|
+
},
|
|
487
|
+
];
|
|
488
|
+
/**
|
|
489
|
+
* La op que espera, **fuera** del toolkit y aparte a propósito. Sigue haciendo
|
|
490
|
+
* falta para dos cosas que no son el toolkit: reconocer la operación de una
|
|
491
|
+
* herramienta ya guardada (si desapareciera, un `send_email_and_wait` creado antes
|
|
492
|
+
* se quedaría sin etiqueta) y el modo de una sola op elegido como herramienta
|
|
493
|
+
* suelta, donde el pipeline sí espera el clic.
|
|
494
|
+
*/
|
|
495
|
+
export const GMAIL_SEND_AND_WAIT_TOOL_SPEC = {
|
|
496
|
+
operation: 'sendAndWaitForResponse',
|
|
497
|
+
label: 'Send and wait for response',
|
|
498
|
+
toolName: 'send_email_and_wait',
|
|
499
|
+
description: 'Send an email with Approve / Disapprove buttons and PAUSE the pipeline until the ' +
|
|
500
|
+
'recipient clicks one. Resumes downstream with `payload._waitResponse = { approved, ' +
|
|
501
|
+
'decidedAt, ipAddress, comment }` so a Conditional Node can branch on the decision. Times ' +
|
|
502
|
+
'out after timeoutMinutes (default 24h) if nobody clicks; the timeout cron auto-resolves ' +
|
|
503
|
+
'with approved=false. Use for human-in-the-loop approvals (e.g. confirm before sending ' +
|
|
504
|
+
'money, deploying, or notifying customers).',
|
|
505
|
+
parameters: [
|
|
506
|
+
p('to', 'Recipient email address(es). Single string or comma-separated list.'),
|
|
507
|
+
p('subject', 'Email subject line.'),
|
|
508
|
+
p('body', 'HTML-formatted email body. The Approve / Disapprove buttons are appended automatically below your content.'),
|
|
509
|
+
p('approveLabel', "Optional. Approve button label. Default: 'Approve'.", false),
|
|
510
|
+
p('disapproveLabel', "Optional. Disapprove button label. Default: 'Disapprove'.", false),
|
|
511
|
+
p('includeDisapprove', 'Optional. Include the Disapprove button. Default: true. Set to false for approve-only confirmations.', false),
|
|
512
|
+
p('timeoutMinutes', 'Optional. Minutes to wait before auto-resolving with approved=false. Default 1440 (24h).', false),
|
|
513
|
+
],
|
|
514
|
+
};
|
|
515
|
+
/** Todo lo que el nodo sabe ejecutar, se ofrezca o no como herramienta. */
|
|
516
|
+
export const GMAIL_ALL_TOOLKIT_SPECS = [
|
|
517
|
+
...GMAIL_TOOLKIT_SPECS,
|
|
518
|
+
GMAIL_SEND_AND_WAIT_TOOL_SPEC,
|
|
519
|
+
];
|
|
520
|
+
/** El toolkit del proveedor nativo (Resend): una sola herramienta. */
|
|
521
|
+
export const NATIVE_EMAIL_TOOLKIT_SPECS = [
|
|
522
|
+
{
|
|
523
|
+
operation: 'send',
|
|
524
|
+
label: 'Send email',
|
|
525
|
+
toolName: 'send_email',
|
|
526
|
+
description: 'Send a transactional email via Resend. Use for confirmations, notifications, receipts, ' +
|
|
527
|
+
'password resets. One email per call. The sender domain is fixed by the node; you cannot ' +
|
|
528
|
+
'change it per call. Body accepts HTML.',
|
|
529
|
+
parameters: [
|
|
530
|
+
p('to', 'Recipient email address(es). Single string or comma-separated list.'),
|
|
531
|
+
p('subject', 'Email subject line.'),
|
|
532
|
+
p('body', 'HTML-formatted email body.'),
|
|
533
|
+
p('cc', 'Optional CC recipients. Single string or comma-separated.', false),
|
|
534
|
+
p('bcc', 'Optional BCC recipients. Single string or comma-separated.', false),
|
|
535
|
+
p('reply_to', 'Optional Reply-To address.', false),
|
|
536
|
+
p('from_name', 'Optional display name for this specific email (overrides the node default).', false),
|
|
537
|
+
p('attachment_file_ids', 'Optional. Comma-separated list of file IDs from `_file.id` refs in the upstream payload (e.g., a File Transform output or a webhook multipart upload). Max 5 files, 30MB total. Do NOT invent IDs — only use values actually present in the current payload.', false),
|
|
538
|
+
],
|
|
539
|
+
},
|
|
540
|
+
];
|
|
541
|
+
export const GMAIL_TOOLKIT_BY_TOOL_NAME = Object.fromEntries(GMAIL_ALL_TOOLKIT_SPECS.map((s) => [s.toolName, s]));
|
|
542
|
+
export const NATIVE_EMAIL_TOOLKIT_BY_TOOL_NAME = Object.fromEntries(NATIVE_EMAIL_TOOLKIT_SPECS.map((s) => [s.toolName, s]));
|
|
543
|
+
/** Los tres campos que un día vivieron en la raíz. */
|
|
544
|
+
export const GMAIL_SEND_LEGACY_FIELDS = ['to', 'subject', 'body'];
|
|
545
|
+
export function resolveGmailSendFields(entity) {
|
|
546
|
+
const cfg = (entity?.operationConfig ?? {});
|
|
547
|
+
const crudoTo = cfg.to ?? entity?.to;
|
|
548
|
+
const to = Array.isArray(crudoTo)
|
|
549
|
+
? crudoTo.filter((x) => typeof x === 'string')
|
|
550
|
+
: typeof crudoTo === 'string' && crudoTo !== ''
|
|
551
|
+
? [crudoTo]
|
|
552
|
+
: [];
|
|
553
|
+
const subject = cfg.subject ?? entity?.subject;
|
|
554
|
+
const body = cfg.body ?? entity?.body;
|
|
555
|
+
return {
|
|
556
|
+
to,
|
|
557
|
+
subject: typeof subject === 'string' ? subject : '',
|
|
558
|
+
body: typeof body === 'string' ? body : '',
|
|
559
|
+
};
|
|
560
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Analytics 4 operation enum — single source of truth across the API,
|
|
3
|
+
* Dashboard, and Message Broker. Used by:
|
|
4
|
+
* - googleAnalyticsAction entity / DTO (api): operation field + validation
|
|
5
|
+
* - dashboard GoogleAnalyticsAction operation type
|
|
6
|
+
* - MCP toolkit specs, si algún día el nodo gana modo toolkit
|
|
7
|
+
*
|
|
8
|
+
* Mismo patrón que `drive-operations.ts` y `sheets-operations.ts`.
|
|
9
|
+
*
|
|
10
|
+
* ── Por qué sólo dos operaciones ──
|
|
11
|
+
*
|
|
12
|
+
* GA4 tiene más superficie (`runPivotReport`, `batchRunReports`,
|
|
13
|
+
* `checkCompatibility`), pero declarar una op que el servicio todavía no
|
|
14
|
+
* implementa la pinta en el desplegable y la deja fallar al ejecutarse: el
|
|
15
|
+
* enum ES el contrato de la pantalla. Entran cuando entre su código.
|
|
16
|
+
*
|
|
17
|
+
* ── Lo que NO es una operación ──
|
|
18
|
+
*
|
|
19
|
+
* Listar propiedades y listar las dimensiones/métricas disponibles NO son
|
|
20
|
+
* ops del nodo: son endpoints del controlador, que es como Drive alimenta su
|
|
21
|
+
* `DriveFilePicker` (`@Get('files/:credentialId')`). Una op existe para
|
|
22
|
+
* producir payload en una corrida; esto otro es para rellenar el formulario.
|
|
23
|
+
*
|
|
24
|
+
* ── Decisiones propias de GA (anti-n8n) ──
|
|
25
|
+
*
|
|
26
|
+
* - La propiedad se ELIGE de una lista, no se teclea. `properties/123456789`
|
|
27
|
+
* y `G-XXXXXXX` se confunden todo el rato y el error de GA no lo aclara.
|
|
28
|
+
* - Las fechas admiten `NdaysAgo` / `yesterday` / `today` además de
|
|
29
|
+
* `YYYY-MM-DD`, que es lo que acepta la API, y son el sitio donde avisar
|
|
30
|
+
* de que el dato no está cerrado hasta pasadas ~48 h.
|
|
31
|
+
* - El filtro común (una dimensión, un valor) son tres campos; la
|
|
32
|
+
* `FilterExpression` cruda queda de escape en Advanced y gana si está.
|
|
33
|
+
*/
|
|
34
|
+
export declare const GOOGLE_ANALYTICS_OPERATIONS: readonly ["runReport", "runRealtimeReport"];
|
|
35
|
+
export type GoogleAnalyticsOperation = (typeof GOOGLE_ANALYTICS_OPERATIONS)[number];
|
|
36
|
+
/** Type guard — para validar entrada no fiable (DTOs, tool calls). */
|
|
37
|
+
export declare function isGoogleAnalyticsOperation(value: unknown): value is GoogleAnalyticsOperation;
|
|
38
|
+
export type GoogleAnalyticsParamType =
|
|
39
|
+
/** Selector vivo de propiedades GA4 (necesita credencial). */
|
|
40
|
+
'analyticsProperty'
|
|
41
|
+
/** Multi-selección de métricas, con las opciones vivas del metadata. */
|
|
42
|
+
| 'analyticsMetrics'
|
|
43
|
+
/** Multi-selección de dimensiones, igual que las métricas. */
|
|
44
|
+
| 'analyticsDimensions'
|
|
45
|
+
/** Texto con autocompletado de `{{payload.*}}`. */
|
|
46
|
+
| 'template'
|
|
47
|
+
/** `<select>` normal; las etiquetas no son los valores, `options` obliga. */
|
|
48
|
+
| 'select' | 'number'
|
|
49
|
+
/**
|
|
50
|
+
* `<select>` de `''` / `'true'` / `'false'` que se guarda como BOOLEANO, o
|
|
51
|
+
* no se guarda si es `''`. Mismo motivo que el `starred` de Drive: "— sin
|
|
52
|
+
* tocar —" tiene que significar que la clave no viaja.
|
|
53
|
+
*/
|
|
54
|
+
| 'booleanSelect'
|
|
55
|
+
/** Área de texto para JSON crudo (la FilterExpression de escape). */
|
|
56
|
+
| 'json';
|
|
57
|
+
export interface GoogleAnalyticsParamSpec {
|
|
58
|
+
/** La clave de `operationConfig`. Es lo que lee la api, no un nombre de UI. */
|
|
59
|
+
name: string;
|
|
60
|
+
label: string;
|
|
61
|
+
type: GoogleAnalyticsParamType;
|
|
62
|
+
required?: boolean;
|
|
63
|
+
/** Ayuda bajo el campo. Texto plano: el paquete no lleva React. */
|
|
64
|
+
description?: string;
|
|
65
|
+
placeholder?: string;
|
|
66
|
+
/** Prerrellenado cuando la config guardada no trae valor para esta clave. */
|
|
67
|
+
default?: string | number;
|
|
68
|
+
/** Obligatorio en `select` y `booleanSelect` — etiqueta y valor difieren. */
|
|
69
|
+
options?: ReadonlyArray<{
|
|
70
|
+
value: string;
|
|
71
|
+
label: string;
|
|
72
|
+
}>;
|
|
73
|
+
min?: number;
|
|
74
|
+
max?: number;
|
|
75
|
+
/** Se pinta en la pestaña "Advanced" en vez de en "Config". */
|
|
76
|
+
advanced?: boolean;
|
|
77
|
+
/** Sólo visible cuando un campo hermano vale uno de estos. */
|
|
78
|
+
showWhen?: {
|
|
79
|
+
field: string;
|
|
80
|
+
in: ReadonlyArray<string>;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export interface GoogleAnalyticsOperationSpec {
|
|
84
|
+
/** Etiqueta de la fila en el desplegable de operación. */
|
|
85
|
+
label: string;
|
|
86
|
+
/** Sub-línea bajo la etiqueta. */
|
|
87
|
+
description: string;
|
|
88
|
+
/** Método de la API al que mapea (developers.google.com/analytics/devguides/reporting/data/v1). */
|
|
89
|
+
apiMethod: string;
|
|
90
|
+
/** Esquema de parámetros. El orden ES el orden en pantalla. */
|
|
91
|
+
params: GoogleAnalyticsParamSpec[];
|
|
92
|
+
}
|
|
93
|
+
export declare const GOOGLE_ANALYTICS_OPERATION_SPECS: Record<GoogleAnalyticsOperation, GoogleAnalyticsOperationSpec>;
|
|
94
|
+
/**
|
|
95
|
+
* Las operaciones tal y como se listan en el desplegable. Hoy es el enum
|
|
96
|
+
* entero; existe para que añadir una op interna (sin fila propia) no obligue
|
|
97
|
+
* a que la página vuelva a decidir por su cuenta qué enseñar.
|
|
98
|
+
*/
|
|
99
|
+
export declare const GOOGLE_ANALYTICS_DROPDOWN_OPERATIONS: readonly GoogleAnalyticsOperation[];
|