1use crate::AdapterOutput;
3use crate::utils::json::JsValue;
4use crate::{AuthError, AuthResult};
5use indexmap::{IndexMap, IndexSet};
6use serde_json::Value;
7use std::{fmt, future::Future, pin::Pin, sync::Arc};
8
9#[derive(Clone, Default)]
11pub struct FieldValues {
12 values: IndexMap<String, JsValue>,
13 adapter_fields: Option<Arc<FieldConfigs>>,
14 undefined_input_keys: IndexSet<String>,
15 transform_omitted: bool,
16 binding_names: IndexMap<String, String>,
17}
18
19impl FieldValues {
20 #[must_use]
21 pub fn new() -> Self {
22 Self::default()
23 }
24 #[must_use]
27 pub fn has_input_fields(&self) -> bool {
28 !self.values.is_empty() || !self.undefined_input_keys.is_empty()
29 }
30 #[must_use]
32 pub fn binding_name<'a>(&'a self, name: &'a str) -> &'a str {
33 self.binding_names.get(name).map_or(name, String::as_str)
34 }
35 pub fn apply_adapter_transforms(&mut self) -> AuthResult<()> {
42 if self.adapter_fields.as_ref().is_some_and(|fields| {
43 fields
44 .values()
45 .any(|field| field.adapter_input_transform.is_some())
46 }) {
47 return Err(AuthError::config(
48 "Asynchronous adapter transforms require apply_adapter_transforms_async",
49 ));
50 }
51 if let Some(fields) = self.adapter_fields.take() {
52 for (name, field) in &*fields {
53 if self.prepare_adapter_value(name, field)
54 && let Some(transform) = &field.transform
55 {
56 let value = transform(self.values.get(name))?;
57 self.set_adapter_value(name, value);
58 }
59 }
60 }
61 self.finish_adapter_transforms();
62 Ok(())
63 }
64
65 pub async fn apply_adapter_transforms_async(&mut self) -> AuthResult<()> {
71 if let Some(fields) = self.adapter_fields.take() {
72 for (name, field) in &*fields {
73 if !self.prepare_adapter_value(name, field) {
74 continue;
75 }
76 let value = if let Some(transform) = &field.adapter_input_transform {
77 transform(self.values.get(name).cloned())
78 .await
79 .map_err(crate::store::adapter::callback_error)?
80 } else if let Some(transform) = &field.transform {
81 transform(self.values.get(name))?
82 } else {
83 continue;
84 };
85 self.set_adapter_value(name, value);
86 }
87 }
88 self.finish_adapter_transforms();
89 Ok(())
90 }
91
92 fn prepare_adapter_value(&mut self, name: &str, field: &FieldConfig) -> bool {
93 if !self.transform_omitted && !self.values.contains_key(name) && field.on_update.is_none() {
94 return false;
95 }
96 if self.transform_omitted
97 && (!self.values.contains_key(name)
98 || (field.required && self.values.get(name).is_some_and(JsValue::is_null)))
99 && let Some(default) = &field.default
100 {
101 _ = self.values.insert(name.to_owned(), default.value());
102 }
103 if !self.transform_omitted
104 && !self.values.contains_key(name)
105 && let Some(update) = &field.on_update
106 {
107 _ = self.values.insert(name.to_owned(), update());
108 }
109 true
110 }
111 fn set_adapter_value(&mut self, name: &str, value: Option<JsValue>) {
112 match value {
113 Some(value) => {
114 _ = self.values.insert(name.to_owned(), value);
115 }
116 None => {
117 _ = self.values.shift_remove(name);
118 }
119 }
120 }
121 fn finish_adapter_transforms(&mut self) {
122 self.undefined_input_keys.clear();
123 self.transform_omitted = false;
124 }
125 pub fn preserve_creation_value(&mut self, name: &str, value: JsValue) {
128 if self
129 .adapter_fields
130 .as_ref()
131 .is_some_and(|fields| fields.contains_key(name))
132 {
133 _ = self.values.entry(name.to_owned()).or_insert(value);
134 }
135 }
136}
137
138impl fmt::Debug for FieldValues {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 self.values.fmt(f)
141 }
142}
143
144impl std::ops::Deref for FieldValues {
145 type Target = IndexMap<String, JsValue>;
146 fn deref(&self) -> &Self::Target {
147 &self.values
148 }
149}
150
151impl std::ops::DerefMut for FieldValues {
152 fn deref_mut(&mut self) -> &mut Self::Target {
153 &mut self.values
154 }
155}
156
157impl From<IndexMap<String, JsValue>> for FieldValues {
158 fn from(values: IndexMap<String, JsValue>) -> Self {
159 Self {
160 values,
161 ..Self::default()
162 }
163 }
164}
165
166impl FromIterator<(String, JsValue)> for FieldValues {
167 fn from_iter<T: IntoIterator<Item = (String, JsValue)>>(iter: T) -> Self {
168 IndexMap::from_iter(iter).into()
169 }
170}
171
172impl IntoIterator for FieldValues {
173 type Item = (String, JsValue);
174 type IntoIter = indexmap::map::IntoIter<String, JsValue>;
175 fn into_iter(self) -> Self::IntoIter {
176 self.values.into_iter()
177 }
178}
179
180impl<'a> IntoIterator for &'a FieldValues {
181 type Item = (&'a String, &'a JsValue);
182 type IntoIter = indexmap::map::Iter<'a, String, JsValue>;
183 fn into_iter(self) -> Self::IntoIter {
184 self.values.iter()
185 }
186}
187
188impl<'a> IntoIterator for &'a mut FieldValues {
189 type Item = (&'a String, &'a mut JsValue);
190 type IntoIter = indexmap::map::IterMut<'a, String, JsValue>;
191 fn into_iter(self) -> Self::IntoIter {
192 self.values.iter_mut()
193 }
194}
195
196impl serde::Serialize for FieldValues {
197 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
198 self.values.serialize(serializer)
199 }
200}
201
202impl<'de> serde::Deserialize<'de> for FieldValues {
203 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
204 IndexMap::deserialize(deserializer).map(Self::from)
205 }
206}
207
208pub type FieldOutput = serde_json::Map<String, Value>;
209
210pub type FieldConfigs = IndexMap<String, FieldConfig>;
211
212pub type FieldValidator = Arc<dyn Fn(&JsValue) -> Result<JsValue, String> + Send + Sync>;
213pub type AsyncFieldValidator = Arc<
214 dyn Fn(JsValue) -> Pin<Box<dyn Future<Output = Result<JsValue, String>> + Send>> + Send + Sync,
215>;
216
217pub type FieldTransform =
219 Arc<dyn Fn(Option<&JsValue>) -> AuthResult<Option<JsValue>> + Send + Sync>;
220
221pub type FieldOutputTransform = Arc<
223 dyn Fn(Option<JsValue>) -> Pin<Box<dyn Future<Output = AuthResult<Option<JsValue>>> + Send>>
224 + Send
225 + Sync,
226>;
227
228#[derive(Clone)]
229pub enum FieldDefault {
230 Value(JsValue),
231 Callback(Arc<dyn Fn() -> JsValue + Send + Sync>),
232}
233
234impl fmt::Debug for FieldDefault {
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 match self {
237 Self::Value(value) => f.debug_tuple("Value").field(value).finish(),
238 Self::Callback(_) => f.write_str("Callback(..)"),
239 }
240 }
241}
242
243impl FieldDefault {
244 #[must_use]
245 pub fn value(&self) -> JsValue {
246 match self {
247 Self::Value(value) => value.clone(),
248 Self::Callback(callback) => callback(),
249 }
250 }
251}
252
253#[derive(Clone)]
255pub struct FieldConfig {
256 pub schema: Value,
257 pub required: bool,
258 pub input: bool,
259 pub returned: bool,
260 pub default: Option<FieldDefault>,
261 pub validator: Option<FieldValidator>,
262 pub async_validator: Option<AsyncFieldValidator>,
263 pub output_validator: Option<FieldValidator>,
265 pub adapter_input_transform: Option<FieldOutputTransform>,
266 pub transform: Option<FieldTransform>,
267 pub output_transform: Option<FieldOutputTransform>,
268 pub on_update: Option<Arc<dyn Fn() -> JsValue + Send + Sync>>,
269 pub field_name: Option<String>,
271}
272
273impl fmt::Debug for FieldConfig {
274 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275 f.debug_struct("FieldConfig")
276 .field("schema", &self.schema)
277 .field("required", &self.required)
278 .field("input", &self.input)
279 .field("returned", &self.returned)
280 .field("default", &self.default)
281 .field("validator", &self.validator.as_ref().map(|_| "callback"))
282 .field(
283 "async_validator",
284 &self.async_validator.as_ref().map(|_| "callback"),
285 )
286 .field(
287 "output_validator",
288 &self.output_validator.as_ref().map(|_| "callback"),
289 )
290 .field(
291 "adapter_input_transform",
292 &self.adapter_input_transform.as_ref().map(|_| "callback"),
293 )
294 .field("transform", &self.transform.as_ref().map(|_| "callback"))
295 .field(
296 "output_transform",
297 &self.output_transform.as_ref().map(|_| "callback"),
298 )
299 .field("on_update", &self.on_update.as_ref().map(|_| "callback"))
300 .field("field_name", &self.field_name)
301 .finish()
302 }
303}
304
305impl FieldConfig {
306 #[must_use]
307 pub fn new(schema: Value) -> Self {
308 Self {
309 schema,
310 required: false,
311 input: true,
312 returned: true,
313 default: None,
314 validator: None,
315 async_validator: None,
316 output_validator: None,
317 adapter_input_transform: None,
318 transform: None,
319 output_transform: None,
320 on_update: None,
321 field_name: None,
322 }
323 }
324 #[must_use]
325 pub fn default_value(mut self, value: impl Into<JsValue>) -> Self {
326 self.default = Some(FieldDefault::Value(value.into()));
327 self
328 }
329 #[must_use]
330 pub fn default_callback(
331 mut self,
332 callback: impl Fn() -> JsValue + Send + Sync + 'static,
333 ) -> Self {
334 self.default = Some(FieldDefault::Callback(Arc::new(callback)));
335 self
336 }
337 #[must_use]
338 pub const fn read_only(mut self) -> Self {
339 self.input = false;
340 self
341 }
342 #[must_use]
343 pub const fn hidden(mut self) -> Self {
344 self.returned = false;
345 self
346 }
347 #[must_use]
348 pub fn validate(
349 mut self,
350 validator: impl Fn(&JsValue) -> Result<JsValue, String> + Send + Sync + 'static,
351 ) -> Self {
352 self.validator = Some(Arc::new(validator));
353 self.async_validator = None;
354 self
355 }
356 #[must_use]
357 pub fn transform(
358 mut self,
359 transform: impl Fn(Option<&JsValue>) -> AuthResult<Option<JsValue>> + Send + Sync + 'static,
360 ) -> Self {
361 self.transform = Some(Arc::new(transform));
362 self
363 }
364
365 #[must_use]
368 pub fn validate_async<F, Fut>(mut self, validate: F) -> Self
369 where
370 F: Fn(JsValue) -> Fut + Send + Sync + 'static,
371 Fut: Future<Output = Result<JsValue, String>> + Send + 'static,
372 {
373 self.async_validator = Some(Arc::new(move |value| Box::pin(validate(value))));
374 self.validator = None;
375 self
376 }
377
378 #[must_use]
379 pub fn validate_output(
380 mut self,
381 validate: impl Fn(&JsValue) -> Result<JsValue, String> + Send + Sync + 'static,
382 ) -> Self {
383 self.output_validator = Some(Arc::new(validate));
384 self
385 }
386
387 #[must_use]
391 pub fn transform_adapter_input<F, Fut>(mut self, transform: F) -> Self
392 where
393 F: Fn(Option<JsValue>) -> Fut + Send + Sync + 'static,
394 Fut: Future<Output = AuthResult<Option<JsValue>>> + Send + 'static,
395 {
396 self.adapter_input_transform = Some(Arc::new(move |value| Box::pin(transform(value))));
397 self
398 }
399
400 #[must_use]
401 pub fn transform_output<F, Fut>(mut self, transform: F) -> Self
402 where
403 F: Fn(Option<JsValue>) -> Fut + Send + Sync + 'static,
404 Fut: Future<Output = AuthResult<Option<JsValue>>> + Send + 'static,
405 {
406 self.output_transform = Some(Arc::new(move |value| Box::pin(transform(value))));
407 self
408 }
409
410 #[must_use]
411 pub fn on_update(mut self, callback: impl Fn() -> JsValue + Send + Sync + 'static) -> Self {
412 self.on_update = Some(Arc::new(callback));
413 self
414 }
415
416 #[must_use]
417 pub fn field_name(mut self, name: impl Into<String>) -> Self {
418 self.field_name = Some(name.into());
419 self
420 }
421}
422
423#[derive(Debug)]
424pub enum FieldInputError {
425 Validation { code: &'static str, message: String },
426 Transform(crate::AuthError),
427}
428
429#[derive(Debug, Clone, Default)]
431pub struct SessionFields(pub IndexMap<String, FieldConfig>);
432
433impl SessionFields {
434 pub fn defaults(&self, values: &mut FieldValues) {
435 for (name, field) in &self.0 {
436 if let Some(default) = &field.default {
437 _ = values
438 .entry(name.clone())
439 .or_insert_with(|| default.value());
440 }
441 }
442 }
443 pub fn parse_update(
447 &self,
448 input: &IndexMap<String, JsValue>,
449 ) -> Result<FieldValues, FieldInputError> {
450 self.parse(input, false)
451 }
452
453 pub fn parse_create(
456 &self,
457 input: &IndexMap<String, JsValue>,
458 ) -> Result<FieldValues, FieldInputError> {
459 self.parse(input, true)
460 }
461
462 fn parse(
463 &self,
464 input: &IndexMap<String, JsValue>,
465 creation: bool,
466 ) -> Result<FieldValues, FieldInputError> {
467 let mut parsed = FieldValues::new();
468 for (name, field) in &self.0 {
469 let Some(value) = input.get(name) else {
470 if creation {
471 if let Some(default) = &field.default {
472 _ = parsed.insert(name.clone(), default.value());
473 } else if field.required {
474 return Err(FieldInputError::Validation {
475 code: "MISSING_FIELD",
476 message: format!("{name} is required"),
477 });
478 }
479 }
480 continue;
481 };
482 if !field.input {
483 if creation && let Some(default) = &field.default {
484 _ = parsed.insert(name.clone(), default.value());
485 continue;
486 }
487 if value.is_truthy() {
488 return Err(FieldInputError::Validation {
489 code: "FIELD_NOT_ALLOWED",
490 message: format!("{name} is not allowed to be set"),
491 });
492 }
493 continue;
494 }
495 if let Some(validator) = &field.async_validator {
496 _ = validator(value.clone());
497 return Err(FieldInputError::Transform(AuthError::Upstream {
498 status: 500,
499 code: "ASYNC_VALIDATION_NOT_SUPPORTED",
500 message: "Async validation is not supported",
501 }));
502 }
503 let value = if let Some(validator) = &field.validator {
504 Some(
505 validator(value).map_err(|message| FieldInputError::Validation {
506 code: "VALIDATION_ERROR",
507 message: if message.is_empty() {
508 "Validation Error".into()
509 } else {
510 message
511 },
512 })?,
513 )
514 } else if let Some(transform) = &field.transform {
515 transform(Some(value)).map_err(FieldInputError::Transform)?
516 } else {
517 Some(value.clone())
518 };
519 match value {
520 Some(value) => {
521 _ = parsed.insert(name.clone(), value);
522 }
523 None => {
524 _ = parsed.undefined_input_keys.insert(name.clone());
525 }
526 }
527 }
528 Ok(parsed)
529 }
530}
531
532#[derive(Debug, Clone, Default)]
534pub struct UserFields(pub SessionFields);
535
536#[derive(Debug, Clone, Default)]
538pub struct AccountFields(pub SessionFields);
539
540#[derive(Debug, Clone, Default)]
542pub struct AdapterFieldPolicies {
543 pub user: SessionAdapterFields,
544 pub account: SessionAdapterFields,
545}
546
547#[derive(Debug, Clone, Default)]
550pub struct SessionAdapterFields(pub Arc<FieldConfigs>);
551
552impl SessionAdapterFields {
553 pub(crate) fn attach(&self, values: &mut FieldValues, creation: bool) {
554 values.transform_omitted = creation;
555 values.adapter_fields = Some(Arc::clone(&self.0));
556 values.binding_names = self
557 .0
558 .iter()
559 .filter_map(|(name, field)| {
560 field
561 .field_name
562 .as_ref()
563 .map(|physical| (name.clone(), physical.clone()))
564 })
565 .collect();
566 }
567
568 pub(crate) async fn record_output(
572 &self,
573 canonical: Value,
574 mut additional: FieldOutput,
575 base: Value,
576 ) -> AuthResult<AdapterOutput> {
577 let (Value::Object(canonical), Value::Object(mut base)) = (canonical, base) else {
578 return Err(AuthError::internal("Adapter output must be an object"));
579 };
580 additional.extend(canonical);
581 for name in self.0.keys() {
582 if !additional.contains_key(name)
586 && let Some(value) = base.get(name)
587 {
588 _ = additional.insert(name.clone(), value.clone());
589 }
590 _ = base.remove(name);
591 }
592 let mut output = AdapterOutput::from_values(base);
593 output.extend(self.output(additional).await?);
594 Ok(output)
595 }
596
597 pub(crate) async fn output(&self, values: FieldOutput) -> AuthResult<AdapterOutput> {
599 let mut output = AdapterOutput::default();
600 for (name, field) in &*self.0 {
601 let value = values
602 .get(name)
603 .or_else(|| {
604 field
605 .field_name
606 .as_ref()
607 .and_then(|physical| values.get(physical))
608 })
609 .cloned()
610 .map(JsValue::from);
611 let value = if let Some(transform) = &field.output_transform {
612 transform(value).await.map_err(|error| match error {
613 AuthError::Api { .. } | AuthError::Upstream { .. } => error,
614 error => AuthError::CallbackFailure(Box::new(error)),
615 })?
616 } else {
617 value
618 };
619 output.insert(
620 name.clone(),
621 value.map(|value| value.to_json_value()).transpose()?,
622 );
623 }
624 Ok(output)
625 }
626}