tinymist_package/registry/
browser.rs1use std::{io::Read, path::Path};
4
5use js_sys::Uint8Array;
6use tinymist_std::ImmutPath;
7use typst::diag::eco_format;
8use wasm_bindgen::{JsValue, prelude::*};
9
10use crate::registry::PackageIndexEntry;
11
12use super::{PackageError, PackageRegistry, PackageSpec};
13
14#[wasm_bindgen]
16#[derive(Debug, Clone)]
17pub struct ProxyContext {
18 context: JsValue,
19}
20
21#[wasm_bindgen]
22impl ProxyContext {
23 #[wasm_bindgen(constructor)]
25 pub fn new(context: JsValue) -> Self {
26 Self { context }
27 }
28
29 #[wasm_bindgen(getter)]
31 pub fn context(&self) -> JsValue {
32 self.context.clone()
33 }
34
35 pub fn untar(&self, data: &[u8], cb: js_sys::Function) -> Result<(), JsValue> {
38 let cb = move |key: String, value: &[u8], mtime: u64| -> Result<(), JsValue> {
39 let key = JsValue::from_str(&key);
40 let value = Uint8Array::from(value);
41 let mtime = JsValue::from_f64(mtime as f64);
42 cb.call3(&self.context, &key, &value, &mtime).map(|_| ())
43 };
44
45 let decompressed = flate2::read::GzDecoder::new(data);
46 let mut reader = tar::Archive::new(decompressed);
47 let entries = reader.entries();
48 let entries = entries.map_err(|err| {
49 let t = PackageError::MalformedArchive(Some(eco_format!("{err}")));
50 JsValue::from_str(&format!("{t:?}"))
51 })?;
52
53 let mut buf = Vec::with_capacity(1024);
54 for entry in entries {
55 let mut entry = entry.map_err(|e| format!("{e:?}"))?;
57 let header = entry.header();
58
59 let is_file = header.entry_type().is_file();
60 if !is_file {
61 continue;
62 }
63
64 let mtime = header.mtime().unwrap_or(0);
65
66 let path = header.path().map_err(|e| format!("{e:?}"))?;
67 let path = path.to_string_lossy().as_ref().to_owned();
68
69 let size = header.size().map_err(|e| format!("{e:?}"))?;
70 buf.clear();
71 buf.reserve(size as usize);
72 entry.read_to_end(&mut buf).map_err(|e| format!("{e:?}"))?;
73
74 cb(path, &buf, mtime)?
75 }
76
77 Ok(())
78 }
79}
80
81#[derive(Debug)]
83pub struct JsRegistry {
84 pub context: ProxyContext,
86 pub real_resolve_fn: js_sys::Function,
88}
89
90impl PackageRegistry for JsRegistry {
91 fn resolve(&self, spec: &PackageSpec) -> Result<std::sync::Arc<Path>, PackageError> {
92 let js_spec = js_sys::Object::new();
94 js_sys::Reflect::set(&js_spec, &"name".into(), &spec.name.to_string().into()).unwrap();
95 js_sys::Reflect::set(
96 &js_spec,
97 &"namespace".into(),
98 &spec.namespace.to_string().into(),
99 )
100 .unwrap();
101 js_sys::Reflect::set(
102 &js_spec,
103 &"version".into(),
104 &spec.version.to_string().into(),
105 )
106 .unwrap();
107
108 self.real_resolve_fn
109 .call1(&self.context.clone().into(), &js_spec)
110 .map_err(|e| PackageError::Other(Some(eco_format!("{:?}", e))))
111 .and_then(|v| {
112 if v.is_undefined() {
113 Err(PackageError::NotFound(spec.clone()))
114 } else {
115 Ok(Path::new(&v.as_string().unwrap()).into())
116 }
117 })
118 }
119
120 fn packages(&self) -> &[PackageIndexEntry] {
122 &[]
123 }
124}
125
126impl JsRegistry {
127 pub fn package_cache_path(&self) -> Option<&ImmutPath> {
130 None
131 }
132
133 pub fn package_path(&self) -> Option<&ImmutPath> {
135 None
136 }
137}
138
139unsafe impl Send for JsRegistry {}
143unsafe impl Sync for JsRegistry {}