@perspective-dev/client 4.0.1 → 4.1.1

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.
Files changed (45) hide show
  1. package/dist/cdn/perspective-server.worker.js +1 -1
  2. package/dist/cdn/perspective-server.worker.js.map +3 -3
  3. package/dist/cdn/perspective.js +2 -2
  4. package/dist/cdn/perspective.js.map +4 -4
  5. package/dist/esm/perspective.browser.d.ts +5 -1
  6. package/dist/esm/perspective.inline.js +2 -2
  7. package/dist/esm/perspective.inline.js.map +4 -4
  8. package/dist/esm/perspective.js +2 -2
  9. package/dist/esm/perspective.js.map +4 -4
  10. package/dist/esm/perspective.node.d.ts +6 -1
  11. package/dist/esm/perspective.node.js +721 -352
  12. package/dist/esm/perspective.node.js.map +4 -4
  13. package/dist/esm/ts-rs/ColumnType.d.ts +4 -0
  14. package/dist/esm/ts-rs/ViewConfig.d.ts +18 -0
  15. package/dist/esm/ts-rs/ViewWindow.d.ts +9 -9
  16. package/dist/esm/virtual_server.d.ts +47 -0
  17. package/dist/esm/virtual_servers/duckdb.d.ts +39 -0
  18. package/dist/esm/virtual_servers/duckdb.js +12 -0
  19. package/dist/esm/virtual_servers/duckdb.js.map +7 -0
  20. package/dist/esm/wasm/browser.d.ts +1 -1
  21. package/dist/wasm/perspective-js.d.ts +52 -13
  22. package/dist/wasm/perspective-js.js +648 -367
  23. package/dist/wasm/perspective-js.wasm +0 -0
  24. package/dist/wasm/perspective-js.wasm.d.ts +20 -8
  25. package/package.json +4 -1
  26. package/src/rust/client.rs +14 -5
  27. package/src/rust/lib.rs +11 -1
  28. package/src/rust/table.rs +3 -2
  29. package/src/rust/table_data.rs +19 -14
  30. package/src/rust/utils/browser.rs +0 -4
  31. package/src/rust/utils/console_logger.rs +3 -2
  32. package/src/rust/utils/errors.rs +10 -28
  33. package/src/rust/utils/futures.rs +10 -4
  34. package/src/rust/utils/json.rs +4 -4
  35. package/src/rust/virtual_server.rs +746 -0
  36. package/src/ts/perspective-server.worker.ts +33 -23
  37. package/src/ts/perspective.browser.ts +17 -2
  38. package/src/ts/perspective.node.ts +46 -11
  39. package/src/ts/ts-rs/ColumnType.ts +6 -0
  40. package/src/ts/ts-rs/ViewConfig.ts +8 -0
  41. package/src/ts/ts-rs/ViewWindow.ts +3 -3
  42. package/src/ts/virtual_server.ts +126 -0
  43. package/src/ts/virtual_servers/duckdb.ts +516 -0
  44. package/src/ts/wasm/browser.ts +17 -9
  45. package/tsconfig.json +1 -0
Binary file
@@ -62,14 +62,26 @@ export const view_remove_delete: (a: number, b: number) => number;
62
62
  export const view_collapse: (a: number, b: number) => number;
63
63
  export const view_expand: (a: number, b: number) => number;
64
64
  export const view_set_depth: (a: number, b: number) => number;
65
+ export const __wbg_jsvirtualdataslice_free: (a: number, b: number) => void;
66
+ export const jsvirtualdataslice_new: () => number;
67
+ export const jsvirtualdataslice_setCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => void;
68
+ export const jsvirtualdataslice_setStringCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
69
+ export const jsvirtualdataslice_setIntegerCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
70
+ export const jsvirtualdataslice_setFloatCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
71
+ export const jsvirtualdataslice_setBooleanCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
72
+ export const jsvirtualdataslice_setDatetimeCol: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
73
+ export const __wbg_jsvirtualserver_free: (a: number, b: number) => void;
74
+ export const jsvirtualserver_new: (a: number, b: number) => void;
75
+ export const jsvirtualserver_handleRequest: (a: number, b: number, c: number) => number;
65
76
  export const init: () => void;
66
77
  export const proxysession_new: (a: number, b: number) => number;
67
- export const __wbindgen_export_0: (a: number, b: number) => number;
68
- export const __wbindgen_export_1: (a: number, b: number, c: number, d: number) => number;
69
- export const __wbindgen_export_2: (a: number) => void;
70
- export const __wbindgen_export_3: (a: number, b: number, c: number) => void;
71
- export const __wbindgen_export_4: WebAssembly.Table;
78
+ export const __wasm_bindgen_func_elem_553: (a: number, b: number) => number;
79
+ export const __wasm_bindgen_func_elem_123: (a: number, b: number) => void;
80
+ export const __wasm_bindgen_func_elem_3515: (a: number, b: number, c: number) => void;
81
+ export const __wasm_bindgen_func_elem_3500: (a: number, b: number) => void;
82
+ export const __wasm_bindgen_func_elem_5070: (a: number, b: number, c: number, d: number) => void;
83
+ export const __wbindgen_export: (a: number, b: number) => number;
84
+ export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
85
+ export const __wbindgen_export3: (a: number) => void;
86
+ export const __wbindgen_export4: (a: number, b: number, c: number) => void;
72
87
  export const __wbindgen_add_to_stack_pointer: (a: number) => number;
73
- export const __wbindgen_export_5: (a: number, b: number) => number;
74
- export const __wbindgen_export_6: (a: number, b: number, c: number) => void;
75
- export const __wbindgen_export_7: (a: number, b: number, c: number, d: number) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@perspective-dev/client",
3
- "version": "4.0.1",
3
+ "version": "4.1.1",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,6 +23,7 @@
23
23
  "types": "./dist/esm/perspective.node.d.ts",
24
24
  "default": "./dist/esm/perspective.node.js"
25
25
  },
26
+ "./virtual_servers/*": "./dist/esm/virtual_servers/*",
26
27
  "./dist/*": "./dist/*",
27
28
  "./src/*": "./src/*",
28
29
  "./test/*": "./test/*",
@@ -47,6 +48,7 @@
47
48
  "@perspective-dev/esbuild-plugin": "",
48
49
  "@perspective-dev/metadata": "",
49
50
  "@perspective-dev/test": "",
51
+ "@duckdb/duckdb-wasm": "^1.30.0",
50
52
  "@playwright/experimental-ct-react": "=1.52.0",
51
53
  "@playwright/test": "=1.52.0",
52
54
  "@types/node": ">=22",
@@ -58,6 +60,7 @@
58
60
  "moment": "^2.30.1",
59
61
  "typedoc": "^0.28.7",
60
62
  "typescript": ">=5 <6",
63
+ "web-worker": "1.4.1",
61
64
  "zx": ">=8 <9"
62
65
  },
63
66
  "scripts": {
@@ -116,8 +116,17 @@ impl ProxySession {
116
116
  #[wasm_bindgen]
117
117
  #[derive(TryFromJsValue, Clone)]
118
118
  pub struct Client {
119
- pub(crate) close: Option<Function>,
120
119
  pub(crate) client: perspective_client::Client,
120
+ pub(crate) close: Option<Function>,
121
+ }
122
+
123
+ impl From<perspective_client::Client> for Client {
124
+ fn from(client: perspective_client::Client) -> Self {
125
+ Client {
126
+ client,
127
+ close: None,
128
+ }
129
+ }
121
130
  }
122
131
 
123
132
  impl PartialEq for Client {
@@ -132,6 +141,8 @@ impl PartialEq for Client {
132
141
  #[derivative(Clone(bound = ""))]
133
142
  struct JsReconnect<I>(Arc<dyn Fn(I) -> js_sys::Promise>);
134
143
 
144
+ // This type is not thread safe, but the JavaScript environment does not allow
145
+ // threading.
135
146
  unsafe impl<I> Send for JsReconnect<I> {}
136
147
  unsafe impl<I> Sync for JsReconnect<I> {}
137
148
 
@@ -414,10 +425,8 @@ impl Client {
414
425
  /// const tables = await client.get_hosted_table_names();
415
426
  /// ```
416
427
  #[wasm_bindgen]
417
- pub async fn get_hosted_table_names(&self) -> ApiResult<JsValue> {
418
- Ok(JsValue::from_serde_ext(
419
- &self.client.get_hosted_table_names().await?,
420
- )?)
428
+ pub async fn get_hosted_table_names(&self) -> ApiResult<Vec<String>> {
429
+ Ok(self.client.get_hosted_table_names().await?)
421
430
  }
422
431
 
423
432
  /// Register a callback which is invoked whenever [`Client::table`] (on this
package/src/rust/lib.rs CHANGED
@@ -30,6 +30,8 @@ mod table;
30
30
  mod table_data;
31
31
  pub mod utils;
32
32
  mod view;
33
+ #[cfg(target_arch = "wasm32")]
34
+ mod virtual_server;
33
35
 
34
36
  #[cfg(feature = "export-init")]
35
37
  use wasm_bindgen::prelude::*;
@@ -37,11 +39,14 @@ use wasm_bindgen::prelude::*;
37
39
  pub use crate::client::Client;
38
40
  pub use crate::table::*;
39
41
  pub use crate::table_data::*;
42
+ #[cfg(target_arch = "wasm32")]
43
+ pub use crate::virtual_server::*;
40
44
 
41
45
  #[cfg(feature = "export-init")]
42
46
  #[wasm_bindgen(typescript_custom_section)]
43
47
  const TS_APPEND_CONTENT: &'static str = r#"
44
48
  export type * from "../../src/ts/ts-rs/ViewWindow.d.ts";
49
+ export type * from "../../src/ts/ts-rs/ColumnType.d.ts";
45
50
  export type * from "../../src/ts/ts-rs/ColumnWindow.d.ts";
46
51
  export type * from "../../src/ts/ts-rs/TableInitOptions.d.ts";
47
52
  export type * from "../../src/ts/ts-rs/ViewConfigUpdate.d.ts";
@@ -49,9 +54,14 @@ export type * from "../../src/ts/ts-rs/ViewOnUpdateResp.d.ts";
49
54
  export type * from "../../src/ts/ts-rs/OnUpdateOptions.d.ts";
50
55
  export type * from "../../src/ts/ts-rs/UpdateOptions.d.ts";
51
56
  export type * from "../../src/ts/ts-rs/DeleteOptions.d.ts";
57
+ export type * from "../../src/ts/ts-rs/Scalar.d.ts";
52
58
  export type * from "../../src/ts/ts-rs/SystemInfo.d.ts";
59
+ export type * from "../../src/ts/ts-rs/SortDir.d.ts";
60
+ export type * from "../../src/ts/ts-rs/Filter.d.ts";
61
+ export type * from "../../src/ts/ts-rs/ViewConfig.d.ts";
53
62
 
54
63
  import type {ColumnWindow} from "../../src/ts/ts-rs/ColumnWindow.d.ts";
64
+ import type {ColumnType} from "../../src/ts/ts-rs/ColumnType.d.ts";
55
65
  import type {ViewWindow} from "../../src/ts/ts-rs/ViewWindow.d.ts";
56
66
  import type {TableInitOptions} from "../../src/ts/ts-rs/TableInitOptions.d.ts";
57
67
  import type {ViewConfigUpdate} from "../../src/ts/ts-rs/ViewConfigUpdate.d.ts";
@@ -65,6 +75,6 @@ import type {SystemInfo} from "../../src/ts/ts-rs/SystemInfo.d.ts";
65
75
  #[cfg(feature = "export-init")]
66
76
  #[wasm_bindgen]
67
77
  pub fn init() {
68
- console_error_panic_hook::set_once();
78
+ // console_error_panic_hook::set_once();
69
79
  utils::set_global_logging();
70
80
  }
package/src/rust/table.rs CHANGED
@@ -57,7 +57,8 @@ impl Table {
57
57
  extern "C" {
58
58
  // TODO Fix me
59
59
  #[wasm_bindgen(typescript_type = "\
60
- string | ArrayBuffer | Record<string, unknown[]> | Record<string, unknown>[]")]
60
+ string | ArrayBuffer | Record<string, unknown[]> | Record<string, unknown>[] | \
61
+ Record<string, ColumnType>")]
61
62
  pub type JsTableInitData;
62
63
 
63
64
  #[wasm_bindgen(typescript_type = "ViewConfigUpdate")]
@@ -179,7 +180,7 @@ impl Table {
179
180
  ///
180
181
  /// Note that all [`Table`] columns are _nullable_, regardless of the data
181
182
  /// type.
182
- #[wasm_bindgen]
183
+ #[wasm_bindgen(unchecked_return_type = "Record<string, ColumnType>")]
183
184
  pub async fn schema(&self) -> ApiResult<JsValue> {
184
185
  let schema = self.0.schema().await?;
185
186
  Ok(JsValue::from_serde_ext(&schema)?)
@@ -15,10 +15,11 @@ use js_sys::{Array, ArrayBuffer, Function, JSON, Object, Reflect, Uint8Array};
15
15
  use perspective_client::config::ColumnType;
16
16
  use perspective_client::{TableData, TableReadFormat, UpdateData};
17
17
  use wasm_bindgen::convert::TryFromJsValue;
18
+ use wasm_bindgen::intern;
18
19
  use wasm_bindgen::prelude::*;
19
20
 
20
21
  use crate::apierror;
21
- use crate::utils::{ApiError, ApiResult, JsValueSerdeExt, ToApiError};
22
+ use crate::utils::{ApiError, ApiResult, JsValueSerdeExt};
22
23
  pub use crate::view::*;
23
24
 
24
25
  #[ext]
@@ -27,10 +28,10 @@ impl Vec<(String, ColumnType)> {
27
28
  Ok(Object::keys(value.unchecked_ref())
28
29
  .iter()
29
30
  .map(|x| -> Result<_, JsValue> {
30
- let key = x.as_string().into_apierror()?;
31
+ let key = x.as_string().expect("Not string??");
31
32
  let val = Reflect::get(value, &x)?
32
33
  .as_string()
33
- .into_apierror()?
34
+ .expect("Y no string?")
34
35
  .into_serde_ext()?;
35
36
 
36
37
  Ok((key, val))
@@ -44,8 +45,10 @@ pub(crate) impl TableData {
44
45
  fn from_js_value(value: &JsValue, format: Option<TableReadFormat>) -> ApiResult<TableData> {
45
46
  if let Some(result) = UpdateData::from_js_value_partial(value, format)? {
46
47
  Ok(result.into())
47
- } else if value.is_instance_of::<Object>() && Reflect::has(value, &"__get_model".into())? {
48
- let val = Reflect::get(value, &"__get_model".into())?
48
+ } else if value.is_instance_of::<Object>()
49
+ && Reflect::has(value, &intern("__get_model").into())?
50
+ {
51
+ let val = Reflect::get(value, &intern("__get_model").into())?
49
52
  .dyn_into::<Function>()?
50
53
  .call0(value)?;
51
54
 
@@ -69,7 +72,9 @@ pub(crate) impl TableData {
69
72
  if all_strings() {
70
73
  Ok(TableData::Schema(Vec::from_js_value(value)?))
71
74
  } else if all_arrays() {
72
- let json = JSON::stringify(value)?.as_string().into_apierror()?;
75
+ let json = JSON::stringify(value)?
76
+ .as_string()
77
+ .expect("STRINGIFY_ARRAY??");
73
78
  Ok(UpdateData::JsonColumns(json).into())
74
79
  } else {
75
80
  Err(apierror!(TableError(value.clone())))
@@ -91,20 +96,20 @@ pub(crate) impl UpdateData {
91
96
  } else if value.is_string() {
92
97
  match format {
93
98
  None | Some(TableReadFormat::Csv) => {
94
- Ok(Some(UpdateData::Csv(value.as_string().into_apierror()?)))
99
+ Ok(Some(UpdateData::Csv(value.as_string().expect("Csv????"))))
95
100
  },
96
101
  Some(TableReadFormat::JsonString) => Ok(Some(UpdateData::JsonRows(
97
- value.as_string().into_apierror()?,
102
+ value.as_string().expect("JSON???"),
98
103
  ))),
99
104
  Some(TableReadFormat::ColumnsString) => Ok(Some(UpdateData::JsonColumns(
100
- value.as_string().into_apierror()?,
105
+ value.as_string().expect("ColumnString???"),
101
106
  ))),
102
107
  Some(TableReadFormat::Arrow) => Ok(Some(UpdateData::Arrow(
103
- value.as_string().into_apierror()?.into_bytes().into(),
108
+ value.as_string().expect("Arrow???").into_bytes().into(),
109
+ ))),
110
+ Some(TableReadFormat::Ndjson) => Ok(Some(UpdateData::Ndjson(
111
+ value.as_string().expect("Ndjson???"),
104
112
  ))),
105
- Some(TableReadFormat::Ndjson) => {
106
- Ok(Some(UpdateData::Ndjson(value.as_string().into_apierror()?)))
107
- },
108
113
  }
109
114
  } else if value.is_instance_of::<ArrayBuffer>() {
110
115
  let uint8array = Uint8Array::new(value);
@@ -138,7 +143,7 @@ pub(crate) impl UpdateData {
138
143
  None | Some(TableReadFormat::Arrow) => Ok(Some(UpdateData::Arrow(slice.into()))),
139
144
  }
140
145
  } else if value.is_instance_of::<Array>() {
141
- let rows = JSON::stringify(value)?.as_string().into_apierror()?;
146
+ let rows = JSON::stringify(value)?.as_string().expect("STRINGIFY??");
142
147
  Ok(Some(UpdateData::JsonRows(rows)))
143
148
  } else {
144
149
  Ok(None)
@@ -32,8 +32,4 @@ pub mod global {
32
32
  pub fn navigator() -> web_sys::Navigator {
33
33
  window().navigator()
34
34
  }
35
-
36
- pub fn clipboard() -> web_sys::Clipboard {
37
- navigator().clipboard()
38
- }
39
35
  }
@@ -18,6 +18,7 @@ use tracing::field::{Field, Visit};
18
18
  use tracing_subscriber::Layer;
19
19
  use tracing_subscriber::layer::Context;
20
20
  use tracing_subscriber::registry::LookupSpan;
21
+ use wasm_bindgen::intern;
21
22
  use wasm_bindgen::prelude::*;
22
23
 
23
24
  use crate::utils::*;
@@ -111,8 +112,8 @@ impl<'a> tracing::Metadata<'a> {
111
112
  level.web_logger_4()(
112
113
  &format!("%c {level} %c {origin}%c {msg} ").into(),
113
114
  &level.web_log_color().into(),
114
- &"color: gray; font-style: italic".into(),
115
- &"color: inherit".into(),
115
+ &intern("color: gray; font-style: italic").into(),
116
+ &intern("color: inherit").into(),
116
117
  );
117
118
  } else {
118
119
  level.web_logger_1()(&format!("{origin} {msg}").into());
@@ -16,6 +16,7 @@ use std::string::FromUtf8Error;
16
16
 
17
17
  use perspective_client::{ClientError, ExprValidationResult};
18
18
  use thiserror::*;
19
+ use wasm_bindgen::intern;
19
20
  use wasm_bindgen::prelude::*;
20
21
 
21
22
  #[macro_export]
@@ -35,7 +36,7 @@ macro_rules! apierror {
35
36
  fn format_js_error(value: &JsValue) -> String {
36
37
  if let Some(err) = value.dyn_ref::<js_sys::Error>() {
37
38
  let msg = err.message().as_string().unwrap();
38
- if let Ok(x) = js_sys::Reflect::get(value, &"stack".into()) {
39
+ if let Ok(x) = js_sys::Reflect::get(value, &intern("stack").into()) {
39
40
  format!("{}\n{}", msg, x.as_string().unwrap())
40
41
  } else {
41
42
  msg
@@ -108,15 +109,6 @@ pub enum ApiErrorType {
108
109
  #[error(transparent)]
109
110
  StdIoError(Rc<std::io::Error>),
110
111
 
111
- #[error(transparent)]
112
- RmpSerdeEncodeError(Rc<rmp_serde::encode::Error>),
113
-
114
- #[error(transparent)]
115
- RmpSerdeDecodeError(Rc<rmp_serde::decode::Error>),
116
-
117
- #[error(transparent)]
118
- Base64DecodeError(#[from] base64::DecodeError),
119
-
120
112
  #[error(transparent)]
121
113
  ChronoParseError(#[from] chrono::ParseError),
122
114
  }
@@ -146,9 +138,6 @@ impl ApiError {
146
138
  ApiErrorType::SerdeWasmBindgenError(_) => "[SerdeWasmBindgenError]",
147
139
  ApiErrorType::Utf8Error(_) => "[FromUtf8Error]",
148
140
  ApiErrorType::StdIoError(_) => "[StdIoError]",
149
- ApiErrorType::RmpSerdeEncodeError(_) => "[RmpSerdeEncodeError]",
150
- ApiErrorType::RmpSerdeDecodeError(_) => "[RmpSerdeDecodeError]",
151
- ApiErrorType::Base64DecodeError(_) => "[Base64DecodeError]",
152
141
  ApiErrorType::ChronoParseError(_) => "[ChronoParseError]",
153
142
  ApiErrorType::ViewerPluginError(_) => "[ViewerPluginError]",
154
143
  ApiErrorType::JsRawError(_) => "[JsRawError]",
@@ -167,7 +156,7 @@ impl ApiError {
167
156
 
168
157
  /// This error's stacktrace from when it was constructed.
169
158
  pub fn stacktrace(&self) -> String {
170
- js_sys::Reflect::get(&self.1.0, &"stack".into())
159
+ js_sys::Reflect::get(&self.1.0, &intern("stack").into())
171
160
  .unwrap()
172
161
  .as_string()
173
162
  .unwrap()
@@ -175,6 +164,8 @@ impl ApiError {
175
164
  }
176
165
  }
177
166
 
167
+ // This type is not thread safe, but the JavaScript environment does not allow
168
+ // threading.
178
169
  unsafe impl Send for ApiError {}
179
170
  unsafe impl Sync for ApiError {}
180
171
 
@@ -210,18 +201,6 @@ impl From<std::io::Error> for ApiError {
210
201
  }
211
202
  }
212
203
 
213
- impl From<rmp_serde::decode::Error> for ApiError {
214
- fn from(value: rmp_serde::decode::Error) -> Self {
215
- ApiErrorType::RmpSerdeDecodeError(Rc::new(value)).into()
216
- }
217
- }
218
-
219
- impl From<rmp_serde::encode::Error> for ApiError {
220
- fn from(value: rmp_serde::encode::Error) -> Self {
221
- ApiErrorType::RmpSerdeEncodeError(Rc::new(value)).into()
222
- }
223
- }
224
-
225
204
  impl From<Box<dyn std::error::Error>> for ApiError {
226
205
  fn from(value: Box<dyn std::error::Error>) -> Self {
227
206
  ApiErrorType::ExternalError(Rc::new(value)).into()
@@ -237,7 +216,10 @@ impl From<serde_json::Error> for ApiError {
237
216
  impl From<JsValue> for ApiError {
238
217
  fn from(err: JsValue) -> Self {
239
218
  if err.is_instance_of::<js_sys::Error>() {
240
- ApiErrorType::JsRawError(err.clone().unchecked_into()).into()
219
+ ApiError(
220
+ ApiErrorType::JsRawError(err.clone().unchecked_into()),
221
+ JsBackTrace(Rc::new(err.unchecked_into())),
222
+ )
241
223
  } else {
242
224
  apierror!(JsError(err))
243
225
  }
@@ -263,7 +245,7 @@ pub trait ToApiError<T> {
263
245
 
264
246
  impl<T> ToApiError<T> for Option<T> {
265
247
  fn into_apierror(self) -> ApiResult<T> {
266
- self.ok_or_else(|| "Unwrap on None".into())
248
+ self.ok_or_else(|| intern("Unwrap on None").into())
267
249
  }
268
250
  }
269
251
 
@@ -46,6 +46,12 @@ where
46
46
  pub fn new<U: Future<Output = ApiResult<T>> + 'static>(x: U) -> Self {
47
47
  Self(Box::pin(x))
48
48
  }
49
+
50
+ pub fn new_throttled<U: Future<Output = ApiResult<T>> + 'static>(x: U) -> ApiFuture<()> {
51
+ ApiFuture::<()>(Box::pin(
52
+ async move { x.await.ignore_view_delete().map(|_| ()) },
53
+ ))
54
+ }
49
55
  }
50
56
 
51
57
  impl<T> ApiFuture<T>
@@ -87,7 +93,7 @@ where
87
93
  future_to_promise(async move {
88
94
  match fut.0.await.ignore_view_delete()? {
89
95
  Some(x) => Ok(x).into_js_result(),
90
- None => Ok::<_, JsValue>(()).into_js_result(),
96
+ None => Err("View not found".into()).into_js_result(),
91
97
  }
92
98
  })
93
99
  }
@@ -161,14 +167,14 @@ pub impl<T> Result<T, ApiError> {
161
167
  /// case (instead of whatever the `async` returns), which is helpful for
162
168
  /// detecting this condition when debugging.
163
169
  fn ignore_view_delete(self) -> Result<Option<T>, ApiError> {
164
- self.map(|x| Some(x)).or_else(|x| match x.inner() {
170
+ self.map(|x| Some(x)).or_else(|err| match err.inner() {
165
171
  ApiErrorType::ClientError(ClientError::ViewNotFound) => Ok(None),
166
172
  ApiErrorType::JsRawError(..) | ApiErrorType::JsError(..)
167
- if format!("{x}").contains("View not found") =>
173
+ if format!("{err}").contains("View not found") =>
168
174
  {
169
175
  Ok(None)
170
176
  },
171
- x => Err(x.clone().into()),
177
+ _ => Err(err),
172
178
  })
173
179
  }
174
180
  }
@@ -106,8 +106,8 @@ macro_rules! json_internal {
106
106
 
107
107
  // Insert the current entry followed by trailing comma.
108
108
  (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
109
- let k = js_intern::js_intern!($($key)+);
110
- js_sys::Reflect::set(&$object, k, &$value).unwrap();
109
+ let k = JsValue::from(wasm_bindgen::intern($($key)+));
110
+ js_sys::Reflect::set(&$object, &k, &$value).unwrap();
111
111
  $crate::json_internal!(@object $object () ($($rest)*) ($($rest)*));
112
112
  };
113
113
 
@@ -118,8 +118,8 @@ macro_rules! json_internal {
118
118
 
119
119
  // Insert the last entry without trailing comma.
120
120
  (@object $object:ident [$($key:tt)+] ($value:expr)) => {
121
- let k = js_intern::js_intern!($($key)+);
122
- js_sys::Reflect::set(&$object, k, &$value).unwrap();
121
+ let k = JsValue::from(wasm_bindgen::intern($($key)+));
122
+ js_sys::Reflect::set(&$object, &k, &$value).unwrap();
123
123
  };
124
124
 
125
125
  // Next value is `null`.