From a3eb083eab974932080b61a0d6f3b28299f9ff53 Mon Sep 17 00:00:00 2001 From: Michal Skvely Date: Tue, 1 Aug 2023 21:14:10 +0200 Subject: [PATCH 01/28] VM2 compatibility additions - Support Node.js-like Buffers (transfer in/out) - Support additional properties on Buffer view objects --- src/external_copy/external_copy.cc | 181 +++++++++++++++---------- src/external_copy/external_copy.h | 15 +- src/external_copy/serializer.h | 18 ++- src/external_copy/serializer_nortti.cc | 46 ++++++- src/isolate/environment.cc | 2 + src/isolate/environment.h | 11 ++ src/isolate/generic/object.h | 33 +++++ src/isolate/node_wrapper.h | 4 + src/module/isolate.cc | 3 + src/module/isolate_handle.cc | 16 ++- src/module/isolate_handle.h | 2 + tests/buffer-copy.js | 61 +++++++++ tests/node-buffer-prototype.js | 74 ++++++++++ 13 files changed, 379 insertions(+), 87 deletions(-) create mode 100644 src/isolate/generic/object.h create mode 100644 tests/buffer-copy.js create mode 100644 tests/node-buffer-prototype.js diff --git a/src/external_copy/external_copy.cc b/src/external_copy/external_copy.cc index bded7b6b..461c32d4 100644 --- a/src/external_copy/external_copy.cc +++ b/src/external_copy/external_copy.cc @@ -8,6 +8,7 @@ #include "isolate/functor_runners.h" #include "isolate/util.h" #include "isolate/v8_version.h" +#include "isolate/generic/object.h" #include #include @@ -128,71 +129,33 @@ auto ExternalCopy::Copy(Local value, bool transfer_out, ArrayRange transf } } else if (value->IsSharedArrayBuffer()) { return std::make_unique(value.As()); - } else if (value->IsArrayBufferView()) { - Local view = value.As(); - using ViewType = ExternalCopyArrayBufferView::ViewType; - ViewType type; - if (view->IsUint8Array()) { - type = ViewType::Uint8; - } else if (view->IsUint8ClampedArray()) { - type = ViewType::Uint8Clamped; - } else if (view->IsInt8Array()) { - type = ViewType::Int8; - } else if (view->IsUint16Array()) { - type = ViewType::Uint16; - } else if (view->IsInt16Array()) { - type = ViewType::Int16; - } else if (view->IsUint32Array()) { - type = ViewType::Uint32; - } else if (view->IsInt32Array()) { - type = ViewType::Int32; - } else if (view->IsFloat32Array()) { - type = ViewType::Float32; - } else if (view->IsFloat64Array()) { - type = ViewType::Float64; - } else if (view->IsBigInt64Array()) { - type = ViewType::BigInt64; - } else if (view->IsBigUint64Array()) { - type = ViewType::BigUint64; - } else if (view->IsDataView()) { - type = ViewType::DataView; - } else { - assert(false); - } - - // Sometimes TypedArrays don't actually have a real buffer allocated for them. The call to - // `Buffer()` below will force v8 to attempt to create a buffer if it doesn't exist, and if - // there is an allocation failure it will crash the process. - if (!view->HasBuffer()) { - auto* allocator = IsolateEnvironment::GetCurrent().GetLimitedAllocator(); - if (allocator != nullptr && !allocator->Check(view->ByteLength())) { - throw RuntimeRangeError("Array buffer allocation failed"); + } else if (value->IsObject()) { + if (value->IsArrayBufferView()) { + Local view = value.As(); + + // Sometimes TypedArrays don't actually have a real buffer allocated for them. The call to + // `Buffer()` below will force v8 to attempt to create a buffer if it doesn't exist, and if + // there is an allocation failure it will crash the process. + if (!view->HasBuffer()) { + auto* allocator = IsolateEnvironment::GetCurrent().GetLimitedAllocator(); + if (allocator != nullptr && !allocator->Check(view->ByteLength())) { + throw RuntimeRangeError("Array buffer allocation failed"); + } + } + + auto buffer = view->Buffer(); + + if (buffer->IsArrayBuffer()) { + // If we are supposed to transfer the buffer out, and it's not in the list of buffers to transfer, + // we simply create a new list + if (transfer_out && std::find(transfer_list.begin(), transfer_list.end(), buffer) == transfer_list.end()) { + auto *isolate = IsolateEnvironment::GetCurrent().GetIsolate(); + auto buffer_value = buffer.As(); + transfer_list = {Array::New(isolate, &buffer_value, 1), isolate->GetCurrentContext()}; + } } } - // `Buffer()` returns a Local but it may be a Local - Local tmp = view->Buffer(); - if (tmp->IsArrayBuffer()) { - Local array_buffer = tmp.As(); - if (!transfer_out) { - transfer_out = std::find(transfer_list.begin(), transfer_list.end(), array_buffer) != transfer_list.end(); - } - // Grab byte_offset and byte_length before the transfer because "neutering" the array buffer will null these out - size_t byte_offset = view->ByteOffset(); - size_t byte_length = view->ByteLength(); - std::unique_ptr external_buffer; - if (transfer_out) { - external_buffer = ExternalCopyArrayBuffer::Transfer(array_buffer); - } else { - external_buffer = std::make_unique(array_buffer); - } - return std::make_unique(std::move(external_buffer), type, byte_offset, byte_length); - } else { - assert(tmp->IsSharedArrayBuffer()); - Local array_buffer = tmp.As(); - return std::make_unique(std::make_unique(array_buffer), type, view->ByteOffset(), view->ByteLength()); - } - } else if (value->IsObject()) { return std::make_unique(value.As(), transfer_list); } else { throw RuntimeTypeError("Unsupported type"); @@ -457,16 +420,17 @@ auto ExternalCopySharedArrayBuffer::CopyInto(bool /*transfer_in*/) -> Local buffer, - ViewType type, size_t byte_offset, size_t byte_length + ViewType type, size_t byte_offset, size_t byte_length, + bool is_node_buffer ) : ExternalCopy(sizeof(ExternalCopyArrayBufferView)), - buffer(std::move(buffer)), - type(type), - byte_offset(byte_offset), byte_length(byte_length) {} + is_node_buffer(is_node_buffer), + type(type), + byte_offset(byte_offset), + byte_length(byte_length) {} template -auto NewTypedArrayView(Local buffer, ExternalCopyArrayBufferView::ViewType type, size_t byte_offset, size_t byte_length) -> Local { +auto NewTypedArrayView(Local buffer, ExternalCopyArrayBufferView::ViewType type, size_t byte_offset, size_t byte_length) -> Local { switch (type) { case ExternalCopyArrayBufferView::ViewType::Uint8: return Uint8Array::New(buffer, byte_offset, byte_length >> 0); @@ -497,13 +461,84 @@ auto NewTypedArrayView(Local buffer, ExternalCopyArrayBufferView::ViewType ty } } -auto ExternalCopyArrayBufferView::CopyInto(bool transfer_in) -> Local { - Local buffer = this->buffer->CopyInto(transfer_in); - if (buffer->IsArrayBuffer()) { - return NewTypedArrayView(buffer.As(), type, byte_offset, byte_length); +auto ExternalCopyArrayBufferView::CopyInto(bool /*transfer_in*/) -> Local { + assert(!underlying_buffer.IsEmpty()); + Local view; + if (underlying_buffer->IsArrayBuffer()) { + view = NewTypedArrayView(underlying_buffer.As(), type, byte_offset, byte_length); + } else { + view = NewTypedArrayView(underlying_buffer.As(), type, byte_offset, byte_length); + } + + if (is_node_buffer && type == ViewType::Uint8) { + auto& environment = IsolateEnvironment::GetCurrent(); + auto buffer_prototype = environment.GetBufferPrototype(); + if (!buffer_prototype.IsEmpty() && buffer_prototype->IsObject()) { + view->SetPrototype(Isolate::GetCurrent()->GetCurrentContext(), buffer_prototype).Check(); + } + } + + if (!own_properties.IsEmpty()) { + Local context = Isolate::GetCurrent()->GetCurrentContext(); + CopyObjectProperties(context, view, own_properties); + } + + return view; +} + +auto ExternalCopyArrayBufferView::Copy(v8::Local view) -> std::unique_ptr { + ViewType type; + if (view->IsUint8Array()) { + type = ViewType::Uint8; + } else if (view->IsUint8ClampedArray()) { + type = ViewType::Uint8Clamped; + } else if (view->IsInt8Array()) { + type = ViewType::Int8; + } else if (view->IsUint16Array()) { + type = ViewType::Uint16; + } else if (view->IsInt16Array()) { + type = ViewType::Int16; + } else if (view->IsUint32Array()) { + type = ViewType::Uint32; + } else if (view->IsInt32Array()) { + type = ViewType::Int32; + } else if (view->IsFloat32Array()) { + type = ViewType::Float32; + } else if (view->IsFloat64Array()) { + type = ViewType::Float64; + } else if (view->IsBigInt64Array()) { + type = ViewType::BigInt64; + } else if (view->IsBigUint64Array()) { + type = ViewType::BigUint64; + } else if (view->IsDataView()) { + type = ViewType::DataView; } else { - return NewTypedArrayView(buffer.As(), type, byte_offset, byte_length); + assert(false); } + + auto& environment = IsolateEnvironment::GetCurrent(); + auto *isolate = Isolate::GetCurrent(); + Local context = isolate->GetCurrentContext(); + + auto buffer_prototype = environment.GetBufferPrototype(); + bool is_node_buffer = !buffer_prototype.IsEmpty() && view->GetPrototype()->Equals(context, buffer_prototype).ToChecked(); + size_t byte_offset = view->ByteOffset(); + size_t byte_length = view->ByteLength(); + + return std::make_unique(type, byte_offset, byte_length, is_node_buffer); +} + +auto ExternalCopyArrayBufferView::CopyOwnProperties(v8::Isolate* isolate, v8::Local view) -> v8::Local { + Local context = isolate->GetCurrentContext(); + Local properties = Object::New(isolate); + + auto property_names = GetObjectOwnProperties(context, view); + if (property_names->Length() > 0) { + CopyObjectProperties(context, properties, view, property_names); + return properties; + } + + return properties; } } // namespace ivm diff --git a/src/external_copy/external_copy.h b/src/external_copy/external_copy.h index 62a4f1b2..4a8689fb 100644 --- a/src/external_copy/external_copy.h +++ b/src/external_copy/external_copy.h @@ -105,13 +105,22 @@ class ExternalCopyArrayBufferView : public ExternalCopy { enum class ViewType { Uint8, Uint8Clamped, Int8, Uint16, Int16, Uint32, Int32, Float32, Float64, BigInt64, BigUint64, DataView }; private: - std::unique_ptr buffer; + bool is_node_buffer; ViewType type; size_t byte_offset, byte_length; + v8::Local underlying_buffer; + v8::Local own_properties; + public: - ExternalCopyArrayBufferView(std::unique_ptr buffer, ViewType type, size_t byte_offset, size_t byte_length); - auto CopyInto(bool transfer_in = false) -> v8::Local final; + ExternalCopyArrayBufferView(ViewType type, size_t byte_offset, size_t byte_length, bool is_node_buffer = false); + auto CopyInto(bool transfer_in) -> v8::Local final; + + auto SetUnderlyingBuffer(v8::Local buffer) -> void { underlying_buffer = buffer; } + auto SetOwnProperties(v8::Local properties) -> void { own_properties = properties; } + + static auto Copy(v8::Local view) -> std::unique_ptr; + static auto CopyOwnProperties(v8::Isolate* isolate, v8::Local view) -> v8::Local; }; } // namespace ivm diff --git a/src/external_copy/serializer.h b/src/external_copy/serializer.h index ce6c84c4..00846de2 100644 --- a/src/external_copy/serializer.h +++ b/src/external_copy/serializer.h @@ -12,12 +12,14 @@ class SerializationDelegateBase { public: SerializationDelegateBase( std::deque>& transferables, + std::deque& array_buffer_view_indexes, std::deque& wasm_modules - ) : transferables{transferables}, wasm_modules{wasm_modules} {} + ) : transferables{transferables}, array_buffer_view_indexes{array_buffer_view_indexes}, wasm_modules{wasm_modules} {} protected: - std::deque>& transferables; - std::deque& wasm_modules; + std::deque>& transferables; + std::deque& array_buffer_view_indexes; + std::deque& wasm_modules; }; class SerializerDelegate : public SerializationDelegateBase, public v8::ValueSerializer::Delegate { @@ -33,6 +35,8 @@ class SerializerDelegate : public SerializationDelegateBase, public v8::ValueSer v8::Isolate* isolate, v8::Local module) -> v8::Maybe final; auto WriteHostObject(v8::Isolate* isolate, v8::Local object) -> v8::Maybe final; + auto WriteArrayBufferView(v8::Isolate* isolate, v8::Local view) -> v8::Maybe; + private: v8::ValueSerializer* serializer = nullptr; }; @@ -49,6 +53,8 @@ class DeserializerDelegate : public SerializationDelegateBase, public v8::ValueD v8::Isolate* isolate, uint32_t transfer_id) -> v8::MaybeLocal final; auto ReadHostObject(v8::Isolate* isolate) -> v8::MaybeLocal final; + auto ReadArrayBufferView(v8::Isolate* isolate, uint32_t transferable_id) -> void; + private: v8::ValueDeserializer* deserializer = nullptr; }; @@ -65,8 +71,9 @@ class BaseSerializer { // Initialize serializer and delegate auto* isolate = v8::Isolate::GetCurrent(); auto context = isolate->GetCurrentContext(); - detail::SerializerDelegate delegate{transferables, wasm_modules}; + detail::SerializerDelegate delegate{transferables, array_buffer_view_indexes, wasm_modules}; v8::ValueSerializer serializer{isolate, &delegate}; + serializer.SetTreatArrayBufferViewsAsHostObjects(true); delegate.SetSerializer(&serializer); // Run serialization @@ -84,7 +91,7 @@ class BaseSerializer { // Initialize deserializer and delegate auto* isolate = v8::Isolate::GetCurrent(); auto context = isolate->GetCurrentContext(); - detail::DeserializerDelegate delegate{transferables, wasm_modules}; + detail::DeserializerDelegate delegate{transferables, array_buffer_view_indexes, wasm_modules}; v8::ValueDeserializer deserializer{isolate, buffer.get(), size, &delegate}; delegate.SetDeserializer(&deserializer); @@ -109,6 +116,7 @@ class BaseSerializer { std::unique_ptr buffer = {nullptr, std::free}; std::deque> transferables; std::deque wasm_modules; + std::deque array_buffer_view_indexes; size_t size; }; diff --git a/src/external_copy/serializer_nortti.cc b/src/external_copy/serializer_nortti.cc index f2ce0981..53a60caf 100644 --- a/src/external_copy/serializer_nortti.cc +++ b/src/external_copy/serializer_nortti.cc @@ -1,6 +1,7 @@ #include "serializer.h" #include "isolate/functor_runners.h" #include "module/transferable.h" +#include "isolate/generic/object.h" /** * This file is compiled *without* runtime type information, which matches the nodejs binary and @@ -33,21 +34,46 @@ auto SerializerDelegate::GetWasmModuleTransferId( return result; } -auto SerializerDelegate::WriteHostObject(Isolate* /*isolate*/, Local object) -> Maybe { +auto SerializerDelegate::WriteHostObject(Isolate* isolate, Local object) -> Maybe { auto result = Nothing(); detail::RunBarrier([&]() { - serializer->WriteUint32(transferables.size()); - transferables.emplace_back(TransferOut(object)); - result = Just(true); + auto host_object_id = transferables.size(); + serializer->WriteUint32(host_object_id); + + if (object->IsArrayBufferView()) { + auto view = object.As(); + transferables.emplace_back(ExternalCopyArrayBufferView::Copy(view)); + array_buffer_view_indexes.emplace_back(host_object_id); + result = WriteArrayBufferView(isolate, view); + } else { + transferables.emplace_back(TransferOut(object)); + result = Just(true); + } }); return result; } -auto DeserializerDelegate::ReadHostObject(Isolate* /*isolate*/) -> MaybeLocal { +auto SerializerDelegate::WriteArrayBufferView(v8::Isolate* isolate, v8::Local view) -> v8::Maybe { + Local context = isolate->GetCurrentContext(); + auto result = serializer->WriteValue(context, view->Buffer()); + + if (result.IsJust()) { + auto properties = ExternalCopyArrayBufferView::CopyOwnProperties(isolate, view); + return serializer->WriteValue(context, properties); + } + + return result; +} + +auto DeserializerDelegate::ReadHostObject(Isolate* isolate) -> MaybeLocal { MaybeLocal result; detail::RunBarrier([&]() { uint32_t ii; assert(deserializer->ReadUint32(&ii)); + if (std::find(array_buffer_view_indexes.begin(), array_buffer_view_indexes.end(), ii) != array_buffer_view_indexes.end()) { + ReadArrayBufferView(isolate, ii); + } + result = transferables[ii]->TransferIn().As(); }); return result; @@ -71,5 +97,15 @@ auto DeserializerDelegate::GetWasmModuleFromId( return result; } +auto DeserializerDelegate::ReadArrayBufferView(Isolate* isolate, uint32_t transferable_id) -> void { + auto *view_copy = reinterpret_cast*>(&transferables[transferable_id])->get(); + Local context = isolate->GetCurrentContext(); + auto underlying_buffer = deserializer->ReadValue(context).ToLocalChecked().As(); + auto properties = deserializer->ReadValue(context).ToLocalChecked().As(); + + view_copy->SetUnderlyingBuffer(underlying_buffer); + view_copy->SetOwnProperties(properties); +} + } // namespace detail } // namespace ivm diff --git a/src/isolate/environment.cc b/src/isolate/environment.cc index 396ab892..bae0d0f9 100644 --- a/src/isolate/environment.cc +++ b/src/isolate/environment.cc @@ -454,6 +454,8 @@ IsolateEnvironment::~IsolateEnvironment() { ExchangeDefault(scheduler_lock->sync_interrupts); ExchangeDefault(scheduler_lock->handle_tasks); ExchangeDefault(scheduler_lock->tasks); + + buffer_prototype.Reset(); } { std::lock_guard allocator_lock{isolate_allocator_mutex}; diff --git a/src/isolate/environment.h b/src/isolate/environment.h index a02b35fd..9e0a29f7 100644 --- a/src/isolate/environment.h +++ b/src/isolate/environment.h @@ -115,6 +115,8 @@ class IsolateEnvironment { std::unordered_map*, std::pair> weak_persistents; std::shared_ptr cpu_profile_manager; + v8::Global buffer_prototype; + public: RemoteHandle error_handler; std::unordered_multimap module_handles; @@ -350,8 +352,17 @@ class IsolateEnvironment { */ void AddWeakCallback(v8::Persistent* handle, void(*fn)(void*), void* param); void RemoveWeakCallback(v8::Persistent* handle); + + inline auto GetBufferPrototype() const -> v8::Local { + return buffer_prototype.Get(isolate); + } + inline void SetBufferPrototype(v8::Local value) { + buffer_prototype.Reset(isolate, value); + } }; + + template template auto IsolateSpecific::Deref(Functor callback) -> v8::Local { diff --git a/src/isolate/generic/object.h b/src/isolate/generic/object.h new file mode 100644 index 00000000..fd8f7225 --- /dev/null +++ b/src/isolate/generic/object.h @@ -0,0 +1,33 @@ +#pragma once +#include + +namespace ivm { + inline auto GetObjectOwnProperties(v8::Local context, v8::Local object) -> v8::Local { + v8::Local property_names = object->GetPropertyNames(context, v8::KeyCollectionMode::kOwnOnly, v8::ALL_PROPERTIES, v8::IndexFilter::kSkipIndices).ToLocalChecked(); + + return property_names; + } + + inline void CopyObjectProperties(v8::Local context, v8::Local target, v8::Local source, v8::Local property_names) { + for (uint32_t i = 0; i < property_names->Length(); i++) { + v8::MaybeLocal key = property_names->Get(context, i); + if (key.IsEmpty()) { + continue; + } + + v8::MaybeLocal value = source->Get(context, key.ToLocalChecked()); + + if (value.IsEmpty()) { + continue; + } + + target->Set(context, key.ToLocalChecked(), value.ToLocalChecked()).Check(); + } + } + + inline void CopyObjectProperties(v8::Local context, v8::Local target, v8::Local source) { + auto property_names = GetObjectOwnProperties(context, source); + + CopyObjectProperties(context, target, source, property_names); + } +} \ No newline at end of file diff --git a/src/isolate/node_wrapper.h b/src/isolate/node_wrapper.h index afa3981f..59ef3b13 100644 --- a/src/isolate/node_wrapper.h +++ b/src/isolate/node_wrapper.h @@ -3,13 +3,17 @@ #ifdef __clang__ #pragma clang system_header #include +#include #elif __GNUC__ #pragma GCC system_header #include +#include #elif _MSC_VER #pragma warning(push, 0) #include +#include #pragma warning(pop) #else #include +#include #endif diff --git a/src/module/isolate.cc b/src/module/isolate.cc index 548dcbcc..15633167 100644 --- a/src/module/isolate.cc +++ b/src/module/isolate.cc @@ -99,6 +99,9 @@ void init(Local target) { auto isolates = default_isolates->write(); assert(isolates->find(isolate) == isolates->end()); auto holder = IsolateEnvironment::New(isolate, context); + auto dummy_buffer = node::Buffer::New(isolate, 0).ToLocalChecked(); + assert(dummy_buffer->GetPrototype()->IsObject()); + holder->GetIsolate()->SetBufferPrototype(dummy_buffer->GetPrototype().As()); isolates->insert(std::make_pair( isolate, IsolateHolderAndJoin{holder, holder->GetIsolate()->GetDisposeWaitHandle()} diff --git a/src/module/isolate_handle.cc b/src/module/isolate_handle.cc index 830a2d0a..9d88ebc3 100644 --- a/src/module/isolate_handle.cc +++ b/src/module/isolate_handle.cc @@ -58,7 +58,8 @@ auto IsolateHandle::Definition() -> Local { "referenceCount", MemberAccessor{}, "wallTime", MemberAccessor{}, "startCpuProfiler", MemberFunction{}, - "stopCpuProfiler", MemberFunction), &IsolateHandle::StopCpuProfiler<1>>{} + "stopCpuProfiler", MemberFunction), &IsolateHandle::StopCpuProfiler<1>>{}, + "setBufferPrototype", MemberFunction{} )); } @@ -433,6 +434,19 @@ auto IsolateHandle::StopCpuProfiler(v8::Local title) -> Local return ThreePhaseTask::Run(*isolate, dest); } +/** + * Reference count + */ +auto IsolateHandle::SetBufferPrototype(Local prototype) -> Local { + auto env = this->isolate->GetIsolate(); + if (!env) { + throw RuntimeGenericError("Isolate is disposed"); + } + env->SetBufferPrototype(prototype); + + return Undefined(Isolate::GetCurrent()); +} + /** * Reference count */ diff --git a/src/module/isolate_handle.h b/src/module/isolate_handle.h index 18c71d95..d105b801 100644 --- a/src/module/isolate_handle.h +++ b/src/module/isolate_handle.h @@ -38,6 +38,8 @@ class IsolateHandle : public TransferableHandle { auto GetWallTime() -> v8::Local; auto StartCpuProfiler(v8::Local title) -> v8::Local; template auto StopCpuProfiler(v8::Local title) -> v8::Local; + + auto SetBufferPrototype(v8::Local prototype) -> v8::Local; auto GetReferenceCount() -> v8::Local; auto IsDisposedGetter() -> v8::Local; diff --git a/tests/buffer-copy.js b/tests/buffer-copy.js new file mode 100644 index 00000000..51eb9c68 --- /dev/null +++ b/tests/buffer-copy.js @@ -0,0 +1,61 @@ +'use strict'; +let ivm = require('isolated-vm'); +let assert = require('assert'); + +const bufferViews = [ + new DataView(new ArrayBuffer(42)), + new Int8Array([1, 2, 3]), + new Int16Array([1, 2, 3]), + new Int32Array([1, 2, 3]), + new Uint8Array([1, 2, 3]), + new Uint8ClampedArray([1, 2, 3]), + new Uint16Array([1, 2, 3]), + new Uint32Array([1, 2, 3]), + new Float32Array([1, 2, 3]), + new Float64Array([1, 2, 3]), + new BigInt64Array([1n, 2n, 3n]), + new BigUint64Array([1n, 2n, 3n]), +]; + +for (const buffer of bufferViews) { + const isolate = new ivm.Isolate(); + + const context = isolate.createContextSync(); + const jail = context.global; + + context.evalSync(`function identity(param) { return param; }`); + + const identityFunctionRef = jail.getSync('identity', { reference: true }); + + // copy without properties + const resultWithoutProps = identityFunctionRef.applySync(null, [buffer], { result: { copy: true }, arguments: { copy: true } }); + assert.deepStrictEqual(buffer, resultWithoutProps); + + // copy with extra properties + buffer.stringProp = "string"; + buffer.numberProp = 42; + buffer.boolProp = true; + buffer.nullProp = null; + buffer.undefinedProp = undefined; + buffer.bigIntProp = 42n; + buffer.emptyArrayProp = []; + buffer.arrayProp = ["string", 42, true, null, undefined, 42n, [], {}]; + buffer.emptyObjectProp = {}; + buffer.objectProp = { + stringProp: "string", + numberProp: 42, + boolProp: true, + nullProp: null, + undefinedProp: undefined, + bigIntProp: 42n, + arrayProp: [], + nested: { + prop: "nested" + } + } + + const resultWithProps = identityFunctionRef.applySync(null, [buffer], { result: { copy: true }, arguments: { copy: true } }); + assert.deepStrictEqual(buffer, resultWithProps); +} + +console.log('pass'); \ No newline at end of file diff --git a/tests/node-buffer-prototype.js b/tests/node-buffer-prototype.js new file mode 100644 index 00000000..610b12b7 --- /dev/null +++ b/tests/node-buffer-prototype.js @@ -0,0 +1,74 @@ +'use strict'; +let ivm = require('isolated-vm'); +let assert = require('assert'); + +let arr = [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 ]; +const buffer = Buffer.from(arr) + +// Without buffer prototype set, buffers copied from isolate are pure Uint8Array instances +{ + const isolate = new ivm.Isolate(); + const context = isolate.createContextSync(); + const jail = context.global; + + jail.setSync('buffer', buffer, { copy: true }); + + const isUint8ArrayInSandbox = context.evalClosureSync(` + return buffer instanceof Uint8Array && buffer.constructor.name === 'Uint8Array' + `, [], { result: { copy: true } }); + + assert(isUint8ArrayInSandbox === true); + + const bufferCopy = jail.getSync('buffer', { copy: true }); + + assert(bufferCopy !== buffer); + assert(bufferCopy instanceof Uint8Array); + assert(!Buffer.isBuffer(bufferCopy)); +} + +{ + const isolate = new ivm.Isolate(); + const context = isolate.createContextSync(); + const jail = context.global; + + context.evalClosureSync(` + class Buffer extends Uint8Array {} + globalThis.Buffer = Buffer; + $0.setBufferPrototype(Buffer.prototype); + `, [isolate]); + + jail.setSync('buffer', buffer, { copy: true }); + + const isBufferObjectInSandbox = context.evalClosureSync(` + return buffer instanceof Buffer && buffer.constructor.name === 'Buffer' + `, [], { result: { copy: true } }); + + assert(isBufferObjectInSandbox === true); + + const bufferCopy = jail.getSync('buffer', { copy: true }); + + assert(bufferCopy !== buffer); + assert(Buffer.isBuffer(bufferCopy)); + assert.deepStrictEqual(bufferCopy, buffer); +} + +{ + const isolate = new ivm.Isolate(); + const context = isolate.createContextSync(); + const jail = context.global; + + context.evalClosureSync(` + class Buffer extends Uint8Array {} + globalThis.Buffer = Buffer; + $0.setBufferPrototype(Buffer.prototype); + `, [isolate]); + + jail.setSync('objectWithBuffer', { buffer, array: [buffer] }, { copy: true }); + + const objectWithBuffer = jail.getSync('objectWithBuffer', { copy: true }); + + assert(Buffer.isBuffer(objectWithBuffer.buffer)); + assert(Buffer.isBuffer(objectWithBuffer.array[0])); +} + +console.log('pass'); From e0bc85fa208c9da2d64d4d7f3e38208ce7273a2a Mon Sep 17 00:00:00 2001 From: Michal Skvely Date: Tue, 12 Sep 2023 09:59:09 +0200 Subject: [PATCH 02/28] Support Proxy object transfer to isolate --- src/external_copy/external_copy.cc | 6 ++++ tests/proxy-copy.js | 48 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 tests/proxy-copy.js diff --git a/src/external_copy/external_copy.cc b/src/external_copy/external_copy.cc index 461c32d4..d333fc62 100644 --- a/src/external_copy/external_copy.cc +++ b/src/external_copy/external_copy.cc @@ -114,6 +114,12 @@ auto ExternalCopy::operator= (ExternalCopy&& that) noexcept -> ExternalCopy& { auto ExternalCopy::Copy(Local value, bool transfer_out, ArrayRange transfer_list) -> std::unique_ptr { + if (value->IsProxy()) { + // We just unwrap target from the proxy object. This will allow us to transfer Proxies that act as a wrapper + // for more sophisticated proxies this will be incorrect. + value = value.As()->GetTarget(); + } + std::unique_ptr copy = CopyIfPrimitive(value); if (copy) { return copy; diff --git a/tests/proxy-copy.js b/tests/proxy-copy.js new file mode 100644 index 00000000..dd9072b5 --- /dev/null +++ b/tests/proxy-copy.js @@ -0,0 +1,48 @@ +'use strict'; +let ivm = require('isolated-vm'); +let assert = require('assert'); + +// Copying Proxy Object directly +{ + const isolate = new ivm.Isolate(); + const context = isolate.createContextSync(); + const jail = context.global; + + const targetObject = { property: 'value' }; + const proxyObject = new Proxy(targetObject, {}); + + jail.setSync('proxyObject', proxyObject, { copy: true }); + + const isProxyObjectInSandbox = context.evalClosureSync(` + return proxyObject.property === 'value' + `, [], { result: { copy: true } }); + + assert(isProxyObjectInSandbox === true); + + const proxyObjectCopy = jail.getSync('proxyObject', { copy: true }); + + assert(proxyObjectCopy !== proxyObject); + assert.deepStrictEqual(targetObject, proxyObjectCopy) +} + +// Copy nested Proxy Object will fail, unfortunately V8 serializer will throw on Proxy object, and +// it looks like there is no way to enable proxy serialization. +{ + const isolate = new ivm.Isolate(); + const context = isolate.createContextSync(); + const jail = context.global; + + const targetObject = { property: 'value' }; + const proxyObject = new Proxy(targetObject, {}); + + const objectWithNesterProxyObject = { proxyObject }; + + try { + jail.setSync('objectWithNesterProxyObject', objectWithNesterProxyObject, { copy: true }); + assert(false); + } catch (e) { + assert(e instanceof TypeError); + } +} + +console.log('pass'); From 8ef4e7e9984202c31a6892af3f9d53a30c195622 Mon Sep 17 00:00:00 2001 From: Michal Skvely Date: Mon, 7 Aug 2023 15:36:18 +0200 Subject: [PATCH 03/28] Add prebuilds to NPM package --- .github/workflows/build.yml | 20 +- .github/workflows/prebuild.yml | 58 ------ .github/workflows/publish.yml | 75 +++++++ .gitignore | 1 - .npmignore | 2 +- isolated-vm.js | 2 +- package-lock.json | 356 +++++++++++++++++++++++++++++++++ package.json | 13 +- 8 files changed, 457 insertions(+), 70 deletions(-) delete mode 100644 .github/workflows/prebuild.yml create mode 100644 .github/workflows/publish.yml create mode 100644 package-lock.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8233b9af..40170050 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,18 @@ name: Build & Test -on: [push, pull_request] +on: + push: + paths: + - 'src/**' + - 'vendor/**' + - 'tests/**' + - '*.js' + pull_request: + paths: + - 'src/**' + - 'vendor/**' + - 'tests/**' + - '*.js' jobs: build-and-test: @@ -8,7 +20,7 @@ jobs: strategy: matrix: node-version: [ 16.x, 18.x, 20.x ] - os: [ ubuntu-latest, macos-latest, windows-latest ] + os: [ ubuntu-latest, macos-latest, windows-latest, macos-m1 ] fail-fast: false steps: - uses: actions/checkout@v4 @@ -27,7 +39,7 @@ jobs: npm install --global node-gyp@latest - name: Build run: | - npm install --build-from-source + npm install && npm run rebuild - name: Test uses: nick-fields/retry@v2 with: @@ -50,7 +62,7 @@ jobs: apk add g++ make python3 - name: Build run: | - npm install --build-from-source + npm install && npm run rebuild - name: Test run: | npm test diff --git a/.github/workflows/prebuild.yml b/.github/workflows/prebuild.yml deleted file mode 100644 index 6a386fde..00000000 --- a/.github/workflows/prebuild.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Add native binaries to release - -on: - push: - tags: ['*'] - workflow_dispatch: - -jobs: - prebuild: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-20.04, macos-latest, windows-latest] - fail-fast: false - steps: - - uses: actions/checkout@v4 - - name: Use Node.js 18.x - uses: actions/setup-node@v4 - with: - node-version: 18.x - - name: Add msbuild to PATH - if: matrix.os == 'windows-latest' - uses: microsoft/setup-msbuild@v1.3 - - name: Install node-gyp - if: matrix.os == 'windows-latest' - run: | - npm install --global node-gyp@latest - - name: Build - run: | - npm install --ignore-scripts - - name: Prebuild - run: | - npm run prebuild - - name: Upload - run: | - npx prebuild --upload ${{ secrets.UPLOAD_TOKEN }} - env: - MAKEFLAGS: -j4 - - prebuild-alpine: - runs-on: ubuntu-latest - container: node:18-alpine3.19 - steps: - - uses: actions/checkout@v4 - - name: install build deps - run: | - apk add g++ make python3 - - name: Build - run: | - npm install --ignore-scripts - - name: Prebuild - run: | - npm run prebuild - - name: Upload - run: | - npx prebuild --upload ${{ secrets.UPLOAD_TOKEN }} - env: - MAKEFLAGS: -j4 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..82aa4c98 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,75 @@ +name: Publish to NPM with pre-built binaries + +on: + release: + types: [created] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-20.04, windows-latest, macos-latest, macos-m1] + + steps: + - uses: actions/checkout@v3 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: 20.x + cache: npm + cache-dependency-path: 'package-lock.json' + + - name: Install dependencies + run: npm ci --ignore-scripts + + - name: Add msbuild to PATH + if: matrix.os == 'windows-latest' + uses: microsoft/setup-msbuild@v1.3 + + - name: Install node-gyp + if: matrix.os == 'windows-latest' + run: | + npm install --global node-gyp@latest + + - name: Build native extension + run: npx prebuildify -t v16.20.1 -t v18.17.0 -t v20.5.0 --strip + env: + npm_config_jobs: max # max parallel node-gyp compile jobs + + - name: Archive production artifacts + uses: actions/upload-artifact@v3 + with: + name: binaries-${{ matrix.os }} + path: ./prebuilds + + publish: + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 20.x + cache: npm + cache-dependency-path: 'package-lock.json' + registry-url: 'https://registry.npmjs.org' + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Install dependencies + run: npm ci --ignore-scripts + + - name: Download all artifacts + uses: actions/download-artifact@v3 + with: + path: /tmp/artifacts + + - name: Move artifacts to prebuilds directory + run: mkdir --parents ./prebuilds && cp --recursive /tmp/artifacts/binaries-*/* ./prebuilds + + - name: Publish to NPM + run: npm publish diff --git a/.gitignore b/.gitignore index ad6e3721..63e41f2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ build/ node_modules/ -package-lock.json out/ .cache/ compile_commands.json diff --git a/.npmignore b/.npmignore index 324e90b6..e5cf696d 100644 --- a/.npmignore +++ b/.npmignore @@ -2,9 +2,9 @@ test.js tests out/ build/ -prebuild/ .github/ .prebuildrc .travis.yml +.clang-tidy .vscode/ *.md diff --git a/isolated-vm.js b/isolated-vm.js index 45d055c2..f4c41c40 100644 --- a/isolated-vm.js +++ b/isolated-vm.js @@ -1 +1 @@ -module.exports = require('./out/isolated_vm').ivm; +module.exports = require('node-gyp-build')(__dirname).ivm; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..72151681 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,356 @@ +{ + "name": "@integromat/isolated-vm", + "version": "4.7.2", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@integromat/isolated-vm", + "version": "4.7.2", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "node-gyp-build": "^4.6.0" + }, + "devDependencies": { + "isolated-vm": ".", + "prebuildify": "^5.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/execspawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/execspawn/-/execspawn-1.0.1.tgz", + "integrity": "sha512-s2k06Jy9i8CUkYe0+DxRlvtkZoOkwwfhB+Xxo5HGUtrISVW2m98jO2tr67DGRFxZwkjQqloA3v/tNtjhBRBieg==", + "dev": true, + "dependencies": { + "util-extend": "^1.0.1" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/isolated-vm": { + "resolved": "", + "link": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "node_modules/node-abi": { + "version": "3.62.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.62.0.tgz", + "integrity": "sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/npm-run-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", + "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/prebuildify": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/prebuildify/-/prebuildify-5.0.1.tgz", + "integrity": "sha512-vXpKLfIEsDCqMJWVIoSrUUBJQIuAk9uHAkLiGJuTdXdqKSJ10sHmWeuNCDkIoRFTV1BDGYMghHVmDFP8NfkA2Q==", + "dev": true, + "dependencies": { + "execspawn": "^1.0.1", + "minimist": "^1.2.5", + "mkdirp-classic": "^0.5.3", + "node-abi": "^3.3.0", + "npm-run-path": "^3.1.0", + "pump": "^3.0.0", + "tar-fs": "^2.1.0" + }, + "bin": { + "prebuildify": "bin.js" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/util-extend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", + "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } +} diff --git a/package.json b/package.json index 79f95f03..44143bed 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,14 @@ { - "name": "isolated-vm", + "name": "@integromat/isolated-vm", "version": "4.7.2", - "description": "Access to multiple isolates", + "description": "Access to multiple isolates - Make Fork", "main": "isolated-vm.js", "types": "isolated-vm.d.ts", "engines": { "node": ">=16.0.0" }, "scripts": { - "install": "prebuild-install || (node-gyp rebuild --release -j max && node-gyp clean)", + "install": "node-gyp-build-optional", "rebuild": "node-gyp rebuild --release -j max", "prebuild": "prebuild", "upload": "prebuild --upload ${GITHUB_TOKEN}", @@ -16,11 +16,14 @@ "test": "node test.js" }, "dependencies": { - "prebuild-install": "^7.1.1" + "node-gyp-build": "^4.6.0" }, "devDependencies": { "isolated-vm": ".", - "prebuild": "^13.0.0" + "prebuildify": "^5.0.1" + }, + "overrides": { + "node-gyp": "^9.4.0" }, "binary": { "module_path": "out" From 7683f7dee83f221361f987d8f78660dd651c86ad Mon Sep 17 00:00:00 2001 From: Michal Skvely Date: Mon, 14 Aug 2023 23:16:11 +0200 Subject: [PATCH 04/28] Lower number of isolates to reduce flakiness on macOS --- tests/workers-threads.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/workers-threads.js b/tests/workers-threads.js index 0922236e..47a67359 100644 --- a/tests/workers-threads.js +++ b/tests/workers-threads.js @@ -6,7 +6,7 @@ const ivm = require('isolated-vm'); const assert = require('assert'); const { Worker, isMainThread, parentPort } = require('worker_threads'); -const kIsolateCount = 100; +const kIsolateCount = 50; const kWorkerCount = 10; if (isMainThread) { Promise.all(Array(kWorkerCount).fill().map(async (_, ii) => { From 5d52548d7366bd8daa1c315c97f073e117155be0 Mon Sep 17 00:00:00 2001 From: Michal Skvely Date: Mon, 6 May 2024 12:11:39 +0200 Subject: [PATCH 05/28] Update Node versions we publish for --- .github/workflows/build.yml | 4 ++-- .github/workflows/publish.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 40170050..7f62a195 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,12 +3,14 @@ name: Build & Test on: push: paths: + - '.github/workflows/build.yml' - 'src/**' - 'vendor/**' - 'tests/**' - '*.js' pull_request: paths: + - '.github/workflows/build.yml' - 'src/**' - 'vendor/**' - 'tests/**' @@ -24,8 +26,6 @@ jobs: fail-fast: false steps: - uses: actions/checkout@v4 - # https://github.com/nodejs/node-gyp/issues/2869 - - run: python3 -m pip install setuptools - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 82aa4c98..79db6fc0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -34,7 +34,7 @@ jobs: npm install --global node-gyp@latest - name: Build native extension - run: npx prebuildify -t v16.20.1 -t v18.17.0 -t v20.5.0 --strip + run: npx prebuildify -t v16.20.2 -t v18.20.2 -t v20.12.2 --strip env: npm_config_jobs: max # max parallel node-gyp compile jobs From 224fc703e77395fc1b5b3773d55b1306098cada5 Mon Sep 17 00:00:00 2001 From: Michal Skvely Date: Mon, 6 May 2024 12:56:27 +0200 Subject: [PATCH 06/28] Install node-gyp as dependency --- .github/workflows/build.yml | 6 +- .github/workflows/publish.yml | 7 +- package-lock.json | 1172 +++++++++++++++++++++++++++++++++ package.json | 4 +- 4 files changed, 1175 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7f62a195..b16b377f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: node-version: [ 16.x, 18.x, 20.x ] - os: [ ubuntu-latest, macos-latest, windows-latest, macos-m1 ] + os: [ ubuntu-latest, macos-latest, windows-latest ] fail-fast: false steps: - uses: actions/checkout@v4 @@ -33,10 +33,6 @@ jobs: - name: Add msbuild to PATH if: matrix.os == 'windows-latest' uses: microsoft/setup-msbuild@v1.3 - - name: Install node-gyp - if: matrix.os == 'windows-latest' - run: | - npm install --global node-gyp@latest - name: Build run: | npm install && npm run rebuild diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 79db6fc0..e2c068b8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -9,7 +9,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, windows-latest, macos-latest, macos-m1] + os: [ubuntu-20.04, windows-latest, macos-latest] steps: - uses: actions/checkout@v3 @@ -28,11 +28,6 @@ jobs: if: matrix.os == 'windows-latest' uses: microsoft/setup-msbuild@v1.3 - - name: Install node-gyp - if: matrix.os == 'windows-latest' - run: | - npm install --global node-gyp@latest - - name: Build native extension run: npx prebuildify -t v16.20.2 -t v18.20.2 -t v20.12.2 --strip env: diff --git a/package-lock.json b/package-lock.json index 72151681..6f6d59c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,12 +14,141 @@ }, "devDependencies": { "isolated-vm": ".", + "node-gyp": "^10.1.0", "prebuildify": "^5.0.1" }, "engines": { "node": ">=16.0.0" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@npmcli/agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", + "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -51,6 +180,15 @@ "readable-stream": "^3.4.0" } }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -75,12 +213,145 @@ "ieee754": "^1.1.13" } }, + "node_modules/cacache": { + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", + "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -90,6 +361,21 @@ "once": "^1.4.0" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, "node_modules/execspawn": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/execspawn/-/execspawn-1.0.1.tgz", @@ -99,12 +385,119 @@ "util-extend": "^1.0.1" } }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/glob": { + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -125,16 +518,95 @@ } ] }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, "node_modules/isolated-vm": { "resolved": "", "link": true }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -147,6 +619,53 @@ "node": ">=10" } }, + "node_modules/make-fetch-happen": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", + "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -156,12 +675,174 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz", + "integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", + "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/node-abi": { "version": "3.62.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.62.0.tgz", @@ -174,6 +855,30 @@ "node": ">=10" } }, + "node_modules/node-gyp": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz", + "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, "node_modules/node-gyp-build": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", @@ -184,6 +889,21 @@ "node-gyp-build-test": "build-test.js" } }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/npm-run-path": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", @@ -205,6 +925,21 @@ "wrappy": "1" } }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -214,6 +949,31 @@ "node": ">=8" } }, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/prebuildify": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/prebuildify/-/prebuildify-5.0.1.tgz", @@ -232,6 +992,28 @@ "prebuildify": "bin.js" } }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -256,6 +1038,15 @@ "node": ">= 6" } }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -276,6 +1067,13 @@ } ] }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true + }, "node_modules/semver": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", @@ -291,6 +1089,95 @@ "node": ">=10" } }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dev": true, + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, + "node_modules/ssri": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", + "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -300,6 +1187,119 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/tar-fs": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", @@ -328,6 +1328,72 @@ "node": ">=6" } }, + "node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -340,6 +1406,112 @@ "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", "dev": true }, + "node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index 44143bed..2928aac8 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,9 @@ }, "devDependencies": { "isolated-vm": ".", + "node-gyp": "^10.1.0", "prebuildify": "^5.0.1" }, - "overrides": { - "node-gyp": "^9.4.0" - }, "binary": { "module_path": "out" }, From 27f91222fdb66c002d3cebe38ef619bb9b1021d3 Mon Sep 17 00:00:00 2001 From: Michal Skvely Date: Mon, 6 May 2024 16:22:35 +0200 Subject: [PATCH 07/28] Fix windows prebuildify build --- package-lock.json | 24 ++++-------------------- package.json | 2 +- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6f6d59c7..7822b5f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "devDependencies": { "isolated-vm": ".", "node-gyp": "^10.1.0", - "prebuildify": "^5.0.1" + "prebuildify": "^6.0.1" }, "engines": { "node": ">=16.0.0" @@ -376,15 +376,6 @@ "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", "dev": true }, - "node_modules/execspawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/execspawn/-/execspawn-1.0.1.tgz", - "integrity": "sha512-s2k06Jy9i8CUkYe0+DxRlvtkZoOkwwfhB+Xxo5HGUtrISVW2m98jO2tr67DGRFxZwkjQqloA3v/tNtjhBRBieg==", - "dev": true, - "dependencies": { - "util-extend": "^1.0.1" - } - }, "node_modules/exponential-backoff": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", @@ -975,12 +966,11 @@ } }, "node_modules/prebuildify": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/prebuildify/-/prebuildify-5.0.1.tgz", - "integrity": "sha512-vXpKLfIEsDCqMJWVIoSrUUBJQIuAk9uHAkLiGJuTdXdqKSJ10sHmWeuNCDkIoRFTV1BDGYMghHVmDFP8NfkA2Q==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/prebuildify/-/prebuildify-6.0.1.tgz", + "integrity": "sha512-8Y2oOOateom/s8dNBsGIcnm6AxPmLH4/nanQzL5lQMU+sC0CMhzARZHizwr36pUPLdvBnOkCNQzxg4djuFSgIw==", "dev": true, "dependencies": { - "execspawn": "^1.0.1", "minimist": "^1.2.5", "mkdirp-classic": "^0.5.3", "node-abi": "^3.3.0", @@ -1400,12 +1390,6 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, - "node_modules/util-extend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", - "dev": true - }, "node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", diff --git a/package.json b/package.json index 2928aac8..ac5d1245 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "devDependencies": { "isolated-vm": ".", "node-gyp": "^10.1.0", - "prebuildify": "^5.0.1" + "prebuildify": "^6.0.1" }, "binary": { "module_path": "out" From aec2a316f45091c37d8365b33ccc56e9bdd59d94 Mon Sep 17 00:00:00 2001 From: Michal Skvely Date: Mon, 6 May 2024 19:54:57 +0200 Subject: [PATCH 08/28] Publish correct prebuilds --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e2c068b8..afa7825a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -29,7 +29,7 @@ jobs: uses: microsoft/setup-msbuild@v1.3 - name: Build native extension - run: npx prebuildify -t v16.20.2 -t v18.20.2 -t v20.12.2 --strip + run: npx prebuildify --napi=false --name isolated-vm -t v16.20.2 -t v18.20.2 -t v20.12.2 --strip env: npm_config_jobs: max # max parallel node-gyp compile jobs From 015d5d24828f5377eb8365043dc04b16306edb3b Mon Sep 17 00:00:00 2001 From: Michal Skvely Date: Mon, 6 May 2024 19:59:35 +0200 Subject: [PATCH 09/28] 4.7.3 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7822b5f5..d87bb9ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@integromat/isolated-vm", - "version": "4.7.2", + "version": "4.7.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@integromat/isolated-vm", - "version": "4.7.2", + "version": "4.7.3", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index ac5d1245..073f647e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@integromat/isolated-vm", - "version": "4.7.2", + "version": "4.7.3", "description": "Access to multiple isolates - Make Fork", "main": "isolated-vm.js", "types": "isolated-vm.d.ts", From 35a8a5fd4f6fe06bf2c92518fcca1e24b2d9047d Mon Sep 17 00:00:00 2001 From: Michal Skvely Date: Mon, 6 May 2024 20:19:41 +0200 Subject: [PATCH 10/28] Update node-gyp-build to load correct modules --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d87bb9ba..5148dcb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "node-gyp-build": "^4.6.0" + "node-gyp-build": "^4.8.1" }, "devDependencies": { "isolated-vm": ".", diff --git a/package.json b/package.json index 073f647e..96761f1b 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "test": "node test.js" }, "dependencies": { - "node-gyp-build": "^4.6.0" + "node-gyp-build": "^4.8.1" }, "devDependencies": { "isolated-vm": ".", From 7279fd532d9d177ae9852547147c66c2855e213f Mon Sep 17 00:00:00 2001 From: Michal Skvely Date: Mon, 6 May 2024 20:20:37 +0200 Subject: [PATCH 11/28] 4.7.4 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5148dcb0..187b4d67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@integromat/isolated-vm", - "version": "4.7.3", + "version": "4.7.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@integromat/isolated-vm", - "version": "4.7.3", + "version": "4.7.4", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 96761f1b..4d967d76 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@integromat/isolated-vm", - "version": "4.7.3", + "version": "4.7.4", "description": "Access to multiple isolates - Make Fork", "main": "isolated-vm.js", "types": "isolated-vm.d.ts", From a17d860fc76fec209f7cce6aec32de871741f2a5 Mon Sep 17 00:00:00 2001 From: skvelymake <112627159+skvelymake@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:55:09 +0200 Subject: [PATCH 12/28] Add Linux ARM build (#1) --- .github/workflows/{build.yml => ci.yml} | 11 ++--------- .github/workflows/publish.yml | 7 +++---- tests/cached-data.js | 24 ++++++++++++++---------- tests/orphaned-isolate-gc.js | 6 ++++++ 4 files changed, 25 insertions(+), 23 deletions(-) rename .github/workflows/{build.yml => ci.yml} (85%) diff --git a/.github/workflows/build.yml b/.github/workflows/ci.yml similarity index 85% rename from .github/workflows/build.yml rename to .github/workflows/ci.yml index b16b377f..2dd1ec82 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/ci.yml @@ -1,16 +1,9 @@ name: Build & Test on: - push: - paths: - - '.github/workflows/build.yml' - - 'src/**' - - 'vendor/**' - - 'tests/**' - - '*.js' pull_request: paths: - - '.github/workflows/build.yml' + - '.github/workflows/ci.yml' - 'src/**' - 'vendor/**' - 'tests/**' @@ -22,7 +15,7 @@ jobs: strategy: matrix: node-version: [ 16.x, 18.x, 20.x ] - os: [ ubuntu-latest, macos-latest, windows-latest ] + os: [ ubuntu-latest, macos-latest, windows-latest, linux-arm ] fail-fast: false steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index afa7825a..24466152 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -9,12 +9,11 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, windows-latest, macos-latest] - + os: [ubuntu-20.04, windows-latest, macos-latest, linux-arm] steps: - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} + - name: Use Node.js uses: actions/setup-node@v3 with: node-version: 20.x @@ -29,7 +28,7 @@ jobs: uses: microsoft/setup-msbuild@v1.3 - name: Build native extension - run: npx prebuildify --napi=false --name isolated-vm -t v16.20.2 -t v18.20.2 -t v20.12.2 --strip + run: npx prebuildify --napi=false --name isolated-vm -t v16.20.2 -t v18.20.4 -t v20.16.0 --strip env: npm_config_jobs: max # max parallel node-gyp compile jobs diff --git a/tests/cached-data.js b/tests/cached-data.js index 5d851031..8e560162 100644 --- a/tests/cached-data.js +++ b/tests/cached-data.js @@ -36,23 +36,27 @@ let cachedData; { // Time compilation with no cached data - let d = Date.now(); - const timeout = 200; - let count = 0; - do { + const count = 10; + + const uncachedCompileStart = Date.now(); + for (let i = 0; i < count; i++) { const isolate = new ivm.Isolate; const script = isolate.compileScriptSync(src); - ++count; - } while (Date.now() < d + timeout); + } + const uncachedCompileEnd = Date.now(); + const uncachedCompileDuration = uncachedCompileEnd - uncachedCompileStart; - // Compare to compilation with cached data - d = Date.now(); - for (let ii = 0; ii < count; ++ii) { + // Time compilation with cached data + const cachedCompileStart = Date.now(); + for (let i = 0; i < count; i++) { const isolate = new ivm.Isolate; const script = isolate.compileScriptSync(src, { cachedData }); assert.ok(!script.cachedDataRejected); } - if (Date.now() - d > timeout / 2) { + const cachedCompileEnd = Date.now(); + const cachedCompileDuration = cachedCompileEnd - cachedCompileStart; + + if (cachedCompileDuration > uncachedCompileDuration * 0.7) { console.log('cached data is suspiciously slow'); } } diff --git a/tests/orphaned-isolate-gc.js b/tests/orphaned-isolate-gc.js index 1d466ffe..d845a9e2 100644 --- a/tests/orphaned-isolate-gc.js +++ b/tests/orphaned-isolate-gc.js @@ -1,5 +1,11 @@ // node-args: --expose-gc const ivm = require('isolated-vm'); + +if (process.memoryUsage().rss === 0) { + console.log('pass'); + return; +} + let isolate = Array(100).fill().map(() => new ivm.Isolate()); gc(); let rss1 = process.memoryUsage().rss; From c6c90122a2a0781b007f9938d9a18df134af03ac Mon Sep 17 00:00:00 2001 From: Michal Skvely Date: Thu, 12 Sep 2024 13:58:55 +0200 Subject: [PATCH 13/28] 4.8.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 187b4d67..53c5005c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@integromat/isolated-vm", - "version": "4.7.4", + "version": "4.8.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@integromat/isolated-vm", - "version": "4.7.4", + "version": "4.8.0", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 4d967d76..c45fbaf4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@integromat/isolated-vm", - "version": "4.7.4", + "version": "4.8.0", "description": "Access to multiple isolates - Make Fork", "main": "isolated-vm.js", "types": "isolated-vm.d.ts", From 5f6311bf29eaa05fe628aa0149e9e3f0e3c4785b Mon Sep 17 00:00:00 2001 From: skvelymake <112627159+skvelymake@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:16:51 +0200 Subject: [PATCH 14/28] build: fix prebuilds to older libc for compatibility (#2) --- .github/workflows/ci.yml | 4 +-- .github/workflows/publish.yml | 49 +++++++++++++++++++++++++++++------ package.json | 2 +- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2dd1ec82..62205656 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,12 +25,12 @@ jobs: node-version: ${{ matrix.node-version }} - name: Add msbuild to PATH if: matrix.os == 'windows-latest' - uses: microsoft/setup-msbuild@v1.3 + uses: microsoft/setup-msbuild@v2 - name: Build run: | npm install && npm run rebuild - name: Test - uses: nick-fields/retry@v2 + uses: nick-fields/retry@v3 with: max_attempts: 3 retry_on: error diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 24466152..aa9ad8e8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -5,16 +5,47 @@ on: types: [created] jobs: - build: + build-linux: runs-on: ${{ matrix.os }} + # This will force build on an older libc version + container: node:20-bullseye strategy: matrix: - os: [ubuntu-20.04, windows-latest, macos-latest, linux-arm] + os: [ ubuntu-latest, linux-arm ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 + with: + node-version: 20.x + cache: npm + cache-dependency-path: 'package-lock.json' + + - name: Install dependencies + run: npm ci --ignore-scripts + + - name: Build native extension + run: npx prebuildify --napi=false --name isolated-vm --tag-libc -t v16.20.2 -t v18.20.4 -t v20.16.0 --strip + env: + npm_config_jobs: max # max parallel node-gyp compile jobs + + - name: Archive production artifacts + uses: actions/upload-artifact@v3 + with: + name: binaries-${{ matrix.os }} + path: ./prebuilds + + build-others: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-latest, macos-latest] + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js + uses: actions/setup-node@v4 with: node-version: 20.x cache: npm @@ -25,7 +56,7 @@ jobs: - name: Add msbuild to PATH if: matrix.os == 'windows-latest' - uses: microsoft/setup-msbuild@v1.3 + uses: microsoft/setup-msbuild@v2 - name: Build native extension run: npx prebuildify --napi=false --name isolated-vm -t v16.20.2 -t v18.20.4 -t v20.16.0 --strip @@ -39,13 +70,15 @@ jobs: path: ./prebuilds publish: - needs: build + needs: + - build-others + - build-linux runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20.x cache: npm diff --git a/package.json b/package.json index c45fbaf4..b86d62e5 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "isolated-vm.js", "types": "isolated-vm.d.ts", "engines": { - "node": ">=16.0.0" + "node": ">=16 <21" }, "scripts": { "install": "node-gyp-build-optional", From 8153fa9d8459d03439485031d0cdd9df32d77214 Mon Sep 17 00:00:00 2001 From: Michal Skvely Date: Thu, 12 Sep 2024 17:17:46 +0200 Subject: [PATCH 15/28] 4.8.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 53c5005c..d359920c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@integromat/isolated-vm", - "version": "4.8.0", + "version": "4.8.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@integromat/isolated-vm", - "version": "4.8.0", + "version": "4.8.1", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index b86d62e5..0d86fe84 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@integromat/isolated-vm", - "version": "4.8.0", + "version": "4.8.1", "description": "Access to multiple isolates - Make Fork", "main": "isolated-vm.js", "types": "isolated-vm.d.ts", From a4f397305381d81ffa3e159e22c07faa8d765ff4 Mon Sep 17 00:00:00 2001 From: "make-pulumi[bot]" <153177201+make-pulumi[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 18:00:10 +0000 Subject: [PATCH 16/28] ci(codeowners): sync CODEOWNERS with repository owner --- .github/CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..88976114 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,3 @@ +# The header of Codeowners is autogenerated from https://github.com/integromat/mono. Don’t edit code before END-AUTOGENERATED-SECTION! +* @integromat/nexus +### END-AUTOGENERATED-SECTION From d4e26d4582b99d0f1a37e647fee6a5c32a05590f Mon Sep 17 00:00:00 2001 From: "make-pulumi[bot]" <153177201+make-pulumi[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 17:13:39 +0000 Subject: [PATCH 17/28] ci: update validate-pr.yml --- .github/workflows/validate-pr.yml | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/validate-pr.yml diff --git a/.github/workflows/validate-pr.yml b/.github/workflows/validate-pr.yml new file mode 100644 index 00000000..10590df1 --- /dev/null +++ b/.github/workflows/validate-pr.yml @@ -0,0 +1,50 @@ +###### +# This file is autogenerated from https://github.com/integromat/mono/blob/master/libs/github-resources/src/repositories/isolated-vm.ts. Do not edit manually!!! +###### + +name: PR +on: + pull_request: + types: + - opened + - reopened + - synchronize + - labeled + - unlabeled + - edited + merge_group: + +# run only latest workflow, cancel other runs of this workflow +concurrency: + group: validate-pr-${{ github.ref }} + cancel-in-progress: true + +env: + FORCE_COLOR: '1' + +jobs: + validate-pr: + name: Validate PR + runs-on: ubuntu-latest + permissions: + id-token: write + issues: write + pull-requests: write + contents: read + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + GITHUB_TOKEN: ${{ github.token }} + steps: + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + if: github.event_name != 'merge_group' + + - name: Setup Node.js + if: github.event_name != 'merge_group' + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 + with: + registry-url: https://registry.npmjs.org + node-version: '>=20.0' + + - name: Validate PR + if: github.event_name != 'merge_group' + run: npx @integromat/actions-toolkit validate-pr From b0481d9948a4931570d562f614a00367e718192e Mon Sep 17 00:00:00 2001 From: skvelymake <112627159+skvelymake@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:43:07 +0100 Subject: [PATCH 18/28] build: add ARM runner (#3) CDM-12573 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 62205656..181c6e8e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: strategy: matrix: node-version: [ 16.x, 18.x, 20.x ] - os: [ ubuntu-latest, macos-latest, windows-latest, linux-arm ] + os: [ ubuntu-latest, macos-latest, windows-latest, make-ubuntu24-arm64-2c ] fail-fast: false steps: - uses: actions/checkout@v4 From b0216c8866605d9bacaa208d6f6de6c39e4bc6be Mon Sep 17 00:00:00 2001 From: skvelymake <112627159+skvelymake@users.noreply.github.com> Date: Fri, 29 Nov 2024 11:30:33 +0100 Subject: [PATCH 19/28] fix: report external memory to parent isolate (#5) CDM-12576 --- src/isolate/environment.cc | 17 ++++++++++++++++- src/isolate/environment.h | 33 +++++++++++++++++++++++++++++++++ tests/garbage-collection.js | 23 +++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 tests/garbage-collection.js diff --git a/src/isolate/environment.cc b/src/isolate/environment.cc index bae0d0f9..d06e302d 100644 --- a/src/isolate/environment.cc +++ b/src/isolate/environment.cc @@ -102,7 +102,11 @@ void IsolateEnvironment::HeapCheck::Epilogue() { env.hit_memory_limit = true; env.Terminate(); throw FatalRuntimeError("Isolate was disposed during execution due to memory limit"); + } else { + env.ReportExternalMemoryToParentIsolate(heap); } + } else { + env.ReportExternalMemoryToParentIsolate(heap); } } } @@ -187,6 +191,7 @@ void IsolateEnvironment::MarkSweepCompactEpilogue(Isolate* isolate, GCType /*gc_ that->isolate->GetHeapStatistics(&heap); size_t total_memory = heap.used_heap_size() + that->extra_allocated_memory; size_t memory_limit = that->memory_limit + that->misc_memory_size; + that->ReportExternalMemoryToParentIsolate(heap); if (total_memory > memory_limit) { if ((gc_flags & (GCCallbackFlags::kGCCallbackFlagCollectAllAvailableGarbage | GCCallbackFlags::kGCCallbackFlagForced)) == 0) { // Force full garbage collection @@ -213,7 +218,6 @@ void IsolateEnvironment::MarkSweepCompactEpilogue(Isolate* isolate, GCType /*gc_ } else { that->RequestMemoryPressureNotification(MemoryPressureLevel::kNone); } - return; } } @@ -430,6 +434,17 @@ IsolateEnvironment::~IsolateEnvironment() { handle.dispose_wait->Join(); } } else { + { + auto parent_isolate_holder = parent_holder.lock(); + if (parent_isolate_holder) { + auto parent_isolate = parent_isolate_holder->GetIsolate(); + if (parent_isolate) { + parent_isolate->GetIsolate()->AdjustAmountOfExternalAllocatedMemory( + -(ssize_t) last_reported_external_memory_size + ); + } + } + } { // Grab local pointer to inspector agent with scheduler lock active auto agent_ptr = [&]() { diff --git a/src/isolate/environment.h b/src/isolate/environment.h index 9e0a29f7..105d4bb0 100644 --- a/src/isolate/environment.h +++ b/src/isolate/environment.h @@ -89,6 +89,7 @@ class IsolateEnvironment { Executor executor; std::shared_ptr dispose_wait{std::make_shared()}; std::weak_ptr holder; + std::weak_ptr parent_holder; std::shared_ptr task_runner; std::unique_ptr inspector_agent; v8::Persistent default_context; @@ -99,6 +100,7 @@ class IsolateEnvironment { size_t memory_limit = 0; size_t initial_heap_size_limit = 0; size_t misc_memory_size = 0; + size_t last_reported_external_memory_size = 0; std::atomic extra_allocated_memory = 0; v8::MemoryPressureLevel memory_pressure = v8::MemoryPressureLevel::kNone; v8::MemoryPressureLevel last_memory_pressure = v8::MemoryPressureLevel::kNone; @@ -192,6 +194,7 @@ class IsolateEnvironment { auto env = std::make_shared(static_cast(*Executor::GetDefaultEnvironment().scheduler)); auto holder = std::make_shared(env); env->holder = holder; + env->parent_holder = IsolateEnvironment::GetCurrentHolder(); env->IsolateCtor(memory_limit_in_mb, std::move(snapshot_blob), snapshot_length); return holder; } @@ -313,6 +316,36 @@ class IsolateEnvironment { extra_allocated_memory += size; } + void ReportExternalMemoryToParentIsolate(v8::HeapStatistics &heap) { + if (nodejs_isolate) { + return; + } + + auto parent_isolate_holder = this->parent_holder.lock(); + if (!parent_isolate_holder) { + return; + } + + size_t new_external_memory_size = + heap.total_heap_size() + + heap.external_memory() + + heap.malloced_memory() + + extra_allocated_memory; + auto delta = static_cast(new_external_memory_size - last_reported_external_memory_size); + last_reported_external_memory_size = new_external_memory_size; + + static_assert(sizeof(ssize_t) <= sizeof(void*), "ssize_t does not fit into a void*"); + + if (delta != 0) { + auto parent_env = parent_isolate_holder->GetIsolate(); + if (parent_env) { + parent_env->isolate->RequestInterrupt([](v8::Isolate* isolate, void* delta) { + isolate->AdjustAmountOfExternalAllocatedMemory(reinterpret_cast(delta)); + }, reinterpret_cast(delta)); // NOLINT(*-no-int-to-ptr) + } + } + } + /** * Returns the current number of outstanding RemoteHandles<> to this isolate. */ diff --git a/tests/garbage-collection.js b/tests/garbage-collection.js new file mode 100644 index 00000000..10fef998 --- /dev/null +++ b/tests/garbage-collection.js @@ -0,0 +1,23 @@ +const ivm = require('isolated-vm'); + +async function run() { + for (let i = 0; i < 1000; i++) { + const isolate = new ivm.Isolate; + const context = isolate.createContextSync(); + const jail = context.global; + + void jail; + + await new Promise(resolve => setTimeout(resolve, 1)); + } + + const memoryUsage = process.memoryUsage(); + const rssMemory = Math.round(memoryUsage.rss / 1024 / 1024); + if (rssMemory < 200) { + console.log('pass'); + } else { + console.log('failed with RSS memory:', rssMemory); + } +} + +run().catch(console.error); \ No newline at end of file From 5152164621f4b5ed4f608ad0bbcab2ed7a4c7580 Mon Sep 17 00:00:00 2001 From: skvelymake <112627159+skvelymake@users.noreply.github.com> Date: Fri, 29 Nov 2024 12:38:55 +0100 Subject: [PATCH 20/28] fix: propagate garbage collector calls to owned isolates (#6) CDM-12576 --- src/isolate/environment.cc | 35 +++++++++++++++++++++++++ src/isolate/environment.h | 1 + tests/cached-data.js | 4 +-- tests/garbage-collection-propagation.js | 29 ++++++++++++++++++++ 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 tests/garbage-collection-propagation.js diff --git a/src/isolate/environment.cc b/src/isolate/environment.cc index d06e302d..8daacac6 100644 --- a/src/isolate/environment.cc +++ b/src/isolate/environment.cc @@ -185,6 +185,39 @@ auto IsolateEnvironment::CodeGenCallback2(Local context, Local s return CodeGenCallback(context, source); } +void IsolateEnvironment::MarkSweepCompactPrologue(Isolate* /*isolate*/, GCType gc_type, GCCallbackFlags /*gc_flags*/, void* data) { +#if V8_AT_LEAST(10, 0, 0) // Node.js 18+ + if ((gc_type & (GCType::kGCTypeMarkSweepCompact | GCType::kGCTypeMinorMarkCompact)) == 0) { + return; + } +#else + if (gc_type != GCType::kGCTypeMarkSweepCompact) { + return; + } +#endif + + auto* that = static_cast(data); + + if (!that->owned_isolates) { + return; + } + + auto isolates = *that->owned_isolates->read(); // copy + for (const auto& handle: isolates) { + auto ref = handle.holder.lock(); + if (!ref) { + continue; + } + + auto owned_isolate = ref->GetIsolate(); + if (owned_isolate && owned_isolate->last_memory_pressure != MemoryPressureLevel::kCritical) { + Executor::Lock lock(*owned_isolate); + owned_isolate->memory_pressure = MemoryPressureLevel::kCritical; + owned_isolate->CheckMemoryPressure(); + } + } +} + void IsolateEnvironment::MarkSweepCompactEpilogue(Isolate* isolate, GCType /*gc_type*/, GCCallbackFlags gc_flags, void* data) { auto* that = static_cast(data); HeapStatistics heap; @@ -356,6 +389,7 @@ IsolateEnvironment::IsolateEnvironment(UvScheduler& default_scheduler) : void IsolateEnvironment::IsolateCtor(Isolate* isolate, Local context) { this->isolate = isolate; + isolate->AddGCPrologueCallback(MarkSweepCompactPrologue, static_cast(this), GCType::kGCTypeAll); default_context.Reset(isolate, context); } @@ -395,6 +429,7 @@ void IsolateEnvironment::IsolateCtor(size_t memory_limit_in_mb, shared_ptrSetModifyCodeGenerationFromStringsCallback(CodeGenCallback2); // Add GC callbacks + isolate->AddGCPrologueCallback(MarkSweepCompactPrologue, static_cast(this), GCType::kGCTypeAll); isolate->AddGCEpilogueCallback(MarkSweepCompactEpilogue, static_cast(this), GCType::kGCTypeMarkSweepCompact); isolate->AddNearHeapLimitCallback(NearHeapLimitCallback, static_cast(this)); diff --git a/src/isolate/environment.h b/src/isolate/environment.h index 105d4bb0..cfcd3559 100644 --- a/src/isolate/environment.h +++ b/src/isolate/environment.h @@ -153,6 +153,7 @@ class IsolateEnvironment { /** * GC hooks to kill this isolate before it runs out of memory */ + static void MarkSweepCompactPrologue(v8::Isolate* isolate, v8::GCType gc_type, v8::GCCallbackFlags gc_flags, void* data); static void MarkSweepCompactEpilogue(v8::Isolate* isolate, v8::GCType gc_type, v8::GCCallbackFlags gc_flags, void* data); static auto NearHeapLimitCallback(void* data, size_t current_heap_limit, size_t initial_heap_limit) -> size_t; void RequestMemoryPressureNotification(v8::MemoryPressureLevel memory_pressure, bool as_interrupt = false); diff --git a/tests/cached-data.js b/tests/cached-data.js index 8e560162..7ec858f7 100644 --- a/tests/cached-data.js +++ b/tests/cached-data.js @@ -35,9 +35,9 @@ let cachedData; } { - // Time compilation with no cached data - const count = 10; + const count = 3; // larger number causes GC to run and mess up the results + // Time compilation with no cached data const uncachedCompileStart = Date.now(); for (let i = 0; i < count; i++) { const isolate = new ivm.Isolate; diff --git a/tests/garbage-collection-propagation.js b/tests/garbage-collection-propagation.js new file mode 100644 index 00000000..1e7907f6 --- /dev/null +++ b/tests/garbage-collection-propagation.js @@ -0,0 +1,29 @@ +const ivm = require('isolated-vm'); + +async function run() { + for (let i = 0; i < 1000; i++) { + const isolate = new ivm.Isolate; + const context = isolate.createContextSync(); + const jail = context.global; + jail.setSync('isolate', isolate); + + isolate.compileScriptSync(` + isolate.compileScriptSync('1'); + delete globalThis.isolate; + `).runSync(context); + + void jail; + + await new Promise(resolve => setTimeout(resolve, 1)); + } + + const memoryUsage = process.memoryUsage(); + const rssMemory = Math.round(memoryUsage.rss / 1024 / 1024); + if (rssMemory < 200) { + console.log('pass'); + } else { + console.log('failed with RSS memory:', rssMemory); + } +} + +run().catch(console.error); \ No newline at end of file From 8837065cdc02fbce343035f4d3090b2ed276b884 Mon Sep 17 00:00:00 2001 From: skvelymake <112627159+skvelymake@users.noreply.github.com> Date: Fri, 29 Nov 2024 15:13:58 +0100 Subject: [PATCH 21/28] 4.8.2-alpha.0 (#7) --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d359920c..1db54b84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@integromat/isolated-vm", - "version": "4.8.1", + "version": "4.8.2-alpha.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@integromat/isolated-vm", - "version": "4.8.1", + "version": "4.8.2-alpha.0", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 0d86fe84..671bec9a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@integromat/isolated-vm", - "version": "4.8.1", + "version": "4.8.2-alpha.0", "description": "Access to multiple isolates - Make Fork", "main": "isolated-vm.js", "types": "isolated-vm.d.ts", From 90e71fce946692553b375c1d5bf19470cdda7721 Mon Sep 17 00:00:00 2001 From: skvelymake <112627159+skvelymake@users.noreply.github.com> Date: Fri, 29 Nov 2024 15:27:46 +0100 Subject: [PATCH 22/28] build: fix publish workflow (#8) --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index aa9ad8e8..7950c8bb 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,7 +11,7 @@ jobs: container: node:20-bullseye strategy: matrix: - os: [ ubuntu-latest, linux-arm ] + os: [ ubuntu-latest, make-ubuntu24-arm64-2c ] steps: - uses: actions/checkout@v4 From 82398b8fbd31f56477155fe8b8c932a39c6e1839 Mon Sep 17 00:00:00 2001 From: skvelymake <112627159+skvelymake@users.noreply.github.com> Date: Thu, 5 Dec 2024 14:08:15 +0100 Subject: [PATCH 23/28] v4.8.2 (#9) --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1db54b84..e4738ab9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@integromat/isolated-vm", - "version": "4.8.2-alpha.0", + "version": "4.8.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@integromat/isolated-vm", - "version": "4.8.2-alpha.0", + "version": "4.8.2", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 671bec9a..18a5ad93 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@integromat/isolated-vm", - "version": "4.8.2-alpha.0", + "version": "4.8.2", "description": "Access to multiple isolates - Make Fork", "main": "isolated-vm.js", "types": "isolated-vm.d.ts", From 1c34925ccd6295142d0ee6c6467edb5a3d5a0a87 Mon Sep 17 00:00:00 2001 From: skvelymake <112627159+skvelymake@users.noreply.github.com> Date: Mon, 23 Dec 2024 12:13:43 +0100 Subject: [PATCH 24/28] fix: correctly propagate exceptions to calling isolate (#10) ## Overview Function call might have swallow an Isolate exception if it wasn't followed by C++ exceptions as well. ## Changes - Add check for caught exceptions and handle them by passing to `fn2` in `RunCatchExternal`. - Add test case to ensure error is thrown when trying to copy a buffer with function properties to the Isolate. - Add test case to ensure error is thrown when trying to copy a buffer with function properties from the Isolate. [VMB-141](https://make.atlassian.net/browse/VMB-141) [VMB-141]: https://make.atlassian.net/browse/VMB-141?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --- src/external_copy/serializer_nortti.cc | 9 +++++++-- src/isolate/functor_runners.h | 5 +++++ tests/buffer-copy.js | 20 ++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/external_copy/serializer_nortti.cc b/src/external_copy/serializer_nortti.cc index 53a60caf..4c860a0b 100644 --- a/src/external_copy/serializer_nortti.cc +++ b/src/external_copy/serializer_nortti.cc @@ -70,8 +70,13 @@ auto DeserializerDelegate::ReadHostObject(Isolate* isolate) -> MaybeLocalReadUint32(&ii)); - if (std::find(array_buffer_view_indexes.begin(), array_buffer_view_indexes.end(), ii) != array_buffer_view_indexes.end()) { - ReadArrayBufferView(isolate, ii); + + // Replacing std::find with a for loop for compatibility with Alpine Linux + for (const auto& value : array_buffer_view_indexes) { + if (value == ii) { + ReadArrayBufferView(isolate, ii); + break; + } } result = transferables[ii]->TransferIn().As(); diff --git a/src/isolate/functor_runners.h b/src/isolate/functor_runners.h index 7eeb1f4d..2fc9666d 100644 --- a/src/isolate/functor_runners.h +++ b/src/isolate/functor_runners.h @@ -39,6 +39,11 @@ inline void RunCatchExternal(v8::Local default_context, F1 fn1, F2 try { try { fn1(); + + if (try_catch.HasCaught()) { + v8::Context::Scope context_scope{default_context}; + fn2(ExternalCopy::CopyThrownValue(try_catch.Exception())); + } } catch (const RuntimeTypeError& cc_error) { // The following errors are just various C++ strings with an error type fn2(std::make_unique(ExternalCopyError::ErrorType::TypeError, cc_error.GetMessage().c_str(), cc_error.GetStackTrace())); diff --git a/tests/buffer-copy.js b/tests/buffer-copy.js index 51eb9c68..c6679fd6 100644 --- a/tests/buffer-copy.js +++ b/tests/buffer-copy.js @@ -56,6 +56,26 @@ for (const buffer of bufferViews) { const resultWithProps = identityFunctionRef.applySync(null, [buffer], { result: { copy: true }, arguments: { copy: true } }); assert.deepStrictEqual(buffer, resultWithProps); + + // fail to copy with function properties to the Isolate + buffer.functionProp = () => {}; + try { + identityFunctionRef.applySync(null, [buffer], { result: { copy: true }, arguments: { copy: true } }); + assert.fail("Expected an error"); + } catch (error) { + assert.strictEqual(error.message, "() => {} could not be cloned."); + } + + // fail to copy with function properties from the Isolate + const constructorName = buffer.constructor.name; + context.evalSync(`function getBuffer() { const buffer = new ${constructorName}(new ArrayBuffer(8)); buffer.x = { functionProp() {} }; return buffer; }`); + const getBufferFunctionRef = jail.getSync('getBuffer', { reference: true }); + try { + getBufferFunctionRef.applySync(null, [], { result: { copy: true } }); + assert.fail("Expected an error"); + } catch (error) { + assert.strictEqual(error.message, "functionProp() {} could not be cloned."); + } } console.log('pass'); \ No newline at end of file From ab8b9729b89f6dceda9401264092a0c99789669e Mon Sep 17 00:00:00 2001 From: skvelymake <112627159+skvelymake@users.noreply.github.com> Date: Mon, 23 Dec 2024 12:36:27 +0100 Subject: [PATCH 25/28] v4.8.3 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e4738ab9..af82b796 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@integromat/isolated-vm", - "version": "4.8.2", + "version": "4.8.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@integromat/isolated-vm", - "version": "4.8.2", + "version": "4.8.3", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 18a5ad93..c1647d8c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@integromat/isolated-vm", - "version": "4.8.2", + "version": "4.8.3", "description": "Access to multiple isolates - Make Fork", "main": "isolated-vm.js", "types": "isolated-vm.d.ts", From 8de32f527bede2aecf505120f54afc85fe1582da Mon Sep 17 00:00:00 2001 From: "make-pulumi[bot]" <153177201+make-pulumi[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 12:16:33 +0000 Subject: [PATCH 26/28] ci: update validate-pr.yml --- .github/workflows/validate-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-pr.yml b/.github/workflows/validate-pr.yml index 10590df1..27402b10 100644 --- a/.github/workflows/validate-pr.yml +++ b/.github/workflows/validate-pr.yml @@ -47,4 +47,4 @@ jobs: - name: Validate PR if: github.event_name != 'merge_group' - run: npx @integromat/actions-toolkit validate-pr + run: npx @integromat/actions-toolkit validate-pr --skipPrDescriptionLengthValidation From 8db4c8327a5890694237c80a9c67b27b2e01b3d6 Mon Sep 17 00:00:00 2001 From: "make-pulumi[bot]" <153177201+make-pulumi[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 03:22:34 +0000 Subject: [PATCH 27/28] ci(codeowners): sync CODEOWNERS with repository owner --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 88976114..17de1688 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ # The header of Codeowners is autogenerated from https://github.com/integromat/mono. Don’t edit code before END-AUTOGENERATED-SECTION! -* @integromat/nexus +* @integromat/build-run-backend ### END-AUTOGENERATED-SECTION From 1aa94a349a40d395d5291effcd6031706f360e85 Mon Sep 17 00:00:00 2001 From: Frantisek Pac Date: Tue, 3 Mar 2026 10:18:49 +0100 Subject: [PATCH 28/28] feat: add agent context files --- AGENTS.md | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 1 + 2 files changed, 122 insertions(+) create mode 100644 AGENTS.md create mode 100644 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..74a76c9f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,121 @@ +# isolated-vm — Agent Context + +## What + +`@integromat/isolated-vm` is a Make-internal fork of the [`isolated-vm`](https://github.com/laverdet/isolated-vm) npm package. It is a native Node.js C++ addon that exposes V8's `Isolate` interface, enabling fully isolated JavaScript sandboxes with separate heaps, memory limits, and security boundaries. The fork is published as `@integromat/isolated-vm` and is currently at v4.8.3 (forked from upstream v4.3.0). + +**Tech stack:** C++17 native addon · Direct V8 API (not NAN/NAPI) · node-gyp build · prebuildify for binary distribution · Node.js >=16 <21. + +## Why + +The package lets Make run untrusted user code in secure, memory-limited V8 isolates completely separated from the host Node.js process. Each isolate has its own heap; data crossing isolate boundaries must be explicitly serialized or transferred. + +## Architecture + +### JS Layer + +`isolated-vm.js` is a single-line shim: `module.exports = require('node-gyp-build')(__dirname).ivm`. The entire public API (all classes and constructors) is native C++. TypeScript types are declared in `isolated-vm.d.ts` as `namespace IsolatedVM`. + +### C++ Source Layout + +- `src/module/` — JS-visible handle classes: `IsolateHandle`, `ContextHandle`, `ScriptHandle`, `ModuleHandle`, `ReferenceHandle`, `ExternalCopyHandle`, `Callback`, `NativeModuleHandle`, `LibraryHandle` +- `src/isolate/` — core runtime: `IsolateEnvironment`, `IsolateHolder`, `Executor`, `Scheduler` hierarchy, `ThreePhaseTask`, `ClassHandle`, `RemoteHandle` +- `src/external_copy/` — cross-isolate value serialization (`ExternalCopy` subclasses, structured clone) +- `src/lib/` — primitives: `thread_pool_t`, `timer`, `lockable_t`, `covariant_t` +- `src/isolated_vm.h` — narrow public C++ API for embedding (exposes `IsolateHolder`, `RemoteHandle`, `Runnable`) +- `vendor/v8_inspector/` — vendored Node.js-version-specific inspector headers for v16/v18/v20 + +### Binding Mechanism + +**Direct V8 API** (no NAN/NAPI). `ClassHandle` (`src/isolate/class_handle.h`) is the base for all JS-exposed objects: +- Creates `v8::FunctionTemplate` with `InternalFieldCount(1)` to store a raw native pointer +- `Wrap()` stores the `ClassHandle*` in `InternalField[0]` and sets a weak GC callback +- `Unwrap()` reads `InternalField[0]` and `dynamic_cast` +- All class prototypes and instances are frozen with `SetIntegrityLevel(kFrozen)` unless opted out + +`IsolateSpecific` (`src/isolate/specific.h`) is a per-isolate analogue of `thread_local` — stores data in `IsolateEnvironment::specifics` (a `std::vector>`) keyed by an atomically assigned global index. Used to cache `FunctionTemplate`s per-isolate. + +### Isolate Lifecycle + +`IsolateEnvironment` (`src/isolate/environment.h`) owns the raw `v8::Isolate*`, scheduler, executor, and memory tracking. Held via `IsolateHolder` (`src/isolate/holder.h`) which wraps it in a `lockable_t>`. + +Two factory paths: +- `IsolateEnvironment::New(v8::Isolate*, v8::Context)` — wraps the existing Node.js default isolate; uses `UvScheduler` +- `IsolateEnvironment::New(memory_limit_mb, snapshot, ...)` — creates a fresh V8 isolate with `LimitedAllocator`; uses `IsolatedScheduler` + +### Scheduler Architecture + +``` +Scheduler (base: mutex + 4 task queues: tasks, handle_tasks, interrupts, sync_interrupts) + └── LockedScheduler + ├── UvScheduler — default Node.js isolate, wakes via uv_async_send + └── IsolatedScheduler — user isolates, dispatches to thread_pool_t +``` + +`thread_pool_t` (`src/lib/thread_pool.h`) is fixed-size (`hardware_concurrency + 1`). Thread affinity (`affinity_t`) tracks which pool threads are associated with each isolate. + +`covariant_t` (`src/lib/covariant.h`) is a tagged-union/aligned-storage that holds one of several types sharing a base class — used so `IsolateEnvironment` stores the scheduler inline without heap allocation. + +### Three-Phase Task Protocol + +All cross-isolate operations use `ThreePhaseTask` (`src/isolate/three_phase_task.h`): + +| Phase | Runs in | Purpose | +|-------|---------|---------| +| Phase 1 (constructor) | Calling isolate | Serialize data out | +| Phase 2 (`Phase2()`) | Target isolate | Do work, serialize results | +| Phase 3 (`Phase3()`) | Calling isolate | Deserialize results, resolve promise | + +`ThreePhaseTask::Run()` dispatches on 4 modes: full async (returns promise), fire-and-forget (ignored), fully sync (acquires `Executor::Lock` directly), and sync+async (suspends caller thread while default isolate handles async work). + +### Thread Safety + +- `v8::Locker` — enforces single-threaded V8 isolate access. `Executor::Lock` RAII-wraps: `v8::Locker → v8::Isolate::Scope → v8::HandleScope`. +- `lockable_t` (`src/lib/lockable.h`) — bundles a resource with a mutex (and optionally a condition variable). Used for `IsolateHolder::isolate`, `AsyncWait::state`, and the global `default_isolates` map. +- `Executor` (`src/isolate/executor.h`) tracks the current environment via `thread_local Executor* current_executor`. `Executor::Scope` sets this on entry. +- `Scheduler::AsyncWait` — parks the calling thread while waiting for cross-isolate async results; uses a waitable `lockable_t`. + +### Method Naming Convention + +Every native operation exposes up to three variants: +- `method()` — async, returns `Promise` +- `methodSync()` — synchronous, blocks calling thread +- `methodIgnored()` — fire-and-forget, returns `undefined`, swallows exceptions + +`applySyncPromise` is special: only callable on default-isolate functions from a non-default thread; the calling isolate suspends while the promise resolves on the default thread. + +### ExternalCopy / Serialization + +`ExternalCopy` subclasses (`src/external_copy/`) serialize V8 values out of one isolate for materialization in another. Key subclasses: `ExternalCopyArrayBuffer` (detaches backing store), `ExternalCopySharedArrayBuffer` (shares backing store), `ExternalCopyError`. `CopyIntoCheckHeap()` calls `IsolateEnvironment::HeapCheck` before materializing to enforce memory limits. Global external size tracked atomically via `TotalExternalSize()`. + +The `nortti` static library target in `binding.gyp` compiles `serializer_nortti.cc` and `allocator_nortti.cc` without RTTI to avoid ODR conflicts with V8's own RTTI-less objects. + +## Build + +```sh +npm run rebuild # full native build (node-gyp rebuild --release -j max) +npm run prebuild # prebuildify (generates platform-specific binaries) +``` + +**`binding.gyp`** defines 3 targets: `isolated_vm` (the `.node` addon, C++17, exceptions+RTTI enabled), `nortti` (static lib without RTTI, non-Windows only), and `action_after_build` (copies `.node` to `out/`). + +## Testing + +```sh +node test.js +``` + +`test.js` spawns each `tests/*.js` file as a subprocess (always with `--no-node-snapshot`). A test passes iff: stdout == `'pass\n'`, stderr is empty, exit code is 0. Tests signal pass via `console.log('pass')`. Assertions use Node's built-in `assert`. To add node flags, place `// node-args: --flag` on line 1 of the test file. + +## Make Fork Specifics + +- Package name `@integromat/isolated-vm`; published to npm via `secrets.NPM_TOKEN` +- CI matrix includes `make-ubuntu24-arm64-2c` (Make internal self-hosted ARM64 runner) +- `validate-pr.yml` and `CODEOWNERS` are autogenerated from `integromat/mono` repo; CODEOWNERS assigns `@integromat/build-run-backend` +- Key fork fix: exception propagation from `Phase2Runner` to calling isolate (`three_phase_task.cc`, commits #9/#10) +- `devDependencies` includes `"isolated-vm": "."` — tests `require('isolated-vm')` which resolves to the local package via `NODE_PATH=__dirname` + +## When in Plan Mode +- Make the plan extremely concise. Sacrifice grammar for the sake of concision. +- Interview user in detail (for Claude: use the AskUserQuestionTool) about literally anything: technical implementation, UI & UX, concerns, tradeoffs, etc. but make sure the questions are not obvious. Be very in-depth and continue interviewing the user continually until it's complete. Use the answers to create a detailed spec. +- Make assumptions explicit: When you must proceed under uncertainty, list assumptions up front and continue. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..43c994c2 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md