mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-04 14:29:45 +00:00
misc bugfixes
This commit is contained in:
@@ -3684,6 +3684,13 @@ help.arg.s9pk-file-path:
|
|||||||
fr_FR: "Chemin vers le fichier de paquet s9pk"
|
fr_FR: "Chemin vers le fichier de paquet s9pk"
|
||||||
pl_PL: "Ścieżka do pliku pakietu s9pk"
|
pl_PL: "Ścieżka do pliku pakietu s9pk"
|
||||||
|
|
||||||
|
help.arg.s9pk-file-paths:
|
||||||
|
en_US: "Paths to s9pk package files"
|
||||||
|
de_DE: "Pfade zu s9pk-Paketdateien"
|
||||||
|
es_ES: "Rutas a los archivos de paquete s9pk"
|
||||||
|
fr_FR: "Chemins vers les fichiers de paquet s9pk"
|
||||||
|
pl_PL: "Ścieżki do plików pakietów s9pk"
|
||||||
|
|
||||||
help.arg.session-ids:
|
help.arg.session-ids:
|
||||||
en_US: "Session identifiers"
|
en_US: "Session identifiers"
|
||||||
de_DE: "Sitzungskennungen"
|
de_DE: "Sitzungskennungen"
|
||||||
@@ -4980,6 +4987,13 @@ about.publish-s9pk:
|
|||||||
fr_FR: "Publier s9pk dans le bucket S3 et indexer dans le registre"
|
fr_FR: "Publier s9pk dans le bucket S3 et indexer dans le registre"
|
||||||
pl_PL: "Opublikuj s9pk do bucketu S3 i zindeksuj w rejestrze"
|
pl_PL: "Opublikuj s9pk do bucketu S3 i zindeksuj w rejestrze"
|
||||||
|
|
||||||
|
about.select-s9pk-for-device:
|
||||||
|
en_US: "Select the best compatible s9pk for a target device"
|
||||||
|
de_DE: "Das beste kompatible s9pk für ein Zielgerät auswählen"
|
||||||
|
es_ES: "Seleccionar el s9pk más compatible para un dispositivo destino"
|
||||||
|
fr_FR: "Sélectionner le meilleur s9pk compatible pour un appareil cible"
|
||||||
|
pl_PL: "Wybierz najlepiej kompatybilny s9pk dla urządzenia docelowego"
|
||||||
|
|
||||||
about.rebuild-service-container:
|
about.rebuild-service-container:
|
||||||
en_US: "Rebuild service container"
|
en_US: "Rebuild service container"
|
||||||
de_DE: "Dienst-Container neu erstellen"
|
de_DE: "Dienst-Container neu erstellen"
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ use std::time::Duration;
|
|||||||
use chrono::{TimeDelta, Utc};
|
use chrono::{TimeDelta, Utc};
|
||||||
use imbl::OrdMap;
|
use imbl::OrdMap;
|
||||||
use imbl_value::InternedString;
|
use imbl_value::InternedString;
|
||||||
use itertools::Itertools;
|
|
||||||
use josekit::jwk::Jwk;
|
use josekit::jwk::Jwk;
|
||||||
use reqwest::{Client, Proxy};
|
use reqwest::{Client, Proxy};
|
||||||
use rpc_toolkit::yajrc::RpcError;
|
use rpc_toolkit::yajrc::RpcError;
|
||||||
@@ -25,7 +24,6 @@ use crate::account::AccountInfo;
|
|||||||
use crate::auth::Sessions;
|
use crate::auth::Sessions;
|
||||||
use crate::context::config::ServerConfig;
|
use crate::context::config::ServerConfig;
|
||||||
use crate::db::model::Database;
|
use crate::db::model::Database;
|
||||||
use crate::db::model::package::TaskSeverity;
|
|
||||||
use crate::disk::OsPartitionInfo;
|
use crate::disk::OsPartitionInfo;
|
||||||
use crate::disk::mount::filesystem::bind::Bind;
|
use crate::disk::mount::filesystem::bind::Bind;
|
||||||
use crate::disk::mount::filesystem::block_dev::BlockDev;
|
use crate::disk::mount::filesystem::block_dev::BlockDev;
|
||||||
@@ -44,7 +42,6 @@ use crate::prelude::*;
|
|||||||
use crate::progress::{FullProgressTracker, PhaseProgressTrackerHandle};
|
use crate::progress::{FullProgressTracker, PhaseProgressTrackerHandle};
|
||||||
use crate::rpc_continuations::{Guid, OpenAuthedContinuations, RpcContinuations};
|
use crate::rpc_continuations::{Guid, OpenAuthedContinuations, RpcContinuations};
|
||||||
use crate::service::ServiceMap;
|
use crate::service::ServiceMap;
|
||||||
use crate::service::action::update_tasks;
|
|
||||||
use crate::service::effects::callbacks::ServiceCallbacks;
|
use crate::service::effects::callbacks::ServiceCallbacks;
|
||||||
use crate::service::effects::subcontainer::NVIDIA_OVERLAY_PATH;
|
use crate::service::effects::subcontainer::NVIDIA_OVERLAY_PATH;
|
||||||
use crate::shutdown::Shutdown;
|
use crate::shutdown::Shutdown;
|
||||||
@@ -53,7 +50,7 @@ use crate::util::future::NonDetachingJoinHandle;
|
|||||||
use crate::util::io::{TmpDir, delete_file};
|
use crate::util::io::{TmpDir, delete_file};
|
||||||
use crate::util::lshw::LshwDevice;
|
use crate::util::lshw::LshwDevice;
|
||||||
use crate::util::sync::{SyncMutex, SyncRwLock, Watch};
|
use crate::util::sync::{SyncMutex, SyncRwLock, Watch};
|
||||||
use crate::{ActionId, DATA_DIR, PLATFORM, PackageId};
|
use crate::{DATA_DIR, PLATFORM, PackageId};
|
||||||
|
|
||||||
pub struct RpcContextSeed {
|
pub struct RpcContextSeed {
|
||||||
is_closed: AtomicBool,
|
is_closed: AtomicBool,
|
||||||
@@ -114,7 +111,6 @@ pub struct CleanupInitPhases {
|
|||||||
cleanup_sessions: PhaseProgressTrackerHandle,
|
cleanup_sessions: PhaseProgressTrackerHandle,
|
||||||
init_services: PhaseProgressTrackerHandle,
|
init_services: PhaseProgressTrackerHandle,
|
||||||
prune_s9pks: PhaseProgressTrackerHandle,
|
prune_s9pks: PhaseProgressTrackerHandle,
|
||||||
check_tasks: PhaseProgressTrackerHandle,
|
|
||||||
}
|
}
|
||||||
impl CleanupInitPhases {
|
impl CleanupInitPhases {
|
||||||
pub fn new(handle: &FullProgressTracker) -> Self {
|
pub fn new(handle: &FullProgressTracker) -> Self {
|
||||||
@@ -122,7 +118,6 @@ impl CleanupInitPhases {
|
|||||||
cleanup_sessions: handle.add_phase("Cleaning up sessions".into(), Some(1)),
|
cleanup_sessions: handle.add_phase("Cleaning up sessions".into(), Some(1)),
|
||||||
init_services: handle.add_phase("Initializing services".into(), Some(10)),
|
init_services: handle.add_phase("Initializing services".into(), Some(10)),
|
||||||
prune_s9pks: handle.add_phase("Pruning S9PKs".into(), Some(1)),
|
prune_s9pks: handle.add_phase("Pruning S9PKs".into(), Some(1)),
|
||||||
check_tasks: handle.add_phase("Checking action requests".into(), Some(1)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +168,7 @@ impl RpcContext {
|
|||||||
init_net_ctrl.complete();
|
init_net_ctrl.complete();
|
||||||
tracing::info!("{}", t!("context.rpc.initialized-net-controller"));
|
tracing::info!("{}", t!("context.rpc.initialized-net-controller"));
|
||||||
|
|
||||||
if PLATFORM.ends_with("-nonfree") {
|
if PLATFORM.ends_with("-nvidia") {
|
||||||
if let Err(e) = Command::new("nvidia-smi")
|
if let Err(e) = Command::new("nvidia-smi")
|
||||||
.invoke(ErrorKind::ParseSysInfo)
|
.invoke(ErrorKind::ParseSysInfo)
|
||||||
.await
|
.await
|
||||||
@@ -411,7 +406,6 @@ impl RpcContext {
|
|||||||
mut cleanup_sessions,
|
mut cleanup_sessions,
|
||||||
mut init_services,
|
mut init_services,
|
||||||
mut prune_s9pks,
|
mut prune_s9pks,
|
||||||
mut check_tasks,
|
|
||||||
}: CleanupInitPhases,
|
}: CleanupInitPhases,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
cleanup_sessions.start();
|
cleanup_sessions.start();
|
||||||
@@ -503,76 +497,6 @@ impl RpcContext {
|
|||||||
}
|
}
|
||||||
prune_s9pks.complete();
|
prune_s9pks.complete();
|
||||||
|
|
||||||
check_tasks.start();
|
|
||||||
let mut action_input: OrdMap<PackageId, BTreeMap<ActionId, Value>> = OrdMap::new();
|
|
||||||
let tasks: BTreeSet<_> = peek
|
|
||||||
.as_public()
|
|
||||||
.as_package_data()
|
|
||||||
.as_entries()?
|
|
||||||
.into_iter()
|
|
||||||
.map(|(_, pde)| {
|
|
||||||
Ok(pde
|
|
||||||
.as_tasks()
|
|
||||||
.as_entries()?
|
|
||||||
.into_iter()
|
|
||||||
.map(|(_, r)| {
|
|
||||||
let t = r.as_task();
|
|
||||||
Ok::<_, Error>(if t.as_input().transpose_ref().is_some() {
|
|
||||||
Some((t.as_package_id().de()?, t.as_action_id().de()?))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.filter_map_ok(|a| a))
|
|
||||||
})
|
|
||||||
.flatten_ok()
|
|
||||||
.map(|a| a.and_then(|a| a))
|
|
||||||
.try_collect()?;
|
|
||||||
let procedure_id = Guid::new();
|
|
||||||
for (package_id, action_id) in tasks {
|
|
||||||
if let Some(service) = self.services.get(&package_id).await.as_ref() {
|
|
||||||
if let Some(input) = service
|
|
||||||
.get_action_input(procedure_id.clone(), action_id.clone(), Value::Null)
|
|
||||||
.await
|
|
||||||
.log_err()
|
|
||||||
.flatten()
|
|
||||||
.and_then(|i| i.value)
|
|
||||||
{
|
|
||||||
action_input
|
|
||||||
.entry(package_id)
|
|
||||||
.or_default()
|
|
||||||
.insert(action_id, input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.db
|
|
||||||
.mutate(|db| {
|
|
||||||
for (package_id, action_input) in &action_input {
|
|
||||||
for (action_id, input) in action_input {
|
|
||||||
for (_, pde) in db.as_public_mut().as_package_data_mut().as_entries_mut()? {
|
|
||||||
pde.as_tasks_mut().mutate(|tasks| {
|
|
||||||
Ok(update_tasks(tasks, package_id, action_id, input, false))
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (_, pde) in db.as_public_mut().as_package_data_mut().as_entries_mut()? {
|
|
||||||
if pde
|
|
||||||
.as_tasks()
|
|
||||||
.de()?
|
|
||||||
.into_iter()
|
|
||||||
.any(|(_, t)| t.active && t.task.severity == TaskSeverity::Critical)
|
|
||||||
{
|
|
||||||
pde.as_status_info_mut().stop()?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.result?;
|
|
||||||
check_tasks.complete();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub async fn call_remote<RemoteContext>(
|
pub async fn call_remote<RemoteContext>(
|
||||||
|
|||||||
@@ -251,11 +251,12 @@ async fn create_task(
|
|||||||
.get(&task.package_id)
|
.get(&task.package_id)
|
||||||
.await
|
.await
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
.filter(|s| s.is_initialized())
|
||||||
{
|
{
|
||||||
let Some(prev) = service
|
let prev = service
|
||||||
.get_action_input(procedure_id.clone(), task.action_id.clone(), Value::Null)
|
.get_action_input(procedure_id.clone(), task.action_id.clone(), Value::Null)
|
||||||
.await?
|
.await?;
|
||||||
else {
|
let Some(prev) = prev else {
|
||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
eyre!(
|
eyre!(
|
||||||
"{}",
|
"{}",
|
||||||
@@ -278,7 +279,9 @@ async fn create_task(
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
true // update when service is installed
|
// Service not installed or not yet initialized — assume active.
|
||||||
|
// Will be retested when service init completes (Service::recheck_tasks).
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -215,6 +215,84 @@ pub struct Service {
|
|||||||
seed: Arc<ServiceActorSeed>,
|
seed: Arc<ServiceActorSeed>,
|
||||||
}
|
}
|
||||||
impl Service {
|
impl Service {
|
||||||
|
pub fn is_initialized(&self) -> bool {
|
||||||
|
self.seed.persistent_container.state.borrow().rt_initialized
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Re-evaluate all tasks that reference this service's actions.
|
||||||
|
/// Called after every service init to update task active state.
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
async fn recheck_tasks(&self) -> Result<(), Error> {
|
||||||
|
let service_id = &self.seed.id;
|
||||||
|
let peek = self.seed.ctx.db.peek().await;
|
||||||
|
let mut action_input: BTreeMap<ActionId, Value> = BTreeMap::new();
|
||||||
|
let tasks: BTreeSet<_> = peek
|
||||||
|
.as_public()
|
||||||
|
.as_package_data()
|
||||||
|
.as_entries()?
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, pde)| {
|
||||||
|
Ok(pde
|
||||||
|
.as_tasks()
|
||||||
|
.as_entries()?
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, r)| {
|
||||||
|
let t = r.as_task();
|
||||||
|
Ok::<_, Error>(
|
||||||
|
if t.as_package_id().de()? == *service_id
|
||||||
|
&& t.as_input().transpose_ref().is_some()
|
||||||
|
{
|
||||||
|
Some(t.as_action_id().de()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.filter_map_ok(|a| a))
|
||||||
|
})
|
||||||
|
.flatten_ok()
|
||||||
|
.map(|a| a.and_then(|a| a))
|
||||||
|
.try_collect()?;
|
||||||
|
let procedure_id = Guid::new();
|
||||||
|
for action_id in tasks {
|
||||||
|
if let Some(input) = self
|
||||||
|
.get_action_input(procedure_id.clone(), action_id.clone(), Value::Null)
|
||||||
|
.await
|
||||||
|
.log_err()
|
||||||
|
.flatten()
|
||||||
|
.and_then(|i| i.value)
|
||||||
|
{
|
||||||
|
action_input.insert(action_id, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.seed
|
||||||
|
.ctx
|
||||||
|
.db
|
||||||
|
.mutate(|db| {
|
||||||
|
for (action_id, input) in &action_input {
|
||||||
|
for (_, pde) in db.as_public_mut().as_package_data_mut().as_entries_mut()? {
|
||||||
|
pde.as_tasks_mut().mutate(|tasks| {
|
||||||
|
Ok(update_tasks(tasks, service_id, action_id, input, false))
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (_, pde) in db.as_public_mut().as_package_data_mut().as_entries_mut()? {
|
||||||
|
if pde
|
||||||
|
.as_tasks()
|
||||||
|
.de()?
|
||||||
|
.into_iter()
|
||||||
|
.any(|(_, t)| t.active && t.task.severity == TaskSeverity::Critical)
|
||||||
|
{
|
||||||
|
pde.as_status_info_mut().stop()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.result?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
async fn new(
|
async fn new(
|
||||||
ctx: RpcContext,
|
ctx: RpcContext,
|
||||||
@@ -263,6 +341,7 @@ impl Service {
|
|||||||
.persistent_container
|
.persistent_container
|
||||||
.init(service.weak(), procedure_id, init_kind)
|
.init(service.weak(), procedure_id, init_kind)
|
||||||
.await?;
|
.await?;
|
||||||
|
service.recheck_tasks().await?;
|
||||||
if let Some(recovery_guard) = recovery_guard {
|
if let Some(recovery_guard) = recovery_guard {
|
||||||
recovery_guard.unmount(true).await?;
|
recovery_guard.unmount(true).await?;
|
||||||
}
|
}
|
||||||
@@ -489,70 +568,8 @@ impl Service {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(mut progress) = progress {
|
|
||||||
progress.finalization_progress.complete();
|
|
||||||
progress.progress.complete();
|
|
||||||
tokio::task::yield_now().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
let peek = ctx.db.peek().await;
|
|
||||||
let mut action_input: BTreeMap<ActionId, Value> = BTreeMap::new();
|
|
||||||
let tasks: BTreeSet<_> = peek
|
|
||||||
.as_public()
|
|
||||||
.as_package_data()
|
|
||||||
.as_entries()?
|
|
||||||
.into_iter()
|
|
||||||
.map(|(_, pde)| {
|
|
||||||
Ok(pde
|
|
||||||
.as_tasks()
|
|
||||||
.as_entries()?
|
|
||||||
.into_iter()
|
|
||||||
.map(|(_, r)| {
|
|
||||||
let t = r.as_task();
|
|
||||||
Ok::<_, Error>(
|
|
||||||
if t.as_package_id().de()? == manifest.id
|
|
||||||
&& t.as_input().transpose_ref().is_some()
|
|
||||||
{
|
|
||||||
Some(t.as_action_id().de()?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.filter_map_ok(|a| a))
|
|
||||||
})
|
|
||||||
.flatten_ok()
|
|
||||||
.map(|a| a.and_then(|a| a))
|
|
||||||
.try_collect()?;
|
|
||||||
for action_id in tasks {
|
|
||||||
if peek
|
|
||||||
.as_public()
|
|
||||||
.as_package_data()
|
|
||||||
.as_idx(&manifest.id)
|
|
||||||
.or_not_found(&manifest.id)?
|
|
||||||
.as_actions()
|
|
||||||
.contains_key(&action_id)?
|
|
||||||
{
|
|
||||||
if let Some(input) = service
|
|
||||||
.get_action_input(procedure_id.clone(), action_id.clone(), Value::Null)
|
|
||||||
.await
|
|
||||||
.log_err()
|
|
||||||
.flatten()
|
|
||||||
.and_then(|i| i.value)
|
|
||||||
{
|
|
||||||
action_input.insert(action_id, input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.db
|
ctx.db
|
||||||
.mutate(|db| {
|
.mutate(|db| {
|
||||||
for (action_id, input) in &action_input {
|
|
||||||
for (_, pde) in db.as_public_mut().as_package_data_mut().as_entries_mut()? {
|
|
||||||
pde.as_tasks_mut().mutate(|tasks| {
|
|
||||||
Ok(update_tasks(tasks, &manifest.id, action_id, input, false))
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let entry = db
|
let entry = db
|
||||||
.as_public_mut()
|
.as_public_mut()
|
||||||
.as_package_data_mut()
|
.as_package_data_mut()
|
||||||
@@ -594,6 +611,12 @@ impl Service {
|
|||||||
.await
|
.await
|
||||||
.result?;
|
.result?;
|
||||||
|
|
||||||
|
if let Some(mut progress) = progress {
|
||||||
|
progress.finalization_progress.complete();
|
||||||
|
progress.progress.complete();
|
||||||
|
tokio::task::yield_now().await;
|
||||||
|
}
|
||||||
|
|
||||||
// Trigger manifest callbacks after successful installation
|
// Trigger manifest callbacks after successful installation
|
||||||
let manifest = service.seed.persistent_container.s9pk.as_manifest();
|
let manifest = service.seed.persistent_container.s9pk.as_manifest();
|
||||||
if let Some(callbacks) = ctx.callbacks.get_service_manifest(&manifest.id) {
|
if let Some(callbacks) = ctx.callbacks.get_service_manifest(&manifest.id) {
|
||||||
|
|||||||
@@ -74,21 +74,38 @@ declare module 'zod' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Override z.object to produce loose objects by default (extra keys are preserved, not stripped).
|
// Override z.object to produce loose objects by default (extra keys are preserved, not stripped).
|
||||||
// Patches the source module in require.cache where 'object' is a writable property;
|
const _origObject = _z.object
|
||||||
|
const _patchedObject = (...args: Parameters<typeof _z.object>) =>
|
||||||
|
_origObject(...args).loose()
|
||||||
|
|
||||||
|
// In CJS (Node.js), patch the source module in require.cache where 'object' is a writable property;
|
||||||
// the CJS getter chain (index → external → schemas) then relays the patched version.
|
// the CJS getter chain (index → external → schemas) then relays the patched version.
|
||||||
// We walk only the zod entry module's dependency tree and match by identity (=== origObject).
|
// We walk only the zod entry module's dependency tree and match by identity (=== origObject).
|
||||||
const _origObject = _z.object
|
try {
|
||||||
const _zodModule = require.cache[require.resolve('zod')]
|
const _zodModule = require.cache[require.resolve('zod')]
|
||||||
for (const child of _zodModule?.children ?? []) {
|
for (const child of _zodModule?.children ?? []) {
|
||||||
for (const grandchild of child.children ?? []) {
|
for (const grandchild of child.children ?? []) {
|
||||||
const desc = Object.getOwnPropertyDescriptor(grandchild.exports, 'object')
|
const desc = Object.getOwnPropertyDescriptor(grandchild.exports, 'object')
|
||||||
if (desc?.value === _origObject && desc.writable) {
|
if (desc?.value === _origObject && desc.writable) {
|
||||||
grandchild.exports.object = (...args: Parameters<typeof _z.object>) =>
|
grandchild.exports.object = _patchedObject
|
||||||
_origObject(...args).loose()
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (_) {
|
||||||
|
// Not in CJS/Node environment (e.g. browser) — require.cache unavailable
|
||||||
}
|
}
|
||||||
|
|
||||||
export { _z as z }
|
// z.object is a non-configurable getter on the zod namespace, so we can't override it directly.
|
||||||
|
// Shadow it by exporting a new object with _z as prototype and our patched object on the instance.
|
||||||
|
const z: typeof _z = Object.create(_z, {
|
||||||
|
object: {
|
||||||
|
value: _patchedObject,
|
||||||
|
writable: true,
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export { z }
|
||||||
|
|
||||||
export * as utils from './util'
|
export * as utils from './util'
|
||||||
|
|||||||
Reference in New Issue
Block a user