function SafeCall:Call(fn, ...)
local results = { pcall(fn, ...) }
local success = table.remove(results, 1)
if not success then
local msg = tostring(results[1])
for _, pattern in ipairs(self._errorFilters) do
if string.match(msg, pattern) then
return false, msg
end
end
self.Log(msg)
for _, handler in ipairs(self._globalHandlers) do
pcall(handler, msg, debug.traceback())
end
end
return success, table.unpack(results)
end
Ensure Call and related wrappers (CallWithTag, CallWithRetry, CallWithTimeout, CallBatch, CallAsync) preserve multiple return values (including nil) so callers receive the exact tuple returned by wrapped functions.
Refactored ProtectTable to preserve method binding and metamethod behavior when proxying tables.
Fixed
Fixed Call not returning tuples; also fixed CallWithRetry, CallWithTimeout, CallBatch, and WrapFunction so they correctly propagate full multi-value returns.
Fixed WrapFunction and BindableFunction wrappers to return the exact tuple of values produced by the underlying callback (preserving nil values).
SafeSandbox (experimental): Allows execution of untrusted or dynamic code in an isolated environment with protected globals, optional whitelisting, and SafeCall-wrapped execution.
SafeRemote (experimental): New SafeRemoteEvent and SafeRemoteFunction wrappers featuring:
Per-player rate limiting
Argument validation hooks
Automatic SafeCall protection
Error propagation & safer security defaults
Fully preserved multi-value returns
Changed
Internal execution paths updated to support sandboxed environments.
SafeCall now exposes CreateSandbox, CreateSafeRemoteEvent, and CreateSafeRemoteFunction.
Fixed
Minor inconsistencies in error forwarding for nested async calls.
Deprecated
None this update.
Removed
None this update.
This is a beta release. API surface for SafeSandbox and SafeRemote may change after developer feedback.