mini_racer 0.19.2 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2730baed1d90aa6181def75b81766dca2481c2ce7406f430436ba524e0dc70d6
4
- data.tar.gz: d1aa0298af002dfe183acee282718a3e2702c9bfb98cb3b80bc6fc93e5a711b3
3
+ metadata.gz: 7cd44fe0925a58e264712d933d805af54b517d31cdbefc26455e7e139e234279
4
+ data.tar.gz: 17190bc083b885c838b0dfc3424c3fc08fb02df354972a3007a292ddf70afc22
5
5
  SHA512:
6
- metadata.gz: 8050de8f1506ed9a85f0e5109089dae8e7413b6eee5902636ab922a7ccd819a3ae3a7aea8b4f0465f3c795afab03e4c3e2c9dccc77325b848304008d6bad4091
7
- data.tar.gz: 3c1e532d346b607278235f837eb5bc35d88c82d3e2e088fc3b833344293c94f02dc5b0303edd7d59b4ee8aa86ccfb20497ef86a777e10892f02f2bd10bd710a6
6
+ metadata.gz: 9cdd4cdf20f9be0e3ceb34daa48f7f1eeb93c4c11eada10c23e2c3e3dbd82cf7a13c8102e67140cc15c028c51a468c6e74ac518c76050cadceb33aa99fd71b7d
7
+ data.tar.gz: c7110aabb771e18bccd85283696e8f811970cf8d03bb0ef1f573a84f2fa7da2ef1014b5138513b09d80825de96ddebe7e6316f79efbe8adecbd1ff202b14e4d5
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ - 0.21.0 - 16-04-2026
2
+ - Add MiniRacer::Binary for returning Uint8Array to JavaScript from attached Ruby callbacks
3
+
4
+ - 0.20.0 - 24-02-2026
5
+ - Add Snapshot.load to restore snapshots from binary data, enabling disk persistence
6
+
1
7
  - 0.19.2 - 24-12-2025
2
8
  - upgrade to node 24.12.0
3
9
 
data/README.md CHANGED
@@ -60,6 +60,25 @@ puts context.eval("array_and_hash()")
60
60
  # => {"a" => 1, "b" => [1, {"a" => 1}]}
61
61
  ```
62
62
 
63
+ ### Return binary data from Ruby to JavaScript
64
+
65
+ Attached Ruby functions can return binary data as `Uint8Array` using `MiniRacer::Binary`:
66
+
67
+ ```ruby
68
+ require "digest"
69
+
70
+ context = MiniRacer::Context.new
71
+ context.attach("sha256_raw", ->(data) {
72
+ MiniRacer::Binary.new(Digest::SHA256.digest(data))
73
+ })
74
+
75
+ # Inside JavaScript the return value is a Uint8Array
76
+ context.eval("sha256_raw('hello') instanceof Uint8Array") # => true
77
+ context.eval("sha256_raw('hello').length") # => 32
78
+ ```
79
+
80
+ This is useful when you need to pass raw bytes (e.g., cryptographic digests, compressed data, binary file contents) from Ruby to JavaScript. The `MiniRacer::Binary` wrapper tells the bridge to serialize the data as a `Uint8Array` on the JavaScript side rather than a string.
81
+
63
82
  ### GIL free JavaScript execution
64
83
 
65
84
  The Ruby Global interpreter lock is released when scripts are executing:
@@ -193,6 +212,25 @@ context.eval("counter")
193
212
  # => 1
194
213
  ```
195
214
 
215
+ Snapshots can also be persisted to disk for faster startup:
216
+
217
+ ```ruby
218
+ # Save a snapshot to disk
219
+ snapshot = MiniRacer::Snapshot.new('var foo = "bar";')
220
+ File.binwrite("snapshot.bin", snapshot.dump)
221
+
222
+ # Load it back in a later process
223
+ blob = File.binread("snapshot.bin")
224
+ snapshot = MiniRacer::Snapshot.load(blob)
225
+ context = MiniRacer::Context.new(snapshot: snapshot)
226
+ context.eval("foo")
227
+ # => "bar"
228
+ ```
229
+
230
+ Note that snapshots are architecture and V8-version specific. A snapshot created on one platform (e.g., ARM64 macOS) cannot be loaded on a different platform (e.g., x86_64 Linux). Snapshots are best used for same-machine caching or homogeneous deployment environments.
231
+
232
+ **Security note:** Only load snapshots from trusted sources. V8 snapshots are not designed to be safely loaded from untrusted input—malformed or malicious snapshot data may cause crashes or memory corruption.
233
+
196
234
  ### Garbage collection
197
235
 
198
236
  You can make the garbage collector more aggressive by defining the context with `MiniRacer::Context.new(ensure_gc_after_idle: 1000)`. Using this will ensure V8 will run a full GC using `context.low_memory_notification` 1 second after the last eval on the context. Low memory notifications ensure long living contexts use minimal amounts of memory.
@@ -193,6 +193,7 @@ static VALUE terminated_error;
193
193
  static VALUE context_class;
194
194
  static VALUE snapshot_class;
195
195
  static VALUE date_time_class;
196
+ static VALUE binary_class;
196
197
  static VALUE js_function_class;
197
198
 
198
199
  static pthread_mutex_t flags_mtx = PTHREAD_MUTEX_INITIALIZER;
@@ -688,10 +689,17 @@ static int serialize1(Ser *s, VALUE refs, VALUE v)
688
689
  // entirely new objects
689
690
  if (rb_respond_to(v, rb_intern("to_time"))) {
690
691
  v = rb_funcall(v, rb_intern("to_time"), 0);
691
- }
692
- if (rb_obj_is_kind_of(v, rb_cTime)) {
693
- struct timeval tv = rb_time_timeval(v);
694
- ser_date(s, tv.tv_sec*1e3 + tv.tv_usec/1e3);
692
+ if (rb_obj_is_kind_of(v, rb_cTime)) {
693
+ struct timeval tv = rb_time_timeval(v);
694
+ ser_date(s, tv.tv_sec*1e3 + tv.tv_usec/1e3);
695
+ } else {
696
+ snprintf(s->err, sizeof(s->err), "unsupported type %s", rb_class2name(CLASS_OF(v)));
697
+ return -1;
698
+ }
699
+ } else if (!NIL_P(binary_class) && rb_obj_is_kind_of(v, binary_class)) {
700
+ t = rb_ivar_get(v, rb_intern("@data"));
701
+ Check_Type(t, T_STRING);
702
+ ser_uint8array(s, RSTRING_PTR(t), RSTRING_LEN(t));
695
703
  } else {
696
704
  snprintf(s->err, sizeof(s->err), "unsupported type %s", rb_class2name(CLASS_OF(v)));
697
705
  return -1;
@@ -1111,6 +1119,11 @@ static VALUE context_alloc(VALUE klass)
1111
1119
  if (Qtrue == rb_funcall(rb_cObject, f, 1, a))
1112
1120
  date_time_class = rb_const_get(rb_cObject, rb_intern("DateTime"));
1113
1121
  }
1122
+ if (NIL_P(binary_class)) {
1123
+ VALUE m = rb_const_get(rb_cObject, rb_intern("MiniRacer"));
1124
+ if (Qtrue == rb_funcall(m, rb_intern("const_defined?"), 1, rb_str_new_cstr("Binary")))
1125
+ binary_class = rb_const_get(m, rb_intern("Binary"));
1126
+ }
1114
1127
  c = ruby_xmalloc(sizeof(*c));
1115
1128
  memset(c, 0, sizeof(*c));
1116
1129
  c->exception = Qnil;
@@ -1690,6 +1703,20 @@ static VALUE snapshot_dump(VALUE self)
1690
1703
  return ss->blob;
1691
1704
  }
1692
1705
 
1706
+ static VALUE snapshot_load(VALUE klass, VALUE blob)
1707
+ {
1708
+ Snapshot *ss;
1709
+ VALUE self;
1710
+
1711
+ Check_Type(blob, T_STRING);
1712
+ self = snapshot_alloc(klass);
1713
+ TypedData_Get_Struct(self, Snapshot, &snapshot_type, ss);
1714
+ ss->blob = rb_str_dup(blob);
1715
+ rb_enc_associate(ss->blob, rb_ascii8bit_encoding());
1716
+ ENC_CODERANGE_SET(ss->blob, ENC_CODERANGE_VALID);
1717
+ return self;
1718
+ }
1719
+
1693
1720
  static VALUE snapshot_size0(VALUE self)
1694
1721
  {
1695
1722
  Snapshot *ss;
@@ -1742,11 +1769,13 @@ void Init_mini_racer_extension(void)
1742
1769
  rb_define_method(c, "warmup!", snapshot_warmup, 1);
1743
1770
  rb_define_method(c, "dump", snapshot_dump, 0);
1744
1771
  rb_define_method(c, "size", snapshot_size0, 0);
1772
+ rb_define_singleton_method(c, "load", snapshot_load, 1);
1745
1773
  rb_define_alloc_func(c, snapshot_alloc);
1746
1774
 
1747
1775
  c = rb_define_class_under(m, "Platform", rb_cObject);
1748
1776
  rb_define_singleton_method(c, "set_flags!", platform_set_flags, -1);
1749
1777
 
1750
1778
  date_time_class = Qnil; // lazy init
1779
+ binary_class = Qnil; // lazy init
1751
1780
  js_function_class = rb_define_class_under(m, "JavaScriptFunction", rb_cObject);
1752
1781
  }
@@ -322,6 +322,19 @@ static void ser_string16(Ser *s, const void *p, size_t n)
322
322
  w(s, p, n);
323
323
  }
324
324
 
325
+ // Uint8Array: ArrayBuffer header + data + typed array view descriptor
326
+ static void ser_uint8array(Ser *s, const void *p, size_t n)
327
+ {
328
+ w_byte(s, 'B'); // ArrayBuffer tag
329
+ w_varint(s, n); // byte length
330
+ w(s, p, n); // raw bytes
331
+ w_byte(s, 'V'); // typed array view tag
332
+ w_byte(s, 'B'); // Uint8Array type
333
+ w_varint(s, 0); // byteOffset
334
+ w_varint(s, n); // byteLength
335
+ w_varint(s, 0); // flags
336
+ }
337
+
325
338
  static void ser_object_begin(Ser *s)
326
339
  {
327
340
  w_byte(s, 'o');
@@ -102,7 +102,7 @@ module MiniRacer
102
102
  else
103
103
  @snapshot = nil
104
104
  end
105
- @is_object_or_array_func, @is_map_func, @is_map_iterator_func, @is_time_func, @js_date_to_time_func, @is_symbol_func, @js_symbol_to_symbol_func, @js_new_date_func, @js_new_array_func = eval_in_context <<-CODE
105
+ @is_object_or_array_func, @is_map_func, @is_map_iterator_func, @is_time_func, @js_date_to_time_func, @is_symbol_func, @js_symbol_to_symbol_func, @js_new_date_func, @js_new_array_func, @js_new_uint8array_func = eval_in_context <<-CODE
106
106
  [
107
107
  (x) => { return (x instanceof Object || x instanceof Array) && !(x instanceof Date) && !(x instanceof Function) },
108
108
  (x) => { return x instanceof Map },
@@ -113,6 +113,7 @@ module MiniRacer
113
113
  (x) => { var r = x.description; return r === undefined ? 'undefined' : r },
114
114
  (x) => { return new Date(x) },
115
115
  (x) => { return new Array(x) },
116
+ (x) => { return new Uint8Array(x) },
116
117
  ]
117
118
  CODE
118
119
  end
@@ -329,6 +330,8 @@ module MiniRacer
329
330
  js_new_date(value.to_f * 1000)
330
331
  when DateTime
331
332
  js_new_date(value.to_time.to_f * 1000)
333
+ when MiniRacer::Binary
334
+ @js_new_uint8array_func.call(value.data.bytes)
332
335
  else
333
336
  "Undefined Conversion"
334
337
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MiniRacer
4
- VERSION = "0.19.2"
4
+ VERSION = "0.21.0"
5
5
  LIBV8_NODE_VERSION = "~> 24.12.0.1"
6
6
  end
data/lib/mini_racer.rb CHANGED
@@ -1,6 +1,17 @@
1
1
  require "mini_racer/version"
2
2
  require "pathname"
3
3
 
4
+ module MiniRacer
5
+ class Binary
6
+ attr_reader :data
7
+
8
+ def initialize(data)
9
+ raise TypeError, "wrong argument type #{data.class} (expected String)" unless data.is_a?(String)
10
+ @data = data
11
+ end
12
+ end
13
+ end
14
+
4
15
  if RUBY_ENGINE == "truffleruby"
5
16
  require "mini_racer/truffleruby"
6
17
  else
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_racer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.2
4
+ version: 0.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
@@ -136,9 +136,9 @@ licenses:
136
136
  - MIT
137
137
  metadata:
138
138
  bug_tracker_uri: https://github.com/discourse/mini_racer/issues
139
- changelog_uri: https://github.com/discourse/mini_racer/blob/v0.19.2/CHANGELOG
140
- documentation_uri: https://www.rubydoc.info/gems/mini_racer/0.19.2
141
- source_code_uri: https://github.com/discourse/mini_racer/tree/v0.19.2
139
+ changelog_uri: https://github.com/discourse/mini_racer/blob/v0.21.0/CHANGELOG
140
+ documentation_uri: https://www.rubydoc.info/gems/mini_racer/0.21.0
141
+ source_code_uri: https://github.com/discourse/mini_racer/tree/v0.21.0
142
142
  rdoc_options: []
143
143
  require_paths:
144
144
  - lib
@@ -154,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
154
  - !ruby/object:Gem::Version
155
155
  version: '0'
156
156
  requirements: []
157
- rubygems_version: 3.7.2
157
+ rubygems_version: 4.0.6
158
158
  specification_version: 4
159
159
  summary: Minimal embedded v8 for Ruby
160
160
  test_files: []