From b5ae1f29ed327f695e77f9c7fe04ca743b60eb38 Mon Sep 17 00:00:00 2001 From: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Date: Sat, 27 Jun 2026 21:35:21 +0800 Subject: [PATCH] feat(automation)!: remove deprecated http_request/http_call/webhook flow-node aliases (ADR-0018 M3, 11.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADR-0018 M3 collapsed the divergent outbound-callout verbs onto the canonical `http` node and kept the old names as deprecated aliases for back-compat. This removes them as part of the 11.0 breaking-change batch. - spec: drop `http_request` from `FlowNodeAction` (so it leaves `FLOW_BUILTIN_NODE_TYPES`); the flow-builder palette offers `http`; BPMN serviceTask maps to `http`. - service-automation: `registerHttpNodes` no longer registers the `http_request` / `http_call` / `webhook` aliases — only the canonical `http`. - examples (showcase, app-crm): migrated to `type: 'http'`. - tests updated; http-nodes gains a guard asserting the aliases are NOT registered. The trigger `eventType: 'webhook'` / `webhook` resume event are untouched — only the HTTP *node* aliases are removed. Authoring a removed type now fails fast at parse instead of silently resolving. Verified: spec (154) + service-automation (111) tests green; showcase + app-crm build clean (flows validate as `http`). Co-Authored-By: Claude Opus 4.8 --- .changeset/v11-remove-http-node-aliases.md | 23 +++++++++++++++++++ .../src/flows/lead-qualification.flow.ts | 4 ++-- examples/app-showcase/src/flows/index.ts | 4 ++-- .../src/builtin/connector-nodes.ts | 6 ++--- .../src/builtin/http-nodes.test.ts | 22 +++++------------- .../src/builtin/http-nodes.ts | 15 ++++-------- .../service-automation/src/builtin/index.ts | 4 ++-- .../src/builtin/notify-node.ts | 2 +- .../service-automation/src/engine.test.ts | 12 +++++----- .../services/service-automation/src/plugin.ts | 2 +- .../spec/src/automation/bpmn-interop.test.ts | 2 +- .../spec/src/automation/bpmn-interop.zod.ts | 2 +- .../spec/src/automation/bpmn-mapping.test.ts | 4 ++-- .../spec/src/automation/execution.test.ts | 6 ++--- packages/spec/src/automation/execution.zod.ts | 2 +- packages/spec/src/automation/flow.test.ts | 12 +++++----- packages/spec/src/automation/flow.zod.ts | 1 - .../spec/src/automation/node-executor.test.ts | 4 ++-- .../spec/src/automation/node-executor.zod.ts | 2 +- packages/spec/src/studio/flow-builder.test.ts | 4 ++-- packages/spec/src/studio/flow-builder.zod.ts | 2 +- 21 files changed, 70 insertions(+), 65 deletions(-) create mode 100644 .changeset/v11-remove-http-node-aliases.md diff --git a/.changeset/v11-remove-http-node-aliases.md b/.changeset/v11-remove-http-node-aliases.md new file mode 100644 index 0000000000..a5cd2d118a --- /dev/null +++ b/.changeset/v11-remove-http-node-aliases.md @@ -0,0 +1,23 @@ +--- +"@objectstack/spec": major +"@objectstack/service-automation": major +--- + +Remove the deprecated `http_request` / `http_call` / `webhook` flow-node aliases — author `http` (ADR-0018 M3). + +ADR-0018 M3 collapsed the divergent outbound-callout verbs onto the canonical +`http` node and kept the old names as deprecated aliases for back-compat. This +removes those aliases (the 11.0 cleanup): + +- `http_request` is dropped from `FlowNodeAction` (and therefore + `FLOW_BUILTIN_NODE_TYPES`); authoring it now fails fast at parse instead of + resolving to `http`. +- `AutomationEngine` no longer registers the `http_request` / `http_call` / + `webhook` node aliases; only `http` is registered. +- The flow-builder palette offers `http`. + +**Breaking.** Flows / workflow rules / approval actions that still use the old +node type must switch to `type: 'http'` (behavior is identical — durable outbox +when `config.durable`, inline fetch otherwise). The trigger `eventType: 'webhook'` +and the `webhook` resume event are unaffected — only the HTTP *node* aliases are +removed. First-party examples (showcase, app-crm) are migrated. diff --git a/examples/app-crm/src/flows/lead-qualification.flow.ts b/examples/app-crm/src/flows/lead-qualification.flow.ts index 66828057c3..c8e0ca5d10 100644 --- a/examples/app-crm/src/flows/lead-qualification.flow.ts +++ b/examples/app-crm/src/flows/lead-qualification.flow.ts @@ -8,7 +8,7 @@ import type { Flow } from '@objectstack/spec/automation'; * Exercises the full breadth of the Flow node type repertoire: * • assignment — initialise scoring variables * • get_record — fetch the related Account - * • http_request — external enrichment API (with fault edge → error handler) + * • http — external enrichment API (with fault edge → error handler) * • script — calculate a composite lead score * • decision — branch on score threshold (conditional + isDefault edges) * • parallel_gateway — AND-split: notify rep AND create Opportunity simultaneously @@ -106,7 +106,7 @@ export const LeadQualificationFlow: Flow = { // A fault edge connects this node to error_handler if it fails. { id: 'enrich_lead', - type: 'http_request', + type: 'http', label: 'Enrich Lead (External API)', config: { method: 'POST', diff --git a/examples/app-showcase/src/flows/index.ts b/examples/app-showcase/src/flows/index.ts index 283440255a..629af8b944 100644 --- a/examples/app-showcase/src/flows/index.ts +++ b/examples/app-showcase/src/flows/index.ts @@ -824,7 +824,7 @@ export const ResilientSyncFlow = defineFlow({ nodes: [ { id: 'push', - type: 'http_request', + type: 'http', label: 'Push to CRM', config: { url: 'https://api.example.com/v1/tasks', @@ -1009,7 +1009,7 @@ export const ProjectEscalationFlow = defineFlow({ retry: { maxRetries: 2, retryDelayMs: 500, backoffMultiplier: 2 }, errorVariable: '$error', try: { - 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' } } }], + nodes: [{ id: 'push', type: 'http', label: 'POST incident', config: { url: 'https://api.example.com/v1/incidents', method: 'POST', body: { project: '{record.id}', severity: 'critical' } } }], edges: [], }, catch: { diff --git a/packages/services/service-automation/src/builtin/connector-nodes.ts b/packages/services/service-automation/src/builtin/connector-nodes.ts index acb539a773..f12d4bc051 100644 --- a/packages/services/service-automation/src/builtin/connector-nodes.ts +++ b/packages/services/service-automation/src/builtin/connector-nodes.ts @@ -7,8 +7,8 @@ import type { AutomationEngine, ConnectorActionContext } from '../engine.js'; /** * Connector built-in node — `connector_action` (generic integration dispatch). * - * Part of the platform baseline alongside `http_request` (ADR-0018 §Addendum): - * where `http_request` calls *any raw URL*, `connector_action` invokes *any + * Part of the platform baseline alongside `http` (ADR-0018 §Addendum): + * where `http` calls *any raw URL*, `connector_action` invokes *any * registered connector's action*. The platform ships the generic dispatch node * + an (initially empty) connector registry on the engine; concrete connectors * — `connector-rest`, `connector-slack`, `connector-salesforce`, … — populate @@ -16,7 +16,7 @@ import type { AutomationEngine, ConnectorActionContext } from '../engine.js'; * * Because the registry starts empty, a flow referencing a connector that no * plugin has registered fails the *step* with a clear error rather than failing - * to register — graceful degradation matching `http_request`'s fail-soft style. + * to register — graceful degradation matching `http`'s fail-soft style. */ export function registerConnectorNodes(engine: AutomationEngine, ctx: PluginContext): void { engine.registerNodeExecutor({ diff --git a/packages/services/service-automation/src/builtin/http-nodes.test.ts b/packages/services/service-automation/src/builtin/http-nodes.test.ts index 69f2731685..7c4bb2be68 100644 --- a/packages/services/service-automation/src/builtin/http-nodes.test.ts +++ b/packages/services/service-automation/src/builtin/http-nodes.test.ts @@ -29,7 +29,7 @@ function createCtx(messaging?: HttpSurface) { } as any; } -function httpFlow(type: 'http' | 'http_request' | 'http_call' | 'webhook', config: Record) { +function httpFlow(type: 'http', config: Record) { return { name: 'http_flow', label: 'HTTP Flow', @@ -50,7 +50,7 @@ function httpFlow(type: 'http' | 'http_request' | 'http_call' | 'webhook', confi }; } -describe('http (canonical node) + deprecated aliases', () => { +describe('http (canonical node)', () => { it('publishes a builtin io descriptor flagged needsOutbox', () => { const engine = new AutomationEngine(createTestLogger()); registerHttpNodes(engine, createCtx()); @@ -61,14 +61,12 @@ describe('http (canonical node) + deprecated aliases', () => { expect(d?.paradigms).toEqual(expect.arrayContaining(['flow', 'approval'])); }); - it('registers http_request/http_call/webhook as deprecated aliases of http', () => { + it('does NOT register the removed http_request/http_call/webhook aliases (11.0)', () => { const engine = new AutomationEngine(createTestLogger()); registerHttpNodes(engine, createCtx()); - for (const alias of ['http_request', 'http_call', 'webhook']) { - expect(engine.getRegisteredNodeTypes()).toContain(alias); - const d = engine.getActionDescriptor(alias); - expect(d?.deprecated).toBe(true); - expect(d?.aliasOf).toBe('http'); + for (const removed of ['http_request', 'http_call', 'webhook']) { + expect(engine.getRegisteredNodeTypes()).not.toContain(removed); + expect(engine.getActionDescriptor(removed)).toBeUndefined(); } }); @@ -149,13 +147,5 @@ describe('http (canonical node) + deprecated aliases', () => { expect(result.error).toContain('url'); }); - it('a legacy http_request node still runs (via the alias → http)', async () => { - const engine = new AutomationEngine(createTestLogger()); - registerHttpNodes(engine, createCtx()); - engine.registerFlow('http_flow', httpFlow('http_request', { url: 'https://legacy.test', method: 'GET' })); - const result = await engine.execute('http_flow'); - expect(result.success).toBe(true); - expect(fetchMock).toHaveBeenCalledOnce(); - }); }); }); diff --git a/packages/services/service-automation/src/builtin/http-nodes.ts b/packages/services/service-automation/src/builtin/http-nodes.ts index e99f19af36..3aa9540dc3 100644 --- a/packages/services/service-automation/src/builtin/http-nodes.ts +++ b/packages/services/service-automation/src/builtin/http-nodes.ts @@ -7,12 +7,11 @@ import type { AutomationEngine } from '../engine.js'; import { interpolate } from './template.js'; /** - * HTTP built-in node — canonical `http` (ADR-0018 M3) + deprecated aliases. + * HTTP built-in node — canonical `http` (ADR-0018 M3). * * `http` is the single outbound-callout verb the platform offers Flow, Workflow - * Rules and Approval. It replaces the five divergent names (`http_request` / - * `http_call` / `webhook` / …) which are kept as **deprecated aliases** of - * `http` for back-compat (registered via {@link AutomationEngine.registerNodeAlias}). + * Rules and Approval. It supersedes the older divergent names (`http_request` / + * `http_call` / `webhook`), which were removed in 11.0 — author `http`. * * Two execution modes: * @@ -159,13 +158,7 @@ export function registerHttpNodes(engine: AutomationEngine, ctx: PluginContext): }, }); - // ADR-0018 M3: collapse the divergent outbound verbs onto `http`. Old saved - // flows / workflow rules / approval actions keep running via these aliases. - engine.registerNodeAlias('http_request', HTTP_TYPE, { name: 'HTTP Request', needsOutbox: true }); - engine.registerNodeAlias('http_call', HTTP_TYPE, { name: 'HTTP Call', needsOutbox: true }); - engine.registerNodeAlias('webhook', HTTP_TYPE, { name: 'Webhook', needsOutbox: true }); - - ctx.logger.info('[HTTP] http executor registered (+ deprecated aliases: http_request, http_call, webhook)'); + ctx.logger.info('[HTTP] http executor registered'); } /** Read a response body as JSON, falling back to text (empty body → null). */ diff --git a/packages/services/service-automation/src/builtin/index.ts b/packages/services/service-automation/src/builtin/index.ts index 1ef6f674e2..fdfb2c5481 100644 --- a/packages/services/service-automation/src/builtin/index.ts +++ b/packages/services/service-automation/src/builtin/index.ts @@ -16,11 +16,11 @@ * - logic — try_catch (structured try/catch/retry, ADR-0031) * - data — get/create/update/delete_record (platform CRUD baseline) * - human — screen / script (core flow capability) - * - io — http_request (foundational outbound I/O) + * - io — http (foundational outbound I/O) * - io — connector_action (generic integration dispatch) * - io — notify (outbound notification via messaging service) * - * `connector_action` is the *generic dispatch* counterpart to `http_request` + * `connector_action` is the *generic dispatch* counterpart to `http` * (ADR-0018 §Addendum): the platform ships the node + an (initially empty) * connector registry on the engine, and *concrete* connectors populate it at * runtime via `engine.registerConnector()`. Third-party node types continue to diff --git a/packages/services/service-automation/src/builtin/notify-node.ts b/packages/services/service-automation/src/builtin/notify-node.ts index 2f5aaee1b9..3b5716520c 100644 --- a/packages/services/service-automation/src/builtin/notify-node.ts +++ b/packages/services/service-automation/src/builtin/notify-node.ts @@ -36,7 +36,7 @@ function toStringList(value: unknown): string[] { /** * `notify` built-in node (ADR-0012) — outbound notification. * - * Baseline node and the human-notification counterpart to `http_request` + * Baseline node and the human-notification counterpart to `http` * ("raw call") and `connector_action` ("call a registered integration"): * `notify` hands a topic + recipients + message to the platform's messaging * service, which fans it out across the user's channels (inbox by default). diff --git a/packages/services/service-automation/src/engine.test.ts b/packages/services/service-automation/src/engine.test.ts index 8a3bdc1c03..48192ba8cc 100644 --- a/packages/services/service-automation/src/engine.test.ts +++ b/packages/services/service-automation/src/engine.test.ts @@ -862,9 +862,9 @@ describe('AutomationServicePlugin (Kernel Integration)', () => { expect(nodeTypes).toContain('script'); // HTTP node (foundational I/O) - expect(nodeTypes).toContain('http_request'); + expect(nodeTypes).toContain('http'); - // connector_action is the generic-dispatch sibling of http_request and is + // connector_action is the generic-dispatch sibling of http and is // baseline (ADR-0018 §Addendum): the engine ships the node + an empty // connector registry; concrete connectors are plugins. expect(nodeTypes).toContain('connector_action'); @@ -1067,9 +1067,9 @@ describe('Built-in HTTP node', () => { engine = kernel.getService('automation'); }); - it('should register the http_request node type', () => { + it('should register the http node type', () => { const types = engine.getRegisteredNodeTypes(); - expect(types).toContain('http_request'); + expect(types).toContain('http'); }); it('should register connector_action in the built-in baseline', () => { @@ -2175,11 +2175,11 @@ describe('Action Descriptor Registry (ADR-0018)', () => { expect(byType.has('decision')).toBe(true); expect(byType.get('decision')?.category).toBe('logic'); expect(byType.get('create_record')?.category).toBe('data'); - expect(byType.get('http_request')?.category).toBe('io'); + expect(byType.get('http')?.category).toBe('io'); // All built-ins are tagged source: 'builtin'. expect(byType.get('decision')?.source).toBe('builtin'); - expect(byType.get('http_request')?.source).toBe('builtin'); + expect(byType.get('http')?.source).toBe('builtin'); }); }); diff --git a/packages/services/service-automation/src/plugin.ts b/packages/services/service-automation/src/plugin.ts index 012b7e6d83..56c78e668e 100644 --- a/packages/services/service-automation/src/plugin.ts +++ b/packages/services/service-automation/src/plugin.ts @@ -39,7 +39,7 @@ export interface AutomationServicePluginOptions { * Responsibilities: * 1. init phase: Create engine instance, register as 'automation' service, and * seed the platform's built-in node executors (logic / CRUD / screen-script / - * http_request) via {@link installBuiltinNodes}. Per ADR-0018, foundational + * http) via {@link installBuiltinNodes}. Per ADR-0018, foundational * capabilities are built into the core, not packaged as optional plugins. * 2. start phase: Trigger 'automation:ready' hook so third-party plugins can * register additional node types, then pull flow definitions from the diff --git a/packages/spec/src/automation/bpmn-interop.test.ts b/packages/spec/src/automation/bpmn-interop.test.ts index f43ed5e86b..a7a2d2438d 100644 --- a/packages/spec/src/automation/bpmn-interop.test.ts +++ b/packages/spec/src/automation/bpmn-interop.test.ts @@ -29,7 +29,7 @@ describe('BpmnElementMappingSchema', () => { it('should accept mapping with notes', () => { const mapping = BpmnElementMappingSchema.parse({ bpmnType: 'bpmn:serviceTask', - flowNodeAction: 'http_request', + flowNodeAction: 'http', bidirectional: true, notes: 'Maps HTTP/connector tasks', }); diff --git a/packages/spec/src/automation/bpmn-interop.zod.ts b/packages/spec/src/automation/bpmn-interop.zod.ts index b3355867f3..2e2617c211 100644 --- a/packages/spec/src/automation/bpmn-interop.zod.ts +++ b/packages/spec/src/automation/bpmn-interop.zod.ts @@ -179,7 +179,7 @@ export const BUILT_IN_BPMN_MAPPINGS: BpmnElementMapping[] = [ { bpmnType: 'bpmn:endEvent', flowNodeAction: 'end', bidirectional: true }, { bpmnType: 'bpmn:exclusiveGateway', flowNodeAction: 'decision', bidirectional: true }, { bpmnType: 'bpmn:parallelGateway', flowNodeAction: 'parallel_gateway', bidirectional: true }, - { bpmnType: 'bpmn:serviceTask', flowNodeAction: 'http_request', bidirectional: true, notes: 'Maps HTTP/connector tasks' }, + { bpmnType: 'bpmn:serviceTask', flowNodeAction: 'http', bidirectional: true, notes: 'Maps HTTP/connector tasks' }, { bpmnType: 'bpmn:scriptTask', flowNodeAction: 'script', bidirectional: true }, { bpmnType: 'bpmn:userTask', flowNodeAction: 'screen', bidirectional: true }, { bpmnType: 'bpmn:callActivity', flowNodeAction: 'subflow', bidirectional: true }, diff --git a/packages/spec/src/automation/bpmn-mapping.test.ts b/packages/spec/src/automation/bpmn-mapping.test.ts index 57f9a70f1e..f8cb9bdbff 100644 --- a/packages/spec/src/automation/bpmn-mapping.test.ts +++ b/packages/spec/src/automation/bpmn-mapping.test.ts @@ -77,7 +77,7 @@ describe('exportConstructsToBpmn — try_catch', () => { nodes: [ node('start', 'start'), node('tc', 'try_catch', { - try: { nodes: [node('charge', 'http_request')], edges: [] }, + try: { nodes: [node('charge', 'http')], edges: [] }, catch: { nodes: [node('flag', 'update_record')], edges: [] }, errorVariable: '$error', retry: { maxRetries: 2, retryDelayMs: 100 }, @@ -179,7 +179,7 @@ describe('importBpmnToConstructs — foreign BPMN (no markers)', () => { it('warns (does not fold) a foreign boundary_event with no marker', () => { const foreign: MappableFlow = { - nodes: [node('host', 'http_request'), node('b', BPMN_BOUNDARY_EVENT)], + nodes: [node('host', 'http'), node('b', BPMN_BOUNDARY_EVENT)], edges: [], }; const { diagnostics, unmappedCount } = importBpmnToConstructs(foreign); diff --git a/packages/spec/src/automation/execution.test.ts b/packages/spec/src/automation/execution.test.ts index 6146a8c8a2..a9203be241 100644 --- a/packages/spec/src/automation/execution.test.ts +++ b/packages/spec/src/automation/execution.test.ts @@ -50,8 +50,8 @@ describe('ExecutionStepLogSchema', () => { it('should accept a step log with error details', () => { const step = ExecutionStepLogSchema.parse({ - nodeId: 'http_request', - nodeType: 'http_request', + nodeId: 'http', + nodeType: 'http', nodeLabel: 'Call External API', status: 'failure', startedAt: '2026-02-01T10:00:00Z', @@ -178,7 +178,7 @@ describe('ExecutionErrorSchema', () => { const error = ExecutionErrorSchema.parse({ id: 'err_001', executionId: 'exec_001', - nodeId: 'http_request', + nodeId: 'http', severity: 'error', code: 'HTTP_TIMEOUT', message: 'Request timed out after 30s', diff --git a/packages/spec/src/automation/execution.zod.ts b/packages/spec/src/automation/execution.zod.ts index e5646f179a..131ea0a2ae 100644 --- a/packages/spec/src/automation/execution.zod.ts +++ b/packages/spec/src/automation/execution.zod.ts @@ -44,7 +44,7 @@ export type ExecutionStatus = z.infer; */ export const ExecutionStepLogSchema = lazySchema(() => z.object({ nodeId: z.string().describe('Node ID that was executed'), - nodeType: z.string().describe('Node action type (e.g., "decision", "http_request")'), + nodeType: z.string().describe('Node action type (e.g., "decision", "http")'), nodeLabel: z.string().optional().describe('Human-readable node label'), status: z.enum(['success', 'failure', 'skipped']).describe('Step execution result'), startedAt: z.string().datetime().describe('When the step started'), diff --git a/packages/spec/src/automation/flow.test.ts b/packages/spec/src/automation/flow.test.ts index a5339a0f39..80817c9403 100644 --- a/packages/spec/src/automation/flow.test.ts +++ b/packages/spec/src/automation/flow.test.ts @@ -17,7 +17,7 @@ describe('FlowNodeAction', () => { const actions = [ 'start', 'end', 'decision', 'assignment', 'loop', 'create_record', 'update_record', 'delete_record', 'get_record', - 'http_request', 'notify', 'script', 'screen', 'wait', 'subflow', 'connector_action', + 'http', 'notify', 'script', 'screen', 'wait', 'subflow', 'connector_action', 'parallel_gateway', 'join_gateway', 'boundary_event', ]; @@ -120,7 +120,7 @@ describe('FlowNodeSchema', () => { const types = [ 'start', 'end', 'decision', 'assignment', 'loop', 'create_record', 'update_record', 'delete_record', 'get_record', - 'http_request', 'notify', 'script', 'screen', 'wait', 'subflow', 'connector_action', + 'http', 'notify', 'script', 'screen', 'wait', 'subflow', 'connector_action', 'parallel_gateway', 'join_gateway', 'boundary_event', ] as const; @@ -137,7 +137,7 @@ describe('FlowNodeSchema', () => { it('should accept node with timeoutMs', () => { const result = FlowNodeSchema.safeParse({ id: 'http_1', - type: 'http_request', + type: 'http', label: 'Call API', timeoutMs: 5000, }); @@ -372,7 +372,7 @@ describe('FlowSchema', () => { }, { id: 'send_approval_request', - type: 'http_request', + type: 'http', label: 'Send to Manager', config: { url: '/api/approvals', @@ -528,7 +528,7 @@ describe('FlowSchema', () => { { id: 'start', type: 'start', label: 'Start' }, { id: 'call_external_api', - type: 'http_request', + type: 'http', label: 'Call External API', config: { url: 'https://api.external.com/v1/data', @@ -1041,7 +1041,7 @@ describe('BPMN — Boundary Event', () => { type: 'autolaunched', nodes: [ { id: 'start', type: 'start', label: 'Start' }, - { id: 'api_call', type: 'http_request', label: 'Call External API', timeoutMs: 5000 }, + { id: 'api_call', type: 'http', label: 'Call External API', timeoutMs: 5000 }, { id: 'api_error_boundary', type: 'boundary_event', diff --git a/packages/spec/src/automation/flow.zod.ts b/packages/spec/src/automation/flow.zod.ts index 20fe402cab..163592380d 100644 --- a/packages/spec/src/automation/flow.zod.ts +++ b/packages/spec/src/automation/flow.zod.ts @@ -30,7 +30,6 @@ export const FlowNodeAction = z.enum([ 'delete_record', // CRUD: Delete 'get_record', // CRUD: Get/Query 'http', // Outbound HTTP callout (ADR-0018 M3) — canonical; outbox-backed when durable - 'http_request', // Deprecated alias of `http` (ADR-0018 M3) 'notify', // Outbound notification (ADR-0012) — dispatched via the messaging service 'script', // Custom action: a built-in side-effect (`config.actionType: 'email'|'slack'`) // or a registered function (`config.function: 'name'` + `config.inputs`), diff --git a/packages/spec/src/automation/node-executor.test.ts b/packages/spec/src/automation/node-executor.test.ts index fdecdc9029..fd9a4b33e4 100644 --- a/packages/spec/src/automation/node-executor.test.ts +++ b/packages/spec/src/automation/node-executor.test.ts @@ -177,7 +177,7 @@ describe('NodeExecutorDescriptorSchema', () => { const desc = NodeExecutorDescriptorSchema.parse({ id: 'objectstack:http-executor', name: 'HTTP Request Executor', - nodeTypes: ['http_request', 'connector_action'], + nodeTypes: ['http', 'connector_action'], version: '2.0.0', description: 'Executes HTTP requests and connector actions', supportsPause: false, @@ -185,7 +185,7 @@ describe('NodeExecutorDescriptorSchema', () => { supportsRetry: true, configSchemaRef: '#/definitions/HttpExecutorConfig', }); - expect(desc.nodeTypes).toContain('http_request'); + expect(desc.nodeTypes).toContain('http'); expect(desc.nodeTypes).toContain('connector_action'); expect(desc.supportsCancellation).toBe(true); }); diff --git a/packages/spec/src/automation/node-executor.zod.ts b/packages/spec/src/automation/node-executor.zod.ts index 1968e2d7fa..3bec43c1ff 100644 --- a/packages/spec/src/automation/node-executor.zod.ts +++ b/packages/spec/src/automation/node-executor.zod.ts @@ -126,7 +126,7 @@ export type WaitExecutorConfig = z.infer; /** * Generic node executor plugin descriptor. - * Each node type (wait, script, http_request, etc.) can register + * Each node type (wait, script, http, etc.) can register * a custom executor via this descriptor. */ export const NodeExecutorDescriptorSchema = lazySchema(() => z.object({ diff --git a/packages/spec/src/studio/flow-builder.test.ts b/packages/spec/src/studio/flow-builder.test.ts index 9f84ea1cc0..5e3564f703 100644 --- a/packages/spec/src/studio/flow-builder.test.ts +++ b/packages/spec/src/studio/flow-builder.test.ts @@ -237,7 +237,7 @@ describe('BUILT_IN_NODE_DESCRIPTORS', () => { expect(actions).toContain('update_record'); expect(actions).toContain('delete_record'); expect(actions).toContain('get_record'); - expect(actions).toContain('http_request'); + expect(actions).toContain('http'); expect(actions).toContain('script'); expect(actions).toContain('screen'); expect(actions).toContain('loop'); @@ -266,7 +266,7 @@ describe('BUILT_IN_NODE_DESCRIPTORS', () => { it('should mark activity nodes as allowing boundary events', () => { const activities = BUILT_IN_NODE_DESCRIPTORS.filter(d => - ['assignment', 'http_request', 'script', 'create_record', 'update_record', 'delete_record', 'get_record', 'loop', 'subflow', 'connector_action', 'wait'].includes(d.action) + ['assignment', 'http', 'script', 'create_record', 'update_record', 'delete_record', 'get_record', 'loop', 'subflow', 'connector_action', 'wait'].includes(d.action) ); activities.forEach(a => { expect(a.allowBoundaryEvents).toBe(true); diff --git a/packages/spec/src/studio/flow-builder.zod.ts b/packages/spec/src/studio/flow-builder.zod.ts index 3568887beb..b0057b6615 100644 --- a/packages/spec/src/studio/flow-builder.zod.ts +++ b/packages/spec/src/studio/flow-builder.zod.ts @@ -279,7 +279,7 @@ export const BUILT_IN_NODE_DESCRIPTORS: FlowNodeRenderDescriptor[] = [ { action: 'update_record', shape: 'rounded_rect', icon: 'edit', defaultLabel: 'Update Record', defaultWidth: 120, defaultHeight: 60, fillColor: '#ffffff', borderColor: '#94a3b8', allowBoundaryEvents: true, paletteCategory: 'data' }, { action: 'delete_record', shape: 'rounded_rect', icon: 'trash-2', defaultLabel: 'Delete Record', defaultWidth: 120, defaultHeight: 60, fillColor: '#ffffff', borderColor: '#94a3b8', allowBoundaryEvents: true, paletteCategory: 'data' }, { action: 'get_record', shape: 'rounded_rect', icon: 'search', defaultLabel: 'Get Record', defaultWidth: 120, defaultHeight: 60, fillColor: '#ffffff', borderColor: '#94a3b8', allowBoundaryEvents: true, paletteCategory: 'data' }, - { action: 'http_request', shape: 'rounded_rect', icon: 'globe', defaultLabel: 'HTTP Request', defaultWidth: 120, defaultHeight: 60, fillColor: '#ffffff', borderColor: '#94a3b8', allowBoundaryEvents: true, paletteCategory: 'activity' }, + { action: 'http', shape: 'rounded_rect', icon: 'globe', defaultLabel: 'HTTP Request', defaultWidth: 120, defaultHeight: 60, fillColor: '#ffffff', borderColor: '#94a3b8', allowBoundaryEvents: true, paletteCategory: 'activity' }, { action: 'script', shape: 'rounded_rect', icon: 'code', defaultLabel: 'Script', defaultWidth: 120, defaultHeight: 60, fillColor: '#ffffff', borderColor: '#94a3b8', allowBoundaryEvents: true, paletteCategory: 'activity' }, { action: 'screen', shape: 'screen_rect', icon: 'monitor', defaultLabel: 'Screen', defaultWidth: 140, defaultHeight: 80, fillColor: '#f0f9ff', borderColor: '#0284c7', allowBoundaryEvents: false, paletteCategory: 'activity' }, { action: 'loop', shape: 'parallelogram', icon: 'repeat', defaultLabel: 'Loop', defaultWidth: 120, defaultHeight: 60, fillColor: '#fef3c7', borderColor: '#d97706', allowBoundaryEvents: true, paletteCategory: 'activity' },