@hew-lang/sandbox-vm 0.6.5 → 0.7.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.
package/README.md CHANGED
@@ -94,6 +94,11 @@ option. The Node test host loads that package automatically; in a source
94
94
  checkout, run `make wasm` to build `hew-wasm/pkg` first. An explicit
95
95
  `HEW_WASM_MODULE` module URL can select another build of the same package.
96
96
 
97
+ JSON, TOML and YAML values use this same bridge for parsing and formatting.
98
+ Their ordinary value operations execute in the VM, including independent copies,
99
+ checked access, mutation and cleanup. The bridge preserves full-width JSON
100
+ integers, YAML mapping keys and tags, and TOML datetimes using the native engines.
101
+
97
102
  UTC calendar operations also require the initialized `executeCalendar`
98
103
  export as `calendarBridge`. Both hosts use the shared Chrono calendar engine;
99
104
  the bridge preserves integer seconds and nanoseconds exactly.
@@ -50,9 +50,12 @@ try {
50
50
  let codecBridge;
51
51
  if (typeof bytecode === "object" &&
52
52
  bytecode !== null &&
53
- "codecs" in bytecode &&
54
- Array.isArray(bytecode.codecs) &&
55
- bytecode.codecs.length) {
53
+ (("codecs" in bytecode &&
54
+ Array.isArray(bytecode.codecs) &&
55
+ bytecode.codecs.length) ||
56
+ ("runtime_families" in bytecode &&
57
+ Array.isArray(bytecode.runtime_families) &&
58
+ bytecode.runtime_families.some((entry) => entry?.family === "Encoding")))) {
56
59
  const local = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../hew-wasm/pkg/hew_wasm.js");
57
60
  const location = process.env.HEW_WASM_MODULE ?? pathToFileURL(local).href;
58
61
  const wasm = await import(location);
@@ -0,0 +1,8 @@
1
+ import { type VmValue } from "../values.js";
2
+ import type { EncodingOp, EncodingFormat } from "./instructions.generated.js";
3
+ import type { ShimHost } from "./shims.js";
4
+ /** Lossless positional bridge to each format's native Value. Null denotes an invalid
5
+ * handle; a live JSON or YAML null is ["null"]. Numeric text retains native kinds. */
6
+ export type { EncodingFormat } from "./instructions.generated.js";
7
+ export type EncodingNode = ["null"] | ["bool", boolean] | ["integer" | "float" | "string", string] | ["array", EncodingNode[]] | ["object", [string, EncodingNode][]] | ["mapping", [EncodingNode, EncodingNode][]] | ["tagged", string, EncodingNode] | ["datetime", string];
8
+ export declare function executeEncoding(host: ShimHost, format: EncodingFormat, operation: EncodingOp, args: VmValue[]): VmValue;
@@ -0,0 +1,215 @@
1
+ import { cloneValue, compareUtf8, stringValue, UNIT, } from "../values.js";
2
+ const owner = (format, value) => ({ kind: "encoding", format, value });
3
+ const integer = (value) => ({
4
+ kind: "i64",
5
+ value: BigInt(value),
6
+ });
7
+ function checkedValue(arg, format) {
8
+ if (arg?.kind !== "encoding" || arg.format !== format)
9
+ throw new TypeError("encoding operation requires a matching format value");
10
+ return arg;
11
+ }
12
+ function text(arg) {
13
+ if (arg?.kind !== "string")
14
+ throw new TypeError("encoding operation requires a string");
15
+ return arg.value;
16
+ }
17
+ function number(arg) {
18
+ if (arg?.kind !== "i64")
19
+ throw new TypeError("encoding operation requires an integer");
20
+ return arg.value;
21
+ }
22
+ function equal(format, left, right) {
23
+ if (!left || !right || left[0] !== right[0])
24
+ return false;
25
+ switch (left[0]) {
26
+ case "null":
27
+ return true;
28
+ case "float":
29
+ return (float(left[1]) === float(right[1]) ||
30
+ (format === "Yaml" &&
31
+ Number.isNaN(float(left[1])) &&
32
+ Number.isNaN(float(right[1]))));
33
+ case "integer":
34
+ return BigInt(left[1]) === BigInt(right[1]);
35
+ case "datetime":
36
+ case "string":
37
+ case "bool":
38
+ return left[1] === right[1];
39
+ case "array": {
40
+ const items = right[1];
41
+ return (left[1].length === items.length &&
42
+ left[1].every((item, i) => equal(format, item, items[i])));
43
+ }
44
+ case "tagged":
45
+ return (left[1] === right[1] && equal(format, left[2], right[2]));
46
+ case "mapping": {
47
+ const entries = right[1];
48
+ return (left[1].length === entries.length &&
49
+ left[1].every(([key, child]) => {
50
+ const entry = entries.find(([candidate]) => equal(format, key, candidate));
51
+ return entry !== undefined && equal(format, child, entry[1]);
52
+ }));
53
+ }
54
+ case "object": {
55
+ const entries = new Map(right[1]);
56
+ return (left[1].length === entries.size &&
57
+ left[1].every(([key, child]) => equal(format, child, entries.get(key) ?? null)));
58
+ }
59
+ }
60
+ }
61
+ export function executeEncoding(host, format, operation, args) {
62
+ const owned = (node) => owner(format, node);
63
+ const value = (arg) => checkedValue(arg, format);
64
+ const copy = (node) => cloneValue(owned(node));
65
+ if (operation === "Parse" || operation === "Stringify") {
66
+ if (!host.codecBridge)
67
+ throw new Error("Encoding text operations require the hew-wasm executeCodec bridge");
68
+ const result = JSON.parse(host.codecBridge(JSON.stringify({
69
+ encoding_value: operation === "Parse"
70
+ ? { format, operation: "parse", text: text(args[0]) }
71
+ : { format, operation: "stringify", value: value(args[0]).value },
72
+ })));
73
+ if (result.failure)
74
+ throw new Error(result.failure);
75
+ host.encodingError(format, result.error ?? "");
76
+ return operation === "Parse"
77
+ ? owned(result.value ?? null)
78
+ : stringValue(result.text ?? "");
79
+ }
80
+ switch (operation) {
81
+ case "LastError":
82
+ return stringValue(host.encodingError(format));
83
+ case "ObjectNew":
84
+ return owned(format === "Yaml" ? ["mapping", []] : ["object", []]);
85
+ case "ArrayNew":
86
+ return owned(["array", []]);
87
+ case "FromNull":
88
+ return owned(["null"]);
89
+ case "FromString":
90
+ return owned(["string", text(args[0])]);
91
+ case "FromBool":
92
+ return owned(["bool", number(args[0]) !== 0n]);
93
+ case "FromInt":
94
+ return owned(["integer", BigInt.asIntN(64, number(args[0])).toString()]);
95
+ case "FromU64":
96
+ return owned(["integer", BigInt.asUintN(64, number(args[0])).toString()]);
97
+ case "FromFloat": {
98
+ const arg = args[0];
99
+ if (arg?.kind !== "f64")
100
+ throw new TypeError("encoding operation requires a float");
101
+ return owned(format !== "Json" || Number.isFinite(arg.value)
102
+ ? ["float", Object.is(arg.value, -0) ? "-0" : String(arg.value)]
103
+ : null);
104
+ }
105
+ case "Eq":
106
+ return integer(equal(format, value(args[0]).value, value(args[1]).value) ? 1 : 0);
107
+ case "Clone":
108
+ return copy(value(args[0]).value);
109
+ case "Free":
110
+ value(args[0]).value = null;
111
+ return UNIT;
112
+ default:
113
+ break;
114
+ }
115
+ const receiver = value(args[0]), node = receiver.value;
116
+ let scalar = node;
117
+ while (scalar?.[0] === "tagged")
118
+ scalar = scalar[2];
119
+ switch (operation) {
120
+ case "Type":
121
+ return integer(node?.[0] === "tagged" || node?.[0] === "datetime"
122
+ ? 7
123
+ : node?.[0] === "mapping"
124
+ ? 6
125
+ : node
126
+ ? [
127
+ "null",
128
+ "bool",
129
+ "integer",
130
+ "float",
131
+ "string",
132
+ "array",
133
+ "object",
134
+ ].indexOf(node[0])
135
+ : -1);
136
+ case "IntStatus":
137
+ return integer(node?.[0] === "integer"
138
+ ? BigInt(node[1]) <= (1n << 63n) - 1n
139
+ ? 1
140
+ : 0
141
+ : -1);
142
+ case "GetBool":
143
+ return integer(scalar?.[0] === "bool" && scalar[1] ? 1 : 0);
144
+ case "GetInt":
145
+ return integer(scalar?.[0] === "integer" && BigInt(scalar[1]) <= (1n << 63n) - 1n
146
+ ? BigInt(scalar[1])
147
+ : 0);
148
+ case "GetU64":
149
+ return integer(node?.[0] === "integer" && BigInt(node[1]) >= 0 ? BigInt(node[1]) : 0);
150
+ case "GetFloat":
151
+ return {
152
+ kind: "f64",
153
+ value: scalar?.[0] === "float" || scalar?.[0] === "integer"
154
+ ? float(scalar[1])
155
+ : 0,
156
+ };
157
+ case "GetString":
158
+ return stringValue(scalar?.[0] === "string" ? scalar[1] : "");
159
+ case "ArrayLen":
160
+ return integer(node?.[0] === "array" ? node[1].length : -1);
161
+ case "GetDatetime":
162
+ return stringValue(node?.[0] === "datetime" ? node[1] : "");
163
+ case "GetField":
164
+ return copy(node?.[0] === "object"
165
+ ? (node[1].find(([key]) => key === text(args[1]))?.[1] ?? null)
166
+ : node?.[0] === "mapping"
167
+ ? (node[1].find(([key]) => key[0] === "string" && key[1] === text(args[1]))?.[1] ?? null)
168
+ : null);
169
+ case "ArrayGet":
170
+ return copy(node?.[0] === "array"
171
+ ? (node[1][Number(BigInt.asIntN(32, number(args[1])))] ?? null)
172
+ : null);
173
+ case "ObjectKeys":
174
+ return owned(node?.[0] === "object"
175
+ ? ["array", node[1].map(([key]) => ["string", key])]
176
+ : node?.[0] === "mapping"
177
+ ? ["array", node[1].map(([key]) => structuredClone(key))]
178
+ : null);
179
+ case "ObjectSet": {
180
+ const child = value(args[2]), key = text(args[1]);
181
+ if (node?.[0] === "object" && child.value) {
182
+ const index = node[1].findIndex(([name]) => name === key);
183
+ if (index < 0) {
184
+ node[1].push([key, child.value]);
185
+ node[1].sort(([a], [b]) => compareUtf8(a, b));
186
+ }
187
+ else
188
+ node[1][index] = [key, child.value];
189
+ }
190
+ if (node?.[0] === "mapping" && child.value) {
191
+ const index = node[1].findIndex(([name]) => name[0] === "string" && name[1] === key);
192
+ if (index < 0)
193
+ node[1].push([["string", key], child.value]);
194
+ else
195
+ node[1][index] = [["string", key], child.value];
196
+ }
197
+ child.value = null;
198
+ return receiver;
199
+ }
200
+ case "ArrayPush": {
201
+ const child = value(args[1]);
202
+ if (node?.[0] === "array" && child.value)
203
+ node[1].push(child.value);
204
+ child.value = null;
205
+ return receiver;
206
+ }
207
+ }
208
+ }
209
+ function float(text) {
210
+ return text === "inf" || text === "Infinity"
211
+ ? Infinity
212
+ : text === "-inf" || text === "-Infinity"
213
+ ? -Infinity
214
+ : Number(text);
215
+ }
@@ -102,6 +102,7 @@ class ExecutorV1 {
102
102
  trace;
103
103
  stdin;
104
104
  options;
105
+ encodingErrors = {};
105
106
  current;
106
107
  host;
107
108
  scheduler;
@@ -140,6 +141,16 @@ class ExecutorV1 {
140
141
  argv: [...(options.argv ?? ["main.hew"])],
141
142
  unixTimeMillis: () => this.trace.virtualTimeMs,
142
143
  calendarBridge: options.calendarBridge,
144
+ codecBridge: options.codecBridge,
145
+ encodingError: (format, message) => {
146
+ const actor = this.current.context.actor;
147
+ const errors = actor
148
+ ? (actor.encodingErrors ??= {})
149
+ : this.encodingErrors;
150
+ if (message !== undefined)
151
+ errors[format] = message;
152
+ return errors[format] ?? "";
153
+ },
143
154
  fileError: (operation) => {
144
155
  const error = this.current.context.fileError;
145
156
  switch (operation) {
@@ -1354,7 +1365,7 @@ class ExecutorV1 {
1354
1365
  typeId: shape.name,
1355
1366
  shape: shape.id,
1356
1367
  tag: deadline ? term.deadline_variant : term.fault_variant,
1357
- payload: [stringValue(faultReport(fault))],
1368
+ payload: [stringValue(faultRecoveryMessage(fault))],
1358
1369
  };
1359
1370
  act.fault = null;
1360
1371
  if (act.context.actor)
@@ -2446,6 +2457,9 @@ class ExecutorV1 {
2446
2457
  while (pending.length) {
2447
2458
  const value = pending.pop();
2448
2459
  switch (value.kind) {
2460
+ case "encoding":
2461
+ value.value = null;
2462
+ break;
2449
2463
  case "string":
2450
2464
  value.release();
2451
2465
  break;
@@ -2578,6 +2592,8 @@ class ExecutorV1 {
2578
2592
  this.directories.call(release.operation, [value]);
2579
2593
  }
2580
2594
  closeValue(value, fault) {
2595
+ if (value.kind === "encoding")
2596
+ value.value = null;
2581
2597
  if (value.kind === "host_resource")
2582
2598
  this.closeHostResource(value);
2583
2599
  if (value.kind === "string")
@@ -3808,7 +3824,8 @@ class ExecutorV1 {
3808
3824
  };
3809
3825
  const runHook = () => {
3810
3826
  if (actor.layout.crash != null) {
3811
- const [code, message] = faultInfo(fault);
3827
+ const [code, reason] = faultInfo(fault);
3828
+ const message = faultApplicationMessage(fault) ?? reason;
3812
3829
  const info = {
3813
3830
  kind: "record",
3814
3831
  typeId: this.aggregateName(actor.layout.crash_info),
@@ -4387,15 +4404,28 @@ function faultInfo(fault) {
4387
4404
  actor_refused: [-4, "Refused"],
4388
4405
  }[fault.trap];
4389
4406
  }
4407
+ function faultApplicationMessage(fault) {
4408
+ return fault.kind === "panic" &&
4409
+ (fault.cancelled || fault.deadline || fault.timerOverdue)
4410
+ ? undefined
4411
+ : fault.message;
4412
+ }
4390
4413
  function faultDiagnostic(fault, secondary = false) {
4391
4414
  const [code, reason] = faultInfo(fault);
4392
4415
  const label = secondary ? "secondary failure" : "failure";
4393
- const message = fault.message === undefined ||
4394
- (fault.kind === "panic" &&
4395
- (fault.cancelled || fault.deadline || fault.timerOverdue))
4396
- ? ""
4397
- : `: ${fault.message}`;
4398
- return `hew: ${label}: ${reason} (${code})${message}\n`;
4416
+ const message = faultApplicationMessage(fault);
4417
+ const detail = message === undefined ? "" : `: ${message}`;
4418
+ return `hew: ${label}: ${reason} (${code})${detail}\n`;
4419
+ }
4420
+ function faultRecoveryMessage(fault) {
4421
+ let text = faultApplicationMessage(fault) ?? faultInfo(fault)[1];
4422
+ for (const diagnostic of fault.secondary ?? []) {
4423
+ text += `; secondary failure: ${faultInfo(diagnostic)[1]}`;
4424
+ const detail = faultApplicationMessage(diagnostic);
4425
+ if (detail !== undefined)
4426
+ text += `: ${detail}`;
4427
+ }
4428
+ return text;
4399
4429
  }
4400
4430
  function faultReport(fault, secondary = false) {
4401
4431
  return (faultDiagnostic(fault, secondary) +
@@ -119,7 +119,7 @@ export type AskDetail = {
119
119
  policy: SendPolicy;
120
120
  sealed: boolean;
121
121
  };
122
- export type AsyncIoOp = "TcpRead" | "TcpWrite" | "TcpAccept" | "TcpConnect" | "TcpConnectTimeout" | "StdinReadLine" | "SinkFinish" | "TlsConnect" | "TlsRead" | "TlsWrite" | "FileRead" | "FileWrite";
122
+ export type AsyncIoOp = "TcpRead" | "TcpWrite" | "TcpAccept" | "TcpConnect" | "TcpConnectTimeout" | "StdinReadLine" | "SinkFinish" | "TlsConnect" | "TlsRead" | "TlsWrite" | "FileRead" | "FileWrite" | "WebSocketAccept";
123
123
  export type BlockV1 = {
124
124
  id: number;
125
125
  params: Array<ValueDef>;
@@ -682,7 +682,7 @@ export type RuntimeCallFamily = {
682
682
  Map: MapValueOp;
683
683
  } | {
684
684
  Set: SetValueOp;
685
- } | "VecAppend" | "VecClear" | "VecClone" | "VecCloneLayout" | "VecCloneOwned" | "VecContainsLayout" | "VecTakeAll" | "VecContainsOwned" | {
685
+ } | "VecAppend" | "VecClear" | "VecClone" | "VecCloneLayout" | "VecCloneOwned" | "VecContainsLayout" | "VecContainsOwned" | {
686
686
  VecContainsScalar: VecContainsScalarElem;
687
687
  } | {
688
688
  VecGet: VecGetElem;
@@ -1097,7 +1097,7 @@ export type VecGetElem = "Bool" | "F32" | "F64" | "I8" | "I16" | "I32" | "I64" |
1097
1097
  export type VecScalarElem = "F32" | "F64" | "I8" | "I16" | "I32" | "I64" | "Ptr" | "Str" | "U8" | "U16";
1098
1098
  export type VecScalarOp = "Push" | "Pop" | "Set" | "RemoveAt";
1099
1099
  export type VecSliceElem = "Bytesize" | "F64" | "I32" | "I64" | "Layout" | "Owned" | "Ptr" | "Str";
1100
- export type VecValueOp = "New" | "Len" | "Contains" | "Index" | "Get" | "Push" | "Set" | "Pop" | "Remove" | "Clear" | "IndexBorrow" | "GetBorrow" | "TakeFirst" | "TakeAll" | "Slice" | "SliceFrom" | "Append" | "Join";
1100
+ export type VecValueOp = "Swap" | "New" | "Len" | "Contains" | "Index" | "Get" | "Push" | "Set" | "Pop" | "Remove" | "Clear" | "IndexBorrow" | "GetBorrow" | "TakeFirst" | "Slice" | "SliceFrom" | "Append" | "Join";
1101
1101
  export type VtableShape = {
1102
1102
  id: number;
1103
1103
  slots: Array<VtableSlot>;
@@ -511,6 +511,7 @@ const schema19 = {
511
511
  "TlsWrite",
512
512
  "FileRead",
513
513
  "FileWrite",
514
+ "WebSocketAccept",
514
515
  ],
515
516
  type: "string",
516
517
  },
@@ -4314,12 +4315,6 @@ const schema19 = {
4314
4315
  },
4315
4316
  required: ["detail"],
4316
4317
  },
4317
- {
4318
- properties: {
4319
- detail: { type: "null" },
4320
- family: { const: "VecTakeAll" },
4321
- },
4322
- },
4323
4318
  {
4324
4319
  properties: {
4325
4320
  detail: { $ref: "#/$defs/VecContainsScalarElem" },
@@ -5985,6 +5980,7 @@ const schema19 = {
5985
5980
  oneOf: [
5986
5981
  {
5987
5982
  enum: [
5983
+ "Swap",
5988
5984
  "New",
5989
5985
  "Len",
5990
5986
  "Contains",
@@ -6013,11 +6009,6 @@ const schema19 = {
6013
6009
  description: "Remove the first element and hand its ownership to the caller. This is\nthe consuming iterator's step for an element with no clone: the vector\nshrinks by one and ends empty when the drain runs to completion.",
6014
6010
  type: "string",
6015
6011
  },
6016
- {
6017
- const: "TakeAll",
6018
- description: "Move the whole buffer out and leave the receiver a valid empty vector\nwith its element representation intact. This is how a `Vec` living in\npersistent storage - an actor state field - is drained by a consuming\niteration: the cursor owns the elements and the seat keeps a usable\nvector a later dispatch can refill.",
6019
- type: "string",
6020
- },
6021
6012
  {
6022
6013
  const: "Slice",
6023
6014
  description: "`v[a..b]` - a fresh independent `Vec<T>` over the selected range.",
@@ -31944,6 +31935,7 @@ const schema70 = {
31944
31935
  "TlsWrite",
31945
31936
  "FileRead",
31946
31937
  "FileWrite",
31938
+ "WebSocketAccept",
31947
31939
  ],
31948
31940
  type: "string",
31949
31941
  };
@@ -31980,7 +31972,8 @@ function validate230(data, { instancePath = "", parentData, parentDataProperty,
31980
31972
  data === "TlsRead" ||
31981
31973
  data === "TlsWrite" ||
31982
31974
  data === "FileRead" ||
31983
- data === "FileWrite")) {
31975
+ data === "FileWrite" ||
31976
+ data === "WebSocketAccept")) {
31984
31977
  validate230.errors = [
31985
31978
  {
31986
31979
  instancePath,
@@ -48958,9 +48951,6 @@ const schema82 = {
48958
48951
  },
48959
48952
  required: ["detail"],
48960
48953
  },
48961
- {
48962
- properties: { detail: { type: "null" }, family: { const: "VecTakeAll" } },
48963
- },
48964
48954
  {
48965
48955
  properties: {
48966
48956
  detail: { $ref: "#/$defs/VecContainsScalarElem" },
@@ -50048,6 +50038,7 @@ const schema94 = {
50048
50038
  oneOf: [
50049
50039
  {
50050
50040
  enum: [
50041
+ "Swap",
50051
50042
  "New",
50052
50043
  "Len",
50053
50044
  "Contains",
@@ -50076,11 +50067,6 @@ const schema94 = {
50076
50067
  description: "Remove the first element and hand its ownership to the caller. This is\nthe consuming iterator's step for an element with no clone: the vector\nshrinks by one and ends empty when the drain runs to completion.",
50077
50068
  type: "string",
50078
50069
  },
50079
- {
50080
- const: "TakeAll",
50081
- description: "Move the whole buffer out and leave the receiver a valid empty vector\nwith its element representation intact. This is how a `Vec` living in\npersistent storage - an actor state field - is drained by a consuming\niteration: the cursor owns the elements and the seat keeps a usable\nvector a later dispatch can refill.",
50082
- type: "string",
50083
- },
50084
50070
  {
50085
50071
  const: "Slice",
50086
50072
  description: "`v[a..b]` - a fresh independent `Vec<T>` over the selected range.",
@@ -50133,7 +50119,8 @@ function validate286(data, { instancePath = "", parentData, parentDataProperty,
50133
50119
  }
50134
50120
  errors++;
50135
50121
  }
50136
- if (!(data === "New" ||
50122
+ if (!(data === "Swap" ||
50123
+ data === "New" ||
50137
50124
  data === "Len" ||
50138
50125
  data === "Contains" ||
50139
50126
  data === "Index" ||
@@ -50309,12 +50296,12 @@ function validate286(data, { instancePath = "", parentData, parentDataProperty,
50309
50296
  }
50310
50297
  errors++;
50311
50298
  }
50312
- if ("TakeAll" !== data) {
50299
+ if ("Slice" !== data) {
50313
50300
  const err9 = {
50314
50301
  instancePath,
50315
50302
  schemaPath: "#/oneOf/4/const",
50316
50303
  keyword: "const",
50317
- params: { allowedValue: "TakeAll" },
50304
+ params: { allowedValue: "Slice" },
50318
50305
  message: "must be equal to constant",
50319
50306
  };
50320
50307
  if (vErrors === null) {
@@ -50352,12 +50339,12 @@ function validate286(data, { instancePath = "", parentData, parentDataProperty,
50352
50339
  }
50353
50340
  errors++;
50354
50341
  }
50355
- if ("Slice" !== data) {
50342
+ if ("SliceFrom" !== data) {
50356
50343
  const err11 = {
50357
50344
  instancePath,
50358
50345
  schemaPath: "#/oneOf/5/const",
50359
50346
  keyword: "const",
50360
- params: { allowedValue: "Slice" },
50347
+ params: { allowedValue: "SliceFrom" },
50361
50348
  message: "must be equal to constant",
50362
50349
  };
50363
50350
  if (vErrors === null) {
@@ -50395,12 +50382,12 @@ function validate286(data, { instancePath = "", parentData, parentDataProperty,
50395
50382
  }
50396
50383
  errors++;
50397
50384
  }
50398
- if ("SliceFrom" !== data) {
50385
+ if ("Append" !== data) {
50399
50386
  const err13 = {
50400
50387
  instancePath,
50401
50388
  schemaPath: "#/oneOf/6/const",
50402
50389
  keyword: "const",
50403
- params: { allowedValue: "SliceFrom" },
50390
+ params: { allowedValue: "Append" },
50404
50391
  message: "must be equal to constant",
50405
50392
  };
50406
50393
  if (vErrors === null) {
@@ -50438,12 +50425,12 @@ function validate286(data, { instancePath = "", parentData, parentDataProperty,
50438
50425
  }
50439
50426
  errors++;
50440
50427
  }
50441
- if ("Append" !== data) {
50428
+ if ("Join" !== data) {
50442
50429
  const err15 = {
50443
50430
  instancePath,
50444
50431
  schemaPath: "#/oneOf/7/const",
50445
50432
  keyword: "const",
50446
- params: { allowedValue: "Append" },
50433
+ params: { allowedValue: "Join" },
50447
50434
  message: "must be equal to constant",
50448
50435
  };
50449
50436
  if (vErrors === null) {
@@ -50464,50 +50451,6 @@ function validate286(data, { instancePath = "", parentData, parentDataProperty,
50464
50451
  valid0 = true;
50465
50452
  passing0 = 7;
50466
50453
  }
50467
- const _errs17 = errors;
50468
- if (typeof data !== "string") {
50469
- const err16 = {
50470
- instancePath,
50471
- schemaPath: "#/oneOf/8/type",
50472
- keyword: "type",
50473
- params: { type: "string" },
50474
- message: "must be string",
50475
- };
50476
- if (vErrors === null) {
50477
- vErrors = [err16];
50478
- }
50479
- else {
50480
- vErrors.push(err16);
50481
- }
50482
- errors++;
50483
- }
50484
- if ("Join" !== data) {
50485
- const err17 = {
50486
- instancePath,
50487
- schemaPath: "#/oneOf/8/const",
50488
- keyword: "const",
50489
- params: { allowedValue: "Join" },
50490
- message: "must be equal to constant",
50491
- };
50492
- if (vErrors === null) {
50493
- vErrors = [err17];
50494
- }
50495
- else {
50496
- vErrors.push(err17);
50497
- }
50498
- errors++;
50499
- }
50500
- var _valid0 = _errs17 === errors;
50501
- if (_valid0 && valid0) {
50502
- valid0 = false;
50503
- passing0 = [passing0, 8];
50504
- }
50505
- else {
50506
- if (_valid0) {
50507
- valid0 = true;
50508
- passing0 = 8;
50509
- }
50510
- }
50511
50454
  }
50512
50455
  }
50513
50456
  }
@@ -50516,7 +50459,7 @@ function validate286(data, { instancePath = "", parentData, parentDataProperty,
50516
50459
  }
50517
50460
  }
50518
50461
  if (!valid0) {
50519
- const err18 = {
50462
+ const err16 = {
50520
50463
  instancePath,
50521
50464
  schemaPath: "#/oneOf",
50522
50465
  keyword: "oneOf",
@@ -50524,10 +50467,10 @@ function validate286(data, { instancePath = "", parentData, parentDataProperty,
50524
50467
  message: "must match exactly one schema in oneOf",
50525
50468
  };
50526
50469
  if (vErrors === null) {
50527
- vErrors = [err18];
50470
+ vErrors = [err16];
50528
50471
  }
50529
50472
  else {
50530
- vErrors.push(err18);
50473
+ vErrors.push(err16);
50531
50474
  }
50532
50475
  errors++;
50533
50476
  validate286.errors = vErrors;
@@ -63159,50 +63102,6 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63159
63102
  }
63160
63103
  }
63161
63104
  }
63162
- else if (tag0 === "VecTakeAll") {
63163
- if (data && typeof data == "object" && !Array.isArray(data)) {
63164
- if (data.detail !== undefined) {
63165
- const _errs1013 = errors;
63166
- if (data.detail !== null) {
63167
- validate260.errors = [
63168
- {
63169
- instancePath: instancePath + "/detail",
63170
- schemaPath: "#/oneOf/252/properties/detail/type",
63171
- keyword: "type",
63172
- params: { type: "null" },
63173
- message: "must be null",
63174
- },
63175
- ];
63176
- return false;
63177
- }
63178
- var valid511 = _errs1013 === errors;
63179
- }
63180
- else {
63181
- var valid511 = true;
63182
- }
63183
- if (valid511) {
63184
- if (data.family !== undefined) {
63185
- const _errs1015 = errors;
63186
- if ("VecTakeAll" !== data.family) {
63187
- validate260.errors = [
63188
- {
63189
- instancePath: instancePath + "/family",
63190
- schemaPath: "#/oneOf/252/properties/family/const",
63191
- keyword: "const",
63192
- params: { allowedValue: "VecTakeAll" },
63193
- message: "must be equal to constant",
63194
- },
63195
- ];
63196
- return false;
63197
- }
63198
- var valid511 = _errs1015 === errors;
63199
- }
63200
- else {
63201
- var valid511 = true;
63202
- }
63203
- }
63204
- }
63205
- }
63206
63105
  else if (tag0 === "VecContainsScalar") {
63207
63106
  if (data && typeof data == "object" && !Array.isArray(data)) {
63208
63107
  let missing19;
@@ -63210,7 +63109,7 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63210
63109
  validate260.errors = [
63211
63110
  {
63212
63111
  instancePath,
63213
- schemaPath: "#/oneOf/253/required",
63112
+ schemaPath: "#/oneOf/252/required",
63214
63113
  keyword: "required",
63215
63114
  params: { missingProperty: missing19 },
63216
63115
  message: "must have required property '" + missing19 + "'",
@@ -63220,7 +63119,7 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63220
63119
  }
63221
63120
  else {
63222
63121
  if (data.detail !== undefined) {
63223
- const _errs1017 = errors;
63122
+ const _errs1013 = errors;
63224
63123
  if (!validate296(data.detail, {
63225
63124
  instancePath: instancePath + "/detail",
63226
63125
  parentData: data,
@@ -63234,19 +63133,19 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63234
63133
  : vErrors.concat(validate296.errors);
63235
63134
  errors = vErrors.length;
63236
63135
  }
63237
- var valid513 = _errs1017 === errors;
63136
+ var valid511 = _errs1013 === errors;
63238
63137
  }
63239
63138
  else {
63240
- var valid513 = true;
63139
+ var valid511 = true;
63241
63140
  }
63242
- if (valid513) {
63141
+ if (valid511) {
63243
63142
  if (data.family !== undefined) {
63244
- const _errs1018 = errors;
63143
+ const _errs1014 = errors;
63245
63144
  if ("VecContainsScalar" !== data.family) {
63246
63145
  validate260.errors = [
63247
63146
  {
63248
63147
  instancePath: instancePath + "/family",
63249
- schemaPath: "#/oneOf/253/properties/family/const",
63148
+ schemaPath: "#/oneOf/252/properties/family/const",
63250
63149
  keyword: "const",
63251
63150
  params: { allowedValue: "VecContainsScalar" },
63252
63151
  message: "must be equal to constant",
@@ -63254,10 +63153,10 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63254
63153
  ];
63255
63154
  return false;
63256
63155
  }
63257
- var valid513 = _errs1018 === errors;
63156
+ var valid511 = _errs1014 === errors;
63258
63157
  }
63259
63158
  else {
63260
- var valid513 = true;
63159
+ var valid511 = true;
63261
63160
  }
63262
63161
  }
63263
63162
  }
@@ -63270,7 +63169,7 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63270
63169
  validate260.errors = [
63271
63170
  {
63272
63171
  instancePath,
63273
- schemaPath: "#/oneOf/254/required",
63172
+ schemaPath: "#/oneOf/253/required",
63274
63173
  keyword: "required",
63275
63174
  params: { missingProperty: missing20 },
63276
63175
  message: "must have required property '" + missing20 + "'",
@@ -63280,7 +63179,7 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63280
63179
  }
63281
63180
  else {
63282
63181
  if (data.detail !== undefined) {
63283
- const _errs1020 = errors;
63182
+ const _errs1016 = errors;
63284
63183
  if (!validate298(data.detail, {
63285
63184
  instancePath: instancePath + "/detail",
63286
63185
  parentData: data,
@@ -63294,19 +63193,19 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63294
63193
  : vErrors.concat(validate298.errors);
63295
63194
  errors = vErrors.length;
63296
63195
  }
63297
- var valid515 = _errs1020 === errors;
63196
+ var valid513 = _errs1016 === errors;
63298
63197
  }
63299
63198
  else {
63300
- var valid515 = true;
63199
+ var valid513 = true;
63301
63200
  }
63302
- if (valid515) {
63201
+ if (valid513) {
63303
63202
  if (data.family !== undefined) {
63304
- const _errs1021 = errors;
63203
+ const _errs1017 = errors;
63305
63204
  if ("VecGet" !== data.family) {
63306
63205
  validate260.errors = [
63307
63206
  {
63308
63207
  instancePath: instancePath + "/family",
63309
- schemaPath: "#/oneOf/254/properties/family/const",
63208
+ schemaPath: "#/oneOf/253/properties/family/const",
63310
63209
  keyword: "const",
63311
63210
  params: { allowedValue: "VecGet" },
63312
63211
  message: "must be equal to constant",
@@ -63314,10 +63213,10 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63314
63213
  ];
63315
63214
  return false;
63316
63215
  }
63317
- var valid515 = _errs1021 === errors;
63216
+ var valid513 = _errs1017 === errors;
63318
63217
  }
63319
63218
  else {
63320
- var valid515 = true;
63219
+ var valid513 = true;
63321
63220
  }
63322
63221
  }
63323
63222
  }
@@ -63330,7 +63229,7 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63330
63229
  validate260.errors = [
63331
63230
  {
63332
63231
  instancePath,
63333
- schemaPath: "#/oneOf/255/required",
63232
+ schemaPath: "#/oneOf/254/required",
63334
63233
  keyword: "required",
63335
63234
  params: { missingProperty: missing21 },
63336
63235
  message: "must have required property '" + missing21 + "'",
@@ -63340,21 +63239,21 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63340
63239
  }
63341
63240
  else {
63342
63241
  if (data.detail !== undefined) {
63343
- let data520 = data.detail;
63344
- const _errs1023 = errors;
63345
- if (errors === _errs1023) {
63346
- if (data520 &&
63347
- typeof data520 == "object" &&
63348
- !Array.isArray(data520)) {
63242
+ let data518 = data.detail;
63243
+ const _errs1019 = errors;
63244
+ if (errors === _errs1019) {
63245
+ if (data518 &&
63246
+ typeof data518 == "object" &&
63247
+ !Array.isArray(data518)) {
63349
63248
  let missing22;
63350
- if ((data520.op === undefined &&
63249
+ if ((data518.op === undefined &&
63351
63250
  (missing22 = "op")) ||
63352
- (data520.elem === undefined &&
63251
+ (data518.elem === undefined &&
63353
63252
  (missing22 = "elem"))) {
63354
63253
  validate260.errors = [
63355
63254
  {
63356
63255
  instancePath: instancePath + "/detail",
63357
- schemaPath: "#/oneOf/255/properties/detail/required",
63256
+ schemaPath: "#/oneOf/254/properties/detail/required",
63358
63257
  keyword: "required",
63359
63258
  params: { missingProperty: missing22 },
63360
63259
  message: "must have required property '" +
@@ -63365,11 +63264,11 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63365
63264
  return false;
63366
63265
  }
63367
63266
  else {
63368
- if (data520.elem !== undefined) {
63369
- const _errs1025 = errors;
63370
- if (!validate300(data520.elem, {
63267
+ if (data518.elem !== undefined) {
63268
+ const _errs1021 = errors;
63269
+ if (!validate300(data518.elem, {
63371
63270
  instancePath: instancePath + "/detail/elem",
63372
- parentData: data520,
63271
+ parentData: data518,
63373
63272
  parentDataProperty: "elem",
63374
63273
  rootData,
63375
63274
  dynamicAnchors,
@@ -63380,17 +63279,17 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63380
63279
  : vErrors.concat(validate300.errors);
63381
63280
  errors = vErrors.length;
63382
63281
  }
63383
- var valid518 = _errs1025 === errors;
63282
+ var valid516 = _errs1021 === errors;
63384
63283
  }
63385
63284
  else {
63386
- var valid518 = true;
63285
+ var valid516 = true;
63387
63286
  }
63388
- if (valid518) {
63389
- if (data520.op !== undefined) {
63390
- const _errs1026 = errors;
63391
- if (!validate302(data520.op, {
63287
+ if (valid516) {
63288
+ if (data518.op !== undefined) {
63289
+ const _errs1022 = errors;
63290
+ if (!validate302(data518.op, {
63392
63291
  instancePath: instancePath + "/detail/op",
63393
- parentData: data520,
63292
+ parentData: data518,
63394
63293
  parentDataProperty: "op",
63395
63294
  rootData,
63396
63295
  dynamicAnchors,
@@ -63401,10 +63300,10 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63401
63300
  : vErrors.concat(validate302.errors);
63402
63301
  errors = vErrors.length;
63403
63302
  }
63404
- var valid518 = _errs1026 === errors;
63303
+ var valid516 = _errs1022 === errors;
63405
63304
  }
63406
63305
  else {
63407
- var valid518 = true;
63306
+ var valid516 = true;
63408
63307
  }
63409
63308
  }
63410
63309
  }
@@ -63413,7 +63312,7 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63413
63312
  validate260.errors = [
63414
63313
  {
63415
63314
  instancePath: instancePath + "/detail",
63416
- schemaPath: "#/oneOf/255/properties/detail/type",
63315
+ schemaPath: "#/oneOf/254/properties/detail/type",
63417
63316
  keyword: "type",
63418
63317
  params: { type: "object" },
63419
63318
  message: "must be object",
@@ -63422,19 +63321,19 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63422
63321
  return false;
63423
63322
  }
63424
63323
  }
63425
- var valid517 = _errs1023 === errors;
63324
+ var valid515 = _errs1019 === errors;
63426
63325
  }
63427
63326
  else {
63428
- var valid517 = true;
63327
+ var valid515 = true;
63429
63328
  }
63430
- if (valid517) {
63329
+ if (valid515) {
63431
63330
  if (data.family !== undefined) {
63432
- const _errs1027 = errors;
63331
+ const _errs1023 = errors;
63433
63332
  if ("VecScalar" !== data.family) {
63434
63333
  validate260.errors = [
63435
63334
  {
63436
63335
  instancePath: instancePath + "/family",
63437
- schemaPath: "#/oneOf/255/properties/family/const",
63336
+ schemaPath: "#/oneOf/254/properties/family/const",
63438
63337
  keyword: "const",
63439
63338
  params: { allowedValue: "VecScalar" },
63440
63339
  message: "must be equal to constant",
@@ -63442,10 +63341,10 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63442
63341
  ];
63443
63342
  return false;
63444
63343
  }
63445
- var valid517 = _errs1027 === errors;
63344
+ var valid515 = _errs1023 === errors;
63446
63345
  }
63447
63346
  else {
63448
- var valid517 = true;
63347
+ var valid515 = true;
63449
63348
  }
63450
63349
  }
63451
63350
  }
@@ -63458,7 +63357,7 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63458
63357
  validate260.errors = [
63459
63358
  {
63460
63359
  instancePath,
63461
- schemaPath: "#/oneOf/256/required",
63360
+ schemaPath: "#/oneOf/255/required",
63462
63361
  keyword: "required",
63463
63362
  params: { missingProperty: missing23 },
63464
63363
  message: "must have required property '" + missing23 + "'",
@@ -63468,7 +63367,7 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63468
63367
  }
63469
63368
  else {
63470
63369
  if (data.detail !== undefined) {
63471
- const _errs1029 = errors;
63370
+ const _errs1025 = errors;
63472
63371
  if (!validate304(data.detail, {
63473
63372
  instancePath: instancePath + "/detail",
63474
63373
  parentData: data,
@@ -63482,19 +63381,19 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63482
63381
  : vErrors.concat(validate304.errors);
63483
63382
  errors = vErrors.length;
63484
63383
  }
63485
- var valid520 = _errs1029 === errors;
63384
+ var valid518 = _errs1025 === errors;
63486
63385
  }
63487
63386
  else {
63488
- var valid520 = true;
63387
+ var valid518 = true;
63489
63388
  }
63490
- if (valid520) {
63389
+ if (valid518) {
63491
63390
  if (data.family !== undefined) {
63492
- const _errs1030 = errors;
63391
+ const _errs1026 = errors;
63493
63392
  if ("VecSliceRange" !== data.family) {
63494
63393
  validate260.errors = [
63495
63394
  {
63496
63395
  instancePath: instancePath + "/family",
63497
- schemaPath: "#/oneOf/256/properties/family/const",
63396
+ schemaPath: "#/oneOf/255/properties/family/const",
63498
63397
  keyword: "const",
63499
63398
  params: { allowedValue: "VecSliceRange" },
63500
63399
  message: "must be equal to constant",
@@ -63502,10 +63401,10 @@ function validate260(data, { instancePath = "", parentData, parentDataProperty,
63502
63401
  ];
63503
63402
  return false;
63504
63403
  }
63505
- var valid520 = _errs1030 === errors;
63404
+ var valid518 = _errs1026 === errors;
63506
63405
  }
63507
63406
  else {
63508
- var valid520 = true;
63407
+ var valid518 = true;
63509
63408
  }
63510
63409
  }
63511
63410
  }
@@ -1,4 +1,5 @@
1
1
  import { type DirectoryOperation } from "./browser-directory.js";
2
+ import { type EncodingFormat } from "./encoding-values.js";
2
3
  import type { Pipes } from "./pipes.js";
3
4
  import { type VmValue } from "../values.js";
4
5
  import { Mt19937 } from "./mt19937.js";
@@ -12,6 +13,8 @@ export interface ShimHost {
12
13
  unixTimeMillis(): number;
13
14
  fileError(operation: "HasError" | "LastErrorKind" | "LastErrno" | "LastError"): VmValue;
14
15
  calendarBridge?: (request: string) => string;
16
+ codecBridge?: (request: string) => string;
17
+ encodingError?(format: EncodingFormat, message?: string): string;
15
18
  pipes?: Pipes;
16
19
  newPipe?(capacity: number): VmValue;
17
20
  generatorStream?(generator: VmValue): VmValue;
@@ -103,6 +106,7 @@ declare const NATIVE_IO_ROUTES: {
103
106
  readonly TlsConnect: Refused;
104
107
  readonly TlsRead: Refused;
105
108
  readonly TlsWrite: Refused;
109
+ readonly WebSocketAccept: Refused;
106
110
  readonly FileRead: "FileRead";
107
111
  readonly FileWrite: "FileWrite";
108
112
  };
@@ -1,5 +1,6 @@
1
1
  import { DIRECTORY_OPERATIONS, } from "./browser-directory.js";
2
2
  import { executeCalendar } from "./calendar.js";
3
+ import { executeEncoding } from "./encoding-values.js";
3
4
  import { charProperty, charCase } from "../unicode.js";
4
5
  /// Runtime implementations and their host execution registration. Admission and
5
6
  /// execution consume the same ordinary, resumable or refused disposition.
@@ -79,6 +80,18 @@ export function resolveRuntime(entry) {
79
80
  case "VecSliceRange":
80
81
  return refused(`${entry.family}::${entry.detail}`);
81
82
  case "Encoding":
83
+ return (entry.detail.op === "GetDatetime"
84
+ ? entry.detail.format === "Toml"
85
+ : entry.detail.format !== "Toml" ||
86
+ !["GetU64", "IntStatus", "FromU64", "FromNull"].includes(entry.detail.op))
87
+ ? {
88
+ kind: "ordinary",
89
+ shim: (host, args) => executeEncoding(host, entry.detail.format, entry.detail.op, args),
90
+ ...(entry.detail.op === "Parse" || entry.detail.op === "Stringify"
91
+ ? { bridge: "codecBridge" }
92
+ : {}),
93
+ }
94
+ : refused(`Encoding::${entry.detail.format}`);
82
95
  case "VecScalar":
83
96
  return refused(entry.family);
84
97
  case "Vector":
@@ -91,10 +104,8 @@ export function resolveRuntime(entry) {
91
104
  family: "Vector",
92
105
  operation: entry.detail,
93
106
  });
94
- case "Pop":
95
107
  case "GetBorrow":
96
108
  case "TakeFirst":
97
- case "TakeAll":
98
109
  case "Append":
99
110
  return refused(`Vector::${entry.detail}`);
100
111
  default:
@@ -203,6 +214,7 @@ const NATIVE_IO_ROUTES = {
203
214
  TlsConnect: refused("NativeIo::TlsConnect", true),
204
215
  TlsRead: refused("NativeIo::TlsRead", true),
205
216
  TlsWrite: refused("NativeIo::TlsWrite", true),
217
+ WebSocketAccept: refused("NativeIo::WebSocketAccept", true),
206
218
  FileRead: "FileRead",
207
219
  FileWrite: "FileWrite",
208
220
  };
@@ -638,7 +650,6 @@ const UNIT_FAMILIES = {
638
650
  VecCloneLayout: refused("VecCloneLayout"),
639
651
  VecCloneOwned: refused("VecCloneOwned"),
640
652
  VecContainsLayout: refused("VecContainsLayout"),
641
- VecTakeAll: refused("VecTakeAll"),
642
653
  VecContainsOwned: refused("VecContainsOwned"),
643
654
  VecIsEmpty: refused("VecIsEmpty"),
644
655
  VecJoinStr: refused("VecJoinStr"),
@@ -661,6 +672,33 @@ const UNIT_FAMILIES = {
661
672
  VtableDispatchPanicOnOob: refused("VtableDispatchPanicOnOob"),
662
673
  };
663
674
  const VECTOR_SHIMS = {
675
+ Swap: (_host, args) => {
676
+ const target = vec(args, 0);
677
+ const left = index(args, 1);
678
+ const right = index(args, 2);
679
+ if (left < 0 ||
680
+ left >= target.items.length ||
681
+ right < 0 ||
682
+ right >= target.items.length) {
683
+ throw new ShimFault("vector_bounds", "vector swap index out of bounds");
684
+ }
685
+ [target.items[left], target.items[right]] = [
686
+ target.items[right],
687
+ target.items[left],
688
+ ];
689
+ return target;
690
+ },
691
+ Pop: (_host, args) => {
692
+ const target = vec(args, 0);
693
+ if (target.items.length === 0) {
694
+ throw new ShimFault("vector_bounds", "pop from empty vector");
695
+ }
696
+ return {
697
+ kind: "record",
698
+ typeId: "",
699
+ fields: [target, target.items.pop()],
700
+ };
701
+ },
664
702
  New: () => ({ kind: "vector", elementType: "", items: [] }),
665
703
  // The receiver arrives by `move` and leaves as the call's result, so the
666
704
  // package can store the vector back into its place. The element carries the
@@ -1,5 +1,6 @@
1
1
  import type { JsonValue } from "./types.js";
2
2
  import { IndexedString } from "./strings.js";
3
+ import type { EncodingNode, EncodingFormat } from "./v1/encoding-values.js";
3
4
  export { stringValue } from "./strings.js";
4
5
  /** One creator-owned membership list; payload destruction uses the ordinary VM release path. */
5
6
  export interface RcOwner {
@@ -15,6 +16,10 @@ export interface RcCell {
15
16
  typeName: string;
16
17
  }
17
18
  export type VmValue = {
19
+ kind: "encoding";
20
+ format: EncodingFormat;
21
+ value: EncodingNode | null;
22
+ } | {
18
23
  kind: "rc";
19
24
  cell: RcCell | null;
20
25
  closed: boolean;
@@ -17,6 +17,8 @@ export function compareUtf8(a, b) {
17
17
  const I64_LITERAL_DECIMAL = /^(?:0|-?[1-9]\d*)$/;
18
18
  export function cloneValue(value) {
19
19
  switch (value.kind) {
20
+ case "encoding":
21
+ return { ...value, value: structuredClone(value.value) };
20
22
  case "rc":
21
23
  if (value.closed)
22
24
  throw new Error("cannot copy a released Rc");
@@ -206,6 +208,8 @@ export function renderF64(value) {
206
208
  }
207
209
  export function renderStdout(value) {
208
210
  switch (value.kind) {
211
+ case "encoding":
212
+ return JSON.stringify(value.value);
209
213
  case "host_resource":
210
214
  return "FilesystemOwner";
211
215
  case "timer":
@@ -265,6 +269,8 @@ export function renderStdout(value) {
265
269
  }
266
270
  export function toJsonValue(value) {
267
271
  switch (value.kind) {
272
+ case "encoding":
273
+ return value.value;
268
274
  case "host_resource":
269
275
  return "FilesystemOwner";
270
276
  case "timer":
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@hew-lang/sandbox-vm",
3
- "version": "0.6.5",
3
+ "version": "0.7.0",
4
4
  "hewSource": {
5
- "commit": "b6336356b8e9485d97a391075ab5891f7b896cd2",
6
- "tag": "v0.6.5",
5
+ "commit": "89cb17bde678afd8b1cdbd791be97a0df393e882",
6
+ "tag": "v0.7.0",
7
7
  "dirty": false
8
8
  },
9
9
  "description": "Deterministic TypeScript interpreter for the Hew educational sandbox",
@@ -21,7 +21,7 @@
21
21
  "cli/"
22
22
  ],
23
23
  "dependencies": {
24
- "@hew-lang/wasm": "0.6.5"
24
+ "@hew-lang/wasm": "0.7.0"
25
25
  },
26
26
  "keywords": [
27
27
  "hew",