Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .changeset/28234-flow-node-help-business-words.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@objectstack/service-automation': patch
'@objectstack/plugin-approvals': patch
---

Clause-②: no
Metadata-protocol: none

The HTTP and approval flow nodes now describe themselves in business words. The node description and
config help are the text the Studio flow palette and node cards show an admin, and the HTTP node's
spoke of the messaging outbox, retry / dead-letter, an HMAC-SHA256 secret, "a literal, read as
written" and a CEL value envelope; the approval node's said it "suspends the flow". The HTTP node now
reads "Send a request to an outside web service: wait for its answer, or hand it off to be delivered
in the background with automatic retries", with plain help for the request kind, background delivery,
the wait time, the signing secret and what to send; the approval node reads "Ask people to approve or
reject a record". The engineer detail moved to code comments beside each entry. No key, type, default,
accepted value or behaviour changed.
7 changes: 5 additions & 2 deletions packages/plugins/plugin-approvals/src/approval-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,11 @@ export function registerApprovalNode(
type: APPROVAL_NODE_TYPE,
version: '1.0.0',
name: 'Approval',
description: 'Route a record for human approval; suspends the flow until a decision, '
+ 'then continues down the approve / reject branch.',
// Palette and node-card text an admin reads, in business words. The run
// suspends here until a decision, then resumes down the `approve` /
// `reject` edge (see `resumeAuthority` below).
description: 'Ask people to approve or reject a record. The flow waits for their decision, '
+ 'then continues down the approve or reject path.',
icon: 'check-circle',
category: 'human',
paradigms: ['flow'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import { registerHttpNodes } from './http-nodes.js';
* wire, on EVERY arm the node can take.
*
* The key is declared without qualification — `HttpConfigSchema.signingSecret`
* and the descriptor's `configSchema` both read "HMAC-SHA256 secret →
* X-Objectstack-Signature" — yet only the durable arm used to hand it to
* anything that signs (the messaging outbox). The inline arm, and the durable
* reads "HMAC-SHA256 secret → X-Objectstack-Signature", and the descriptor's
* `configSchema` says it signs each request — yet only the durable arm used
* to hand it to anything that signs (the messaging outbox). The inline arm,
* and the durable
* arm's no-outbox fallback that degrades to it, built their `fetch` from
* `headers` alone: the request went out unsigned and the run said
* `success: true`.
Expand Down
41 changes: 32 additions & 9 deletions packages/services/service-automation/src/builtin/http-nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,15 @@ export function registerHttpNodes(engine: AutomationEngine, ctx: PluginContext):
type: HTTP_TYPE,
version: '1.0.0',
name: 'HTTP',
// The description and the config help below are the Studio flow
// palette and node-card text an admin reads, so they speak business
// words. The engineer detail they used to carry lives here: with
// `durable: true` the call is enqueued on the messaging HTTP outbox
// (retry / dead-letter) and the run does not see the response;
// otherwise it runs inline and returns the response.
description:
'Call an external HTTP endpoint. With `durable: true`, the call is enqueued on the '
+ 'messaging outbox with retry / dead-letter; otherwise it runs inline and returns the response.',
'Send a request to an outside web service: wait for its answer, or hand it off to be '
+ 'delivered in the background with automatic retries.',
icon: 'globe',
category: 'io',
source: 'builtin',
Expand Down Expand Up @@ -166,9 +172,13 @@ export function registerHttpNodes(engine: AutomationEngine, ctx: PluginContext):
+ 'path is the secret: call the service through a token-authenticated connector instead, such '
+ 'as the `slack` connector with its bot token.',
},
// `method` is a literal, read as written (#19939): no `{{ }}`
// rendering. Default `GET`; `POST` when `durable` is true.
method: {
type: 'string',
description: 'HTTP method (default GET; POST when durable) — a literal, read as written',
description:
'The kind of request, such as GET or POST. GET by default; POST when the request is '
+ 'delivered in the background.',
},
headers: {
type: 'object',
Expand All @@ -180,19 +190,32 @@ export function registerHttpNodes(engine: AutomationEngine, ctx: PluginContext):
+ 'authenticated upstream through a `connector_action` on a declarative connector whose '
+ '`auth.credentialRef` names the secret.',
},
// `body` is JSON-serialised: a CEL value envelope
// `{ dialect: 'cel', source }` evaluated per run to the payload,
// or a literal sent as written.
body: {
description:
'Request body (JSON-serialised) — a CEL value envelope `{ dialect: \'cel\', source }` '
+ 'evaluated per run to the payload, or a literal sent as written',
description: 'What to send, as JSON: a fixed value, or an expression worked out on each run.',
},
// `durable: true` is fire-and-forget through the messaging HTTP
// outbox (retry / dead-letter) instead of an inline
// request / response.
durable: {
type: 'boolean',
description: 'Fire-and-forget via the durable outbox (retry/dead-letter) instead of inline request/response',
description:
'Deliver the request in the background and keep retrying if it fails, instead of '
+ 'waiting for the answer; the flow does not see the response.',
},
timeoutMs: { type: 'number', description: 'Per-request timeout (ms)' },
// Per-request timeout in milliseconds, on both arms; a literal
// number, read as written.
timeoutMs: { type: 'number', description: 'How long to wait for an answer, in milliseconds.' },
// The HMAC-SHA256 secret that signs the request body into the
// `X-Objectstack-Signature` header, on every arm; the secret
// itself, read as written (`''` sends unsigned on purpose).
signingSecret: {
type: 'string',
description: 'HMAC-SHA256 secret → X-Objectstack-Signature — the secret itself, read as written',
description:
'A shared secret used to sign each request, so the receiving service can check it came '
+ 'from you (sent as the X-Objectstack-Signature header).',
},
},
},
Expand Down
Loading