@smithers-orchestrator/gateway 0.22.0 → 0.24.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/openapi.yaml CHANGED
@@ -867,8 +867,7 @@ paths:
867
867
  - InvalidRequest
868
868
  - Unauthorized
869
869
  - Forbidden
870
- - RunNotFound
871
- - Busy
870
+ - RUN_NOT_ACTIVE
872
871
  - Internal
873
872
  message:
874
873
  type: string
@@ -923,8 +922,7 @@ paths:
923
922
  - InvalidRequest
924
923
  - Unauthorized
925
924
  - Forbidden
926
- - RunNotFound
927
- - Busy
925
+ - RUN_NOT_ACTIVE
928
926
  - Internal
929
927
  message:
930
928
  type: string
@@ -979,64 +977,7 @@ paths:
979
977
  - InvalidRequest
980
978
  - Unauthorized
981
979
  - Forbidden
982
- - RunNotFound
983
- - Busy
984
- - Internal
985
- message:
986
- type: string
987
- requiredScope:
988
- type: string
989
- enum:
990
- - run:read
991
- - run:write
992
- - run:admin
993
- - approval:submit
994
- - signal:submit
995
- - cron:read
996
- - cron:write
997
- - observability:read
998
- refresh:
999
- type: string
1000
- 404:
1001
- description: "The run does not exist."
1002
- content:
1003
- application/json:
1004
- schema:
1005
- type: object
1006
- required:
1007
- - type
1008
- - id
1009
- - ok
1010
- - apiVersion
1011
- - error
1012
- additionalProperties: false
1013
- properties:
1014
- type:
1015
- const: res
1016
- id:
1017
- type: string
1018
- ok:
1019
- const: false
1020
- apiVersion:
1021
- const: v1
1022
- error:
1023
- type: object
1024
- required:
1025
- - version
1026
- - code
1027
- - message
1028
- additionalProperties: true
1029
- properties:
1030
- version:
1031
- const: v1
1032
- code:
1033
- type: string
1034
- enum:
1035
- - InvalidRequest
1036
- - Unauthorized
1037
- - Forbidden
1038
- - RunNotFound
1039
- - Busy
980
+ - RUN_NOT_ACTIVE
1040
981
  - Internal
1041
982
  message:
1042
983
  type: string
@@ -1054,7 +995,7 @@ paths:
1054
995
  refresh:
1055
996
  type: string
1056
997
  409:
1057
- description: "Another conflicting mutation is in progress."
998
+ description: "The run is not currently active and cannot be cancelled."
1058
999
  content:
1059
1000
  application/json:
1060
1001
  schema:
@@ -1091,8 +1032,7 @@ paths:
1091
1032
  - InvalidRequest
1092
1033
  - Unauthorized
1093
1034
  - Forbidden
1094
- - RunNotFound
1095
- - Busy
1035
+ - RUN_NOT_ACTIVE
1096
1036
  - Internal
1097
1037
  message:
1098
1038
  type: string
@@ -1147,8 +1087,7 @@ paths:
1147
1087
  - InvalidRequest
1148
1088
  - Unauthorized
1149
1089
  - Forbidden
1150
- - RunNotFound
1151
- - Busy
1090
+ - RUN_NOT_ACTIVE
1152
1091
  - Internal
1153
1092
  message:
1154
1093
  type: string
@@ -2284,7 +2223,7 @@ paths:
2284
2223
  iteration: 0
2285
2224
  approved: true
2286
2225
  400:
2287
- description: "The request shape is invalid."
2226
+ description: "The request input failed validation."
2288
2227
  content:
2289
2228
  application/json:
2290
2229
  schema:
@@ -2319,10 +2258,11 @@ paths:
2319
2258
  type: string
2320
2259
  enum:
2321
2260
  - InvalidRequest
2261
+ - InvalidInput
2322
2262
  - Unauthorized
2323
2263
  - Forbidden
2324
2264
  - RunNotFound
2325
- - NodeNotFound
2265
+ - AlreadyDecided
2326
2266
  - Internal
2327
2267
  message:
2328
2268
  type: string
@@ -2375,10 +2315,11 @@ paths:
2375
2315
  type: string
2376
2316
  enum:
2377
2317
  - InvalidRequest
2318
+ - InvalidInput
2378
2319
  - Unauthorized
2379
2320
  - Forbidden
2380
2321
  - RunNotFound
2381
- - NodeNotFound
2322
+ - AlreadyDecided
2382
2323
  - Internal
2383
2324
  message:
2384
2325
  type: string
@@ -2431,10 +2372,11 @@ paths:
2431
2372
  type: string
2432
2373
  enum:
2433
2374
  - InvalidRequest
2375
+ - InvalidInput
2434
2376
  - Unauthorized
2435
2377
  - Forbidden
2436
2378
  - RunNotFound
2437
- - NodeNotFound
2379
+ - AlreadyDecided
2438
2380
  - Internal
2439
2381
  message:
2440
2382
  type: string
@@ -2452,7 +2394,7 @@ paths:
2452
2394
  refresh:
2453
2395
  type: string
2454
2396
  404:
2455
- description: "The node does not exist on the run."
2397
+ description: "The run does not exist."
2456
2398
  content:
2457
2399
  application/json:
2458
2400
  schema:
@@ -2487,10 +2429,68 @@ paths:
2487
2429
  type: string
2488
2430
  enum:
2489
2431
  - InvalidRequest
2432
+ - InvalidInput
2490
2433
  - Unauthorized
2491
2434
  - Forbidden
2492
2435
  - RunNotFound
2493
- - NodeNotFound
2436
+ - AlreadyDecided
2437
+ - Internal
2438
+ message:
2439
+ type: string
2440
+ requiredScope:
2441
+ type: string
2442
+ enum:
2443
+ - run:read
2444
+ - run:write
2445
+ - run:admin
2446
+ - approval:submit
2447
+ - signal:submit
2448
+ - cron:read
2449
+ - cron:write
2450
+ - observability:read
2451
+ refresh:
2452
+ type: string
2453
+ 409:
2454
+ description: "The approval decision has already been submitted."
2455
+ content:
2456
+ application/json:
2457
+ schema:
2458
+ type: object
2459
+ required:
2460
+ - type
2461
+ - id
2462
+ - ok
2463
+ - apiVersion
2464
+ - error
2465
+ additionalProperties: false
2466
+ properties:
2467
+ type:
2468
+ const: res
2469
+ id:
2470
+ type: string
2471
+ ok:
2472
+ const: false
2473
+ apiVersion:
2474
+ const: v1
2475
+ error:
2476
+ type: object
2477
+ required:
2478
+ - version
2479
+ - code
2480
+ - message
2481
+ additionalProperties: true
2482
+ properties:
2483
+ version:
2484
+ const: v1
2485
+ code:
2486
+ type: string
2487
+ enum:
2488
+ - InvalidRequest
2489
+ - InvalidInput
2490
+ - Unauthorized
2491
+ - Forbidden
2492
+ - RunNotFound
2493
+ - AlreadyDecided
2494
2494
  - Internal
2495
2495
  message:
2496
2496
  type: string
@@ -2543,10 +2543,11 @@ paths:
2543
2543
  type: string
2544
2544
  enum:
2545
2545
  - InvalidRequest
2546
+ - InvalidInput
2546
2547
  - Unauthorized
2547
2548
  - Forbidden
2548
2549
  - RunNotFound
2549
- - NodeNotFound
2550
+ - AlreadyDecided
2550
2551
  - Internal
2551
2552
  message:
2552
2553
  type: string
@@ -2963,7 +2964,7 @@ paths:
2963
2964
  post:
2964
2965
  operationId: getRun
2965
2966
  summary: "Get Run"
2966
- description: "Fetch the current RunStateView for one run."
2967
+ description: "Fetch one run record with node-state counts and optional derived runState."
2967
2968
  tags:
2968
2969
  - "Gateway RPC"
2969
2970
  security:
@@ -3036,9 +3037,69 @@ paths:
3036
3037
  const: v1
3037
3038
  payload:
3038
3039
  type: object
3039
- description: RunStateView.
3040
- properties: {}
3041
- required: []
3040
+ description: "Current run record, including node-state counts and optional derived runState."
3041
+ properties:
3042
+ runId:
3043
+ type: string
3044
+ description: "Stable run identifier."
3045
+ workflowKey:
3046
+ type: string
3047
+ description: "Registered Gateway workflow key."
3048
+ status:
3049
+ type: string
3050
+ description: "Persisted run status."
3051
+ createdAtMs:
3052
+ type: integer
3053
+ minimum: 0
3054
+ description: "Unix epoch milliseconds."
3055
+ startedAtMs:
3056
+ type: integer
3057
+ minimum: 0
3058
+ description: "Unix epoch milliseconds."
3059
+ nullable: true
3060
+ finishedAtMs:
3061
+ type: integer
3062
+ minimum: 0
3063
+ description: "Unix epoch milliseconds."
3064
+ nullable: true
3065
+ summary:
3066
+ type: object
3067
+ description: "Counts keyed by persisted node state."
3068
+ properties: {}
3069
+ required: []
3070
+ additionalProperties: true
3071
+ runState:
3072
+ type: object
3073
+ description: "Derived RunStateView for the run."
3074
+ properties:
3075
+ runId:
3076
+ type: string
3077
+ description: "Stable run identifier."
3078
+ state:
3079
+ type: string
3080
+ description: "Derived lifecycle state."
3081
+ computedAt:
3082
+ type: string
3083
+ description: "ISO timestamp for when the view was computed."
3084
+ blocked:
3085
+ type: object
3086
+ description: "Optional blocked-run reason."
3087
+ properties: {}
3088
+ required: []
3089
+ additionalProperties: true
3090
+ unhealthy:
3091
+ type: object
3092
+ description: "Optional unhealthy-run reason."
3093
+ properties: {}
3094
+ required: []
3095
+ additionalProperties: true
3096
+ required:
3097
+ - runId
3098
+ - state
3099
+ - computedAt
3100
+ additionalProperties: true
3101
+ required:
3102
+ - runId
3042
3103
  additionalProperties: true
3043
3104
  example:
3044
3105
  type: res
@@ -3049,6 +3110,12 @@ paths:
3049
3110
  runId: run_01
3050
3111
  status: finished
3051
3112
  workflowKey: deploy
3113
+ summary:
3114
+ finished: 3
3115
+ runState:
3116
+ runId: run_01
3117
+ state: succeeded
3118
+ computedAt: 2026-01-01T00:00:00.000Z
3052
3119
  400:
3053
3120
  description: "The request shape is invalid."
3054
3121
  content:
@@ -4755,6 +4822,10 @@ paths:
4755
4822
  type: integer
4756
4823
  minimum: 0
4757
4824
  description: "Replay events with sequence numbers greater than this value."
4825
+ fromSeq:
4826
+ type: integer
4827
+ minimum: 0
4828
+ description: "Legacy alias for afterSeq on DevTools streams."
4758
4829
  required:
4759
4830
  - runId
4760
4831
  additionalProperties: false
@@ -4803,6 +4874,10 @@ paths:
4803
4874
  runId:
4804
4875
  type: string
4805
4876
  description: "Stable run identifier."
4877
+ fromSeq:
4878
+ type:
4879
+ - integer
4880
+ - "null"
4806
4881
  afterSeq:
4807
4882
  type:
4808
4883
  - integer
@@ -4810,6 +4885,8 @@ paths:
4810
4885
  required:
4811
4886
  - streamId
4812
4887
  - runId
4888
+ - fromSeq
4889
+ - afterSeq
4813
4890
  additionalProperties: false
4814
4891
  example:
4815
4892
  type: res
@@ -4819,6 +4896,7 @@ paths:
4819
4896
  payload:
4820
4897
  streamId: stream_01
4821
4898
  runId: run_01
4899
+ fromSeq: 10
4822
4900
  afterSeq: 10
4823
4901
  400:
4824
4902
  description: "The requested stream sequence is in the future."
@@ -7489,6 +7567,7 @@ components:
7489
7567
  - Unauthorized
7490
7568
  - Forbidden
7491
7569
  - RunNotFound
7570
+ - RUN_NOT_ACTIVE
7492
7571
  - CronNotFound
7493
7572
  - NodeNotFound
7494
7573
  - IterationNotFound
@@ -7496,6 +7575,7 @@ components:
7496
7575
  - FrameOutOfRange
7497
7576
  - SeqOutOfRange
7498
7577
  - Busy
7578
+ - AlreadyDecided
7499
7579
  - RateLimited
7500
7580
  - PayloadTooLarge
7501
7581
  - BackpressureDisconnect
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smithers-orchestrator/gateway",
3
- "version": "0.22.0",
3
+ "version": "0.24.0",
4
4
  "description": "Stable Smithers Gateway RPC contracts, auth scopes, and deployment metadata",
5
5
  "type": "module",
6
6
  "sideEffects": false,
package/src/rpc/index.ts CHANGED
@@ -30,6 +30,7 @@ export type GatewayRpcErrorCode =
30
30
  | "Unauthorized"
31
31
  | "Forbidden"
32
32
  | "RunNotFound"
33
+ | "RUN_NOT_ACTIVE"
33
34
  | "CronNotFound"
34
35
  | "NodeNotFound"
35
36
  | "IterationNotFound"
@@ -37,6 +38,7 @@ export type GatewayRpcErrorCode =
37
38
  | "FrameOutOfRange"
38
39
  | "SeqOutOfRange"
39
40
  | "Busy"
41
+ | "AlreadyDecided"
40
42
  | "RateLimited"
41
43
  | "PayloadTooLarge"
42
44
  | "BackpressureDisconnect"
@@ -232,6 +234,7 @@ export type StreamRunEventsResponse = {
232
234
  export type StreamDevToolsRequest = {
233
235
  runId: string;
234
236
  afterSeq?: number;
237
+ fromSeq?: number;
235
238
  };
236
239
 
237
240
  export type NodeRequest = {
@@ -310,6 +313,7 @@ const workflow = stringSchema("Registered Gateway workflow key.");
310
313
  const nodeId = stringSchema("Workflow node id.");
311
314
  const iteration = integerSchema("Node iteration.", 0);
312
315
  const afterSeq = integerSchema("Replay events with sequence numbers greater than this value.", 0);
316
+ const fromSeq = integerSchema("Legacy alias for afterSeq on DevTools streams.", 0);
313
317
  const runSummary = objectSchema(
314
318
  {
315
319
  runId,
@@ -321,6 +325,33 @@ const runSummary = objectSchema(
321
325
  "Run summary view.",
322
326
  true,
323
327
  );
328
+ const runStateView = objectSchema(
329
+ {
330
+ runId,
331
+ state: stringSchema("Derived lifecycle state."),
332
+ computedAt: stringSchema("ISO timestamp for when the view was computed."),
333
+ blocked: objectSchema({}, [], "Optional blocked-run reason.", true),
334
+ unhealthy: objectSchema({}, [], "Optional unhealthy-run reason.", true),
335
+ },
336
+ ["runId", "state", "computedAt"],
337
+ "Derived RunStateView for the run.",
338
+ true,
339
+ );
340
+ const runRecord = objectSchema(
341
+ {
342
+ runId,
343
+ workflowKey: workflow,
344
+ status: stringSchema("Persisted run status."),
345
+ createdAtMs: integerSchema("Unix epoch milliseconds.", 0),
346
+ startedAtMs: { ...integerSchema("Unix epoch milliseconds.", 0), nullable: true },
347
+ finishedAtMs: { ...integerSchema("Unix epoch milliseconds.", 0), nullable: true },
348
+ summary: objectSchema({}, [], "Counts keyed by persisted node state.", true),
349
+ runState: runStateView,
350
+ },
351
+ ["runId"],
352
+ "Current run record, including node-state counts and optional derived runState.",
353
+ true,
354
+ );
324
355
 
325
356
  export const GATEWAY_RPC_ERRORS: Record<GatewayRpcErrorCode, GatewayRpcErrorDefinition> = {
326
357
  InvalidRequest: { version: SMITHERS_API_VERSION, code: "InvalidRequest", httpStatus: 400, description: "The request shape is invalid." },
@@ -328,6 +359,7 @@ export const GATEWAY_RPC_ERRORS: Record<GatewayRpcErrorCode, GatewayRpcErrorDefi
328
359
  Unauthorized: { version: SMITHERS_API_VERSION, code: "Unauthorized", httpStatus: 401, description: "Authentication failed or the token expired." },
329
360
  Forbidden: { version: SMITHERS_API_VERSION, code: "Forbidden", httpStatus: 403, description: "The token is missing the required scope." },
330
361
  RunNotFound: { version: SMITHERS_API_VERSION, code: "RunNotFound", httpStatus: 404, description: "The run does not exist." },
362
+ RUN_NOT_ACTIVE: { version: SMITHERS_API_VERSION, code: "RUN_NOT_ACTIVE", httpStatus: 409, description: "The run is not currently active and cannot be cancelled." },
331
363
  CronNotFound: { version: SMITHERS_API_VERSION, code: "CronNotFound", httpStatus: 404, description: "The cron schedule does not exist." },
332
364
  NodeNotFound: { version: SMITHERS_API_VERSION, code: "NodeNotFound", httpStatus: 404, description: "The node does not exist on the run." },
333
365
  IterationNotFound: { version: SMITHERS_API_VERSION, code: "IterationNotFound", httpStatus: 404, description: "The requested node iteration does not exist." },
@@ -335,6 +367,7 @@ export const GATEWAY_RPC_ERRORS: Record<GatewayRpcErrorCode, GatewayRpcErrorDefi
335
367
  FrameOutOfRange: { version: SMITHERS_API_VERSION, code: "FrameOutOfRange", httpStatus: 400, description: "The requested frame is outside the available range." },
336
368
  SeqOutOfRange: { version: SMITHERS_API_VERSION, code: "SeqOutOfRange", httpStatus: 400, description: "The requested stream sequence is in the future." },
337
369
  Busy: { version: SMITHERS_API_VERSION, code: "Busy", httpStatus: 409, description: "Another conflicting mutation is in progress." },
370
+ AlreadyDecided: { version: SMITHERS_API_VERSION, code: "AlreadyDecided", httpStatus: 409, description: "The approval decision has already been submitted." },
338
371
  RateLimited: { version: SMITHERS_API_VERSION, code: "RateLimited", httpStatus: 429, description: "The caller exceeded a configured quota." },
339
372
  PayloadTooLarge: { version: SMITHERS_API_VERSION, code: "PayloadTooLarge", httpStatus: 413, description: "The response exceeds the configured payload limit." },
340
373
  BackpressureDisconnect: { version: SMITHERS_API_VERSION, code: "BackpressureDisconnect", httpStatus: 429, description: "A stream subscriber exceeded the bounded outbound queue." },
@@ -407,7 +440,7 @@ export const GATEWAY_RPC_DEFINITIONS: readonly GatewayRpcDefinition[] = [
407
440
  requiredScope: "run:write",
408
441
  requestSchema: objectSchema({ runId }, ["runId"]),
409
442
  responseSchema: objectSchema({ runId, status: { type: "string", enum: ["cancelling"] } }, ["runId", "status"]),
410
- errors: ["InvalidRequest", "Unauthorized", "Forbidden", "RunNotFound", "Busy", "Internal"],
443
+ errors: ["InvalidRequest", "Unauthorized", "Forbidden", "RUN_NOT_ACTIVE", "Internal"],
411
444
  exampleRequest: { runId: "run_01" },
412
445
  exampleResponse: { runId: "run_01", status: "cancelling" },
413
446
  },
@@ -458,7 +491,7 @@ export const GATEWAY_RPC_DEFINITIONS: readonly GatewayRpcDefinition[] = [
458
491
  }, ["approved"]),
459
492
  }, ["runId", "nodeId", "decision"]),
460
493
  responseSchema: objectSchema({ runId, nodeId, iteration, approved: booleanSchema("Whether the approval was granted.") }, ["runId", "nodeId", "iteration", "approved"]),
461
- errors: ["InvalidRequest", "Unauthorized", "Forbidden", "RunNotFound", "NodeNotFound", "Internal"],
494
+ errors: ["InvalidRequest", "InvalidInput", "Unauthorized", "Forbidden", "RunNotFound", "AlreadyDecided", "Internal"],
462
495
  exampleRequest: { runId: "run_01", nodeId: "approve", decision: { approved: true, note: "ship it" } },
463
496
  exampleResponse: { runId: "run_01", nodeId: "approve", iteration: 0, approved: true },
464
497
  },
@@ -480,15 +513,21 @@ export const GATEWAY_RPC_DEFINITIONS: readonly GatewayRpcDefinition[] = [
480
513
  version: SMITHERS_API_VERSION,
481
514
  method: "getRun",
482
515
  title: "Get Run",
483
- description: "Fetch the current RunStateView for one run.",
516
+ description: "Fetch one run record with node-state counts and optional derived runState.",
484
517
  maturity: "stable",
485
518
  transport: "http+websocket",
486
519
  requiredScope: "run:read",
487
520
  requestSchema: objectSchema({ runId }, ["runId"]),
488
- responseSchema: objectSchema({}, [], "RunStateView.", true),
521
+ responseSchema: runRecord,
489
522
  errors: ["InvalidRequest", "Unauthorized", "Forbidden", "RunNotFound", "Internal"],
490
523
  exampleRequest: { runId: "run_01" },
491
- exampleResponse: { runId: "run_01", status: "finished", workflowKey: "deploy" },
524
+ exampleResponse: {
525
+ runId: "run_01",
526
+ status: "finished",
527
+ workflowKey: "deploy",
528
+ summary: { finished: 3 },
529
+ runState: { runId: "run_01", state: "succeeded", computedAt: "2026-01-01T00:00:00.000Z" },
530
+ },
492
531
  },
493
532
  {
494
533
  version: SMITHERS_API_VERSION,
@@ -570,11 +609,16 @@ export const GATEWAY_RPC_DEFINITIONS: readonly GatewayRpcDefinition[] = [
570
609
  maturity: "stable",
571
610
  transport: "websocket",
572
611
  requiredScope: "observability:read",
573
- requestSchema: objectSchema({ runId, afterSeq }, ["runId"]),
574
- responseSchema: objectSchema({ streamId: stringSchema("Stream id."), runId, afterSeq: { type: ["integer", "null"] } }, ["streamId", "runId"]),
612
+ requestSchema: objectSchema({ runId, afterSeq, fromSeq }, ["runId"]),
613
+ responseSchema: objectSchema({
614
+ streamId: stringSchema("Stream id."),
615
+ runId,
616
+ fromSeq: { type: ["integer", "null"] },
617
+ afterSeq: { type: ["integer", "null"] },
618
+ }, ["streamId", "runId", "fromSeq", "afterSeq"]),
575
619
  errors: ["InvalidRequest", "Unauthorized", "Forbidden", "RunNotFound", "SeqOutOfRange", "BackpressureDisconnect", "Internal"],
576
620
  exampleRequest: { runId: "run_01", afterSeq: 10 },
577
- exampleResponse: { streamId: "stream_01", runId: "run_01", afterSeq: 10 },
621
+ exampleResponse: { streamId: "stream_01", runId: "run_01", fromSeq: 10, afterSeq: 10 },
578
622
  },
579
623
  {
580
624
  version: SMITHERS_API_VERSION,