@frontera-sdk/workflow 1.50.62-next.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/src/types.ts ADDED
@@ -0,0 +1,483 @@
1
+ import type { InputsSchema } from '@frontera-sdk/functions'
2
+
3
+ export type WorkflowRunStatus = 'queued' | 'running' | 'succeeded' | 'failed' | 'canceled'
4
+ export type WorkflowNodeStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'skipped' | 'canceled'
5
+
6
+ export const TERMINAL_RUN_STATUSES: ReadonlySet<WorkflowRunStatus> = new Set<WorkflowRunStatus>([
7
+ 'succeeded',
8
+ 'failed',
9
+ 'canceled',
10
+ ])
11
+
12
+ export function isTerminalRunStatus(status: string): boolean {
13
+ return TERMINAL_RUN_STATUSES.has(status as WorkflowRunStatus)
14
+ }
15
+
16
+ /** A row of `GET /v1/workflows`. */
17
+ export interface WorkflowSummary {
18
+ id: string
19
+ slug: string
20
+ enabled: boolean
21
+ description: string | null
22
+ liveVersion: number | null
23
+ latestDraftNumber: number | null
24
+ versionCount: number
25
+ runCount: number
26
+ lastRunAt: string | null
27
+ lastRunStatus: WorkflowRunStatus | null
28
+ triggerKinds: string[]
29
+ cron: string | null
30
+ subjectApiName: string | null
31
+ subjectLabel: string | null
32
+ /** One per webhook trigger. Absent from a service that predates webhooks. */
33
+ webhooks?: WorkflowWebhook[]
34
+ }
35
+
36
+ export interface WorkflowWebhook {
37
+ methods: string[]
38
+ path: string
39
+ auth: string
40
+ respond: string
41
+ url: string
42
+ testUrl: string
43
+ }
44
+
45
+ /** The whole workflow row, which the two create routes answer with. */
46
+ export interface Workflow {
47
+ id: string
48
+ orgId: string
49
+ workspaceId: string
50
+ slug: string
51
+ displayName: string | null
52
+ subjectObjectTypeId: string | null
53
+ enabled: boolean
54
+ liveVersionId: string | null
55
+ testHookVersionId: string | null
56
+ testHookUntil: string | null
57
+ createdBy: string
58
+ createdAt: string
59
+ }
60
+
61
+ export interface CreateWorkflowInput {
62
+ /** Lowercase, digits and hyphens; unique in the workspace. */
63
+ slug: string
64
+ /** A Blueprint object type id. Every run is then about one of its objects. */
65
+ subjectObjectTypeId?: string
66
+ }
67
+
68
+ /** `createDraft`: the workflow and the empty draft made with it, in one write. */
69
+ export interface WorkflowDraft {
70
+ workflow: Workflow
71
+ version: { id: string; number: number; status: WorkflowVersionStatus }
72
+ }
73
+
74
+ /** What `rename` answers with. The slug does not move with the name. */
75
+ export interface RenameResult {
76
+ id: string
77
+ slug: string
78
+ displayName: string
79
+ }
80
+
81
+ export interface EnabledResult {
82
+ id: string
83
+ enabled: boolean
84
+ }
85
+
86
+ export interface WorkflowDeleteResult {
87
+ deleted: boolean
88
+ runsDeleted: number
89
+ }
90
+
91
+ /** Answered by the two routes that remove a version or a binding. */
92
+ export interface DeletedResult {
93
+ deleted: boolean
94
+ }
95
+
96
+ /** draft | live | draining | retired */
97
+ export type WorkflowVersionStatus = 'draft' | 'live' | 'draining' | 'retired'
98
+
99
+ /** A row of `GET /v1/workflows/:slug/versions`, narrowed to what a listing shows. */
100
+ export interface VersionSummary {
101
+ id: string
102
+ number: number
103
+ status: WorkflowVersionStatus
104
+ createdAt: string
105
+ createdVia: string | null
106
+ }
107
+
108
+ /** The whole row `GET /v1/workflows/:slug/versions/:n` answers with. */
109
+ export interface WorkflowVersion {
110
+ id: string
111
+ workflowId: string
112
+ number: number
113
+ status: WorkflowVersionStatus
114
+ definition: Record<string, unknown>
115
+ grants: string[]
116
+ lineage: LineageEdge[]
117
+ inputSchema: InputsSchema | null
118
+ /** Presentation only; null means none saved. */
119
+ layout?: WorkflowLayout | null
120
+ createdVia: string | null
121
+ createdBy: string
122
+ createdAt: string
123
+ }
124
+
125
+ /** Canvas card positions keyed by node id. Never read by the engine. */
126
+ export type WorkflowLayout = Record<string, { x: number; y: number }>
127
+
128
+ /** What `saveLayout` answers with. */
129
+ export interface LayoutResult {
130
+ versionId: string
131
+ number: number
132
+ layout: WorkflowLayout | null
133
+ }
134
+
135
+ /**
136
+ * One step run on its own against the draft's newest test data.
137
+ *
138
+ * `ok: false` is the step failing, not the request failing — a 200 carries it.
139
+ * `preview` marks a kind that only reports what it would do, so its output is
140
+ * never what a real run would put in `$steps`.
141
+ */
142
+ export type NodeTestResult =
143
+ | { ok: true; nodeId: string; kind: string; mocked: boolean; preview?: boolean; input: unknown; output: unknown }
144
+ | {
145
+ ok: false
146
+ nodeId: string
147
+ kind: string
148
+ mocked: boolean
149
+ preview?: boolean
150
+ input: unknown
151
+ error: Record<string, unknown>
152
+ }
153
+
154
+ /** One step's newest stored step test, as `stepTests` lists them. */
155
+ export interface StepTest {
156
+ nodeId: string
157
+ kind: string
158
+ status: 'succeeded' | 'failed'
159
+ mocked: boolean
160
+ preview: boolean
161
+ input: unknown
162
+ output: unknown
163
+ error: Record<string, unknown> | null
164
+ testedAt: string
165
+ }
166
+
167
+ /** How long the draft's test webhook URL stays armed, ISO. */
168
+ export interface WebhookTestWindow {
169
+ until: string
170
+ }
171
+
172
+ /**
173
+ * What a push answers with.
174
+ *
175
+ * `ok: false` is a result, not a transport failure, and only on a dry run. A
176
+ * real push that fails validation comes back as a 400 whose
177
+ * `FronteraError.details.errors` lists the reasons.
178
+ */
179
+ export interface PushResult {
180
+ ok: boolean
181
+ errors?: string[]
182
+ workflowId?: string
183
+ version?: { id: string; number: number; status: WorkflowVersionStatus }
184
+ grants?: string[]
185
+ lineage?: LineageEdge[]
186
+ }
187
+
188
+ export interface PromoteResult {
189
+ workflowId: string
190
+ versionId: string
191
+ /** True when the version was already live and nothing changed. */
192
+ alreadyLive: boolean
193
+ }
194
+
195
+ export interface LineageEdge {
196
+ kind: string
197
+ resourceKind: string
198
+ resourceId: string
199
+ label?: string | null
200
+ property?: string | null
201
+ nodeId?: string | null
202
+ }
203
+
204
+ export interface VersionLineage {
205
+ version: number
206
+ status: WorkflowVersionStatus
207
+ grants: string[]
208
+ lineage: LineageEdge[]
209
+ }
210
+
211
+ export interface RunRequest {
212
+ /**
213
+ * A `File` value here is sent as its own multipart part, named after the
214
+ * `file` input it fills; everything else travels as JSON.
215
+ */
216
+ input?: Record<string, unknown>
217
+ subject?: { pk: string }
218
+ /** A version number; without it the live version runs. */
219
+ version?: number
220
+ /** `test` is allowed only against a draft. */
221
+ source?: 'manual' | 'test'
222
+ }
223
+
224
+ export interface RunResult {
225
+ runId: string
226
+ versionNumber: number
227
+ /** True when an idempotency key matched a run that already existed. */
228
+ reused?: boolean
229
+ }
230
+
231
+ /** A row of `GET /v1/workflows/:slug/runs`. */
232
+ export interface RunSummary {
233
+ id: string
234
+ orgId: string
235
+ workflowId: string
236
+ versionId: string
237
+ status: WorkflowRunStatus
238
+ triggerSource: string
239
+ triggerIndex: number | null
240
+ triggeredBy: string | null
241
+ subjectObjectTypeId: string | null
242
+ subjectPk: string | null
243
+ rootRunId: string | null
244
+ parentRunId: string | null
245
+ depth: number
246
+ input: Record<string, unknown>
247
+ output: unknown
248
+ error: Record<string, unknown> | null
249
+ nodeCalls: number
250
+ conversationId: string | null
251
+ idempotencyKey: string | null
252
+ invocationDepth: number
253
+ iteration: { nodePath: string; nodeId: string; index: number; item: unknown; outerSteps: Record<string, unknown> } | null
254
+ startedAt: string
255
+ endedAt: string | null
256
+ versionNumber: number
257
+ workflowSlug: string
258
+ workflowDisplayName: string | null
259
+ triggeredByName: string | null
260
+ triggeredByEmail: string | null
261
+ subjectLabel: string | null
262
+ }
263
+
264
+ export type RunListFilters = {
265
+ /** `live` hides test runs; `test` shows only them. */
266
+ source?: 'live' | 'test'
267
+ status?: WorkflowRunStatus
268
+ /** Default 50, maximum 200. */
269
+ limit?: number
270
+ /** Keyset cursor `<startedAt ISO>|<run id>`; see `runCursor`. */
271
+ before?: string
272
+ from?: string
273
+ to?: string
274
+ }
275
+
276
+ /**
277
+ * `workspaceRuns` filters: the per-workflow set plus the slug that narrows to
278
+ * one workflow. A `type`, not an `interface`, because it is passed as a query
279
+ * bag and only a type alias carries an implicit index signature.
280
+ */
281
+ export type WorkspaceRunListFilters = RunListFilters & {
282
+ /** A workflow slug. Without it, every workflow in the workspace is included. */
283
+ workflow?: string
284
+ }
285
+
286
+ export type RunMetricsPeriod = '24h' | '7d' | '30d' | '90d'
287
+
288
+ export type RunMetricsQuery = {
289
+ /** Default `7d`. */
290
+ period?: RunMetricsPeriod
291
+ /** A workflow slug; without it the whole workspace is counted. */
292
+ workflow?: string
293
+ }
294
+
295
+ /** Run counts over one window. Test runs and forEach children are excluded. */
296
+ export interface RunMetricsTotals {
297
+ runs: number
298
+ succeeded: number
299
+ failed: number
300
+ canceled: number
301
+ running: number
302
+ /** Succeeded over finished. Null when nothing finished in the window. */
303
+ successRate: number | null
304
+ p50DurationMs: number | null
305
+ p95DurationMs: number | null
306
+ nodeCalls: number
307
+ lastRunAt: string | null
308
+ }
309
+
310
+ export interface RunMetricsByWorkflow extends RunMetricsTotals {
311
+ workflowId: string
312
+ workflowSlug: string
313
+ }
314
+
315
+ export interface RunVolumeBucket {
316
+ /** Bucket start, ISO. */
317
+ at: string
318
+ succeeded: number
319
+ failed: number
320
+ }
321
+
322
+ export interface RunMetrics {
323
+ period: RunMetricsPeriod
324
+ /** The current window, ISO; `to` is exclusive. `previous` is the span before it. */
325
+ range: { from: string; to: string }
326
+ granularity: 'hour' | 'day' | 'week' | 'month'
327
+ current: RunMetricsTotals
328
+ previous: RunMetricsTotals
329
+ buckets: RunVolumeBucket[]
330
+ byWorkflow: RunMetricsByWorkflow[]
331
+ }
332
+
333
+ /** A step output stored by reference, read back whole. */
334
+ export interface NodeOutput {
335
+ id: string
336
+ runId: string
337
+ nodeId: string
338
+ output: unknown
339
+ }
340
+
341
+ /** `run` implies `read`; `read` grants the observation tools and no run tool. */
342
+ export type BindingAccess = 'read' | 'run'
343
+
344
+ /** One agent's standing permission on one workflow, from the workflow's side. */
345
+ export interface WorkflowBinding {
346
+ agentId: string
347
+ agentSlug: string
348
+ agentName: string
349
+ enabled: boolean
350
+ access: BindingAccess
351
+ requiresApproval: boolean
352
+ waitSeconds: number
353
+ createdBy: string
354
+ createdAt: string
355
+ }
356
+
357
+ /**
358
+ * The same permission from the agent's side, plus whether it currently grants
359
+ * anything: a row can exist while nothing is promoted, or while the live
360
+ * version declares a redacted input an agent may not supply.
361
+ */
362
+ export interface AgentBinding {
363
+ workflowId: string
364
+ workflowSlug: string
365
+ enabled: boolean
366
+ access: BindingAccess
367
+ requiresApproval: boolean
368
+ waitSeconds: number
369
+ runnable: boolean
370
+ /** Why not, when `runnable` is false. */
371
+ inertReason: 'no_live_version' | 'input_redacted' | 'disabled' | 'read_only' | null
372
+ }
373
+
374
+ /** Every field is optional: an omitted one keeps what the row already holds. */
375
+ export interface BindAgentInput {
376
+ enabled?: boolean
377
+ /** Defaults to `run` on a binding that does not exist yet. */
378
+ access?: BindingAccess
379
+ requiresApproval?: boolean
380
+ /** 5 to 300; defaults to 90. */
381
+ waitSeconds?: number
382
+ }
383
+
384
+ /** The `before` cursor for the page after `run`, the last row of the current page. */
385
+ export function runCursor(run: Pick<RunSummary, 'startedAt' | 'id'>): string {
386
+ return `${run.startedAt}|${run.id}`
387
+ }
388
+
389
+ export interface RunTreeNode {
390
+ id: string
391
+ nodePath: string
392
+ nodeId: string
393
+ kind: string
394
+ status: WorkflowNodeStatus
395
+ attempt: number
396
+ input: unknown
397
+ output: unknown
398
+ error: unknown
399
+ startedAt: string
400
+ endedAt: string | null
401
+ functionRunId: string | null
402
+ actionRequestId: string | null
403
+ conversationId: string | null
404
+ childRunId: string | null
405
+ /** Present with `depth: 'all'`. */
406
+ functionRun?: {
407
+ id: string
408
+ slug: string | null
409
+ status: string
410
+ startedAt: string
411
+ endedAt: string | null
412
+ result: unknown
413
+ errorMessage: string | null
414
+ steps: Array<{
415
+ id: string
416
+ seq: number
417
+ kind: string
418
+ label: string
419
+ status: string
420
+ durationMs: number | null
421
+ stepName: string | null
422
+ }>
423
+ } | null
424
+ /** Present with `depth: 'all'`. */
425
+ actionRequest?: {
426
+ id: string
427
+ lifecycle: string
428
+ createdAt: string
429
+ attempts: Array<{ id: string; createdAt: string }>
430
+ approvals: Array<{ id: string; decision: string; createdAt: string }>
431
+ outcomes: Array<{ id: string; certainty: string; businessOutcomeCode: string | null; createdAt: string }>
432
+ } | null
433
+ /** Present with `depth: 'all'`. */
434
+ conversation?: {
435
+ id: string
436
+ status: string | null
437
+ createdAt: string | null
438
+ messages: Array<{ id: string; role: string; createdAt: string | null }>
439
+ } | null
440
+ /** Present with `depth: 'all'`. */
441
+ childRun?: RunTree | null
442
+ }
443
+
444
+ export interface RunTree {
445
+ id: string
446
+ workflowId: string
447
+ slug: string
448
+ versionId: string
449
+ versionNumber: number | null
450
+ status: WorkflowRunStatus
451
+ triggerSource: string
452
+ triggeredBy: string | null
453
+ triggeredByName: string | null
454
+ subject: { objectTypeId: string; pk: string; apiName: string | null; label: string | null } | null
455
+ rootRunId: string | null
456
+ parentRunId: string | null
457
+ depth: number
458
+ input: Record<string, unknown>
459
+ output: unknown
460
+ error: unknown
461
+ nodeCalls: number
462
+ startedAt: string
463
+ endedAt: string | null
464
+ nodes: RunTreeNode[]
465
+ /** Only on the root of the tree, and only for a webhook delivery. */
466
+ triggerCapture?: unknown
467
+ }
468
+
469
+ export interface CancelResult {
470
+ runId: string
471
+ status: WorkflowRunStatus
472
+ }
473
+
474
+ export interface WaitForRunOptions {
475
+ /** Default 1500. */
476
+ intervalMs?: number
477
+ /** Default 10 minutes. The run is left running on timeout. */
478
+ timeoutMs?: number
479
+ signal?: AbortSignal
480
+ /** Default `'run'`. */
481
+ depth?: 'run' | 'all'
482
+ onPoll?: (run: RunTree) => void
483
+ }