1use derive_builder::Builder;
2use reqwest::Client as HttpClient;
3use serde::{Deserialize, Serialize, Serializer, ser::SerializeMap};
4use urlencoding::encode;
5
6use crate::{
7 error::OpenRouterError,
8 strip_option_vec_setter,
9 transport::{request as transport_request, response as transport_response},
10 types::{ApiResponse, PaginationOptions},
11};
12
13#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
15#[non_exhaustive]
16#[serde(rename_all = "lowercase")]
17pub enum ContentFilterAction {
18 Redact,
19 Block,
20}
21
22#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
24#[non_exhaustive]
25#[serde(rename_all = "lowercase")]
26pub enum ContentFilterBuiltinAction {
27 Redact,
28 Block,
29 Flag,
30}
31
32#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
34#[non_exhaustive]
35#[serde(rename_all = "kebab-case")]
36pub enum ContentFilterBuiltinSlug {
37 Email,
38 Phone,
39 Ssn,
40 CreditCard,
41 IpAddress,
42 PersonName,
43 Address,
44 RegexPromptInjection,
45}
46
47#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
49#[non_exhaustive]
50pub struct ContentFilterBuiltinEntry {
51 pub slug: ContentFilterBuiltinSlug,
52 pub action: ContentFilterBuiltinAction,
53 #[serde(skip_serializing_if = "Option::is_none")]
54 pub label: Option<String>,
55}
56
57impl ContentFilterBuiltinEntry {
58 pub fn new(slug: ContentFilterBuiltinSlug, action: ContentFilterBuiltinAction) -> Self {
59 Self {
60 slug,
61 action,
62 label: None,
63 }
64 }
65
66 pub fn label(mut self, label: impl Into<String>) -> Self {
67 self.label = Some(label.into());
68 self
69 }
70}
71
72#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
74#[non_exhaustive]
75pub struct ContentFilterEntry {
76 pub pattern: String,
77 pub action: ContentFilterAction,
78 #[serde(skip_serializing_if = "Option::is_none")]
79 pub label: Option<String>,
80}
81
82impl ContentFilterEntry {
83 pub fn new(pattern: impl Into<String>, action: ContentFilterAction) -> Self {
84 Self {
85 pattern: pattern.into(),
86 action,
87 label: None,
88 }
89 }
90
91 pub fn label(mut self, label: impl Into<String>) -> Self {
92 self.label = Some(label.into());
93 self
94 }
95}
96
97#[derive(Serialize, Deserialize, Debug, Clone)]
99#[non_exhaustive]
100pub struct Guardrail {
101 pub id: String,
102 pub name: String,
103 #[serde(skip_serializing_if = "Option::is_none")]
104 pub description: Option<String>,
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub limit_usd: Option<f64>,
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub reset_interval: Option<String>,
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub allowed_providers: Option<Vec<String>>,
111 #[serde(skip_serializing_if = "Option::is_none")]
112 pub allowed_models: Option<Vec<String>>,
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub content_filter_builtins: Option<Vec<ContentFilterBuiltinEntry>>,
115 #[serde(skip_serializing_if = "Option::is_none")]
116 pub content_filters: Option<Vec<ContentFilterEntry>>,
117 #[serde(skip_serializing_if = "Option::is_none")]
118 pub enforce_zdr: Option<bool>,
119 #[serde(skip_serializing_if = "Option::is_none")]
120 pub enforce_zdr_anthropic: Option<bool>,
121 #[serde(skip_serializing_if = "Option::is_none")]
122 pub enforce_zdr_openai: Option<bool>,
123 #[serde(skip_serializing_if = "Option::is_none")]
124 pub enforce_zdr_google: Option<bool>,
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub enforce_zdr_other: Option<bool>,
127 pub created_at: String,
128 #[serde(skip_serializing_if = "Option::is_none")]
129 pub updated_at: Option<String>,
130 #[serde(skip_serializing_if = "Option::is_none")]
131 pub workspace_id: Option<String>,
132}
133
134#[derive(Serialize, Deserialize, Debug, Clone)]
136#[non_exhaustive]
137pub struct GuardrailListResponse {
138 pub data: Vec<Guardrail>,
139 pub total_count: f64,
140}
141
142#[derive(Serialize, Deserialize, Debug, Clone, Builder)]
144#[builder(build_fn(error = "OpenRouterError"))]
145#[non_exhaustive]
146pub struct CreateGuardrailRequest {
147 #[builder(setter(into))]
148 name: String,
149 #[builder(setter(into, strip_option), default)]
150 #[serde(skip_serializing_if = "Option::is_none")]
151 description: Option<String>,
152 #[builder(setter(strip_option), default)]
153 #[serde(skip_serializing_if = "Option::is_none")]
154 limit_usd: Option<f64>,
155 #[builder(setter(into, strip_option), default)]
156 #[serde(skip_serializing_if = "Option::is_none")]
157 reset_interval: Option<String>,
158 #[builder(setter(custom), default)]
159 #[serde(skip_serializing_if = "Option::is_none")]
160 allowed_providers: Option<Vec<String>>,
161 #[builder(setter(custom), default)]
162 #[serde(skip_serializing_if = "Option::is_none")]
163 allowed_models: Option<Vec<String>>,
164 #[builder(setter(custom), default)]
165 #[serde(skip_serializing_if = "Option::is_none")]
166 content_filter_builtins: Option<Vec<ContentFilterBuiltinEntry>>,
167 #[builder(setter(custom), default)]
168 #[serde(skip_serializing_if = "Option::is_none")]
169 content_filters: Option<Vec<ContentFilterEntry>>,
170 #[builder(setter(strip_option), default)]
171 #[serde(skip_serializing_if = "Option::is_none")]
172 enforce_zdr: Option<bool>,
173 #[builder(setter(strip_option), default)]
174 #[serde(skip_serializing_if = "Option::is_none")]
175 enforce_zdr_anthropic: Option<bool>,
176 #[builder(setter(strip_option), default)]
177 #[serde(skip_serializing_if = "Option::is_none")]
178 enforce_zdr_openai: Option<bool>,
179 #[builder(setter(strip_option), default)]
180 #[serde(skip_serializing_if = "Option::is_none")]
181 enforce_zdr_google: Option<bool>,
182 #[builder(setter(strip_option), default)]
183 #[serde(skip_serializing_if = "Option::is_none")]
184 enforce_zdr_other: Option<bool>,
185 #[builder(setter(into, strip_option), default)]
186 #[serde(skip_serializing_if = "Option::is_none")]
187 workspace_id: Option<String>,
188}
189
190impl CreateGuardrailRequestBuilder {
191 strip_option_vec_setter!(allowed_providers, String);
192 strip_option_vec_setter!(allowed_models, String);
193 strip_option_vec_setter!(content_filter_builtins, ContentFilterBuiltinEntry);
194 strip_option_vec_setter!(content_filters, ContentFilterEntry);
195}
196
197impl CreateGuardrailRequest {
198 pub fn builder() -> CreateGuardrailRequestBuilder {
199 CreateGuardrailRequestBuilder::default()
200 }
201}
202
203#[derive(Deserialize, Debug, Clone, Builder)]
205#[builder(build_fn(error = "OpenRouterError"))]
206#[non_exhaustive]
207pub struct UpdateGuardrailRequest {
208 #[builder(setter(into, strip_option), default)]
209 name: Option<String>,
210 #[builder(setter(into, strip_option), default)]
211 description: Option<String>,
212 #[builder(setter(strip_option), default)]
213 limit_usd: Option<f64>,
214 #[builder(setter(into, strip_option), default)]
215 reset_interval: Option<String>,
216 #[builder(setter(custom), default)]
217 allowed_providers: Option<Vec<String>>,
218 #[serde(skip)]
219 #[builder(setter(custom), default)]
220 clear_allowed_providers: bool,
221 #[builder(setter(custom), default)]
222 allowed_models: Option<Vec<String>>,
223 #[serde(skip)]
224 #[builder(setter(custom), default)]
225 clear_allowed_models: bool,
226 #[builder(setter(custom), default)]
227 content_filter_builtins: Option<Vec<ContentFilterBuiltinEntry>>,
228 #[serde(skip)]
229 #[builder(setter(custom), default)]
230 clear_content_filter_builtins: bool,
231 #[builder(setter(custom), default)]
232 content_filters: Option<Vec<ContentFilterEntry>>,
233 #[serde(skip)]
234 #[builder(setter(custom), default)]
235 clear_content_filters: bool,
236 #[builder(setter(strip_option), default)]
237 enforce_zdr: Option<bool>,
238 #[builder(setter(strip_option), default)]
239 enforce_zdr_anthropic: Option<bool>,
240 #[builder(setter(strip_option), default)]
241 enforce_zdr_openai: Option<bool>,
242 #[builder(setter(strip_option), default)]
243 enforce_zdr_google: Option<bool>,
244 #[builder(setter(strip_option), default)]
245 enforce_zdr_other: Option<bool>,
246}
247
248impl Serialize for UpdateGuardrailRequest {
249 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
250 where
251 S: Serializer,
252 {
253 let mut map = serializer.serialize_map(None)?;
254 if let Some(value) = &self.name {
255 map.serialize_entry("name", value)?;
256 }
257 if let Some(value) = &self.description {
258 map.serialize_entry("description", value)?;
259 }
260 if let Some(value) = &self.limit_usd {
261 map.serialize_entry("limit_usd", value)?;
262 }
263 if let Some(value) = &self.reset_interval {
264 map.serialize_entry("reset_interval", value)?;
265 }
266 if self.clear_allowed_providers {
267 map.serialize_entry("allowed_providers", &Option::<Vec<String>>::None)?;
268 } else if let Some(value) = &self.allowed_providers {
269 map.serialize_entry("allowed_providers", value)?;
270 }
271 if self.clear_allowed_models {
272 map.serialize_entry("allowed_models", &Option::<Vec<String>>::None)?;
273 } else if let Some(value) = &self.allowed_models {
274 map.serialize_entry("allowed_models", value)?;
275 }
276 if self.clear_content_filter_builtins {
277 map.serialize_entry(
278 "content_filter_builtins",
279 &Option::<Vec<ContentFilterBuiltinEntry>>::None,
280 )?;
281 } else if let Some(value) = &self.content_filter_builtins {
282 map.serialize_entry("content_filter_builtins", value)?;
283 }
284 if self.clear_content_filters {
285 map.serialize_entry("content_filters", &Option::<Vec<ContentFilterEntry>>::None)?;
286 } else if let Some(value) = &self.content_filters {
287 map.serialize_entry("content_filters", value)?;
288 }
289 if let Some(value) = &self.enforce_zdr {
290 map.serialize_entry("enforce_zdr", value)?;
291 }
292 if let Some(value) = &self.enforce_zdr_anthropic {
293 map.serialize_entry("enforce_zdr_anthropic", value)?;
294 }
295 if let Some(value) = &self.enforce_zdr_openai {
296 map.serialize_entry("enforce_zdr_openai", value)?;
297 }
298 if let Some(value) = &self.enforce_zdr_google {
299 map.serialize_entry("enforce_zdr_google", value)?;
300 }
301 if let Some(value) = &self.enforce_zdr_other {
302 map.serialize_entry("enforce_zdr_other", value)?;
303 }
304 map.end()
305 }
306}
307
308impl UpdateGuardrailRequestBuilder {
309 pub fn allowed_providers<T, S>(&mut self, items: T) -> &mut Self
310 where
311 T: IntoIterator<Item = S>,
312 S: Into<String>,
313 {
314 self.allowed_providers = Some(Some(items.into_iter().map(Into::into).collect()));
315 self.clear_allowed_providers = Some(false);
316 self
317 }
318
319 pub fn allowed_models<T, S>(&mut self, items: T) -> &mut Self
320 where
321 T: IntoIterator<Item = S>,
322 S: Into<String>,
323 {
324 self.allowed_models = Some(Some(items.into_iter().map(Into::into).collect()));
325 self.clear_allowed_models = Some(false);
326 self
327 }
328
329 pub fn clear_allowed_providers(&mut self) -> &mut Self {
330 self.allowed_providers = Some(None);
331 self.clear_allowed_providers = Some(true);
332 self
333 }
334
335 pub fn clear_allowed_models(&mut self) -> &mut Self {
336 self.allowed_models = Some(None);
337 self.clear_allowed_models = Some(true);
338 self
339 }
340
341 pub fn content_filter_builtins<T, S>(&mut self, items: T) -> &mut Self
342 where
343 T: IntoIterator<Item = S>,
344 S: Into<ContentFilterBuiltinEntry>,
345 {
346 self.content_filter_builtins = Some(Some(items.into_iter().map(Into::into).collect()));
347 self.clear_content_filter_builtins = Some(false);
348 self
349 }
350
351 pub fn content_filters<T, S>(&mut self, items: T) -> &mut Self
352 where
353 T: IntoIterator<Item = S>,
354 S: Into<ContentFilterEntry>,
355 {
356 self.content_filters = Some(Some(items.into_iter().map(Into::into).collect()));
357 self.clear_content_filters = Some(false);
358 self
359 }
360
361 pub fn clear_content_filter_builtins(&mut self) -> &mut Self {
362 self.content_filter_builtins = Some(None);
363 self.clear_content_filter_builtins = Some(true);
364 self
365 }
366
367 pub fn clear_content_filters(&mut self) -> &mut Self {
368 self.content_filters = Some(None);
369 self.clear_content_filters = Some(true);
370 self
371 }
372}
373
374impl UpdateGuardrailRequest {
375 pub fn builder() -> UpdateGuardrailRequestBuilder {
376 UpdateGuardrailRequestBuilder::default()
377 }
378}
379
380#[derive(Serialize, Deserialize, Debug, Clone)]
381struct DeleteGuardrailResponse {
382 deleted: bool,
383}
384
385#[derive(Serialize, Deserialize, Debug, Clone)]
387#[non_exhaustive]
388pub struct GuardrailKeyAssignment {
389 pub id: String,
390 pub key_hash: String,
391 pub guardrail_id: String,
392 pub key_name: String,
393 pub key_label: String,
394 pub assigned_by: String,
395 pub created_at: String,
396}
397
398#[derive(Serialize, Deserialize, Debug, Clone)]
400#[non_exhaustive]
401pub struct GuardrailMemberAssignment {
402 pub id: String,
403 pub user_id: String,
404 pub organization_id: String,
405 pub guardrail_id: String,
406 pub assigned_by: String,
407 pub created_at: String,
408}
409
410#[derive(Serialize, Deserialize, Debug, Clone)]
412#[non_exhaustive]
413pub struct GuardrailKeyAssignmentsResponse {
414 pub data: Vec<GuardrailKeyAssignment>,
415 pub total_count: f64,
416}
417
418#[derive(Serialize, Deserialize, Debug, Clone)]
420#[non_exhaustive]
421pub struct GuardrailMemberAssignmentsResponse {
422 pub data: Vec<GuardrailMemberAssignment>,
423 pub total_count: f64,
424}
425
426#[derive(Serialize, Deserialize, Debug, Clone, Builder)]
428#[builder(build_fn(error = "OpenRouterError"))]
429#[non_exhaustive]
430pub struct BulkKeyAssignmentRequest {
431 key_hashes: Vec<String>,
432}
433
434impl BulkKeyAssignmentRequest {
435 pub fn builder() -> BulkKeyAssignmentRequestBuilder {
436 BulkKeyAssignmentRequestBuilder::default()
437 }
438}
439
440#[derive(Serialize, Deserialize, Debug, Clone, Builder)]
442#[builder(build_fn(error = "OpenRouterError"))]
443#[non_exhaustive]
444pub struct BulkMemberAssignmentRequest {
445 member_user_ids: Vec<String>,
446}
447
448impl BulkMemberAssignmentRequest {
449 pub fn builder() -> BulkMemberAssignmentRequestBuilder {
450 BulkMemberAssignmentRequestBuilder::default()
451 }
452}
453
454#[derive(Serialize, Deserialize, Debug, Clone)]
456#[non_exhaustive]
457pub struct AssignedCountResponse {
458 pub assigned_count: f64,
459}
460
461#[derive(Serialize, Deserialize, Debug, Clone)]
463#[non_exhaustive]
464pub struct UnassignedCountResponse {
465 pub unassigned_count: f64,
466}
467
468#[derive(Serialize)]
469struct ListGuardrailsQuery {
470 #[serde(skip_serializing_if = "Option::is_none")]
471 offset: Option<u32>,
472 #[serde(skip_serializing_if = "Option::is_none")]
473 limit: Option<u32>,
474 #[serde(skip_serializing_if = "Option::is_none")]
475 workspace_id: Option<String>,
476}
477
478fn with_pagination(url: String, pagination: Option<PaginationOptions>) -> String {
479 let params = pagination
480 .map(PaginationOptions::to_query_pairs)
481 .unwrap_or_default()
482 .into_iter()
483 .map(|(key, value)| format!("{key}={value}"))
484 .collect::<Vec<_>>();
485
486 if params.is_empty() {
487 url
488 } else {
489 format!("{url}?{}", params.join("&"))
490 }
491}
492
493pub async fn list_guardrails(
494 base_url: &str,
495 management_key: &str,
496 pagination: Option<PaginationOptions>,
497) -> Result<GuardrailListResponse, OpenRouterError> {
498 let http_client = crate::transport::new_client()?;
499 list_guardrails_in_workspace_with_client(
500 &http_client,
501 base_url,
502 management_key,
503 pagination,
504 None,
505 )
506 .await
507}
508
509pub(crate) async fn list_guardrails_with_client(
510 http_client: &HttpClient,
511 base_url: &str,
512 management_key: &str,
513 pagination: Option<PaginationOptions>,
514) -> Result<GuardrailListResponse, OpenRouterError> {
515 list_guardrails_in_workspace_with_client(
516 http_client,
517 base_url,
518 management_key,
519 pagination,
520 None,
521 )
522 .await
523}
524
525pub async fn list_guardrails_in_workspace(
526 base_url: &str,
527 management_key: &str,
528 pagination: Option<PaginationOptions>,
529 workspace_id: Option<&str>,
530) -> Result<GuardrailListResponse, OpenRouterError> {
531 let http_client = crate::transport::new_client()?;
532 list_guardrails_in_workspace_with_client(
533 &http_client,
534 base_url,
535 management_key,
536 pagination,
537 workspace_id,
538 )
539 .await
540}
541
542pub(crate) async fn list_guardrails_in_workspace_with_client(
543 http_client: &HttpClient,
544 base_url: &str,
545 management_key: &str,
546 pagination: Option<PaginationOptions>,
547 workspace_id: Option<&str>,
548) -> Result<GuardrailListResponse, OpenRouterError> {
549 let url = format!("{base_url}/guardrails");
550 let query = ListGuardrailsQuery {
551 offset: pagination.and_then(|p| p.offset),
552 limit: pagination.and_then(|p| p.limit),
553 workspace_id: workspace_id.map(ToOwned::to_owned),
554 };
555 let req = transport_request::with_bearer_auth(
556 transport_request::get(http_client, &url),
557 management_key,
558 );
559 let response =
560 if query.offset.is_none() && query.limit.is_none() && query.workspace_id.is_none() {
561 req.send().await?
562 } else {
563 req.query(&query).send().await?
564 };
565
566 if response.status().is_success() {
567 transport_response::parse_json_response(response, "guardrail list").await
568 } else {
569 transport_response::handle_error(response).await?;
570 unreachable!()
571 }
572}
573
574pub async fn create_guardrail(
575 base_url: &str,
576 management_key: &str,
577 request: &CreateGuardrailRequest,
578) -> Result<Guardrail, OpenRouterError> {
579 let http_client = crate::transport::new_client()?;
580 create_guardrail_with_client(&http_client, base_url, management_key, request).await
581}
582
583pub(crate) async fn create_guardrail_with_client(
584 http_client: &HttpClient,
585 base_url: &str,
586 management_key: &str,
587 request: &CreateGuardrailRequest,
588) -> Result<Guardrail, OpenRouterError> {
589 let url = format!("{base_url}/guardrails");
590 let response = transport_request::with_bearer_auth(
591 transport_request::post(http_client, &url),
592 management_key,
593 )
594 .json(request)
595 .send()
596 .await?;
597
598 if response.status().is_success() {
599 let payload: ApiResponse<Guardrail> =
600 transport_response::parse_json_response(response, "guardrail creation").await?;
601 Ok(payload.data)
602 } else {
603 transport_response::handle_error(response).await?;
604 unreachable!()
605 }
606}
607
608pub async fn get_guardrail(
609 base_url: &str,
610 management_key: &str,
611 id: &str,
612) -> Result<Guardrail, OpenRouterError> {
613 let http_client = crate::transport::new_client()?;
614 get_guardrail_with_client(&http_client, base_url, management_key, id).await
615}
616
617pub(crate) async fn get_guardrail_with_client(
618 http_client: &HttpClient,
619 base_url: &str,
620 management_key: &str,
621 id: &str,
622) -> Result<Guardrail, OpenRouterError> {
623 let url = format!("{base_url}/guardrails/{}", encode(id));
624 let response = transport_request::with_bearer_auth(
625 transport_request::get(http_client, &url),
626 management_key,
627 )
628 .send()
629 .await?;
630
631 if response.status().is_success() {
632 let payload: ApiResponse<Guardrail> =
633 transport_response::parse_json_response(response, "guardrail lookup").await?;
634 Ok(payload.data)
635 } else {
636 transport_response::handle_error(response).await?;
637 unreachable!()
638 }
639}
640
641pub async fn update_guardrail(
642 base_url: &str,
643 management_key: &str,
644 id: &str,
645 request: &UpdateGuardrailRequest,
646) -> Result<Guardrail, OpenRouterError> {
647 let http_client = crate::transport::new_client()?;
648 update_guardrail_with_client(&http_client, base_url, management_key, id, request).await
649}
650
651pub(crate) async fn update_guardrail_with_client(
652 http_client: &HttpClient,
653 base_url: &str,
654 management_key: &str,
655 id: &str,
656 request: &UpdateGuardrailRequest,
657) -> Result<Guardrail, OpenRouterError> {
658 let url = format!("{base_url}/guardrails/{}", encode(id));
659 let response = transport_request::with_bearer_auth(
660 transport_request::patch(http_client, &url),
661 management_key,
662 )
663 .json(request)
664 .send()
665 .await?;
666
667 if response.status().is_success() {
668 let payload: ApiResponse<Guardrail> =
669 transport_response::parse_json_response(response, "guardrail update").await?;
670 Ok(payload.data)
671 } else {
672 transport_response::handle_error(response).await?;
673 unreachable!()
674 }
675}
676
677pub async fn delete_guardrail(
678 base_url: &str,
679 management_key: &str,
680 id: &str,
681) -> Result<bool, OpenRouterError> {
682 let http_client = crate::transport::new_client()?;
683 delete_guardrail_with_client(&http_client, base_url, management_key, id).await
684}
685
686pub(crate) async fn delete_guardrail_with_client(
687 http_client: &HttpClient,
688 base_url: &str,
689 management_key: &str,
690 id: &str,
691) -> Result<bool, OpenRouterError> {
692 let url = format!("{base_url}/guardrails/{}", encode(id));
693 let response = transport_request::with_bearer_auth(
694 transport_request::delete(http_client, &url),
695 management_key,
696 )
697 .send()
698 .await?;
699
700 if response.status().is_success() {
701 let payload: DeleteGuardrailResponse =
702 transport_response::parse_json_response(response, "guardrail deletion").await?;
703 Ok(payload.deleted)
704 } else {
705 transport_response::handle_error(response).await?;
706 unreachable!()
707 }
708}
709
710pub async fn list_guardrail_key_assignments(
711 base_url: &str,
712 management_key: &str,
713 id: &str,
714 pagination: Option<PaginationOptions>,
715) -> Result<GuardrailKeyAssignmentsResponse, OpenRouterError> {
716 let http_client = crate::transport::new_client()?;
717 list_guardrail_key_assignments_with_client(
718 &http_client,
719 base_url,
720 management_key,
721 id,
722 pagination,
723 )
724 .await
725}
726
727pub(crate) async fn list_guardrail_key_assignments_with_client(
728 http_client: &HttpClient,
729 base_url: &str,
730 management_key: &str,
731 id: &str,
732 pagination: Option<PaginationOptions>,
733) -> Result<GuardrailKeyAssignmentsResponse, OpenRouterError> {
734 let url = with_pagination(
735 format!("{base_url}/guardrails/{}/assignments/keys", encode(id)),
736 pagination,
737 );
738 let response = transport_request::with_bearer_auth(
739 transport_request::get(http_client, &url),
740 management_key,
741 )
742 .send()
743 .await?;
744
745 if response.status().is_success() {
746 transport_response::parse_json_response(response, "guardrail key assignments").await
747 } else {
748 transport_response::handle_error(response).await?;
749 unreachable!()
750 }
751}
752
753pub async fn bulk_assign_keys_to_guardrail(
754 base_url: &str,
755 management_key: &str,
756 id: &str,
757 request: &BulkKeyAssignmentRequest,
758) -> Result<AssignedCountResponse, OpenRouterError> {
759 let http_client = crate::transport::new_client()?;
760 bulk_assign_keys_to_guardrail_with_client(&http_client, base_url, management_key, id, request)
761 .await
762}
763
764pub(crate) async fn bulk_assign_keys_to_guardrail_with_client(
765 http_client: &HttpClient,
766 base_url: &str,
767 management_key: &str,
768 id: &str,
769 request: &BulkKeyAssignmentRequest,
770) -> Result<AssignedCountResponse, OpenRouterError> {
771 let url = format!("{base_url}/guardrails/{}/assignments/keys", encode(id));
772 let response = transport_request::with_bearer_auth(
773 transport_request::post(http_client, &url),
774 management_key,
775 )
776 .json(request)
777 .send()
778 .await?;
779
780 if response.status().is_success() {
781 transport_response::parse_json_response(response, "guardrail key bulk assignment").await
782 } else {
783 transport_response::handle_error(response).await?;
784 unreachable!()
785 }
786}
787
788pub async fn bulk_unassign_keys_from_guardrail(
789 base_url: &str,
790 management_key: &str,
791 id: &str,
792 request: &BulkKeyAssignmentRequest,
793) -> Result<UnassignedCountResponse, OpenRouterError> {
794 let http_client = crate::transport::new_client()?;
795 bulk_unassign_keys_from_guardrail_with_client(
796 &http_client,
797 base_url,
798 management_key,
799 id,
800 request,
801 )
802 .await
803}
804
805pub(crate) async fn bulk_unassign_keys_from_guardrail_with_client(
806 http_client: &HttpClient,
807 base_url: &str,
808 management_key: &str,
809 id: &str,
810 request: &BulkKeyAssignmentRequest,
811) -> Result<UnassignedCountResponse, OpenRouterError> {
812 let url = format!(
813 "{base_url}/guardrails/{}/assignments/keys/remove",
814 encode(id)
815 );
816 let response = transport_request::with_bearer_auth(
817 transport_request::post(http_client, &url),
818 management_key,
819 )
820 .json(request)
821 .send()
822 .await?;
823
824 if response.status().is_success() {
825 transport_response::parse_json_response(response, "guardrail key bulk removal").await
826 } else {
827 transport_response::handle_error(response).await?;
828 unreachable!()
829 }
830}
831
832pub async fn list_guardrail_member_assignments(
833 base_url: &str,
834 management_key: &str,
835 id: &str,
836 pagination: Option<PaginationOptions>,
837) -> Result<GuardrailMemberAssignmentsResponse, OpenRouterError> {
838 let http_client = crate::transport::new_client()?;
839 list_guardrail_member_assignments_with_client(
840 &http_client,
841 base_url,
842 management_key,
843 id,
844 pagination,
845 )
846 .await
847}
848
849pub(crate) async fn list_guardrail_member_assignments_with_client(
850 http_client: &HttpClient,
851 base_url: &str,
852 management_key: &str,
853 id: &str,
854 pagination: Option<PaginationOptions>,
855) -> Result<GuardrailMemberAssignmentsResponse, OpenRouterError> {
856 let url = with_pagination(
857 format!("{base_url}/guardrails/{}/assignments/members", encode(id)),
858 pagination,
859 );
860 let response = transport_request::with_bearer_auth(
861 transport_request::get(http_client, &url),
862 management_key,
863 )
864 .send()
865 .await?;
866
867 if response.status().is_success() {
868 transport_response::parse_json_response(response, "guardrail member assignments").await
869 } else {
870 transport_response::handle_error(response).await?;
871 unreachable!()
872 }
873}
874
875pub async fn bulk_assign_members_to_guardrail(
876 base_url: &str,
877 management_key: &str,
878 id: &str,
879 request: &BulkMemberAssignmentRequest,
880) -> Result<AssignedCountResponse, OpenRouterError> {
881 let http_client = crate::transport::new_client()?;
882 bulk_assign_members_to_guardrail_with_client(
883 &http_client,
884 base_url,
885 management_key,
886 id,
887 request,
888 )
889 .await
890}
891
892pub(crate) async fn bulk_assign_members_to_guardrail_with_client(
893 http_client: &HttpClient,
894 base_url: &str,
895 management_key: &str,
896 id: &str,
897 request: &BulkMemberAssignmentRequest,
898) -> Result<AssignedCountResponse, OpenRouterError> {
899 let url = format!("{base_url}/guardrails/{}/assignments/members", encode(id));
900 let response = transport_request::with_bearer_auth(
901 transport_request::post(http_client, &url),
902 management_key,
903 )
904 .json(request)
905 .send()
906 .await?;
907
908 if response.status().is_success() {
909 transport_response::parse_json_response(response, "guardrail member bulk assignment").await
910 } else {
911 transport_response::handle_error(response).await?;
912 unreachable!()
913 }
914}
915
916pub async fn bulk_unassign_members_from_guardrail(
917 base_url: &str,
918 management_key: &str,
919 id: &str,
920 request: &BulkMemberAssignmentRequest,
921) -> Result<UnassignedCountResponse, OpenRouterError> {
922 let http_client = crate::transport::new_client()?;
923 bulk_unassign_members_from_guardrail_with_client(
924 &http_client,
925 base_url,
926 management_key,
927 id,
928 request,
929 )
930 .await
931}
932
933pub(crate) async fn bulk_unassign_members_from_guardrail_with_client(
934 http_client: &HttpClient,
935 base_url: &str,
936 management_key: &str,
937 id: &str,
938 request: &BulkMemberAssignmentRequest,
939) -> Result<UnassignedCountResponse, OpenRouterError> {
940 let url = format!(
941 "{base_url}/guardrails/{}/assignments/members/remove",
942 encode(id)
943 );
944 let response = transport_request::with_bearer_auth(
945 transport_request::post(http_client, &url),
946 management_key,
947 )
948 .json(request)
949 .send()
950 .await?;
951
952 if response.status().is_success() {
953 transport_response::parse_json_response(response, "guardrail member bulk removal").await
954 } else {
955 transport_response::handle_error(response).await?;
956 unreachable!()
957 }
958}
959
960pub async fn list_key_assignments(
961 base_url: &str,
962 management_key: &str,
963 pagination: Option<PaginationOptions>,
964) -> Result<GuardrailKeyAssignmentsResponse, OpenRouterError> {
965 let http_client = crate::transport::new_client()?;
966 list_key_assignments_with_client(&http_client, base_url, management_key, pagination).await
967}
968
969pub(crate) async fn list_key_assignments_with_client(
970 http_client: &HttpClient,
971 base_url: &str,
972 management_key: &str,
973 pagination: Option<PaginationOptions>,
974) -> Result<GuardrailKeyAssignmentsResponse, OpenRouterError> {
975 let url = with_pagination(
976 format!("{base_url}/guardrails/assignments/keys"),
977 pagination,
978 );
979 let response = transport_request::with_bearer_auth(
980 transport_request::get(http_client, &url),
981 management_key,
982 )
983 .send()
984 .await?;
985
986 if response.status().is_success() {
987 transport_response::parse_json_response(response, "global key assignments").await
988 } else {
989 transport_response::handle_error(response).await?;
990 unreachable!()
991 }
992}
993
994pub async fn list_member_assignments(
995 base_url: &str,
996 management_key: &str,
997 pagination: Option<PaginationOptions>,
998) -> Result<GuardrailMemberAssignmentsResponse, OpenRouterError> {
999 let http_client = crate::transport::new_client()?;
1000 list_member_assignments_with_client(&http_client, base_url, management_key, pagination).await
1001}
1002
1003pub(crate) async fn list_member_assignments_with_client(
1004 http_client: &HttpClient,
1005 base_url: &str,
1006 management_key: &str,
1007 pagination: Option<PaginationOptions>,
1008) -> Result<GuardrailMemberAssignmentsResponse, OpenRouterError> {
1009 let url = with_pagination(
1010 format!("{base_url}/guardrails/assignments/members"),
1011 pagination,
1012 );
1013 let response = transport_request::with_bearer_auth(
1014 transport_request::get(http_client, &url),
1015 management_key,
1016 )
1017 .send()
1018 .await?;
1019
1020 if response.status().is_success() {
1021 transport_response::parse_json_response(response, "global member assignments").await
1022 } else {
1023 transport_response::handle_error(response).await?;
1024 unreachable!()
1025 }
1026}