@aglyn/plugins-workflows 1.0.0-beta.143
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 +201 -0
- package/README.md +52 -0
- package/package.json +53 -0
- package/src/index.d.ts +18 -0
- package/src/index.js +19 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/automation-step-fields.component.d.ts +74 -0
- package/src/lib/components/automation-step-fields.component.js +1210 -0
- package/src/lib/components/automation-step-fields.component.js.map +1 -0
- package/src/lib/components/host-actions-card.component.d.ts +15 -0
- package/src/lib/components/host-actions-card.component.js +1229 -0
- package/src/lib/components/host-actions-card.component.js.map +1 -0
- package/src/lib/components/host-activity-card.component.d.ts +84 -0
- package/src/lib/components/host-activity-card.component.js +280 -0
- package/src/lib/components/host-activity-card.component.js.map +1 -0
- package/src/lib/components/host-run-history-card.component.d.ts +40 -0
- package/src/lib/components/host-run-history-card.component.js +284 -0
- package/src/lib/components/host-run-history-card.component.js.map +1 -0
- package/src/lib/components/host-webhooks-card.component.d.ts +15 -0
- package/src/lib/components/host-webhooks-card.component.js +421 -0
- package/src/lib/components/host-webhooks-card.component.js.map +1 -0
- package/src/lib/components/host-workflows-card.component.d.ts +18 -0
- package/src/lib/components/host-workflows-card.component.js +952 -0
- package/src/lib/components/host-workflows-card.component.js.map +1 -0
- package/src/lib/components/run-quota-line.component.d.ts +27 -0
- package/src/lib/components/run-quota-line.component.js +72 -0
- package/src/lib/components/run-quota-line.component.js.map +1 -0
- package/src/lib/components/use-automation-step-pickers.d.ts +27 -0
- package/src/lib/components/use-automation-step-pickers.js +205 -0
- package/src/lib/components/use-automation-step-pickers.js.map +1 -0
- package/src/lib/components/workflow-zones.d.ts +36 -0
- package/src/lib/components/workflow-zones.js +19 -0
- package/src/lib/components/workflow-zones.js.map +1 -0
- package/src/lib/components/workflows-console-page.d.ts +25 -0
- package/src/lib/components/workflows-console-page.js +112 -0
- package/src/lib/components/workflows-console-page.js.map +1 -0
- package/src/lib/components/workflows-console-sections.d.ts +34 -0
- package/src/lib/components/workflows-console-sections.js +50 -0
- package/src/lib/components/workflows-console-sections.js.map +1 -0
- package/src/lib/constants/bundle-common.d.ts +8 -0
- package/src/lib/constants/bundle-common.js +9 -0
- package/src/lib/constants/bundle-common.js.map +1 -0
- package/src/lib/declarations.server.d.ts +41 -0
- package/src/lib/declarations.server.js +54 -0
- package/src/lib/declarations.server.js.map +1 -0
- package/src/lib/engine/crm-action-steps.d.ts +129 -0
- package/src/lib/engine/crm-action-steps.js +432 -0
- package/src/lib/engine/crm-action-steps.js.map +1 -0
- package/src/lib/engine/flow-enrollments.d.ts +264 -0
- package/src/lib/engine/flow-enrollments.js +386 -0
- package/src/lib/engine/flow-enrollments.js.map +1 -0
- package/src/lib/engine/run-event-actions.d.ts +232 -0
- package/src/lib/engine/run-event-actions.js +1392 -0
- package/src/lib/engine/run-event-actions.js.map +1 -0
- package/src/lib/engine/run-event-automations.d.ts +28 -0
- package/src/lib/engine/run-event-automations.js +37 -0
- package/src/lib/engine/run-event-automations.js.map +1 -0
- package/src/lib/engine/run-event-workflows.d.ts +75 -0
- package/src/lib/engine/run-event-workflows.js +311 -0
- package/src/lib/engine/run-event-workflows.js.map +1 -0
- package/src/lib/engine/workflow-steps.d.ts +107 -0
- package/src/lib/engine/workflow-steps.js +124 -0
- package/src/lib/engine/workflow-steps.js.map +1 -0
- package/src/lib/plugin.d.ts +33 -0
- package/src/lib/plugin.js +94 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/server-automation-drafts.d.ts +90 -0
- package/src/lib/server-automation-drafts.js +429 -0
- package/src/lib/server-automation-drafts.js.map +1 -0
- package/src/lib/server-console.d.ts +27 -0
- package/src/lib/server-console.js +35 -0
- package/src/lib/server-console.js.map +1 -0
- package/src/lib/server.d.ts +29 -0
- package/src/lib/server.js +298 -0
- package/src/lib/server.js.map +1 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
19
|
+
import { checkEntitlement, createResourceUid, pluginDocsHelp, WEBHOOK_MAX_PER_HOST, WEBHOOK_URL_PATTERN } from "@aglyn/aglyn";
|
|
20
|
+
import { CardDisplay, useConfirmationContext } from "@aglyn/shared-ui-jsx";
|
|
21
|
+
import { hostPublicOrigin } from "@aglyn/aglyn/app-utils/host-naming";
|
|
22
|
+
import { useSnackbar } from "@aglyn/shared-ui-snackstack";
|
|
23
|
+
import { Timestamp } from "@aglyn/shared-util-timestamp";
|
|
24
|
+
import { Alert, Button, Dialog, DialogActions, DialogContent, DialogTitle, MenuItem, Stack, TextField, Typography } from "@mui/material";
|
|
25
|
+
import { collection, doc, updateDoc } from "firebase/firestore";
|
|
26
|
+
import { useCallback, useState } from "react";
|
|
27
|
+
import { useFirestore, useFirestoreCollection, useFirestoreDoc, useHostResourceApi } from "@aglyn/tenant-feature-instance";
|
|
28
|
+
/*
|
|
29
|
+
* The MODULE, not the barrel, for the two PURE helpers — the specs that render
|
|
30
|
+
* this card mock `@aglyn/tenant-feature-instance` wholesale to stage their
|
|
31
|
+
* Firestore hooks, and a query builder imported through that barrel disappears
|
|
32
|
+
* under the mock. Neither of these is a hook.
|
|
33
|
+
*/ import { ceilingedWindow, collectionCeiling } from "@aglyn/tenant-feature-instance/hooks/host-collection-queries";
|
|
34
|
+
/**
|
|
35
|
+
* How many webhook documents the card reads.
|
|
36
|
+
*
|
|
37
|
+
* Above `WEBHOOK_MAX_PER_HOST` on purpose. The cap counts LIVE hooks and the
|
|
38
|
+
* collection keeps soft-deleted ones, so a site that has created and deleted
|
|
39
|
+
* its five several times holds more documents than it may have hooks.
|
|
40
|
+
*/ const WEBHOOK_CEILING = 20;
|
|
41
|
+
/**
|
|
42
|
+
* How many workflows the inbound-endpoint picker offers.
|
|
43
|
+
*
|
|
44
|
+
* Paid for only while the editor is open, which is what makes a ceiling this
|
|
45
|
+
* size affordable: it is one operator mid-edit rather than every visitor to
|
|
46
|
+
* the page.
|
|
47
|
+
*/ const WORKFLOW_OPTION_CEILING = 100;
|
|
48
|
+
function generateSecret() {
|
|
49
|
+
const bytes = new Uint8Array(24);
|
|
50
|
+
crypto.getRandomValues(bytes);
|
|
51
|
+
return Array.from(bytes, (byte)=>byte.toString(16).padStart(2, '0')).join('');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Webhooks manager (AGL-149): outbound targets (used by the actions
|
|
55
|
+
* builder's "Send a webhook" step, HMAC-signed) and inbound endpoints
|
|
56
|
+
* (`/api/hooks/{hostId}/{hookId}`, secret-verified, run a workflow with
|
|
57
|
+
* the payload in scope). Business tier.
|
|
58
|
+
*/ export function HostWebhooksCard(props) {
|
|
59
|
+
var _hostPublicOrigin, _ref, _ref1, _ref2, _ref3, _ref4;
|
|
60
|
+
const { hostId, org } = props;
|
|
61
|
+
const firestore = useFirestore();
|
|
62
|
+
const { enqueueSnackbar } = useSnackbar();
|
|
63
|
+
const { confirm } = useConfirmationContext();
|
|
64
|
+
const createResource = useHostResourceApi();
|
|
65
|
+
const [draft, setDraft] = useState(null);
|
|
66
|
+
/**
|
|
67
|
+
* The editor has been opened at least once in this session.
|
|
68
|
+
*
|
|
69
|
+
* A LATCH rather than `draft` itself, because the workflow picker below keys its
|
|
70
|
+
* listeners on it. Tracking the dialog would tear that subscription down
|
|
71
|
+
* on Cancel and pay for them again on the next Edit, so a merchant working
|
|
72
|
+
* through ten actions would buy the same window ten times — worse than
|
|
73
|
+
* the mount-time read this replaces. Latched, a reader who never edits pays
|
|
74
|
+
* nothing and a reader who edits pays once.
|
|
75
|
+
*/ const [editorOpened, setEditorOpened] = useState(false);
|
|
76
|
+
if (draft && !editorOpened) setEditorOpened(true);
|
|
77
|
+
/*
|
|
78
|
+
* ORDERED AND CEILINGED (AGL-2501). A bare `limit` is answered in
|
|
79
|
+
* DOCUMENT-ID order, so an unnamed window is an arbitrary twenty that the
|
|
80
|
+
* `localeCompare` below would arrange alphabetically. `collectionCeiling`
|
|
81
|
+
* does not change WHICH twenty; it NAMES the order, and the probe row it
|
|
82
|
+
* adds is what lets the card say when the ceiling bites.
|
|
83
|
+
*/ const { data: webhookRead } = useFirestoreCollection(()=>collectionCeiling(collection(firestore, 'hosts', hostId, 'webhooks'), WEBHOOK_CEILING), [
|
|
84
|
+
firestore,
|
|
85
|
+
hostId
|
|
86
|
+
], {
|
|
87
|
+
idField: '$id'
|
|
88
|
+
});
|
|
89
|
+
const { rows: readWebhooks, truncated: webhooksTruncated } = ceilingedWindow(webhookRead, WEBHOOK_CEILING);
|
|
90
|
+
/*
|
|
91
|
+
* READ WHEN THE EDITOR OPENS, not when the card mounts. The only thing that
|
|
92
|
+
* consumes these rows is the inbound-endpoint select inside the dialog — the
|
|
93
|
+
* table renders a hook's stored `workflowName` — so an unconditional
|
|
94
|
+
* listener would charge every visitor to this page a hundred workflows to
|
|
95
|
+
* fill a control most of them never see, and one that only appears for the
|
|
96
|
+
* inbound half of the form at that.
|
|
97
|
+
*/ const { data: workflowRead } = useFirestoreCollection(()=>editorOpened ? collectionCeiling(collection(firestore, 'hosts', hostId, 'workflows'), WORKFLOW_OPTION_CEILING) : null, [
|
|
98
|
+
firestore,
|
|
99
|
+
hostId,
|
|
100
|
+
editorOpened
|
|
101
|
+
], {
|
|
102
|
+
idField: '$id'
|
|
103
|
+
});
|
|
104
|
+
const { rows: readWorkflows, truncated: workflowOptionsTruncated } = ceilingedWindow(workflowRead, WORKFLOW_OPTION_CEILING);
|
|
105
|
+
const { data: host } = useFirestoreDoc(()=>doc(firestore, 'hosts', hostId), [
|
|
106
|
+
firestore,
|
|
107
|
+
hostId
|
|
108
|
+
], {
|
|
109
|
+
idField: '$id'
|
|
110
|
+
});
|
|
111
|
+
// Sorting the whole ceiling, not a page of it.
|
|
112
|
+
const webhooks = [
|
|
113
|
+
...readWebhooks
|
|
114
|
+
].filter((hook)=>!hook.deletedAt).sort((a, b)=>{
|
|
115
|
+
var _a_name, _b_name;
|
|
116
|
+
return String((_a_name = a.name) != null ? _a_name : '').localeCompare(String((_b_name = b.name) != null ? _b_name : ''));
|
|
117
|
+
});
|
|
118
|
+
const workflowNames = readWorkflows.filter((workflow)=>!workflow.deletedAt && workflow.name).map((workflow)=>workflow.name).sort();
|
|
119
|
+
// `hostPublicOrigin` (AGL-2195) — this base is printed into the webhook
|
|
120
|
+
// sample payload an operator copies into a third-party system.
|
|
121
|
+
const siteBase = (_hostPublicOrigin = hostPublicOrigin(host)) != null ? _hostPublicOrigin : '';
|
|
122
|
+
const handleAdd = useCallback(()=>{
|
|
123
|
+
if (!checkEntitlement(org, 'webhooks')) {
|
|
124
|
+
return void enqueueSnackbar('Webhooks require a Business plan — see Billing to upgrade', {
|
|
125
|
+
variant: 'warning',
|
|
126
|
+
persist: false
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
// An affordance, NOT the limit (AGL-1360). `webhooks` comes from a
|
|
130
|
+
// Firestore listener and the console runs `persistentLocalCache`, so this
|
|
131
|
+
// count can be arbitrarily stale — it is here to fail fast when it
|
|
132
|
+
// happens to be right, never to authorise the create. The cap that holds
|
|
133
|
+
// is counted server-side in /api/hosts/resources.
|
|
134
|
+
if (webhooks.length >= WEBHOOK_MAX_PER_HOST) {
|
|
135
|
+
return void enqueueSnackbar(`Webhooks are capped at ${WEBHOOK_MAX_PER_HOST} per site`, {
|
|
136
|
+
variant: 'warning',
|
|
137
|
+
persist: false
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
setDraft({
|
|
141
|
+
id: null,
|
|
142
|
+
name: '',
|
|
143
|
+
direction: 'outbound',
|
|
144
|
+
url: '',
|
|
145
|
+
workflowName: '',
|
|
146
|
+
secret: generateSecret()
|
|
147
|
+
});
|
|
148
|
+
}, [
|
|
149
|
+
org,
|
|
150
|
+
webhooks.length,
|
|
151
|
+
enqueueSnackbar
|
|
152
|
+
]);
|
|
153
|
+
const handleSave = useCallback(async ()=>{
|
|
154
|
+
if (!draft || !draft.name.trim()) return;
|
|
155
|
+
if (draft.direction === 'outbound') {
|
|
156
|
+
if (!WEBHOOK_URL_PATTERN.test(draft.url.trim())) {
|
|
157
|
+
return void enqueueSnackbar('Outbound URLs must be public https addresses', {
|
|
158
|
+
variant: 'warning',
|
|
159
|
+
persist: false
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
} else if (!draft.workflowName.trim()) {
|
|
163
|
+
return void enqueueSnackbar('Pick the workflow this endpoint runs', {
|
|
164
|
+
variant: 'warning',
|
|
165
|
+
persist: false
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
// Creates go through /api/hosts/resources (AGL-1360), which counts the
|
|
170
|
+
// live webhooks with the Admin SDK before allowing one more; Firestore
|
|
171
|
+
// rules deny client `create` on this collection. The card has no edit
|
|
172
|
+
// path — every save is a create — so there is no update branch here.
|
|
173
|
+
await createResource({
|
|
174
|
+
hostId,
|
|
175
|
+
resource: 'webhook',
|
|
176
|
+
id: createResourceUid(),
|
|
177
|
+
data: _extends({
|
|
178
|
+
name: draft.name.trim().slice(0, 60),
|
|
179
|
+
direction: draft.direction
|
|
180
|
+
}, draft.direction === 'outbound' ? {
|
|
181
|
+
url: draft.url.trim()
|
|
182
|
+
} : {
|
|
183
|
+
workflowName: draft.workflowName.trim()
|
|
184
|
+
}, {
|
|
185
|
+
secret: draft.secret,
|
|
186
|
+
enabled: true
|
|
187
|
+
})
|
|
188
|
+
});
|
|
189
|
+
setDraft(null);
|
|
190
|
+
enqueueSnackbar('Webhook saved', {
|
|
191
|
+
variant: 'success',
|
|
192
|
+
persist: false
|
|
193
|
+
});
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.error(error);
|
|
196
|
+
// The route's message is the useful one — it names the cap, the
|
|
197
|
+
// entitlement or the role that refused.
|
|
198
|
+
enqueueSnackbar((error == null ? void 0 : error.message) || 'An error has occurred', {
|
|
199
|
+
variant: 'error',
|
|
200
|
+
allowDuplicate: true
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}, [
|
|
204
|
+
draft,
|
|
205
|
+
createResource,
|
|
206
|
+
hostId,
|
|
207
|
+
enqueueSnackbar
|
|
208
|
+
]);
|
|
209
|
+
const handleDelete = useCallback((hook)=>async ()=>{
|
|
210
|
+
const confirmed = await confirm({
|
|
211
|
+
title: 'Delete this webhook?',
|
|
212
|
+
description: `"${hook.name}" stops ${hook.direction === 'outbound' ? 'delivering' : 'accepting calls'} immediately.`,
|
|
213
|
+
confirmationText: 'Delete',
|
|
214
|
+
confirmationButtonProps: {
|
|
215
|
+
color: 'error'
|
|
216
|
+
}
|
|
217
|
+
}).then(()=>true).catch(()=>false);
|
|
218
|
+
if (!confirmed) return;
|
|
219
|
+
await updateDoc(doc(firestore, 'hosts', hostId, 'webhooks', hook.$id), {
|
|
220
|
+
deletedAt: Timestamp.now()
|
|
221
|
+
});
|
|
222
|
+
}, [
|
|
223
|
+
confirm,
|
|
224
|
+
firestore,
|
|
225
|
+
hostId
|
|
226
|
+
]);
|
|
227
|
+
return /*#__PURE__*/ _jsxs(CardDisplay, {
|
|
228
|
+
header: 'Webhooks',
|
|
229
|
+
help: pluginDocsHelp('webhooks', {
|
|
230
|
+
anchor: '#outbound-webhooks'
|
|
231
|
+
}),
|
|
232
|
+
contentGutterX: true,
|
|
233
|
+
contentGutterY: true,
|
|
234
|
+
children: [
|
|
235
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
236
|
+
spacing: 1,
|
|
237
|
+
children: [
|
|
238
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
239
|
+
variant: "body2",
|
|
240
|
+
color: "text.secondary",
|
|
241
|
+
children: 'Send signed JSON to outside systems from the actions builder, ' + 'or accept calls that run a workflow. Business plans.'
|
|
242
|
+
}),
|
|
243
|
+
webhooks.map((hook)=>/*#__PURE__*/ _jsxs(Stack, {
|
|
244
|
+
direction: "row",
|
|
245
|
+
spacing: 1,
|
|
246
|
+
sx: {
|
|
247
|
+
alignItems: 'center'
|
|
248
|
+
},
|
|
249
|
+
children: [
|
|
250
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
251
|
+
sx: {
|
|
252
|
+
flex: 1,
|
|
253
|
+
minWidth: 0
|
|
254
|
+
},
|
|
255
|
+
children: [
|
|
256
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
257
|
+
variant: "body2",
|
|
258
|
+
noWrap: true,
|
|
259
|
+
children: hook.name
|
|
260
|
+
}),
|
|
261
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
262
|
+
variant: "caption",
|
|
263
|
+
color: "text.secondary",
|
|
264
|
+
noWrap: true,
|
|
265
|
+
children: hook.direction === 'outbound' ? `outbound · ${hook.url}` : `inbound · ${siteBase}/api/hooks/${hostId}/${hook.$id}` + ` → ${hook.workflowName}`
|
|
266
|
+
})
|
|
267
|
+
]
|
|
268
|
+
}),
|
|
269
|
+
hook.direction === 'inbound' ? /*#__PURE__*/ _jsx(Button, {
|
|
270
|
+
size: "small",
|
|
271
|
+
onClick: ()=>{
|
|
272
|
+
void navigator.clipboard.writeText(`${siteBase}/api/hooks/${hostId}/${hook.$id}`);
|
|
273
|
+
enqueueSnackbar('Endpoint URL copied — send the secret in x-aglyn-secret', {
|
|
274
|
+
variant: 'success',
|
|
275
|
+
persist: false
|
|
276
|
+
});
|
|
277
|
+
},
|
|
278
|
+
children: 'Copy URL'
|
|
279
|
+
}) : null,
|
|
280
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
281
|
+
size: "small",
|
|
282
|
+
onClick: ()=>{
|
|
283
|
+
var _hook_secret;
|
|
284
|
+
void navigator.clipboard.writeText((_hook_secret = hook.secret) != null ? _hook_secret : '');
|
|
285
|
+
enqueueSnackbar('Secret copied', {
|
|
286
|
+
variant: 'success',
|
|
287
|
+
persist: false
|
|
288
|
+
});
|
|
289
|
+
},
|
|
290
|
+
children: 'Secret'
|
|
291
|
+
}),
|
|
292
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
293
|
+
size: "small",
|
|
294
|
+
color: "error",
|
|
295
|
+
onClick: handleDelete(hook),
|
|
296
|
+
children: 'Delete'
|
|
297
|
+
})
|
|
298
|
+
]
|
|
299
|
+
}, hook.$id)),
|
|
300
|
+
webhooksTruncated ? /*#__PURE__*/ _jsx(Alert, {
|
|
301
|
+
severity: "info",
|
|
302
|
+
children: `Showing the first ${WEBHOOK_CEILING} webhook documents on this ` + 'site, ordered by id. There are more, so a hook may be missing ' + 'from this list.'
|
|
303
|
+
}) : null,
|
|
304
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
305
|
+
size: "small",
|
|
306
|
+
color: "primary",
|
|
307
|
+
sx: {
|
|
308
|
+
alignSelf: 'flex-start'
|
|
309
|
+
},
|
|
310
|
+
onClick: handleAdd,
|
|
311
|
+
children: 'Add webhook'
|
|
312
|
+
})
|
|
313
|
+
]
|
|
314
|
+
}),
|
|
315
|
+
/*#__PURE__*/ _jsxs(Dialog, {
|
|
316
|
+
open: Boolean(draft),
|
|
317
|
+
onClose: ()=>setDraft(null),
|
|
318
|
+
maxWidth: "xs",
|
|
319
|
+
fullWidth: true,
|
|
320
|
+
children: [
|
|
321
|
+
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
322
|
+
children: 'Add webhook'
|
|
323
|
+
}),
|
|
324
|
+
/*#__PURE__*/ _jsxs(DialogContent, {
|
|
325
|
+
sx: {
|
|
326
|
+
display: 'flex',
|
|
327
|
+
flexDirection: 'column',
|
|
328
|
+
gap: 1.5,
|
|
329
|
+
pt: 1
|
|
330
|
+
},
|
|
331
|
+
children: [
|
|
332
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
333
|
+
label: "Name",
|
|
334
|
+
value: (_ref = draft == null ? void 0 : draft.name) != null ? _ref : '',
|
|
335
|
+
onChange: (event)=>setDraft((prev)=>prev ? _extends({}, prev, {
|
|
336
|
+
name: event.target.value
|
|
337
|
+
}) : prev),
|
|
338
|
+
size: "small",
|
|
339
|
+
autoFocus: true,
|
|
340
|
+
sx: {
|
|
341
|
+
mt: 1
|
|
342
|
+
}
|
|
343
|
+
}),
|
|
344
|
+
/*#__PURE__*/ _jsxs(TextField, {
|
|
345
|
+
select: true,
|
|
346
|
+
label: "Direction",
|
|
347
|
+
value: (_ref1 = draft == null ? void 0 : draft.direction) != null ? _ref1 : 'outbound',
|
|
348
|
+
onChange: (event)=>setDraft((prev)=>prev ? _extends({}, prev, {
|
|
349
|
+
direction: event.target.value
|
|
350
|
+
}) : prev),
|
|
351
|
+
size: "small",
|
|
352
|
+
children: [
|
|
353
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
354
|
+
value: "outbound",
|
|
355
|
+
children: 'Outbound — send data to a URL'
|
|
356
|
+
}),
|
|
357
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
358
|
+
value: "inbound",
|
|
359
|
+
children: 'Inbound — receive data, run a workflow'
|
|
360
|
+
})
|
|
361
|
+
]
|
|
362
|
+
}),
|
|
363
|
+
(draft == null ? void 0 : draft.direction) === 'outbound' ? /*#__PURE__*/ _jsx(TextField, {
|
|
364
|
+
label: "Delivery URL",
|
|
365
|
+
placeholder: "https://example.com/hooks/aglyn",
|
|
366
|
+
value: (_ref2 = draft == null ? void 0 : draft.url) != null ? _ref2 : '',
|
|
367
|
+
onChange: (event)=>setDraft((prev)=>prev ? _extends({}, prev, {
|
|
368
|
+
url: event.target.value
|
|
369
|
+
}) : prev),
|
|
370
|
+
size: "small"
|
|
371
|
+
}) : /*#__PURE__*/ _jsx(TextField, {
|
|
372
|
+
select: true,
|
|
373
|
+
label: "Workflow to run",
|
|
374
|
+
helperText: workflowOptionsTruncated ? `Showing ${WORKFLOW_OPTION_CEILING} workflows, ordered ` + 'by id. This site has more, so one of them is not ' + 'offered here.' : undefined,
|
|
375
|
+
value: (_ref3 = draft == null ? void 0 : draft.workflowName) != null ? _ref3 : '',
|
|
376
|
+
onChange: (event)=>setDraft((prev)=>prev ? _extends({}, prev, {
|
|
377
|
+
workflowName: event.target.value
|
|
378
|
+
}) : prev),
|
|
379
|
+
size: "small",
|
|
380
|
+
children: workflowNames.map((name)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
381
|
+
value: name,
|
|
382
|
+
children: name
|
|
383
|
+
}, name))
|
|
384
|
+
}),
|
|
385
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
386
|
+
label: "Secret",
|
|
387
|
+
helperText: (draft == null ? void 0 : draft.direction) === 'outbound' ? 'Signs deliveries (X-Aglyn-Signature, HMAC-SHA256)' : 'Callers send this in the x-aglyn-secret header',
|
|
388
|
+
value: (_ref4 = draft == null ? void 0 : draft.secret) != null ? _ref4 : '',
|
|
389
|
+
size: "small",
|
|
390
|
+
slotProps: {
|
|
391
|
+
input: {
|
|
392
|
+
readOnly: true
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
})
|
|
396
|
+
]
|
|
397
|
+
}),
|
|
398
|
+
/*#__PURE__*/ _jsxs(DialogActions, {
|
|
399
|
+
children: [
|
|
400
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
401
|
+
onClick: ()=>setDraft(null),
|
|
402
|
+
children: 'Cancel'
|
|
403
|
+
}),
|
|
404
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
405
|
+
variant: "contained",
|
|
406
|
+
color: "primary",
|
|
407
|
+
disabled: !(draft == null ? void 0 : draft.name.trim()),
|
|
408
|
+
onClick: handleSave,
|
|
409
|
+
children: 'Save webhook'
|
|
410
|
+
})
|
|
411
|
+
]
|
|
412
|
+
})
|
|
413
|
+
]
|
|
414
|
+
})
|
|
415
|
+
]
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
HostWebhooksCard.displayName = 'HostWebhooksCard';
|
|
419
|
+
export default HostWebhooksCard;
|
|
420
|
+
|
|
421
|
+
//# sourceMappingURL=host-webhooks-card.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/host-webhooks-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n type AglynOrgBilling,\n checkEntitlement,\n createResourceUid,\n pluginDocsHelp,\n WEBHOOK_MAX_PER_HOST,\n WEBHOOK_URL_PATTERN,\n} from '@aglyn/aglyn'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { hostPublicOrigin } from '@aglyn/aglyn/app-utils/host-naming'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { Timestamp } from '@aglyn/shared-util-timestamp'\nimport {\n Alert,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { collection, doc, updateDoc } from 'firebase/firestore'\nimport { useCallback, useState } from 'react'\nimport {\n useFirestore,\n useFirestoreCollection,\n useFirestoreDoc,\n useHostResourceApi,\n} from '@aglyn/tenant-feature-instance'\n/*\n * The MODULE, not the barrel, for the two PURE helpers — the specs that render\n * this card mock `@aglyn/tenant-feature-instance` wholesale to stage their\n * Firestore hooks, and a query builder imported through that barrel disappears\n * under the mock. Neither of these is a hook.\n */\nimport {\n ceilingedWindow,\n collectionCeiling,\n} from '@aglyn/tenant-feature-instance/hooks/host-collection-queries'\n\n/**\n * How many webhook documents the card reads.\n *\n * Above `WEBHOOK_MAX_PER_HOST` on purpose. The cap counts LIVE hooks and the\n * collection keeps soft-deleted ones, so a site that has created and deleted\n * its five several times holds more documents than it may have hooks.\n */\nconst WEBHOOK_CEILING = 20\n\n/**\n * How many workflows the inbound-endpoint picker offers.\n *\n * Paid for only while the editor is open, which is what makes a ceiling this\n * size affordable: it is one operator mid-edit rather than every visitor to\n * the page.\n */\nconst WORKFLOW_OPTION_CEILING = 100\n\nfunction generateSecret(): string {\n const bytes = new Uint8Array(24)\n crypto.getRandomValues(bytes)\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join(\n '',\n )\n}\n\ninterface WebhookDraft {\n id: string | null\n name: string\n direction: 'outbound' | 'inbound'\n url: string\n workflowName: string\n secret: string\n}\n\n/**\n * Webhooks manager (AGL-149): outbound targets (used by the actions\n * builder's \"Send a webhook\" step, HMAC-signed) and inbound endpoints\n * (`/api/hooks/{hostId}/{hookId}`, secret-verified, run a workflow with\n * the payload in scope). Business tier.\n */\nexport function HostWebhooksCard(props: {\n hostId: string\n org?: Partial<AglynOrgBilling>\n}) {\n const { hostId, org } = props\n const firestore = useFirestore()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const createResource = useHostResourceApi()\n\n\n const [draft, setDraft] = useState<WebhookDraft | null>(null)\n /**\n * The editor has been opened at least once in this session.\n *\n * A LATCH rather than `draft` itself, because the workflow picker below keys its\n * listeners on it. Tracking the dialog would tear that subscription down\n * on Cancel and pay for them again on the next Edit, so a merchant working\n * through ten actions would buy the same window ten times — worse than\n * the mount-time read this replaces. Latched, a reader who never edits pays\n * nothing and a reader who edits pays once.\n */\n const [editorOpened, setEditorOpened] = useState(false)\n if (draft && !editorOpened) setEditorOpened(true)\n /*\n * ORDERED AND CEILINGED (AGL-2501). A bare `limit` is answered in\n * DOCUMENT-ID order, so an unnamed window is an arbitrary twenty that the\n * `localeCompare` below would arrange alphabetically. `collectionCeiling`\n * does not change WHICH twenty; it NAMES the order, and the probe row it\n * adds is what lets the card say when the ceiling bites.\n */\n const { data: webhookRead } = useFirestoreCollection<any>(\n () =>\n collectionCeiling(\n collection(firestore, 'hosts', hostId, 'webhooks'),\n WEBHOOK_CEILING,\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { rows: readWebhooks, truncated: webhooksTruncated } =\n ceilingedWindow<any>(webhookRead, WEBHOOK_CEILING)\n /*\n * READ WHEN THE EDITOR OPENS, not when the card mounts. The only thing that\n * consumes these rows is the inbound-endpoint select inside the dialog — the\n * table renders a hook's stored `workflowName` — so an unconditional\n * listener would charge every visitor to this page a hundred workflows to\n * fill a control most of them never see, and one that only appears for the\n * inbound half of the form at that.\n */\n const { data: workflowRead } = useFirestoreCollection<any>(\n () =>\n editorOpened\n ? collectionCeiling(\n collection(firestore, 'hosts', hostId, 'workflows'),\n WORKFLOW_OPTION_CEILING,\n )\n : null,\n [firestore, hostId, editorOpened],\n { idField: '$id' },\n )\n const { rows: readWorkflows, truncated: workflowOptionsTruncated } =\n ceilingedWindow<any>(workflowRead, WORKFLOW_OPTION_CEILING)\n const { data: host } = useFirestoreDoc<any>(\n () => doc(firestore, 'hosts', hostId),\n [firestore, hostId],\n { idField: '$id' },\n )\n // Sorting the whole ceiling, not a page of it.\n const webhooks = [...readWebhooks]\n .filter((hook: any) => !hook.deletedAt)\n .sort((a: any, b: any) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n )\n const workflowNames = readWorkflows\n .filter((workflow: any) => !workflow.deletedAt && workflow.name)\n .map((workflow: any) => workflow.name as string)\n .sort()\n // `hostPublicOrigin` (AGL-2195) — this base is printed into the webhook\n // sample payload an operator copies into a third-party system.\n const siteBase = hostPublicOrigin(host) ?? ''\n\n const handleAdd = useCallback(() => {\n if (!checkEntitlement(org, 'webhooks')) {\n return void enqueueSnackbar(\n 'Webhooks require a Business plan — see Billing to upgrade',\n { variant: 'warning', persist: false },\n )\n }\n // An affordance, NOT the limit (AGL-1360). `webhooks` comes from a\n // Firestore listener and the console runs `persistentLocalCache`, so this\n // count can be arbitrarily stale — it is here to fail fast when it\n // happens to be right, never to authorise the create. The cap that holds\n // is counted server-side in /api/hosts/resources.\n if (webhooks.length >= WEBHOOK_MAX_PER_HOST) {\n return void enqueueSnackbar(\n `Webhooks are capped at ${WEBHOOK_MAX_PER_HOST} per site`,\n { variant: 'warning', persist: false },\n )\n }\n setDraft({\n id: null,\n name: '',\n direction: 'outbound',\n url: '',\n workflowName: '',\n secret: generateSecret(),\n })\n }, [org, webhooks.length, enqueueSnackbar])\n\n const handleSave = useCallback(async () => {\n if (!draft || !draft.name.trim()) return\n if (draft.direction === 'outbound') {\n if (!WEBHOOK_URL_PATTERN.test(draft.url.trim())) {\n return void enqueueSnackbar(\n 'Outbound URLs must be public https addresses',\n { variant: 'warning', persist: false },\n )\n }\n } else if (!draft.workflowName.trim()) {\n return void enqueueSnackbar('Pick the workflow this endpoint runs', {\n variant: 'warning',\n persist: false,\n })\n }\n try {\n // Creates go through /api/hosts/resources (AGL-1360), which counts the\n // live webhooks with the Admin SDK before allowing one more; Firestore\n // rules deny client `create` on this collection. The card has no edit\n // path — every save is a create — so there is no update branch here.\n await createResource({\n hostId,\n resource: 'webhook',\n id: createResourceUid(),\n data: {\n name: draft.name.trim().slice(0, 60),\n direction: draft.direction,\n ...(draft.direction === 'outbound'\n ? { url: draft.url.trim() }\n : { workflowName: draft.workflowName.trim() }),\n secret: draft.secret,\n enabled: true,\n },\n })\n setDraft(null)\n enqueueSnackbar('Webhook saved', { variant: 'success', persist: false })\n } catch (error: any) {\n console.error(error)\n // The route's message is the useful one — it names the cap, the\n // entitlement or the role that refused.\n enqueueSnackbar(error?.message || 'An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n }, [draft, createResource, hostId, enqueueSnackbar])\n\n const handleDelete = useCallback(\n (hook: any) => async () => {\n const confirmed = await confirm({\n title: 'Delete this webhook?',\n description: `\"${hook.name}\" stops ${\n hook.direction === 'outbound' ? 'delivering' : 'accepting calls'\n } immediately.`,\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n await updateDoc(doc(firestore, 'hosts', hostId, 'webhooks', hook.$id), {\n deletedAt: Timestamp.now(),\n })\n },\n [confirm, firestore, hostId],\n )\n\n return (\n <CardDisplay\n header={'Webhooks'}\n help={pluginDocsHelp('webhooks', { anchor: '#outbound-webhooks' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Send signed JSON to outside systems from the actions builder, ' +\n 'or accept calls that run a workflow. Business plans.'}\n </Typography>\n {webhooks.map((hook: any) => (\n <Stack\n key={hook.$id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {hook.name}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {hook.direction === 'outbound'\n ? `outbound · ${hook.url}`\n : `inbound · ${siteBase}/api/hooks/${hostId}/${hook.$id}` +\n ` → ${hook.workflowName}`}\n </Typography>\n </Stack>\n {hook.direction === 'inbound' ? (\n <Button\n size=\"small\"\n onClick={() => {\n void navigator.clipboard.writeText(\n `${siteBase}/api/hooks/${hostId}/${hook.$id}`,\n )\n enqueueSnackbar(\n 'Endpoint URL copied — send the secret in x-aglyn-secret',\n { variant: 'success', persist: false },\n )\n }}\n >\n {'Copy URL'}\n </Button>\n ) : null}\n <Button\n size=\"small\"\n onClick={() => {\n void navigator.clipboard.writeText(hook.secret ?? '')\n enqueueSnackbar('Secret copied', {\n variant: 'success',\n persist: false,\n })\n }}\n >\n {'Secret'}\n </Button>\n <Button size=\"small\" color=\"error\" onClick={handleDelete(hook)}>\n {'Delete'}\n </Button>\n </Stack>\n ))}\n {webhooksTruncated ? (\n <Alert severity=\"info\">\n {`Showing the first ${WEBHOOK_CEILING} webhook documents on this ` +\n 'site, ordered by id. There are more, so a hook may be missing ' +\n 'from this list.'}\n </Alert>\n ) : null}\n <Button\n size=\"small\"\n color=\"primary\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={handleAdd}\n >\n {'Add webhook'}\n </Button>\n </Stack>\n\n <Dialog\n open={Boolean(draft)}\n onClose={() => setDraft(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{'Add webhook'}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, pt: 1 }}\n >\n <TextField\n label=\"Name\"\n value={draft?.name ?? ''}\n onChange={(event) =>\n setDraft((prev) =>\n prev ? { ...prev, name: event.target.value } : prev,\n )\n }\n size=\"small\"\n autoFocus\n sx={{ mt: 1 }}\n />\n <TextField\n select\n label=\"Direction\"\n value={draft?.direction ?? 'outbound'}\n onChange={(event) =>\n setDraft((prev) =>\n prev\n ? { ...prev, direction: event.target.value as any }\n : prev,\n )\n }\n size=\"small\"\n >\n <MenuItem value=\"outbound\">\n {'Outbound — send data to a URL'}\n </MenuItem>\n <MenuItem value=\"inbound\">\n {'Inbound — receive data, run a workflow'}\n </MenuItem>\n </TextField>\n {draft?.direction === 'outbound' ? (\n <TextField\n label=\"Delivery URL\"\n placeholder=\"https://example.com/hooks/aglyn\"\n value={draft?.url ?? ''}\n onChange={(event) =>\n setDraft((prev) =>\n prev ? { ...prev, url: event.target.value } : prev,\n )\n }\n size=\"small\"\n />\n ) : (\n <TextField\n select\n label=\"Workflow to run\"\n helperText={\n workflowOptionsTruncated\n ? `Showing ${WORKFLOW_OPTION_CEILING} workflows, ordered ` +\n 'by id. This site has more, so one of them is not ' +\n 'offered here.'\n : undefined\n }\n value={draft?.workflowName ?? ''}\n onChange={(event) =>\n setDraft((prev) =>\n prev ? { ...prev, workflowName: event.target.value } : prev,\n )\n }\n size=\"small\"\n >\n {workflowNames.map((name) => (\n <MenuItem key={name} value={name}>\n {name}\n </MenuItem>\n ))}\n </TextField>\n )}\n <TextField\n label=\"Secret\"\n helperText={\n draft?.direction === 'outbound'\n ? 'Signs deliveries (X-Aglyn-Signature, HMAC-SHA256)'\n : 'Callers send this in the x-aglyn-secret header'\n }\n value={draft?.secret ?? ''}\n size=\"small\"\n slotProps={{ input: { readOnly: true } }}\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setDraft(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!draft?.name.trim()}\n onClick={handleSave}\n >\n {'Save webhook'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nHostWebhooksCard.displayName = 'HostWebhooksCard'\n\nexport default HostWebhooksCard\n"],"names":["checkEntitlement","createResourceUid","pluginDocsHelp","WEBHOOK_MAX_PER_HOST","WEBHOOK_URL_PATTERN","CardDisplay","useConfirmationContext","hostPublicOrigin","useSnackbar","Timestamp","Alert","Button","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","Stack","TextField","Typography","collection","doc","updateDoc","useCallback","useState","useFirestore","useFirestoreCollection","useFirestoreDoc","useHostResourceApi","ceilingedWindow","collectionCeiling","WEBHOOK_CEILING","WORKFLOW_OPTION_CEILING","generateSecret","bytes","Uint8Array","crypto","getRandomValues","Array","from","byte","toString","padStart","join","HostWebhooksCard","props","hostId","org","firestore","enqueueSnackbar","confirm","createResource","draft","setDraft","editorOpened","setEditorOpened","data","webhookRead","idField","rows","readWebhooks","truncated","webhooksTruncated","workflowRead","readWorkflows","workflowOptionsTruncated","host","webhooks","filter","hook","deletedAt","sort","a","b","String","name","localeCompare","workflowNames","workflow","map","siteBase","handleAdd","variant","persist","length","id","direction","url","workflowName","secret","handleSave","trim","test","resource","slice","enabled","error","console","message","allowDuplicate","handleDelete","confirmed","title","description","confirmationText","confirmationButtonProps","color","then","catch","$id","now","header","help","anchor","contentGutterX","contentGutterY","spacing","sx","alignItems","flex","minWidth","noWrap","size","onClick","navigator","clipboard","writeText","severity","alignSelf","open","Boolean","onClose","maxWidth","fullWidth","display","flexDirection","gap","pt","label","value","onChange","event","prev","target","autoFocus","mt","select","placeholder","helperText","undefined","slotProps","input","readOnly","disabled","displayName"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type AglynOrgBilling } from '@aglyn/aglyn';
|
|
2
|
+
export interface HostWorkflowsCardProps {
|
|
3
|
+
hostId: string;
|
|
4
|
+
/** Resolved entitlement source for quota checks (AGL-395). */
|
|
5
|
+
org?: Partial<AglynOrgBilling>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Workflow builder v1 (AGL-101): pipelines of host-function calls — each
|
|
9
|
+
* step's argument expressions see host variables and previous step results
|
|
10
|
+
* (`step1`, or a custom result name). Runs through the pure `runWorkflow`
|
|
11
|
+
* evaluator; test-run panel included. Plan-gated (`workflows` flag +
|
|
12
|
+
* `workflowsPerHost` cap, AGL-99); site-event triggers are v2.
|
|
13
|
+
*/
|
|
14
|
+
export declare function HostWorkflowsCard(props: HostWorkflowsCardProps): import("react").JSX.Element;
|
|
15
|
+
export declare namespace HostWorkflowsCard {
|
|
16
|
+
var displayName: string;
|
|
17
|
+
}
|
|
18
|
+
export default HostWorkflowsCard;
|