Skip to content

Commit 82ff91c

Browse files
authored
feat(automation)!: remove deprecated http_request/http_call/webhook flow-node aliases (ADR-0018 M3, 11.0) (#2369)
1 parent a658523 commit 82ff91c

21 files changed

Lines changed: 70 additions & 65 deletions
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
"@objectstack/spec": major
3+
"@objectstack/service-automation": major
4+
---
5+
6+
Remove the deprecated `http_request` / `http_call` / `webhook` flow-node aliases — author `http` (ADR-0018 M3).
7+
8+
ADR-0018 M3 collapsed the divergent outbound-callout verbs onto the canonical
9+
`http` node and kept the old names as deprecated aliases for back-compat. This
10+
removes those aliases (the 11.0 cleanup):
11+
12+
- `http_request` is dropped from `FlowNodeAction` (and therefore
13+
`FLOW_BUILTIN_NODE_TYPES`); authoring it now fails fast at parse instead of
14+
resolving to `http`.
15+
- `AutomationEngine` no longer registers the `http_request` / `http_call` /
16+
`webhook` node aliases; only `http` is registered.
17+
- The flow-builder palette offers `http`.
18+
19+
**Breaking.** Flows / workflow rules / approval actions that still use the old
20+
node type must switch to `type: 'http'` (behavior is identical — durable outbox
21+
when `config.durable`, inline fetch otherwise). The trigger `eventType: 'webhook'`
22+
and the `webhook` resume event are unaffected — only the HTTP *node* aliases are
23+
removed. First-party examples (showcase, app-crm) are migrated.

examples/app-crm/src/flows/lead-qualification.flow.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { Flow } from '@objectstack/spec/automation';
88
* Exercises the full breadth of the Flow node type repertoire:
99
* • assignment — initialise scoring variables
1010
* • get_record — fetch the related Account
11-
* • http_request — external enrichment API (with fault edge → error handler)
11+
* • http — external enrichment API (with fault edge → error handler)
1212
* • script — calculate a composite lead score
1313
* • decision — branch on score threshold (conditional + isDefault edges)
1414
* • parallel_gateway — AND-split: notify rep AND create Opportunity simultaneously
@@ -106,7 +106,7 @@ export const LeadQualificationFlow: Flow = {
106106
// A fault edge connects this node to error_handler if it fails.
107107
{
108108
id: 'enrich_lead',
109-
type: 'http_request',
109+
type: 'http',
110110
label: 'Enrich Lead (External API)',
111111
config: {
112112
method: 'POST',

examples/app-showcase/src/flows/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ export const ResilientSyncFlow = defineFlow({
824824
nodes: [
825825
{
826826
id: 'push',
827-
type: 'http_request',
827+
type: 'http',
828828
label: 'Push to CRM',
829829
config: {
830830
url: 'https://api.example.com/v1/tasks',
@@ -1009,7 +1009,7 @@ export const ProjectEscalationFlow = defineFlow({
10091009
retry: { maxRetries: 2, retryDelayMs: 500, backoffMultiplier: 2 },
10101010
errorVariable: '$error',
10111011
try: {
1012-
nodes: [{ id: 'push', type: 'http_request', label: 'POST incident', config: { url: 'https://api.example.com/v1/incidents', method: 'POST', body: { project: '{record.id}', severity: 'critical' } } }],
1012+
nodes: [{ id: 'push', type: 'http', label: 'POST incident', config: { url: 'https://api.example.com/v1/incidents', method: 'POST', body: { project: '{record.id}', severity: 'critical' } } }],
10131013
edges: [],
10141014
},
10151015
catch: {

packages/services/service-automation/src/builtin/connector-nodes.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ import type { AutomationEngine, ConnectorActionContext } from '../engine.js';
77
/**
88
* Connector built-in node — `connector_action` (generic integration dispatch).
99
*
10-
* Part of the platform baseline alongside `http_request` (ADR-0018 §Addendum):
11-
* where `http_request` calls *any raw URL*, `connector_action` invokes *any
10+
* Part of the platform baseline alongside `http` (ADR-0018 §Addendum):
11+
* where `http` calls *any raw URL*, `connector_action` invokes *any
1212
* registered connector's action*. The platform ships the generic dispatch node
1313
* + an (initially empty) connector registry on the engine; concrete connectors
1414
* — `connector-rest`, `connector-slack`, `connector-salesforce`, … — populate
1515
* the registry at runtime via `engine.registerConnector()`.
1616
*
1717
* Because the registry starts empty, a flow referencing a connector that no
1818
* plugin has registered fails the *step* with a clear error rather than failing
19-
* to register — graceful degradation matching `http_request`'s fail-soft style.
19+
* to register — graceful degradation matching `http`'s fail-soft style.
2020
*/
2121
export function registerConnectorNodes(engine: AutomationEngine, ctx: PluginContext): void {
2222
engine.registerNodeExecutor({

packages/services/service-automation/src/builtin/http-nodes.test.ts

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ function createCtx(messaging?: HttpSurface) {
2929
} as any;
3030
}
3131

32-
function httpFlow(type: 'http' | 'http_request' | 'http_call' | 'webhook', config: Record<string, unknown>) {
32+
function httpFlow(type: 'http', config: Record<string, unknown>) {
3333
return {
3434
name: 'http_flow',
3535
label: 'HTTP Flow',
@@ -50,7 +50,7 @@ function httpFlow(type: 'http' | 'http_request' | 'http_call' | 'webhook', confi
5050
};
5151
}
5252

53-
describe('http (canonical node) + deprecated aliases', () => {
53+
describe('http (canonical node)', () => {
5454
it('publishes a builtin io descriptor flagged needsOutbox', () => {
5555
const engine = new AutomationEngine(createTestLogger());
5656
registerHttpNodes(engine, createCtx());
@@ -61,14 +61,12 @@ describe('http (canonical node) + deprecated aliases', () => {
6161
expect(d?.paradigms).toEqual(expect.arrayContaining(['flow', 'approval']));
6262
});
6363

64-
it('registers http_request/http_call/webhook as deprecated aliases of http', () => {
64+
it('does NOT register the removed http_request/http_call/webhook aliases (11.0)', () => {
6565
const engine = new AutomationEngine(createTestLogger());
6666
registerHttpNodes(engine, createCtx());
67-
for (const alias of ['http_request', 'http_call', 'webhook']) {
68-
expect(engine.getRegisteredNodeTypes()).toContain(alias);
69-
const d = engine.getActionDescriptor(alias);
70-
expect(d?.deprecated).toBe(true);
71-
expect(d?.aliasOf).toBe('http');
67+
for (const removed of ['http_request', 'http_call', 'webhook']) {
68+
expect(engine.getRegisteredNodeTypes()).not.toContain(removed);
69+
expect(engine.getActionDescriptor(removed)).toBeUndefined();
7270
}
7371
});
7472

@@ -149,13 +147,5 @@ describe('http (canonical node) + deprecated aliases', () => {
149147
expect(result.error).toContain('url');
150148
});
151149

152-
it('a legacy http_request node still runs (via the alias → http)', async () => {
153-
const engine = new AutomationEngine(createTestLogger());
154-
registerHttpNodes(engine, createCtx());
155-
engine.registerFlow('http_flow', httpFlow('http_request', { url: 'https://legacy.test', method: 'GET' }));
156-
const result = await engine.execute('http_flow');
157-
expect(result.success).toBe(true);
158-
expect(fetchMock).toHaveBeenCalledOnce();
159-
});
160150
});
161151
});

packages/services/service-automation/src/builtin/http-nodes.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ import type { AutomationEngine } from '../engine.js';
77
import { interpolate } from './template.js';
88

99
/**
10-
* HTTP built-in node — canonical `http` (ADR-0018 M3) + deprecated aliases.
10+
* HTTP built-in node — canonical `http` (ADR-0018 M3).
1111
*
1212
* `http` is the single outbound-callout verb the platform offers Flow, Workflow
13-
* Rules and Approval. It replaces the five divergent names (`http_request` /
14-
* `http_call` / `webhook` / …) which are kept as **deprecated aliases** of
15-
* `http` for back-compat (registered via {@link AutomationEngine.registerNodeAlias}).
13+
* Rules and Approval. It supersedes the older divergent names (`http_request` /
14+
* `http_call` / `webhook`), which were removed in 11.0 — author `http`.
1615
*
1716
* Two execution modes:
1817
*
@@ -159,13 +158,7 @@ export function registerHttpNodes(engine: AutomationEngine, ctx: PluginContext):
159158
},
160159
});
161160

162-
// ADR-0018 M3: collapse the divergent outbound verbs onto `http`. Old saved
163-
// flows / workflow rules / approval actions keep running via these aliases.
164-
engine.registerNodeAlias('http_request', HTTP_TYPE, { name: 'HTTP Request', needsOutbox: true });
165-
engine.registerNodeAlias('http_call', HTTP_TYPE, { name: 'HTTP Call', needsOutbox: true });
166-
engine.registerNodeAlias('webhook', HTTP_TYPE, { name: 'Webhook', needsOutbox: true });
167-
168-
ctx.logger.info('[HTTP] http executor registered (+ deprecated aliases: http_request, http_call, webhook)');
161+
ctx.logger.info('[HTTP] http executor registered');
169162
}
170163

171164
/** Read a response body as JSON, falling back to text (empty body → null). */

packages/services/service-automation/src/builtin/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
* - logic — try_catch (structured try/catch/retry, ADR-0031)
1717
* - data — get/create/update/delete_record (platform CRUD baseline)
1818
* - human — screen / script (core flow capability)
19-
* - io — http_request (foundational outbound I/O)
19+
* - io — http (foundational outbound I/O)
2020
* - io — connector_action (generic integration dispatch)
2121
* - io — notify (outbound notification via messaging service)
2222
*
23-
* `connector_action` is the *generic dispatch* counterpart to `http_request`
23+
* `connector_action` is the *generic dispatch* counterpart to `http`
2424
* (ADR-0018 §Addendum): the platform ships the node + an (initially empty)
2525
* connector registry on the engine, and *concrete* connectors populate it at
2626
* runtime via `engine.registerConnector()`. Third-party node types continue to

packages/services/service-automation/src/builtin/notify-node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ function toStringList(value: unknown): string[] {
3636
/**
3737
* `notify` built-in node (ADR-0012) — outbound notification.
3838
*
39-
* Baseline node and the human-notification counterpart to `http_request`
39+
* Baseline node and the human-notification counterpart to `http`
4040
* ("raw call") and `connector_action` ("call a registered integration"):
4141
* `notify` hands a topic + recipients + message to the platform's messaging
4242
* service, which fans it out across the user's channels (inbox by default).

packages/services/service-automation/src/engine.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -862,9 +862,9 @@ describe('AutomationServicePlugin (Kernel Integration)', () => {
862862
expect(nodeTypes).toContain('script');
863863

864864
// HTTP node (foundational I/O)
865-
expect(nodeTypes).toContain('http_request');
865+
expect(nodeTypes).toContain('http');
866866

867-
// connector_action is the generic-dispatch sibling of http_request and is
867+
// connector_action is the generic-dispatch sibling of http and is
868868
// baseline (ADR-0018 §Addendum): the engine ships the node + an empty
869869
// connector registry; concrete connectors are plugins.
870870
expect(nodeTypes).toContain('connector_action');
@@ -1067,9 +1067,9 @@ describe('Built-in HTTP node', () => {
10671067
engine = kernel.getService<AutomationEngine>('automation');
10681068
});
10691069

1070-
it('should register the http_request node type', () => {
1070+
it('should register the http node type', () => {
10711071
const types = engine.getRegisteredNodeTypes();
1072-
expect(types).toContain('http_request');
1072+
expect(types).toContain('http');
10731073
});
10741074

10751075
it('should register connector_action in the built-in baseline', () => {
@@ -2175,11 +2175,11 @@ describe('Action Descriptor Registry (ADR-0018)', () => {
21752175
expect(byType.has('decision')).toBe(true);
21762176
expect(byType.get('decision')?.category).toBe('logic');
21772177
expect(byType.get('create_record')?.category).toBe('data');
2178-
expect(byType.get('http_request')?.category).toBe('io');
2178+
expect(byType.get('http')?.category).toBe('io');
21792179

21802180
// All built-ins are tagged source: 'builtin'.
21812181
expect(byType.get('decision')?.source).toBe('builtin');
2182-
expect(byType.get('http_request')?.source).toBe('builtin');
2182+
expect(byType.get('http')?.source).toBe('builtin');
21832183
});
21842184
});
21852185

packages/services/service-automation/src/plugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export interface AutomationServicePluginOptions {
3939
* Responsibilities:
4040
* 1. init phase: Create engine instance, register as 'automation' service, and
4141
* seed the platform's built-in node executors (logic / CRUD / screen-script /
42-
* http_request) via {@link installBuiltinNodes}. Per ADR-0018, foundational
42+
* http) via {@link installBuiltinNodes}. Per ADR-0018, foundational
4343
* capabilities are built into the core, not packaged as optional plugins.
4444
* 2. start phase: Trigger 'automation:ready' hook so third-party plugins can
4545
* register additional node types, then pull flow definitions from the

0 commit comments

Comments
 (0)