1use crate::types::common::{Amount, Interval, Receiver};
2use crate::types::wallet_address::JsonWebKey;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
10#[serde(untagged)]
11pub enum Client {
12 WalletAddressUrl(String),
14 WalletAddress {
16 #[serde(rename = "walletAddress")]
17 wallet_address: String,
18 },
19 Jwk { jwk: JsonWebKey },
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
25pub struct Subject {
26 pub sub_ids: Vec<SubjectIdentifier>,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
30pub struct SubjectIdentifier {
31 pub id: String,
32 pub format: SubjectIdentifierFormat,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
36#[serde(rename_all = "lowercase")]
37pub enum SubjectIdentifierFormat {
38 Uri,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
42#[serde(tag = "type", rename_all = "kebab-case")]
43pub enum AccessItem {
44 #[serde(rename = "incoming-payment")]
45 IncomingPayment {
46 actions: Vec<IncomingPaymentAction>,
47 #[serde(skip_serializing_if = "Option::is_none")]
48 identifier: Option<String>,
49 },
50 #[serde(rename = "outgoing-payment")]
51 OutgoingPayment {
52 actions: Vec<OutgoingPaymentAction>,
53 identifier: String,
54 #[serde(skip_serializing_if = "Option::is_none")]
55 limits: Option<LimitsOutgoing>,
56 },
57 #[serde(rename = "quote")]
58 Quote { actions: Vec<QuoteAction> },
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
62#[serde(rename_all = "kebab-case")]
63pub enum IncomingPaymentAction {
64 Create,
65 Complete,
66 Read,
67 ReadAll,
68 List,
69 ListAll,
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
73#[serde(rename_all = "kebab-case")]
74pub enum OutgoingPaymentAction {
75 Create,
76 Read,
77 ReadAll,
78 List,
79 ListAll,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
83#[serde(rename_all = "kebab-case")]
84pub enum QuoteAction {
85 Create,
86 Read,
87 ReadAll,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
91#[serde(rename_all = "camelCase")]
92pub struct LimitsOutgoing {
93 #[serde(skip_serializing_if = "Option::is_none")]
94 pub receiver: Option<Receiver>,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 pub debit_amount: Option<Amount>,
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub receive_amount: Option<Amount>,
99 #[serde(skip_serializing_if = "Option::is_none")]
100 pub interval: Option<Interval>,
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
104pub struct AccessToken {
105 pub value: String,
106 pub manage: String,
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub expires_in: Option<i64>,
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub access: Option<Vec<AccessItem>>,
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
114pub struct AccessTokenResponse {
115 pub access_token: AccessToken,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
119pub struct GrantRequest {
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub access_token: Option<AccessTokenRequest>,
122 pub(crate) client: Client,
123 #[serde(skip_serializing_if = "Option::is_none")]
124 pub interact: Option<InteractRequest>,
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub subject: Option<Subject>,
127}
128
129impl GrantRequest {
130 pub fn new(access_token: AccessTokenRequest, interact: Option<InteractRequest>) -> Self {
135 Self {
136 access_token: Some(access_token),
137 client: Client::WalletAddressUrl(String::new()),
138 interact,
139 subject: None,
140 }
141 }
142
143 pub fn subject_only(subject: Subject, interact: Option<InteractRequest>) -> Self {
145 Self {
146 access_token: None,
147 client: Client::WalletAddressUrl(String::new()),
148 interact,
149 subject: Some(subject),
150 }
151 }
152
153 pub fn with_subject(mut self, subject: Subject) -> Self {
155 self.subject = Some(subject);
156 self
157 }
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
161pub struct AccessTokenRequest {
162 pub access: Vec<AccessItem>,
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
166pub struct InteractRequest {
167 pub start: Vec<String>,
168 pub finish: Option<InteractFinish>,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
172pub struct InteractFinish {
173 pub method: String,
174 pub uri: String,
175 pub nonce: String,
176}
177
178#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
179pub struct InteractResponse {
180 pub redirect: String,
181 pub finish: String,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
185pub struct Continue {
186 pub access_token: ContinueAccessToken,
187 pub uri: String,
188 pub wait: Option<i64>,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
192pub struct ContinueAccessToken {
193 pub value: String,
194}
195
196#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
197#[serde(untagged)]
198pub enum GrantResponse {
199 WithInteraction {
200 interact: InteractResponse,
201 #[serde(rename = "continue")]
202 continue_: Continue,
203 },
204 WithToken {
205 access_token: AccessToken,
206 #[serde(rename = "continue")]
207 continue_: Continue,
208 #[serde(default, skip_serializing_if = "Option::is_none")]
209 subject: Option<Subject>,
210 },
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
214pub struct ContinueRequest {
215 pub interact_ref: Option<String>,
216}
217
218#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
219#[serde(untagged)]
220pub enum ContinueResponse {
221 WithToken {
222 access_token: AccessToken,
223 #[serde(rename = "continue")]
224 continue_: Continue,
225 #[serde(default, skip_serializing_if = "Option::is_none")]
226 subject: Option<Subject>,
227 },
228 WithSubject {
229 subject: Subject,
230 #[serde(rename = "continue")]
231 continue_: Continue,
232 },
233 Pending {
234 #[serde(rename = "continue")]
235 continue_: Continue,
236 },
237}
238
239impl ContinueResponse {
240 pub fn has_access_token(&self) -> bool {
241 matches!(self, Self::WithToken { .. })
242 }
243
244 pub fn has_subject(&self) -> bool {
245 match self {
246 Self::WithSubject { .. } => true,
247 Self::WithToken { subject, .. } => subject.is_some(),
248 Self::Pending { .. } => false,
249 }
250 }
251}