@epilot/cli 0.1.54 → 0.1.56

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.
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.0.3",
3
3
  "info": {
4
4
  "title": "Integration Toolkit API",
5
- "version": "1.2.0",
5
+ "version": "1.5.1",
6
6
  "description": "API for integrating with external systems in a standardised way."
7
7
  },
8
8
  "tags": [
@@ -1839,6 +1839,164 @@
1839
1839
  }
1840
1840
  }
1841
1841
  },
1842
+ "/v2/integrations/{integrationId}/notifications/history": {
1843
+ "get": {
1844
+ "operationId": "listNotificationHistory",
1845
+ "summary": "listNotificationHistory",
1846
+ "description": "Returns the cursor-paginated, newest-first notification history for an\nintegration (every real notification decision — both fired and suppressed).\nRequires the `integration:view` permission on the integration's organization.\n",
1847
+ "tags": [
1848
+ "integrations"
1849
+ ],
1850
+ "security": [
1851
+ {
1852
+ "EpilotAuth": []
1853
+ }
1854
+ ],
1855
+ "parameters": [
1856
+ {
1857
+ "name": "integrationId",
1858
+ "in": "path",
1859
+ "required": true,
1860
+ "description": "The integration ID",
1861
+ "schema": {
1862
+ "type": "string",
1863
+ "format": "uuid"
1864
+ }
1865
+ },
1866
+ {
1867
+ "name": "cursor",
1868
+ "in": "query",
1869
+ "required": false,
1870
+ "description": "Opaque base64 pagination cursor returned as `next_cursor` by a prior page.",
1871
+ "schema": {
1872
+ "type": "string"
1873
+ }
1874
+ },
1875
+ {
1876
+ "name": "limit",
1877
+ "in": "query",
1878
+ "required": false,
1879
+ "description": "Maximum number of items to return (clamped to 100).",
1880
+ "schema": {
1881
+ "type": "integer",
1882
+ "minimum": 1,
1883
+ "maximum": 100,
1884
+ "default": 50
1885
+ }
1886
+ },
1887
+ {
1888
+ "name": "type",
1889
+ "in": "query",
1890
+ "required": false,
1891
+ "description": "Optional notification type filter (e.g. `critical_error`, `error_threshold`).",
1892
+ "schema": {
1893
+ "type": "string"
1894
+ }
1895
+ }
1896
+ ],
1897
+ "responses": {
1898
+ "200": {
1899
+ "description": "Cursor-paginated notification history (newest first)",
1900
+ "content": {
1901
+ "application/json": {
1902
+ "schema": {
1903
+ "$ref": "#/components/schemas/NotificationHistoryResponse"
1904
+ }
1905
+ }
1906
+ }
1907
+ },
1908
+ "400": {
1909
+ "$ref": "#/components/responses/BadRequest"
1910
+ },
1911
+ "401": {
1912
+ "$ref": "#/components/responses/Unauthorized"
1913
+ },
1914
+ "403": {
1915
+ "$ref": "#/components/responses/Forbidden"
1916
+ },
1917
+ "404": {
1918
+ "$ref": "#/components/responses/NotFound"
1919
+ },
1920
+ "500": {
1921
+ "$ref": "#/components/responses/InternalServerError"
1922
+ }
1923
+ }
1924
+ }
1925
+ },
1926
+ "/v2/integrations/{integrationId}/notifications/test": {
1927
+ "post": {
1928
+ "operationId": "testSendNotification",
1929
+ "summary": "testSendNotification",
1930
+ "description": "Renders and sends ONE representative notification of the requested kind/type to\nthe CALLING USER ONLY (never any other recipient), so an operator can preview how\na notification looks. A test send does NOT write to the notification history.\nRequires the `integration:manage` permission on the integration's organization.\n",
1931
+ "tags": [
1932
+ "integrations"
1933
+ ],
1934
+ "security": [
1935
+ {
1936
+ "EpilotAuth": []
1937
+ }
1938
+ ],
1939
+ "parameters": [
1940
+ {
1941
+ "name": "integrationId",
1942
+ "in": "path",
1943
+ "required": true,
1944
+ "description": "The integration ID",
1945
+ "schema": {
1946
+ "type": "string",
1947
+ "format": "uuid"
1948
+ }
1949
+ }
1950
+ ],
1951
+ "requestBody": {
1952
+ "required": true,
1953
+ "content": {
1954
+ "application/json": {
1955
+ "schema": {
1956
+ "$ref": "#/components/schemas/TestNotificationRequest"
1957
+ }
1958
+ }
1959
+ }
1960
+ },
1961
+ "responses": {
1962
+ "202": {
1963
+ "description": "Test notification accepted for delivery to the calling user (sent is true)",
1964
+ "content": {
1965
+ "application/json": {
1966
+ "schema": {
1967
+ "$ref": "#/components/schemas/TestNotificationResponse"
1968
+ }
1969
+ }
1970
+ }
1971
+ },
1972
+ "400": {
1973
+ "$ref": "#/components/responses/BadRequest"
1974
+ },
1975
+ "401": {
1976
+ "$ref": "#/components/responses/Unauthorized"
1977
+ },
1978
+ "403": {
1979
+ "$ref": "#/components/responses/Forbidden"
1980
+ },
1981
+ "404": {
1982
+ "$ref": "#/components/responses/NotFound"
1983
+ },
1984
+ "500": {
1985
+ "$ref": "#/components/responses/InternalServerError"
1986
+ },
1987
+ "502": {
1988
+ "description": "The downstream notification service rejected or failed the test send.\nThe body uses TestNotificationResponse with sent set to false so the\noperator sees the real (failed) delivery outcome.\n",
1989
+ "content": {
1990
+ "application/json": {
1991
+ "schema": {
1992
+ "$ref": "#/components/schemas/TestNotificationResponse"
1993
+ }
1994
+ }
1995
+ }
1996
+ }
1997
+ }
1998
+ }
1999
+ },
1842
2000
  "/v2/integrations/{integrationId}/use-cases/{useCaseId}/secure-proxy-whitelist": {
1843
2001
  "get": {
1844
2002
  "operationId": "getSecureProxyWhitelist",
@@ -3100,11 +3258,11 @@
3100
3258
  }
3101
3259
  },
3102
3260
  "502": {
3103
- "description": "Upstream error from the proxied target",
3261
+ "description": "Upstream failure: epilot could not obtain an HTTP response from the proxied target\n(e.g. TLS handshake failure, connection refused/reset, DNS failure or timeout).\nThe body's `code`/`reason` identify the underlying cause, distinguishing a\nremote-side problem from an epilot-side one. When the target *does* answer with\nits own status, that status and body are passed through unchanged via\n`SecureProxyResponse` instead.\n",
3104
3262
  "content": {
3105
3263
  "application/json": {
3106
3264
  "schema": {
3107
- "$ref": "#/components/schemas/ErrorResponseBase"
3265
+ "$ref": "#/components/schemas/SecureProxyUpstreamError"
3108
3266
  }
3109
3267
  }
3110
3268
  }
@@ -3402,6 +3560,166 @@
3402
3560
  }
3403
3561
  },
3404
3562
  "schemas": {
3563
+ "NotificationHistoryItem": {
3564
+ "type": "object",
3565
+ "description": "A single notification-history row (one real notification decision).",
3566
+ "required": [
3567
+ "id",
3568
+ "type",
3569
+ "severity",
3570
+ "title",
3571
+ "occurred_at",
3572
+ "notified",
3573
+ "recipients",
3574
+ "context",
3575
+ "created_at"
3576
+ ],
3577
+ "properties": {
3578
+ "id": {
3579
+ "type": "string",
3580
+ "description": "Stable history row id (ULID)."
3581
+ },
3582
+ "type": {
3583
+ "type": "string",
3584
+ "description": "The notification/rule type (e.g. critical_error, error_threshold, integration_digest)."
3585
+ },
3586
+ "state_transition": {
3587
+ "type": "string",
3588
+ "nullable": true,
3589
+ "description": "The state transition that produced this decision (e.g. OK->ALERTING), when applicable."
3590
+ },
3591
+ "severity": {
3592
+ "type": "string",
3593
+ "enum": [
3594
+ "error",
3595
+ "warning",
3596
+ "info"
3597
+ ],
3598
+ "description": "Severity of the decision."
3599
+ },
3600
+ "title": {
3601
+ "type": "string",
3602
+ "description": "Human-readable title at decision time."
3603
+ },
3604
+ "occurred_at": {
3605
+ "type": "string",
3606
+ "format": "date-time",
3607
+ "description": "When the decision occurred (newest-first ordering key)."
3608
+ },
3609
+ "notified": {
3610
+ "type": "boolean",
3611
+ "description": "Whether the notification was actually sent (true) or suppressed (false)."
3612
+ },
3613
+ "suppressed_reason": {
3614
+ "type": "string",
3615
+ "nullable": true,
3616
+ "enum": [
3617
+ "muted",
3618
+ "debounced",
3619
+ "recipient_opt_out"
3620
+ ],
3621
+ "description": "Why the notification was suppressed (only set when notified is false)."
3622
+ },
3623
+ "recipients": {
3624
+ "type": "array",
3625
+ "description": "epilot user ids the notification was (or would have been) delivered to.",
3626
+ "items": {
3627
+ "type": "string"
3628
+ }
3629
+ },
3630
+ "context": {
3631
+ "type": "object",
3632
+ "additionalProperties": true,
3633
+ "description": "Type-specific context captured at decision time."
3634
+ },
3635
+ "created_at": {
3636
+ "type": "string",
3637
+ "format": "date-time",
3638
+ "description": "When the history row was written."
3639
+ }
3640
+ }
3641
+ },
3642
+ "NotificationHistoryResponse": {
3643
+ "type": "object",
3644
+ "required": [
3645
+ "history"
3646
+ ],
3647
+ "properties": {
3648
+ "history": {
3649
+ "type": "array",
3650
+ "description": "Notification-history rows, newest first.",
3651
+ "items": {
3652
+ "$ref": "#/components/schemas/NotificationHistoryItem"
3653
+ }
3654
+ },
3655
+ "next_cursor": {
3656
+ "type": "string",
3657
+ "nullable": true,
3658
+ "description": "Opaque base64 cursor for the next page, or null when there are no more rows."
3659
+ }
3660
+ }
3661
+ },
3662
+ "TestNotificationRequest": {
3663
+ "type": "object",
3664
+ "required": [
3665
+ "kind"
3666
+ ],
3667
+ "properties": {
3668
+ "kind": {
3669
+ "type": "string",
3670
+ "enum": [
3671
+ "alert",
3672
+ "digest"
3673
+ ],
3674
+ "description": "The kind of notification to render and send."
3675
+ },
3676
+ "type": {
3677
+ "type": "string",
3678
+ "description": "The alert type to render when kind=alert (e.g. critical_error, error_threshold)."
3679
+ },
3680
+ "channels": {
3681
+ "type": "array",
3682
+ "description": "Delivery channels to use; defaults to the integration's configured channels.",
3683
+ "items": {
3684
+ "type": "string",
3685
+ "enum": [
3686
+ "email",
3687
+ "in_app"
3688
+ ]
3689
+ }
3690
+ }
3691
+ }
3692
+ },
3693
+ "TestNotificationResponse": {
3694
+ "type": "object",
3695
+ "required": [
3696
+ "sent",
3697
+ "recipient",
3698
+ "channels"
3699
+ ],
3700
+ "properties": {
3701
+ "sent": {
3702
+ "type": "boolean",
3703
+ "description": "Whether the test notification was accepted for delivery."
3704
+ },
3705
+ "recipient": {
3706
+ "type": "string",
3707
+ "description": "The calling user id the test was sent to (the only recipient)."
3708
+ },
3709
+ "channels": {
3710
+ "type": "array",
3711
+ "description": "The channels the test was delivered on.",
3712
+ "items": {
3713
+ "type": "string"
3714
+ }
3715
+ },
3716
+ "notification_id": {
3717
+ "type": "string",
3718
+ "nullable": true,
3719
+ "description": "The svc-notification-api message id, or null when not returned."
3720
+ }
3721
+ }
3722
+ },
3405
3723
  "ErrorResponseBase": {
3406
3724
  "type": "object",
3407
3725
  "properties": {
@@ -4007,6 +4325,9 @@
4007
4325
  "properties": {
4008
4326
  "autoRefresh": {
4009
4327
  "$ref": "#/components/schemas/AutoRefreshSettings"
4328
+ },
4329
+ "notifications": {
4330
+ "$ref": "#/components/schemas/IntegrationNotificationConfig"
4010
4331
  }
4011
4332
  }
4012
4333
  },
@@ -4026,6 +4347,241 @@
4026
4347
  }
4027
4348
  }
4028
4349
  },
4350
+ "IntegrationNotificationConfig": {
4351
+ "type": "object",
4352
+ "description": "Integration monitoring notification configuration. Rides Integration.settings.notifications (camelCase) and surfaces on both v1 and v2 GET/PUT. Unknown keys are stripped server-side to stay forward-compatible with deferred (V2) rule types.",
4353
+ "required": [
4354
+ "enabled",
4355
+ "recipients",
4356
+ "defaultChannels",
4357
+ "rules",
4358
+ "digest"
4359
+ ],
4360
+ "properties": {
4361
+ "enabled": {
4362
+ "type": "boolean",
4363
+ "description": "Master switch for this integration's notifications."
4364
+ },
4365
+ "recipients": {
4366
+ "type": "array",
4367
+ "description": "epilot user ids notified for this integration. Same-org membership and per-user notification preferences are enforced at send time (Phases 3–5), not at config-write time.",
4368
+ "items": {
4369
+ "$ref": "#/components/schemas/NotificationRecipient"
4370
+ }
4371
+ },
4372
+ "defaultChannels": {
4373
+ "$ref": "#/components/schemas/NotificationChannelSet"
4374
+ },
4375
+ "monitoredUseCases": {
4376
+ "type": "array",
4377
+ "description": "Integration-level use-case include-filter; absent/empty means all use cases.",
4378
+ "items": {
4379
+ "type": "string"
4380
+ }
4381
+ },
4382
+ "monitoredCodes": {
4383
+ "type": "array",
4384
+ "description": "Integration-level code scope; absent/empty resolves to ['_error_']. Accepts concrete monitoring error codes or group sentinels (_error_, _warning_, _success_, _info_, _any_, _parent_).",
4385
+ "items": {
4386
+ "type": "string"
4387
+ }
4388
+ },
4389
+ "rules": {
4390
+ "type": "array",
4391
+ "description": "Enabled triggers and their params. A type MAY repeat; capped at 20 rules (enforced at the write boundary).",
4392
+ "items": {
4393
+ "$ref": "#/components/schemas/NotificationRule"
4394
+ }
4395
+ },
4396
+ "digest": {
4397
+ "$ref": "#/components/schemas/NotificationDigestConfig"
4398
+ },
4399
+ "muteUntil": {
4400
+ "type": "string",
4401
+ "format": "date-time",
4402
+ "description": "ISO instant; snooze all non-digest alerts until this time."
4403
+ }
4404
+ }
4405
+ },
4406
+ "NotificationRecipient": {
4407
+ "type": "object",
4408
+ "description": "A configured recipient. Only the epilot user_id is stored.",
4409
+ "required": [
4410
+ "user_id"
4411
+ ],
4412
+ "properties": {
4413
+ "user_id": {
4414
+ "type": "string",
4415
+ "description": "epilot user id. Same-org membership is enforced at send time (Phases 3–5), which re-validates each recipient against the integration's org before fanning out — it is not enforced at config-write time."
4416
+ }
4417
+ }
4418
+ },
4419
+ "NotificationChannelSet": {
4420
+ "type": "object",
4421
+ "description": "Delivery channel toggles. New channels added in svc-notification-api inherit here.",
4422
+ "required": [
4423
+ "email",
4424
+ "in_app"
4425
+ ],
4426
+ "properties": {
4427
+ "email": {
4428
+ "type": "boolean"
4429
+ },
4430
+ "in_app": {
4431
+ "type": "boolean"
4432
+ }
4433
+ }
4434
+ },
4435
+ "NotificationRule": {
4436
+ "type": "object",
4437
+ "description": "A single notification rule. Only the params relevant to a given type are set. The id is a server-minted ULID, preserved across edits.",
4438
+ "required": [
4439
+ "id",
4440
+ "type",
4441
+ "enabled"
4442
+ ],
4443
+ "properties": {
4444
+ "id": {
4445
+ "type": "string",
4446
+ "description": "Stable server-minted ULID. AlertState + baseline key."
4447
+ },
4448
+ "name": {
4449
+ "type": "string",
4450
+ "description": "Optional human label disambiguating two rules of the same type."
4451
+ },
4452
+ "type": {
4453
+ "type": "string",
4454
+ "description": "Rule trigger type. V1 produces the first six; the remaining values are deferred (V2) catalog types accepted by the data model but not produced by any V1 producer.",
4455
+ "enum": [
4456
+ "critical_error",
4457
+ "error_threshold",
4458
+ "warning_threshold",
4459
+ "success_rate_drop",
4460
+ "recovery",
4461
+ "silence",
4462
+ "consecutive_failures",
4463
+ "first_error",
4464
+ "new_error_code",
4465
+ "auth_expiry",
4466
+ "ack_timeout",
4467
+ "validation_surge"
4468
+ ]
4469
+ },
4470
+ "enabled": {
4471
+ "type": "boolean"
4472
+ },
4473
+ "channels": {
4474
+ "$ref": "#/components/schemas/NotificationChannelSet"
4475
+ },
4476
+ "codes": {
4477
+ "type": "array",
4478
+ "description": "Per-rule code scope. Event-matching rules default to ['_parent_']; silence defaults to ['_any_']. success_rate_drop and recovery take no codes.",
4479
+ "items": {
4480
+ "type": "string"
4481
+ }
4482
+ },
4483
+ "threshold": {
4484
+ "description": "Count or percentage; 'auto' selects anomaly-baseline mode.",
4485
+ "oneOf": [
4486
+ {
4487
+ "type": "number"
4488
+ },
4489
+ {
4490
+ "type": "string",
4491
+ "enum": [
4492
+ "auto"
4493
+ ]
4494
+ }
4495
+ ]
4496
+ },
4497
+ "sensitivity": {
4498
+ "type": "string",
4499
+ "description": "Band width for 'auto' mode.",
4500
+ "enum": [
4501
+ "low",
4502
+ "medium",
4503
+ "high"
4504
+ ]
4505
+ },
4506
+ "fallbackThreshold": {
4507
+ "type": "number",
4508
+ "description": "Static value used while the 'auto' baseline is immature (cold start)."
4509
+ },
4510
+ "window": {
4511
+ "type": "string",
4512
+ "description": "Evaluation window, e.g. '15m', '1h', '24h'."
4513
+ },
4514
+ "minSampleSize": {
4515
+ "type": "integer",
4516
+ "description": "success_rate_drop minimum sample size guard."
4517
+ },
4518
+ "consecutive": {
4519
+ "type": "integer",
4520
+ "description": "consecutive_failures count."
4521
+ },
4522
+ "quietPeriod": {
4523
+ "type": "string",
4524
+ "description": "silence quiet period, e.g. '12h'."
4525
+ }
4526
+ }
4527
+ },
4528
+ "NotificationDigestConfig": {
4529
+ "type": "object",
4530
+ "description": "Digest schedule and content configuration.",
4531
+ "required": [
4532
+ "enabled",
4533
+ "frequency",
4534
+ "timeOfDay",
4535
+ "timezone",
4536
+ "channels",
4537
+ "includeHealthy",
4538
+ "skipIfEmpty"
4539
+ ],
4540
+ "properties": {
4541
+ "enabled": {
4542
+ "type": "boolean"
4543
+ },
4544
+ "frequency": {
4545
+ "type": "string",
4546
+ "enum": [
4547
+ "daily",
4548
+ "weekly"
4549
+ ]
4550
+ },
4551
+ "dayOfWeek": {
4552
+ "type": "integer",
4553
+ "description": "Weekly only. 0 = Sunday … 6 = Saturday.",
4554
+ "enum": [
4555
+ 0,
4556
+ 1,
4557
+ 2,
4558
+ 3,
4559
+ 4,
4560
+ 5,
4561
+ 6
4562
+ ]
4563
+ },
4564
+ "timeOfDay": {
4565
+ "type": "string",
4566
+ "description": "HH:mm"
4567
+ },
4568
+ "timezone": {
4569
+ "type": "string",
4570
+ "description": "IANA timezone, e.g. 'Europe/Berlin'."
4571
+ },
4572
+ "channels": {
4573
+ "$ref": "#/components/schemas/NotificationChannelSet"
4574
+ },
4575
+ "includeHealthy": {
4576
+ "type": "boolean",
4577
+ "description": "List all integrations vs. only ones with issues."
4578
+ },
4579
+ "skipIfEmpty": {
4580
+ "type": "boolean",
4581
+ "description": "Suppress the digest when nothing happened."
4582
+ }
4583
+ }
4584
+ },
4029
4585
  "SetIntegrationAppMappingRequest": {
4030
4586
  "type": "object",
4031
4587
  "required": [
@@ -5856,7 +6412,32 @@
5856
6412
  "description": "Response headers from upstream"
5857
6413
  },
5858
6414
  "body": {
5859
- "description": "Response body from upstream"
6415
+ "description": "Response body from upstream. When `status_code` is 502 and the target never produced an HTTP response (TLS/connection/DNS failure or timeout), this is a `SecureProxyUpstreamError` describing the underlying cause."
6416
+ }
6417
+ }
6418
+ },
6419
+ "SecureProxyUpstreamError": {
6420
+ "type": "object",
6421
+ "description": "Error payload returned when epilot could not obtain an HTTP response from the proxied target. The failure is epilot-generated (HTTP 502) but the cause is usually remote-side; `code`/`reason` make that attributable.",
6422
+ "required": [
6423
+ "message"
6424
+ ],
6425
+ "properties": {
6426
+ "message": {
6427
+ "type": "string",
6428
+ "description": "Short error category.",
6429
+ "enum": [
6430
+ "Upstream network error",
6431
+ "Upstream error"
6432
+ ]
6433
+ },
6434
+ "code": {
6435
+ "type": "string",
6436
+ "description": "Underlying Node.js/axios error code when available (e.g. `UNABLE_TO_VERIFY_LEAF_SIGNATURE`, `ECONNREFUSED`, `ETIMEDOUT`, `ENOTFOUND`)."
6437
+ },
6438
+ "reason": {
6439
+ "type": "string",
6440
+ "description": "Human-readable explanation, present only for well-known codes (TLS/certificate, DNS and connection failures)."
5860
6441
  }
5861
6442
  }
5862
6443
  },
@@ -6908,7 +7489,7 @@
6908
7489
  "block"
6909
7490
  ],
6910
7491
  "default": "dead_letter",
6911
- "description": "What happens when an item exhausts max_delivery_attempts: dead_letter routes the exhausted item to the dead-letter queue; block halts the queue until operator/consumer action. Enforcement lands with the queue consumer (Phase 10) this field defines the contract."
7492
+ "description": "What happens when an item exhausts max_delivery_attempts: dead_letter routes the exhausted item to the dead-letter queue and advances past it so the stream keeps flowing; block halts the queue at that item until operator/consumer action removes it."
6912
7493
  },
6913
7494
  "max_delivery_attempts": {
6914
7495
  "type": "integer",