@rsvelte/vite-plugin-svelte-native 0.2.6 → 0.2.8

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.
package/envelope.js CHANGED
@@ -12,6 +12,8 @@
12
12
 
13
13
  'use strict';
14
14
 
15
+ const { isWindowOutOfBounds, windowOutOfBoundsMessage } = require('./lib/bounds-check.js');
16
+
15
17
  const MAGIC = 0x31565352; // "RSV1" little-endian
16
18
  const VERSION = 1;
17
19
  const HEADER_LEN = 60;
@@ -27,10 +29,8 @@ const WARN_HAS_FRAME = 1 << 3;
27
29
 
28
30
  /**
29
31
  * Validate that the byte window `[off, off + len)` lies fully inside a
30
- * buffer of `bufLen` bytes. The encoder writes offsets/lengths as u32s
31
- * the decoder otherwise trusts blindly — `buf.toString` / `subarray`
32
- * silently *clamp* an out-of-range window, so a malformed envelope would
33
- * decode to truncated data instead of failing loudly. Throw instead (M-012).
32
+ * buffer of `bufLen` bytes (see `./lib/bounds-check.js` for why this must
33
+ * throw rather than let `toString`/`subarray` clamp silently — M-012).
34
34
  *
35
35
  * @param {number} bufLen
36
36
  * @param {number} off
@@ -38,11 +38,8 @@ const WARN_HAS_FRAME = 1 << 3;
38
38
  * @param {string} label
39
39
  */
40
40
  function assertWindow(bufLen, off, len, label) {
41
- if (off < 0 || len < 0 || off + len > bufLen) {
42
- throw new Error(
43
- `[rsvelte] envelope ${label} out of bounds ` +
44
- `(offset ${off} + length ${len} exceeds buffer of ${bufLen} bytes)`,
45
- );
41
+ if (isWindowOutOfBounds(off, len, bufLen)) {
42
+ throw new Error(`[rsvelte] envelope ${windowOutOfBoundsMessage(label, off, len, bufLen)}`);
46
43
  }
47
44
  }
48
45
 
package/index.cjs CHANGED
@@ -137,6 +137,8 @@ module.exports.parseEnvelope = binding.parseEnvelope;
137
137
  module.exports.decodeParseEnvelope = decodeParseEnvelope;
138
138
  // Upstream Svelte version this binding emits code for — used by
139
139
  // downstream consumers (the `@rsvelte/vite-plugin-svelte` fork, etc.)
140
- // for `gte(VERSION, '5.36.0')`-style feature detection. Synced
141
- // manually against `submodules/svelte/packages/svelte/package.json`.
142
- module.exports.VERSION = '5.51.3';
140
+ // for `gte(VERSION, '5.36.0')`-style feature detection. Kept in sync
141
+ // with `submodules/svelte/packages/svelte/package.json` by hand; run
142
+ // `node scripts/dev/check-vps-version.mjs` (also wired into CI) to
143
+ // catch drift.
144
+ module.exports.VERSION = '5.56.4';
@@ -0,0 +1,38 @@
1
+ // Shared bounds-check primitive for the two raw-transfer envelope decoders
2
+ // (`../envelope.js` for `compileEnvelope`/`compileModuleEnvelope`, and
3
+ // `../parse-envelope.js` for `parseEnvelope`). Both wire formats encode
4
+ // offsets/lengths as u32s that the decoder otherwise trusts blindly —
5
+ // `Buffer.toString` / `Uint8Array.subarray` silently *clamp* an
6
+ // out-of-range window instead of throwing, so a malformed envelope would
7
+ // decode to truncated/misaligned data rather than failing loudly (M-012).
8
+ //
9
+ // Each decoder wraps this in its own `assertWindow` helper so it can throw
10
+ // its own Error subtype with its own message prefix (`[rsvelte] envelope …`
11
+ // vs `parse envelope: …`) while sharing the actual bounds arithmetic and
12
+ // message body.
13
+
14
+ 'use strict';
15
+
16
+ /**
17
+ * @param {number} off
18
+ * @param {number} len
19
+ * @param {number} bufLen
20
+ * @returns {boolean} true when the byte window `[off, off + len)` does NOT
21
+ * lie fully inside a buffer of `bufLen` bytes.
22
+ */
23
+ function isWindowOutOfBounds(off, len, bufLen) {
24
+ return off < 0 || len < 0 || off + len > bufLen;
25
+ }
26
+
27
+ /**
28
+ * @param {string} label
29
+ * @param {number} off
30
+ * @param {number} len
31
+ * @param {number} bufLen
32
+ * @returns {string}
33
+ */
34
+ function windowOutOfBoundsMessage(label, off, len, bufLen) {
35
+ return `${label} out of bounds (offset ${off} + length ${len} exceeds buffer of ${bufLen} bytes)`;
36
+ }
37
+
38
+ module.exports = { isWindowOutOfBounds, windowOutOfBoundsMessage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rsvelte/vite-plugin-svelte-native",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "NAPI bindings to the rsvelte compiler — used by the @rsvelte vite-plugin-svelte shim",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -24,15 +24,16 @@
24
24
  "files": [
25
25
  "envelope.js",
26
26
  "parse-envelope.js",
27
+ "lib/bounds-check.js",
27
28
  "index.cjs",
28
29
  "index.d.ts"
29
30
  ],
30
31
  "optionalDependencies": {
31
- "@rsvelte/vite-plugin-svelte-native-darwin-arm64": "^0.2.6",
32
- "@rsvelte/vite-plugin-svelte-native-darwin-x64": "^0.2.6",
33
- "@rsvelte/vite-plugin-svelte-native-linux-arm64-gnu": "^0.2.6",
34
- "@rsvelte/vite-plugin-svelte-native-linux-x64-gnu": "^0.2.6",
35
- "@rsvelte/vite-plugin-svelte-native-win32-x64-msvc": "^0.2.6"
32
+ "@rsvelte/vite-plugin-svelte-native-darwin-arm64": "^0.2.8",
33
+ "@rsvelte/vite-plugin-svelte-native-darwin-x64": "^0.2.8",
34
+ "@rsvelte/vite-plugin-svelte-native-linux-arm64-gnu": "^0.2.8",
35
+ "@rsvelte/vite-plugin-svelte-native-linux-x64-gnu": "^0.2.8",
36
+ "@rsvelte/vite-plugin-svelte-native-win32-x64-msvc": "^0.2.8"
36
37
  },
37
38
  "publishConfig": {
38
39
  "access": "public"
package/parse-envelope.js CHANGED
@@ -12,6 +12,8 @@
12
12
 
13
13
  'use strict';
14
14
 
15
+ const { isWindowOutOfBounds, windowOutOfBoundsMessage } = require('./lib/bounds-check.js');
16
+
15
17
  const MAGIC = 0x3156_5052; // "RPV1" little-endian
16
18
  const VERSION = 1;
17
19
  const HEADER_LEN = 24;
@@ -74,7 +76,7 @@ const TAG_AWAIT_BLOCK = 0x72;
74
76
  const TAG_KEY_BLOCK = 0x73;
75
77
  const TAG_SNIPPET_BLOCK = 0x74;
76
78
 
77
- // JsNode (estree) tags — 0x80..0xCB. Mirrors `napi_raw_parse.rs`.
79
+ // JsNode (estree) tags — 0x80..0xCC. Mirrors `napi_raw_parse.rs`.
78
80
  const JS_IDENTIFIER = 0x80;
79
81
  const JS_PRIVATE_IDENTIFIER = 0x81;
80
82
  const JS_LITERAL = 0x82;
@@ -150,7 +152,14 @@ const JS_TS_ENUM_DECLARATION = 0xc7;
150
152
  const JS_TS_MODULE_DECLARATION = 0xc8;
151
153
  const JS_COMMENT = 0xc9;
152
154
  const JS_NULL = 0xca;
153
- const JS_RAW_JSON = 0xcb;
155
+ // 0xcb was the former whole-node JS_RAW_JSON escape (removed — TS type
156
+ // annotations now ride a per-node trailer; see readOptTypeAnnotation).
157
+ const JS_TS_PARAMETER_PROPERTY = 0xcc;
158
+ const JS_TS_AS_EXPRESSION = 0xcd;
159
+ const JS_TS_SATISFIES_EXPRESSION = 0xce;
160
+ const JS_TS_NON_NULL_EXPRESSION = 0xcf;
161
+ const JS_TS_TYPE_ASSERTION = 0xd0;
162
+ const JS_TS_INSTANTIATION_EXPRESSION = 0xd1;
154
163
 
155
164
  // LiteralValue inner tag (within a JS_LITERAL payload).
156
165
  const LV_NULL = 0;
@@ -253,10 +262,31 @@ function readU32(ctx) {
253
262
  function readBool(ctx) {
254
263
  return readU8(ctx) !== 0;
255
264
  }
265
+
266
+ /**
267
+ * Validate that the byte window `[start, start + len)` lies fully inside
268
+ * `ctx.bytes` (see `./lib/bounds-check.js`, shared with `envelope.js`'s
269
+ * `assertWindow`, for why this must throw rather than let
270
+ * `Buffer.toString`/`Uint8Array.subarray` clamp silently — M-012).
271
+ *
272
+ * @param {object} ctx
273
+ * @param {number} start
274
+ * @param {number} len
275
+ * @param {string} label
276
+ */
277
+ function assertWindow(ctx, start, len, label) {
278
+ if (isWindowOutOfBounds(start, len, ctx.bytes.byteLength)) {
279
+ throw new EnvelopeError(
280
+ `parse envelope: ${windowOutOfBoundsMessage(label, start, len, ctx.bytes.byteLength)}`,
281
+ );
282
+ }
283
+ }
284
+
256
285
  function readStr(ctx) {
257
286
  const len = readU32(ctx);
258
287
  const start = ctx.pos;
259
288
  const end = start + len;
289
+ assertWindow(ctx, start, len, 'string');
260
290
  ctx.pos = end;
261
291
  // Branch is monomorphic per envelope: V8 specialises after warmup.
262
292
  return ctx.isBuffer
@@ -287,6 +317,7 @@ function readInlineJson(ctx) {
287
317
  const len = readU32(ctx);
288
318
  const start = ctx.pos;
289
319
  const end = start + len;
320
+ assertWindow(ctx, start, len, 'inline JSON');
290
321
  ctx.pos = end;
291
322
  if (len === 0) return null;
292
323
  return JSON.parse(
@@ -301,6 +332,16 @@ function readJsonNodePayload(ctx) {
301
332
  return readInlineJson(ctx);
302
333
  }
303
334
 
335
+ /**
336
+ * Read an optional TS `typeAnnotation` trailer: a flag byte, then (when set) a
337
+ * length-prefixed JSON blob. Mirrors `write_opt_type_annotation` in
338
+ * `napi_raw_parse.rs`. Returns `null` when absent.
339
+ */
340
+ function readOptTypeAnnotation(ctx) {
341
+ if (readU8(ctx) === 0) return null;
342
+ return readInlineJson(ctx);
343
+ }
344
+
304
345
  // ---------------------------------------------------------------------------
305
346
  // Dispatch on tag
306
347
  // ---------------------------------------------------------------------------
@@ -397,8 +438,6 @@ function readNodeBody(ctx, tag, start, end) {
397
438
  // ----- JsNode (estree) ----------------------------------------
398
439
  case JS_NULL:
399
440
  return null;
400
- case JS_RAW_JSON:
401
- return readJsonNodePayload(ctx);
402
441
  case JS_IDENTIFIER:
403
442
  return readJsIdentifier(ctx, start, end);
404
443
  case JS_PRIVATE_IDENTIFIER:
@@ -543,8 +582,20 @@ function readNodeBody(ctx, tag, start, end) {
543
582
  return readJsTSTypeAnnotation(ctx, start, end);
544
583
  case JS_TS_ENUM_DECLARATION:
545
584
  return readJsBareExpr(ctx, 'TSEnumDeclaration', start, end);
585
+ case JS_TS_PARAMETER_PROPERTY:
586
+ return readJsBareExpr(ctx, 'TSParameterProperty', start, end);
546
587
  case JS_TS_MODULE_DECLARATION:
547
588
  return readJsTSModuleDeclaration(ctx, start, end);
589
+ case JS_TS_AS_EXPRESSION:
590
+ return readJsTSAssertion(ctx, 'TSAsExpression', start, end, true);
591
+ case JS_TS_SATISFIES_EXPRESSION:
592
+ return readJsTSAssertion(ctx, 'TSSatisfiesExpression', start, end, true);
593
+ case JS_TS_NON_NULL_EXPRESSION:
594
+ return readJsTSAssertion(ctx, 'TSNonNullExpression', start, end, false);
595
+ case JS_TS_TYPE_ASSERTION:
596
+ return readJsTSTypeAssertion(ctx, start, end);
597
+ case JS_TS_INSTANTIATION_EXPRESSION:
598
+ return readJsTSInstantiationExpression(ctx, start, end);
548
599
  case JS_COMMENT:
549
600
  return readJsComment_(ctx, start, end);
550
601
 
@@ -650,6 +701,8 @@ function readJsIdentifier(ctx, start, end) {
650
701
  const node = { type: 'Identifier', start, end };
651
702
  if (loc !== null) node.loc = loc;
652
703
  node.name = name;
704
+ const typeAnnotation = readOptTypeAnnotation(ctx);
705
+ if (typeAnnotation !== null) node.typeAnnotation = typeAnnotation;
653
706
  return node;
654
707
  }
655
708
 
@@ -937,6 +990,45 @@ function readJsChainExpression(ctx, start, end) {
937
990
  return node;
938
991
  }
939
992
 
993
+ // TS assertion wrappers (`x as T` / `x satisfies T` / `x!`). As/Satisfies carry
994
+ // a `typeAnnotation` trailer; NonNull does not (`hasTypeAnnotation` is false).
995
+ function readJsTSAssertion(ctx, typeName, start, end, hasTypeAnnotation) {
996
+ const loc = readTypedLoc(ctx);
997
+ const expression = readNode(ctx);
998
+ const node = { type: typeName, start, end };
999
+ if (loc !== null) node.loc = loc;
1000
+ node.expression = expression;
1001
+ if (hasTypeAnnotation) {
1002
+ const typeAnnotation = readOptTypeAnnotation(ctx);
1003
+ if (typeAnnotation !== null) node.typeAnnotation = typeAnnotation;
1004
+ }
1005
+ return node;
1006
+ }
1007
+
1008
+ function readJsTSTypeAssertion(ctx, start, end) {
1009
+ // Wire order: loc, expression, typeAnnotation — but svelte/compiler emits
1010
+ // `typeAnnotation` before `expression`, so build the object in that order.
1011
+ const loc = readTypedLoc(ctx);
1012
+ const expression = readNode(ctx);
1013
+ const typeAnnotation = readOptTypeAnnotation(ctx);
1014
+ const node = { type: 'TSTypeAssertion', start, end };
1015
+ if (loc !== null) node.loc = loc;
1016
+ if (typeAnnotation !== null) node.typeAnnotation = typeAnnotation;
1017
+ node.expression = expression;
1018
+ return node;
1019
+ }
1020
+
1021
+ function readJsTSInstantiationExpression(ctx, start, end) {
1022
+ const loc = readTypedLoc(ctx);
1023
+ const expression = readNode(ctx);
1024
+ const typeArguments = readOptTypeAnnotation(ctx);
1025
+ const node = { type: 'TSInstantiationExpression', start, end };
1026
+ if (loc !== null) node.loc = loc;
1027
+ node.expression = expression;
1028
+ if (typeArguments !== null) node.typeArguments = typeArguments;
1029
+ return node;
1030
+ }
1031
+
940
1032
  function readJsMetaProperty(ctx, start, end) {
941
1033
  const loc = readTypedLoc(ctx);
942
1034
  const meta = readNode(ctx);
@@ -963,6 +1055,8 @@ function readJsObjectPattern(ctx, start, end) {
963
1055
  const node = { type: 'ObjectPattern', start, end };
964
1056
  if (loc !== null) node.loc = loc;
965
1057
  node.properties = properties;
1058
+ const typeAnnotation = readOptTypeAnnotation(ctx);
1059
+ if (typeAnnotation !== null) node.typeAnnotation = typeAnnotation;
966
1060
  return node;
967
1061
  }
968
1062
 
@@ -972,6 +1066,8 @@ function readJsArrayPattern(ctx, start, end) {
972
1066
  const node = { type: 'ArrayPattern', start, end };
973
1067
  if (loc !== null) node.loc = loc;
974
1068
  node.elements = elements;
1069
+ const typeAnnotation = readOptTypeAnnotation(ctx);
1070
+ if (typeAnnotation !== null) node.typeAnnotation = typeAnnotation;
975
1071
  return node;
976
1072
  }
977
1073