@iveri/contracts 0.4.0 → 0.6.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/README.md +11 -4
- package/dist/cjs/api/conduit/connection.type.d.ts +100 -0
- package/dist/cjs/api/conduit/connection.type.d.ts.map +1 -0
- package/dist/cjs/api/conduit/connection.type.js +3 -0
- package/dist/cjs/api/conduit/connection.type.js.map +1 -0
- package/dist/cjs/api/conduit/connector-auth-type.enum.d.ts +42 -0
- package/dist/cjs/api/conduit/connector-auth-type.enum.d.ts.map +1 -0
- package/dist/cjs/api/conduit/connector-auth-type.enum.js +46 -0
- package/dist/cjs/api/conduit/connector-auth-type.enum.js.map +1 -0
- package/dist/cjs/api/conduit/connector.type.d.ts +179 -0
- package/dist/cjs/api/conduit/connector.type.d.ts.map +1 -0
- package/dist/cjs/api/conduit/connector.type.js +13 -0
- package/dist/cjs/api/conduit/connector.type.js.map +1 -0
- package/dist/cjs/api/conduit/delivery-status.enum.d.ts +39 -0
- package/dist/cjs/api/conduit/delivery-status.enum.d.ts.map +1 -0
- package/dist/cjs/api/conduit/delivery-status.enum.js +43 -0
- package/dist/cjs/api/conduit/delivery-status.enum.js.map +1 -0
- package/dist/cjs/api/conduit/delivery.type.d.ts +79 -0
- package/dist/cjs/api/conduit/delivery.type.d.ts.map +1 -0
- package/dist/cjs/api/conduit/delivery.type.js +3 -0
- package/dist/cjs/api/conduit/delivery.type.js.map +1 -0
- package/dist/cjs/api/conduit/destination.type.d.ts +73 -0
- package/dist/cjs/api/conduit/destination.type.d.ts.map +1 -0
- package/dist/cjs/api/conduit/destination.type.js +3 -0
- package/dist/cjs/api/conduit/destination.type.js.map +1 -0
- package/dist/cjs/api/conduit/dispatch-status.enum.d.ts +40 -0
- package/dist/cjs/api/conduit/dispatch-status.enum.d.ts.map +1 -0
- package/dist/cjs/api/conduit/dispatch-status.enum.js +44 -0
- package/dist/cjs/api/conduit/dispatch-status.enum.js.map +1 -0
- package/dist/cjs/api/conduit/dispatch.type.d.ts +143 -0
- package/dist/cjs/api/conduit/dispatch.type.d.ts.map +1 -0
- package/dist/cjs/api/conduit/dispatch.type.js +3 -0
- package/dist/cjs/api/conduit/dispatch.type.js.map +1 -0
- package/dist/cjs/api/conduit/index.d.ts +10 -0
- package/dist/cjs/api/conduit/index.d.ts.map +1 -1
- package/dist/cjs/api/conduit/index.js +10 -0
- package/dist/cjs/api/conduit/index.js.map +1 -1
- package/dist/cjs/api/conduit/match-operator.enum.d.ts +22 -0
- package/dist/cjs/api/conduit/match-operator.enum.d.ts.map +1 -0
- package/dist/cjs/api/conduit/match-operator.enum.js +26 -0
- package/dist/cjs/api/conduit/match-operator.enum.js.map +1 -0
- package/dist/cjs/api/conduit/route.type.d.ts +124 -0
- package/dist/cjs/api/conduit/route.type.d.ts.map +1 -0
- package/dist/cjs/api/conduit/route.type.js +3 -0
- package/dist/cjs/api/conduit/route.type.js.map +1 -0
- package/dist/cjs/enum/user-permission.enum.d.ts +40 -1
- package/dist/cjs/enum/user-permission.enum.d.ts.map +1 -1
- package/dist/cjs/enum/user-permission.enum.js +42 -0
- package/dist/cjs/enum/user-permission.enum.js.map +1 -1
- package/dist/esm/api/conduit/connection.type.d.ts +100 -0
- package/dist/esm/api/conduit/connection.type.d.ts.map +1 -0
- package/dist/esm/api/conduit/connection.type.js +2 -0
- package/dist/esm/api/conduit/connection.type.js.map +1 -0
- package/dist/esm/api/conduit/connector-auth-type.enum.d.ts +42 -0
- package/dist/esm/api/conduit/connector-auth-type.enum.d.ts.map +1 -0
- package/dist/esm/api/conduit/connector-auth-type.enum.js +43 -0
- package/dist/esm/api/conduit/connector-auth-type.enum.js.map +1 -0
- package/dist/esm/api/conduit/connector.type.d.ts +179 -0
- package/dist/esm/api/conduit/connector.type.d.ts.map +1 -0
- package/dist/esm/api/conduit/connector.type.js +10 -0
- package/dist/esm/api/conduit/connector.type.js.map +1 -0
- package/dist/esm/api/conduit/delivery-status.enum.d.ts +39 -0
- package/dist/esm/api/conduit/delivery-status.enum.d.ts.map +1 -0
- package/dist/esm/api/conduit/delivery-status.enum.js +40 -0
- package/dist/esm/api/conduit/delivery-status.enum.js.map +1 -0
- package/dist/esm/api/conduit/delivery.type.d.ts +79 -0
- package/dist/esm/api/conduit/delivery.type.d.ts.map +1 -0
- package/dist/esm/api/conduit/delivery.type.js +2 -0
- package/dist/esm/api/conduit/delivery.type.js.map +1 -0
- package/dist/esm/api/conduit/destination.type.d.ts +73 -0
- package/dist/esm/api/conduit/destination.type.d.ts.map +1 -0
- package/dist/esm/api/conduit/destination.type.js +2 -0
- package/dist/esm/api/conduit/destination.type.js.map +1 -0
- package/dist/esm/api/conduit/dispatch-status.enum.d.ts +40 -0
- package/dist/esm/api/conduit/dispatch-status.enum.d.ts.map +1 -0
- package/dist/esm/api/conduit/dispatch-status.enum.js +41 -0
- package/dist/esm/api/conduit/dispatch-status.enum.js.map +1 -0
- package/dist/esm/api/conduit/dispatch.type.d.ts +143 -0
- package/dist/esm/api/conduit/dispatch.type.d.ts.map +1 -0
- package/dist/esm/api/conduit/dispatch.type.js +2 -0
- package/dist/esm/api/conduit/dispatch.type.js.map +1 -0
- package/dist/esm/api/conduit/index.d.ts +10 -0
- package/dist/esm/api/conduit/index.d.ts.map +1 -1
- package/dist/esm/api/conduit/index.js +10 -0
- package/dist/esm/api/conduit/index.js.map +1 -1
- package/dist/esm/api/conduit/match-operator.enum.d.ts +22 -0
- package/dist/esm/api/conduit/match-operator.enum.d.ts.map +1 -0
- package/dist/esm/api/conduit/match-operator.enum.js +23 -0
- package/dist/esm/api/conduit/match-operator.enum.js.map +1 -0
- package/dist/esm/api/conduit/route.type.d.ts +124 -0
- package/dist/esm/api/conduit/route.type.d.ts.map +1 -0
- package/dist/esm/api/conduit/route.type.js +2 -0
- package/dist/esm/api/conduit/route.type.js.map +1 -0
- package/dist/esm/enum/user-permission.enum.d.ts +40 -1
- package/dist/esm/enum/user-permission.enum.d.ts.map +1 -1
- package/dist/esm/enum/user-permission.enum.js +42 -0
- package/dist/esm/enum/user-permission.enum.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,10 +77,17 @@ one consumer each and stay in the service until a second one appears.
|
|
|
77
77
|
|
|
78
78
|
### `api/conduit/` → `@iveri/contracts/conduit`
|
|
79
79
|
|
|
80
|
-
`conduit-api`'s full admin surface
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
`
|
|
80
|
+
`conduit-api`'s full admin surface.
|
|
81
|
+
|
|
82
|
+
Inspect mode: `Endpoint`, `CaptureSummary`/`CaptureDetail`, `Provider` with its
|
|
83
|
+
`SignatureManifest`/`HandshakeManifest`, `Replay`, `SignatureDiagnostic`.
|
|
84
|
+
|
|
85
|
+
Gateway mode: `Destination`, `Route` with its `HeaderMatcher`/`BodyMatcher`, `Delivery` and
|
|
86
|
+
`DeliveryAttempt`.
|
|
87
|
+
|
|
88
|
+
Plus the request bodies for each, and the seven enums they are built from — `SignatureVerdict`,
|
|
89
|
+
`SignatureAlgorithm`, `SignatureEncoding`, `SignatureHeaderScheme`, `HandshakeKind`,
|
|
90
|
+
`MatchOperator`, `DeliveryStatus`.
|
|
84
91
|
|
|
85
92
|
### Why the wire shapes moved here
|
|
86
93
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { IsoDateTime } from '../../type/iso-date-time.type.js';
|
|
2
|
+
import type { Nullable } from '../../type/nil.type.js';
|
|
3
|
+
import type { UUID } from '../../type/uuid.type.js';
|
|
4
|
+
/**
|
|
5
|
+
* One tenant's configured instance of a connector: the credentials and the account details that
|
|
6
|
+
* turn a manifest into something that can actually send.
|
|
7
|
+
*
|
|
8
|
+
* The split is the reason a manifest can ship in the binary. A connector says "WhatsApp Cloud
|
|
9
|
+
* lives at graph.facebook.com and authenticates with a bearer token"; a connection says "and
|
|
10
|
+
* *this* is our token, for *this* phone number". One is ours and identical for everybody; the
|
|
11
|
+
* other is the customer's and is the single most sensitive thing this service holds.
|
|
12
|
+
*
|
|
13
|
+
* **No endpoint of this API returns a credential value**, in any form — not masked, not
|
|
14
|
+
* truncated, not a length. `credentialNames` answers the only question an operator has, which is
|
|
15
|
+
* whether something is configured. Same control as a destination's headers and an endpoint's
|
|
16
|
+
* signing secret, for the same reason: §11 says one leak ends the company.
|
|
17
|
+
*/
|
|
18
|
+
export interface Connection {
|
|
19
|
+
id: UUID;
|
|
20
|
+
/** Stable identifier a dispatch names instead of an id, so callers can be configured by name. */
|
|
21
|
+
key: string;
|
|
22
|
+
name: string;
|
|
23
|
+
description: Nullable<string>;
|
|
24
|
+
/** The manifest this connection instantiates. Built-in or tenant-defined. */
|
|
25
|
+
connectorKey: string;
|
|
26
|
+
/** Sorted. **The values are never returned by any endpoint of this API.** */
|
|
27
|
+
credentialNames: string[];
|
|
28
|
+
/**
|
|
29
|
+
* Non-secret values filling `{placeholders}` in an operation path — a phone number id, an
|
|
30
|
+
* account id, an API version.
|
|
31
|
+
*
|
|
32
|
+
* Deliberately separate from credentials rather than one map with a secrecy flag: a flag is
|
|
33
|
+
* a thing somebody sets wrong once, and the failure mode is a token in a response body.
|
|
34
|
+
* Variables are returned in full because they are the part an operator needs to check.
|
|
35
|
+
*/
|
|
36
|
+
variables: Record<string, string>;
|
|
37
|
+
/**
|
|
38
|
+
* When the cached OAuth access token stops being usable, or null when there is none —
|
|
39
|
+
* either because the connector authenticates statically or because nothing has fetched one
|
|
40
|
+
* yet.
|
|
41
|
+
*
|
|
42
|
+
* The expiry is returned, the token is not. It is what makes "why is this connection
|
|
43
|
+
* failing" answerable without exposing anything.
|
|
44
|
+
*/
|
|
45
|
+
accessTokenExpiresAt: Nullable<IsoDateTime>;
|
|
46
|
+
/**
|
|
47
|
+
* Why the last authentication attempt failed, or null when the last one worked.
|
|
48
|
+
*
|
|
49
|
+
* A refresh token that a provider has revoked is the most common real failure on this
|
|
50
|
+
* aggregate, and it is invisible otherwise: dispatches simply dead-letter with a 401 and
|
|
51
|
+
* nothing points at the connection.
|
|
52
|
+
*/
|
|
53
|
+
lastAuthError: Nullable<string>;
|
|
54
|
+
/** Stops *new* dispatches being accepted. Does not cancel ones already queued. */
|
|
55
|
+
isActive: boolean;
|
|
56
|
+
createdAt: IsoDateTime;
|
|
57
|
+
updatedAt: IsoDateTime;
|
|
58
|
+
}
|
|
59
|
+
/** `GET /api/v1/connections`. Offset-paginated — a small, slow-moving collection. */
|
|
60
|
+
export interface ConnectionsPage {
|
|
61
|
+
items: Connection[];
|
|
62
|
+
total: number;
|
|
63
|
+
limit: number;
|
|
64
|
+
offset: number;
|
|
65
|
+
}
|
|
66
|
+
/** `POST /api/v1/connections`. */
|
|
67
|
+
export interface CreateConnectionBody {
|
|
68
|
+
key: string;
|
|
69
|
+
name: string;
|
|
70
|
+
description?: Nullable<string>;
|
|
71
|
+
connectorKey: string;
|
|
72
|
+
/**
|
|
73
|
+
* Secrets this connection authenticates with. **Stored encrypted and never returned.**
|
|
74
|
+
*
|
|
75
|
+
* Which names are expected depends on the connector's auth type: an `API_KEY_HEADER`
|
|
76
|
+
* manifest names its own, an OAuth one wants `clientId`/`clientSecret` and, for the refresh
|
|
77
|
+
* grant, `refreshToken`.
|
|
78
|
+
*/
|
|
79
|
+
credentials: Record<string, string>;
|
|
80
|
+
variables?: Nullable<Record<string, string>>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* `PATCH /api/v1/connections/:id`.
|
|
84
|
+
*
|
|
85
|
+
* **`credentials` has three states, not two.** Omitting it leaves the stored map untouched,
|
|
86
|
+
* `null` clears it, an object replaces it wholesale. A form that sends `{}` meaning "unchanged"
|
|
87
|
+
* deletes the customer's token, and the symptom is every dispatch dead-lettering on a 401.
|
|
88
|
+
*
|
|
89
|
+
* Replacing credentials also discards the cached access token: a token minted from the old
|
|
90
|
+
* client secret is not evidence that the new one works, and keeping it would hide a typo until
|
|
91
|
+
* the token happened to expire.
|
|
92
|
+
*/
|
|
93
|
+
export interface UpdateConnectionBody {
|
|
94
|
+
name?: string;
|
|
95
|
+
description?: Nullable<string>;
|
|
96
|
+
credentials?: Nullable<Record<string, string>>;
|
|
97
|
+
variables?: Nullable<Record<string, string>>;
|
|
98
|
+
isActive?: boolean;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=connection.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.type.d.ts","sourceRoot":"","sources":["../../../../src/api/conduit/connection.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,IAAI,CAAC;IAET,iGAAiG;IACjG,GAAG,EAAE,MAAM,CAAC;IAEZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE9B,6EAA6E;IAC7E,YAAY,EAAE,MAAM,CAAC;IAErB,6EAA6E;IAC7E,eAAe,EAAE,MAAM,EAAE,CAAC;IAE1B;;;;;;;OAOG;IACH,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAElC;;;;;;;OAOG;IACH,oBAAoB,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAE5C;;;;;;OAMG;IACH,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEhC,kFAAkF;IAClF,QAAQ,EAAE,OAAO,CAAC;IAElB,SAAS,EAAE,WAAW,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;CAC1B;AAED,qFAAqF;AACrF,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,kCAAkC;AAClC,MAAM,WAAW,oBAAoB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;IAErB;;;;;;OAMG;IACH,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEpC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAChD;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,oBAAoB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.type.js","sourceRoot":"","sources":["../../../../src/api/conduit/connection.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a connector proves who we are to the third-party API it fronts.
|
|
3
|
+
*
|
|
4
|
+
* This is the field that decides whether Conduit has to hold a *renewable* credential or merely
|
|
5
|
+
* a static one, and the two are very different operationally: a static key works until someone
|
|
6
|
+
* rotates it, an OAuth token stops working on a schedule and something has to notice first.
|
|
7
|
+
*
|
|
8
|
+
* The list is deliberately short. Every member is a scheme a manifest can describe entirely as
|
|
9
|
+
* data — adding a provider that uses one of these is a manifest and a credential, never a code
|
|
10
|
+
* change, which is the whole promise of §11's connector manifest. A provider needing anything
|
|
11
|
+
* else (a request-signing scheme, mutual TLS) does not get a special case bolted on here; it
|
|
12
|
+
* gets a new member, designed once, with the same "no per-provider branches" rule applied to it.
|
|
13
|
+
*/
|
|
14
|
+
export declare enum ConnectorAuthType {
|
|
15
|
+
/** The API is open, or the credential travels in the payload. Nothing is added to a request. */
|
|
16
|
+
NONE = "none",
|
|
17
|
+
/**
|
|
18
|
+
* A static secret sent in a header — `X-Api-Key: …`, `Authorization: Basic …`.
|
|
19
|
+
*
|
|
20
|
+
* The header name and any literal prefix come from the manifest; only the secret comes from
|
|
21
|
+
* the connection. That split is what lets one manifest serve every tenant.
|
|
22
|
+
*/
|
|
23
|
+
API_KEY_HEADER = "api-key-header",
|
|
24
|
+
/** A static bearer token. Shorthand for {@link API_KEY_HEADER} with the header and prefix fixed. */
|
|
25
|
+
BEARER_STATIC = "bearer-static",
|
|
26
|
+
/**
|
|
27
|
+
* OAuth 2.0 client credentials (RFC 6749 §4.4): exchange a client id and secret for a
|
|
28
|
+
* short-lived access token, and do it again when it expires. Machine-to-machine, no user.
|
|
29
|
+
*/
|
|
30
|
+
OAUTH2_CLIENT_CREDENTIALS = "oauth2-client-credentials",
|
|
31
|
+
/**
|
|
32
|
+
* OAuth 2.0 refresh token (RFC 6749 §6): a long-lived refresh token buys short-lived access
|
|
33
|
+
* tokens.
|
|
34
|
+
*
|
|
35
|
+
* **The refresh token may be rotated by the provider on every use**, and Conduit stores
|
|
36
|
+
* whichever one came back last. That single fact is why refreshing has to be serialised
|
|
37
|
+
* across replicas rather than left to race — two simultaneous refreshes rotate twice, one
|
|
38
|
+
* of the two results is stored, and the connection is dead until a human re-authorises it.
|
|
39
|
+
*/
|
|
40
|
+
OAUTH2_REFRESH_TOKEN = "oauth2-refresh-token"
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=connector-auth-type.enum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector-auth-type.enum.d.ts","sourceRoot":"","sources":["../../../../src/api/conduit/connector-auth-type.enum.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,oBAAY,iBAAiB;IACzB,gGAAgG;IAChG,IAAI,SAAS;IAEb;;;;;OAKG;IACH,cAAc,mBAAmB;IAEjC,oGAAoG;IACpG,aAAa,kBAAkB;IAE/B;;;OAGG;IACH,yBAAyB,8BAA8B;IAEvD;;;;;;;;OAQG;IACH,oBAAoB,yBAAyB;CAChD"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConnectorAuthType = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* How a connector proves who we are to the third-party API it fronts.
|
|
6
|
+
*
|
|
7
|
+
* This is the field that decides whether Conduit has to hold a *renewable* credential or merely
|
|
8
|
+
* a static one, and the two are very different operationally: a static key works until someone
|
|
9
|
+
* rotates it, an OAuth token stops working on a schedule and something has to notice first.
|
|
10
|
+
*
|
|
11
|
+
* The list is deliberately short. Every member is a scheme a manifest can describe entirely as
|
|
12
|
+
* data — adding a provider that uses one of these is a manifest and a credential, never a code
|
|
13
|
+
* change, which is the whole promise of §11's connector manifest. A provider needing anything
|
|
14
|
+
* else (a request-signing scheme, mutual TLS) does not get a special case bolted on here; it
|
|
15
|
+
* gets a new member, designed once, with the same "no per-provider branches" rule applied to it.
|
|
16
|
+
*/
|
|
17
|
+
var ConnectorAuthType;
|
|
18
|
+
(function (ConnectorAuthType) {
|
|
19
|
+
/** The API is open, or the credential travels in the payload. Nothing is added to a request. */
|
|
20
|
+
ConnectorAuthType["NONE"] = "none";
|
|
21
|
+
/**
|
|
22
|
+
* A static secret sent in a header — `X-Api-Key: …`, `Authorization: Basic …`.
|
|
23
|
+
*
|
|
24
|
+
* The header name and any literal prefix come from the manifest; only the secret comes from
|
|
25
|
+
* the connection. That split is what lets one manifest serve every tenant.
|
|
26
|
+
*/
|
|
27
|
+
ConnectorAuthType["API_KEY_HEADER"] = "api-key-header";
|
|
28
|
+
/** A static bearer token. Shorthand for {@link API_KEY_HEADER} with the header and prefix fixed. */
|
|
29
|
+
ConnectorAuthType["BEARER_STATIC"] = "bearer-static";
|
|
30
|
+
/**
|
|
31
|
+
* OAuth 2.0 client credentials (RFC 6749 §4.4): exchange a client id and secret for a
|
|
32
|
+
* short-lived access token, and do it again when it expires. Machine-to-machine, no user.
|
|
33
|
+
*/
|
|
34
|
+
ConnectorAuthType["OAUTH2_CLIENT_CREDENTIALS"] = "oauth2-client-credentials";
|
|
35
|
+
/**
|
|
36
|
+
* OAuth 2.0 refresh token (RFC 6749 §6): a long-lived refresh token buys short-lived access
|
|
37
|
+
* tokens.
|
|
38
|
+
*
|
|
39
|
+
* **The refresh token may be rotated by the provider on every use**, and Conduit stores
|
|
40
|
+
* whichever one came back last. That single fact is why refreshing has to be serialised
|
|
41
|
+
* across replicas rather than left to race — two simultaneous refreshes rotate twice, one
|
|
42
|
+
* of the two results is stored, and the connection is dead until a human re-authorises it.
|
|
43
|
+
*/
|
|
44
|
+
ConnectorAuthType["OAUTH2_REFRESH_TOKEN"] = "oauth2-refresh-token";
|
|
45
|
+
})(ConnectorAuthType || (exports.ConnectorAuthType = ConnectorAuthType = {}));
|
|
46
|
+
//# sourceMappingURL=connector-auth-type.enum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector-auth-type.enum.js","sourceRoot":"","sources":["../../../../src/api/conduit/connector-auth-type.enum.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;GAYG;AACH,IAAY,iBA+BX;AA/BD,WAAY,iBAAiB;IACzB,gGAAgG;IAChG,kCAAa,CAAA;IAEb;;;;;OAKG;IACH,sDAAiC,CAAA;IAEjC,oGAAoG;IACpG,oDAA+B,CAAA;IAE/B;;;OAGG;IACH,4EAAuD,CAAA;IAEvD;;;;;;;;OAQG;IACH,kEAA6C,CAAA;AACjD,CAAC,EA/BW,iBAAiB,iCAAjB,iBAAiB,QA+B5B"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import type { IsoDateTime } from '../../type/iso-date-time.type.js';
|
|
2
|
+
import type { Nullable } from '../../type/nil.type.js';
|
|
3
|
+
import type { UUID } from '../../type/uuid.type.js';
|
|
4
|
+
import type { ConnectorAuthType } from './connector-auth-type.enum.js';
|
|
5
|
+
/**
|
|
6
|
+
* Credential names an OAuth manifest expects to find on a connection.
|
|
7
|
+
*
|
|
8
|
+
* Fixed rather than manifest-configurable: these are the field names RFC 6749 gives the token
|
|
9
|
+
* request, so letting a manifest rename them would only allow it to be wrong.
|
|
10
|
+
*/
|
|
11
|
+
export declare const CONNECTOR_CREDENTIAL_CLIENT_ID = "clientId";
|
|
12
|
+
export declare const CONNECTOR_CREDENTIAL_CLIENT_SECRET = "clientSecret";
|
|
13
|
+
export declare const CONNECTOR_CREDENTIAL_REFRESH_TOKEN = "refreshToken";
|
|
14
|
+
/**
|
|
15
|
+
* How a connector authenticates, as data.
|
|
16
|
+
*
|
|
17
|
+
* Flat with a discriminating {@link ConnectorAuthType} and nullable fields, matching
|
|
18
|
+
* `SignatureManifest` — a discriminated union reads better in TypeScript and validates far worse
|
|
19
|
+
* as a request body, and this shape has to survive `class-validator` on the way in.
|
|
20
|
+
*
|
|
21
|
+
* **A manifest holds no secret.** It names *where* the credential goes; the credential itself
|
|
22
|
+
* lives on a connection, encrypted. That is what makes a manifest safe to return in full to
|
|
23
|
+
* anyone with `conduit:connector:read` and safe to ship in the binary.
|
|
24
|
+
*/
|
|
25
|
+
export interface ConnectorAuthManifest {
|
|
26
|
+
type: ConnectorAuthType;
|
|
27
|
+
/**
|
|
28
|
+
* Which credential on the connection holds the secret. `API_KEY_HEADER` only.
|
|
29
|
+
*
|
|
30
|
+
* OAuth manifests do not set it — they read the fixed names above, because those are defined
|
|
31
|
+
* by the grant rather than by us.
|
|
32
|
+
*/
|
|
33
|
+
credentialKey: Nullable<string>;
|
|
34
|
+
/** Lowercase header the credential is sent in. `API_KEY_HEADER` only. */
|
|
35
|
+
headerName: Nullable<string>;
|
|
36
|
+
/** Literal text before the credential, e.g. `Bearer ` or `Basic `. Kept verbatim, spaces included. */
|
|
37
|
+
valuePrefix: Nullable<string>;
|
|
38
|
+
/** Token endpoint. `OAUTH2_*` only. Vetted against the SSRF blocklist like any other target. */
|
|
39
|
+
tokenUrl: Nullable<string>;
|
|
40
|
+
/** `scope` sent with the token request, when the provider wants one. */
|
|
41
|
+
scope: Nullable<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Seconds shaved off a token's reported lifetime before it counts as expired.
|
|
44
|
+
*
|
|
45
|
+
* Not a nicety. A token that expires while a request is in flight fails with a 401 that looks
|
|
46
|
+
* exactly like a revoked credential, and the retry that would fix it is indistinguishable
|
|
47
|
+
* from one that never will. Refreshing slightly early makes that case rare instead of
|
|
48
|
+
* routine. Null falls back to the service default.
|
|
49
|
+
*/
|
|
50
|
+
expirySkewSeconds: Nullable<number>;
|
|
51
|
+
}
|
|
52
|
+
/** {@link ConnectorAuthManifest} as sent on create/update: nullable fields may simply be omitted. */
|
|
53
|
+
export interface ConnectorAuthManifestInput {
|
|
54
|
+
type: ConnectorAuthType;
|
|
55
|
+
credentialKey?: Nullable<string>;
|
|
56
|
+
headerName?: Nullable<string>;
|
|
57
|
+
valuePrefix?: Nullable<string>;
|
|
58
|
+
tokenUrl?: Nullable<string>;
|
|
59
|
+
scope?: Nullable<string>;
|
|
60
|
+
expirySkewSeconds?: Nullable<number>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* One thing a connector can be asked to do.
|
|
64
|
+
*
|
|
65
|
+
* A dispatch names an operation by {@link key} rather than supplying a URL, and that is the
|
|
66
|
+
* whole security model of the outbound side: a caller chooses from a list somebody with
|
|
67
|
+
* `conduit:connector:manage` wrote down, instead of naming a host Conduit will then post to.
|
|
68
|
+
* Outbound would otherwise be an open proxy with authentication attached.
|
|
69
|
+
*/
|
|
70
|
+
export interface ConnectorOperation {
|
|
71
|
+
/** Stable identifier a dispatch names. Lowercase kebab-case: `send-message`. */
|
|
72
|
+
key: string;
|
|
73
|
+
/** Human-readable label for the admin UI. */
|
|
74
|
+
name: string;
|
|
75
|
+
method: string;
|
|
76
|
+
/**
|
|
77
|
+
* Path appended to the connector's `baseUrl`.
|
|
78
|
+
*
|
|
79
|
+
* `{name}` placeholders are filled from the connection's variables first and the dispatch's
|
|
80
|
+
* `pathParams` second. Every placeholder must resolve, or the dispatch is refused at submit
|
|
81
|
+
* time rather than dead-lettering later — the caller is still on the phone at submit time.
|
|
82
|
+
*/
|
|
83
|
+
path: string;
|
|
84
|
+
description: Nullable<string>;
|
|
85
|
+
}
|
|
86
|
+
/** Requests per minute, and how many may arrive at once. Applied per connection. */
|
|
87
|
+
export interface ConnectorRateLimit {
|
|
88
|
+
perMinute: number;
|
|
89
|
+
burst: number;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* When to try again, and when to stop.
|
|
93
|
+
*
|
|
94
|
+
* Per connector rather than global because providers genuinely differ: one returns 429 with a
|
|
95
|
+
* generous window, another treats a burst as abuse and blocks for an hour.
|
|
96
|
+
*/
|
|
97
|
+
export interface ConnectorRetryPolicy {
|
|
98
|
+
maxAttempts: number;
|
|
99
|
+
backoffBaseMs: number;
|
|
100
|
+
backoffMaxMs: number;
|
|
101
|
+
/**
|
|
102
|
+
* Statuses to retry **in addition** to the transient default set (5xx, 408, 425, 429).
|
|
103
|
+
*
|
|
104
|
+
* Additive, never subtractive: a manifest can say "this provider's 400 is transient", which
|
|
105
|
+
* is a fact about that provider, but it cannot claim a 502 is permanent — nothing about a
|
|
106
|
+
* gateway error is provider-specific and the ability to get it wrong buys nothing.
|
|
107
|
+
*/
|
|
108
|
+
retryableStatuses: number[];
|
|
109
|
+
/**
|
|
110
|
+
* Statuses meaning the access token is stale.
|
|
111
|
+
*
|
|
112
|
+
* Handled once per attempt and unlike any other status: the token is discarded, refreshed,
|
|
113
|
+
* and the request is sent again immediately rather than after a backoff. A token that
|
|
114
|
+
* expired thirty seconds early is not a failing destination and should not be treated as one.
|
|
115
|
+
*/
|
|
116
|
+
authFailureStatuses: number[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* A third-party API, described entirely as data. §11's "connector manifest".
|
|
120
|
+
*
|
|
121
|
+
* Conduit contains no `if (connector === 'whatsapp')` anywhere. Adding TikTok is a manifest and
|
|
122
|
+
* a credential; the code that sends the request never learns a provider's name.
|
|
123
|
+
*/
|
|
124
|
+
export interface Connector {
|
|
125
|
+
/** Null for a built-in — it is not a row and cannot be edited or deleted. */
|
|
126
|
+
id: Nullable<UUID>;
|
|
127
|
+
/** Stable identifier a connection references. Lowercase kebab-case. */
|
|
128
|
+
key: string;
|
|
129
|
+
name: string;
|
|
130
|
+
description: Nullable<string>;
|
|
131
|
+
/** Absolute https base every operation path is appended to. */
|
|
132
|
+
baseUrl: string;
|
|
133
|
+
auth: ConnectorAuthManifest;
|
|
134
|
+
operations: ConnectorOperation[];
|
|
135
|
+
/** Null means only the service-wide default applies. */
|
|
136
|
+
rateLimit: Nullable<ConnectorRateLimit>;
|
|
137
|
+
retry: ConnectorRetryPolicy;
|
|
138
|
+
/**
|
|
139
|
+
* Ships with Conduit, in code rather than as a seeded row. Override it by defining your own
|
|
140
|
+
* under the same key — resolution checks a tenant's rows first.
|
|
141
|
+
*/
|
|
142
|
+
isBuiltIn: boolean;
|
|
143
|
+
/** Null for a built-in. */
|
|
144
|
+
createdAt: Nullable<IsoDateTime>;
|
|
145
|
+
/** Null for a built-in. */
|
|
146
|
+
updatedAt: Nullable<IsoDateTime>;
|
|
147
|
+
}
|
|
148
|
+
/** Built-ins plus whatever one customer has defined. `GET /api/v1/connectors`. */
|
|
149
|
+
export interface ConnectorsList {
|
|
150
|
+
items: Connector[];
|
|
151
|
+
}
|
|
152
|
+
/** `POST /api/v1/connectors`. */
|
|
153
|
+
export interface CreateConnectorBody {
|
|
154
|
+
key: string;
|
|
155
|
+
name: string;
|
|
156
|
+
description?: Nullable<string>;
|
|
157
|
+
baseUrl: string;
|
|
158
|
+
auth: ConnectorAuthManifestInput;
|
|
159
|
+
operations: ConnectorOperation[];
|
|
160
|
+
rateLimit?: Nullable<ConnectorRateLimit>;
|
|
161
|
+
retry?: Nullable<ConnectorRetryPolicy>;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* `PATCH /api/v1/connectors/:id`.
|
|
165
|
+
*
|
|
166
|
+
* `operations` replaces the list wholesale — there is no per-operation patch. Merging would make
|
|
167
|
+
* "remove an operation" unexpressible, and an operation nobody can remove is a URL Conduit will
|
|
168
|
+
* post to forever.
|
|
169
|
+
*/
|
|
170
|
+
export interface UpdateConnectorBody {
|
|
171
|
+
name?: string;
|
|
172
|
+
description?: Nullable<string>;
|
|
173
|
+
baseUrl?: string;
|
|
174
|
+
auth?: ConnectorAuthManifestInput;
|
|
175
|
+
operations?: ConnectorOperation[];
|
|
176
|
+
rateLimit?: Nullable<ConnectorRateLimit>;
|
|
177
|
+
retry?: Nullable<ConnectorRetryPolicy>;
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=connector.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector.type.d.ts","sourceRoot":"","sources":["../../../../src/api/conduit/connector.type.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CONNECTOR_CREDENTIAL_REFRESH_TOKEN = exports.CONNECTOR_CREDENTIAL_CLIENT_SECRET = exports.CONNECTOR_CREDENTIAL_CLIENT_ID = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Credential names an OAuth manifest expects to find on a connection.
|
|
6
|
+
*
|
|
7
|
+
* Fixed rather than manifest-configurable: these are the field names RFC 6749 gives the token
|
|
8
|
+
* request, so letting a manifest rename them would only allow it to be wrong.
|
|
9
|
+
*/
|
|
10
|
+
exports.CONNECTOR_CREDENTIAL_CLIENT_ID = 'clientId';
|
|
11
|
+
exports.CONNECTOR_CREDENTIAL_CLIENT_SECRET = 'clientSecret';
|
|
12
|
+
exports.CONNECTOR_CREDENTIAL_REFRESH_TOKEN = 'refreshToken';
|
|
13
|
+
//# sourceMappingURL=connector.type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector.type.js","sourceRoot":"","sources":["../../../../src/api/conduit/connector.type.ts"],"names":[],"mappings":";;;AAMA;;;;;GAKG;AACU,QAAA,8BAA8B,GAAG,UAAU,CAAC;AAC5C,QAAA,kCAAkC,GAAG,cAAc,CAAC;AACpD,QAAA,kCAAkC,GAAG,cAAc,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where one delivery is in its life.
|
|
3
|
+
*
|
|
4
|
+
* The states a processor can be interrupted in matter as much as the ones it ends in, which is
|
|
5
|
+
* why `IN_FLIGHT` is a status rather than an implied one: a replica killed mid-attempt leaves
|
|
6
|
+
* rows in it, and the reclaim query needs something to look for.
|
|
7
|
+
*/
|
|
8
|
+
export declare enum DeliveryStatus {
|
|
9
|
+
/** Waiting for its next attempt time. The only state the processor claims from. */
|
|
10
|
+
PENDING = "pending",
|
|
11
|
+
/**
|
|
12
|
+
* Claimed by a replica and being attempted right now.
|
|
13
|
+
*
|
|
14
|
+
* A row stuck here past the claim timeout is assumed abandoned and reclaimed. That reclaim
|
|
15
|
+
* is where at-least-once becomes visible — a replica that died *after* the receiver
|
|
16
|
+
* processed the request will have its work redone, which is what the idempotency key is
|
|
17
|
+
* for.
|
|
18
|
+
*/
|
|
19
|
+
IN_FLIGHT = "in-flight",
|
|
20
|
+
/** The destination answered 2xx. Terminal. */
|
|
21
|
+
DELIVERED = "delivered",
|
|
22
|
+
/**
|
|
23
|
+
* Every attempt was used and none succeeded, or the failure was permanent. Terminal until an
|
|
24
|
+
* operator redrives it.
|
|
25
|
+
*
|
|
26
|
+
* **This is the dead-letter queue** — a status, not a separate resource. A DLQ that lives
|
|
27
|
+
* somewhere else is a DLQ nobody looks at.
|
|
28
|
+
*/
|
|
29
|
+
DEAD_LETTERED = "dead-lettered",
|
|
30
|
+
/**
|
|
31
|
+
* An operator stopped it before it succeeded. Terminal.
|
|
32
|
+
*
|
|
33
|
+
* Distinct from `DEAD_LETTERED`: dead-lettered means the gateway tried and failed, cancelled
|
|
34
|
+
* means someone decided it should not be sent. Collapsing them makes "how reliable is our
|
|
35
|
+
* delivery" unanswerable.
|
|
36
|
+
*/
|
|
37
|
+
CANCELLED = "cancelled"
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=delivery-status.enum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery-status.enum.d.ts","sourceRoot":"","sources":["../../../../src/api/conduit/delivery-status.enum.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,oBAAY,cAAc;IACtB,mFAAmF;IACnF,OAAO,YAAY;IAEnB;;;;;;;OAOG;IACH,SAAS,cAAc;IAEvB,8CAA8C;IAC9C,SAAS,cAAc;IAEvB;;;;;;OAMG;IACH,aAAa,kBAAkB;IAE/B;;;;;;OAMG;IACH,SAAS,cAAc;CAC1B"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeliveryStatus = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Where one delivery is in its life.
|
|
6
|
+
*
|
|
7
|
+
* The states a processor can be interrupted in matter as much as the ones it ends in, which is
|
|
8
|
+
* why `IN_FLIGHT` is a status rather than an implied one: a replica killed mid-attempt leaves
|
|
9
|
+
* rows in it, and the reclaim query needs something to look for.
|
|
10
|
+
*/
|
|
11
|
+
var DeliveryStatus;
|
|
12
|
+
(function (DeliveryStatus) {
|
|
13
|
+
/** Waiting for its next attempt time. The only state the processor claims from. */
|
|
14
|
+
DeliveryStatus["PENDING"] = "pending";
|
|
15
|
+
/**
|
|
16
|
+
* Claimed by a replica and being attempted right now.
|
|
17
|
+
*
|
|
18
|
+
* A row stuck here past the claim timeout is assumed abandoned and reclaimed. That reclaim
|
|
19
|
+
* is where at-least-once becomes visible — a replica that died *after* the receiver
|
|
20
|
+
* processed the request will have its work redone, which is what the idempotency key is
|
|
21
|
+
* for.
|
|
22
|
+
*/
|
|
23
|
+
DeliveryStatus["IN_FLIGHT"] = "in-flight";
|
|
24
|
+
/** The destination answered 2xx. Terminal. */
|
|
25
|
+
DeliveryStatus["DELIVERED"] = "delivered";
|
|
26
|
+
/**
|
|
27
|
+
* Every attempt was used and none succeeded, or the failure was permanent. Terminal until an
|
|
28
|
+
* operator redrives it.
|
|
29
|
+
*
|
|
30
|
+
* **This is the dead-letter queue** — a status, not a separate resource. A DLQ that lives
|
|
31
|
+
* somewhere else is a DLQ nobody looks at.
|
|
32
|
+
*/
|
|
33
|
+
DeliveryStatus["DEAD_LETTERED"] = "dead-lettered";
|
|
34
|
+
/**
|
|
35
|
+
* An operator stopped it before it succeeded. Terminal.
|
|
36
|
+
*
|
|
37
|
+
* Distinct from `DEAD_LETTERED`: dead-lettered means the gateway tried and failed, cancelled
|
|
38
|
+
* means someone decided it should not be sent. Collapsing them makes "how reliable is our
|
|
39
|
+
* delivery" unanswerable.
|
|
40
|
+
*/
|
|
41
|
+
DeliveryStatus["CANCELLED"] = "cancelled";
|
|
42
|
+
})(DeliveryStatus || (exports.DeliveryStatus = DeliveryStatus = {}));
|
|
43
|
+
//# sourceMappingURL=delivery-status.enum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery-status.enum.js","sourceRoot":"","sources":["../../../../src/api/conduit/delivery-status.enum.ts"],"names":[],"mappings":";;;AAAA;;;;;;GAMG;AACH,IAAY,cAkCX;AAlCD,WAAY,cAAc;IACtB,mFAAmF;IACnF,qCAAmB,CAAA;IAEnB;;;;;;;OAOG;IACH,yCAAuB,CAAA;IAEvB,8CAA8C;IAC9C,yCAAuB,CAAA;IAEvB;;;;;;OAMG;IACH,iDAA+B,CAAA;IAE/B;;;;;;OAMG;IACH,yCAAuB,CAAA;AAC3B,CAAC,EAlCW,cAAc,8BAAd,cAAc,QAkCzB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { CursorPage } from '../../type/cursor-page.type.js';
|
|
2
|
+
import type { IsoDateTime } from '../../type/iso-date-time.type.js';
|
|
3
|
+
import type { Nullable } from '../../type/nil.type.js';
|
|
4
|
+
import type { UUID } from '../../type/uuid.type.js';
|
|
5
|
+
import type { DeliveryStatus } from './delivery-status.enum.js';
|
|
6
|
+
/** One capture on its way to one destination. */
|
|
7
|
+
export interface Delivery {
|
|
8
|
+
id: UUID;
|
|
9
|
+
captureId: UUID;
|
|
10
|
+
/** The route that matched. May since have been deleted — the reference is loose. */
|
|
11
|
+
routeId: UUID;
|
|
12
|
+
destinationId: UUID;
|
|
13
|
+
/**
|
|
14
|
+
* Snapshotted when the delivery was enqueued, not read from the destination now: "we sent it
|
|
15
|
+
* here" must not silently become "we sent it wherever that points today".
|
|
16
|
+
*/
|
|
17
|
+
targetUrl: string;
|
|
18
|
+
method: string;
|
|
19
|
+
/**
|
|
20
|
+
* Sent as `Idempotency-Key`, stable across every retry and every redrive.
|
|
21
|
+
*
|
|
22
|
+
* **At-least-once is the only guarantee Conduit offers.** A timeout that actually succeeded,
|
|
23
|
+
* a replica that died after the request landed, and an operator redriving a dead letter all
|
|
24
|
+
* arrive with the same key — a receiver must dedupe on it.
|
|
25
|
+
*/
|
|
26
|
+
idempotencyKey: string;
|
|
27
|
+
status: DeliveryStatus;
|
|
28
|
+
attemptCount: number;
|
|
29
|
+
/** Snapshotted from the destination when enqueued. */
|
|
30
|
+
maxAttempts: number;
|
|
31
|
+
nextAttemptAt: IsoDateTime;
|
|
32
|
+
lastAttemptAt: Nullable<IsoDateTime>;
|
|
33
|
+
/** Null when no response arrived. See `lastError`. */
|
|
34
|
+
lastResponseStatus: Nullable<number>;
|
|
35
|
+
lastResponseBodyPreview: Nullable<string>;
|
|
36
|
+
lastError: Nullable<string>;
|
|
37
|
+
/** Set when an operator redrove this. */
|
|
38
|
+
redrivenByUserId: Nullable<UUID>;
|
|
39
|
+
completedAt: Nullable<IsoDateTime>;
|
|
40
|
+
createdAt: IsoDateTime;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* One attempt at one delivery.
|
|
44
|
+
*
|
|
45
|
+
* What makes a dead letter diagnosable: "timed out, 502, 502, 401" is a different afternoon from
|
|
46
|
+
* "failed after 5 attempts", and the difference is whether the receiver was down or the
|
|
47
|
+
* credential is wrong.
|
|
48
|
+
*/
|
|
49
|
+
export interface DeliveryAttempt {
|
|
50
|
+
id: UUID;
|
|
51
|
+
/** 1-based. */
|
|
52
|
+
attemptNumber: number;
|
|
53
|
+
/** Null when no response arrived at all. */
|
|
54
|
+
responseStatus: Nullable<number>;
|
|
55
|
+
responseBodyPreview: Nullable<string>;
|
|
56
|
+
errorMessage: Nullable<string>;
|
|
57
|
+
/** Wall time, so a receiver that is slow rather than broken is visible. */
|
|
58
|
+
durationMs: number;
|
|
59
|
+
isSuccess: boolean;
|
|
60
|
+
createdAt: IsoDateTime;
|
|
61
|
+
}
|
|
62
|
+
/** `GET /api/v1/deliveries/:id/attempts`. Oldest first — an attempt history reads as a story. */
|
|
63
|
+
export interface DeliveryAttemptsList {
|
|
64
|
+
items: DeliveryAttempt[];
|
|
65
|
+
}
|
|
66
|
+
/** `GET /api/v1/deliveries`. Cursor-paginated: the collection is appended to while it is read. */
|
|
67
|
+
export type DeliveriesPage = CursorPage<Delivery>;
|
|
68
|
+
/** Query for `GET /api/v1/deliveries`. */
|
|
69
|
+
export interface GetDeliveriesQuery {
|
|
70
|
+
limit?: number;
|
|
71
|
+
/** Opaque cursor from the previous page's `nextCursor`. Never parse it. */
|
|
72
|
+
after?: Nullable<string>;
|
|
73
|
+
/** `dead-lettered` is the DLQ view. The DLQ is a filter, not a separate resource. */
|
|
74
|
+
status?: Nullable<DeliveryStatus>;
|
|
75
|
+
destinationId?: Nullable<UUID>;
|
|
76
|
+
/** Everything one capture fanned out to. */
|
|
77
|
+
captureId?: Nullable<UUID>;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=delivery.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery.type.d.ts","sourceRoot":"","sources":["../../../../src/api/conduit/delivery.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE,iDAAiD;AACjD,MAAM,WAAW,QAAQ;IACrB,EAAE,EAAE,IAAI,CAAC;IACT,SAAS,EAAE,IAAI,CAAC;IAEhB,oFAAoF;IACpF,OAAO,EAAE,IAAI,CAAC;IAEd,aAAa,EAAE,IAAI,CAAC;IAEpB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB,MAAM,EAAE,MAAM,CAAC;IAEf;;;;;;OAMG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB,MAAM,EAAE,cAAc,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IAErB,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IAEpB,aAAa,EAAE,WAAW,CAAC;IAC3B,aAAa,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAErC,sDAAsD;IACtD,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAErC,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1C,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE5B,yCAAyC;IACzC,gBAAgB,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEjC,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IACnC,SAAS,EAAE,WAAW,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC5B,EAAE,EAAE,IAAI,CAAC;IAET,eAAe;IACf,aAAa,EAAE,MAAM,CAAC;IAEtB,4CAA4C;IAC5C,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEjC,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE/B,2EAA2E;IAC3E,UAAU,EAAE,MAAM,CAAC;IAEnB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,WAAW,CAAC;CAC1B;AAED,iGAAiG;AACjG,MAAM,WAAW,oBAAoB;IACjC,KAAK,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED,kGAAkG;AAClG,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;AAElD,0CAA0C;AAC1C,MAAM,WAAW,kBAAkB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,2EAA2E;IAC3E,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEzB,qFAAqF;IACrF,MAAM,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;IAElC,aAAa,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE/B,4CAA4C;IAC5C,SAAS,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;CAC9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery.type.js","sourceRoot":"","sources":["../../../../src/api/conduit/delivery.type.ts"],"names":[],"mappings":""}
|