@ricsam/isolate-console 0.1.3 → 0.1.6
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 +118 -25
- package/dist/cjs/index.cjs +103 -21
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/index.mjs +103 -21
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/types/index.d.ts +106 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,24 +1,110 @@
|
|
|
1
1
|
# @ricsam/isolate-console
|
|
2
2
|
|
|
3
|
-
Console API with logging, timing, counting, and grouping.
|
|
3
|
+
Console API with logging, timing, counting, and grouping for isolated-vm V8 sandbox.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm add @ricsam/isolate-console
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
The console module uses a single `onEntry` callback that receives structured `ConsoleEntry` objects:
|
|
4
14
|
|
|
5
15
|
```typescript
|
|
6
|
-
import { setupConsole } from "@ricsam/isolate-console";
|
|
16
|
+
import { setupConsole, type ConsoleEntry } from "@ricsam/isolate-console";
|
|
7
17
|
|
|
8
18
|
const handle = await setupConsole(context, {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
onEntry: (entry: ConsoleEntry) => {
|
|
20
|
+
switch (entry.type) {
|
|
21
|
+
case "output":
|
|
22
|
+
console.log(`[${entry.level}]`, ...entry.args);
|
|
23
|
+
break;
|
|
24
|
+
case "time":
|
|
25
|
+
console.log(`${entry.label}: ${entry.duration}ms`);
|
|
26
|
+
break;
|
|
27
|
+
case "count":
|
|
28
|
+
console.log(`${entry.label}: ${entry.count}`);
|
|
29
|
+
break;
|
|
30
|
+
case "group":
|
|
31
|
+
console.group(entry.label);
|
|
32
|
+
break;
|
|
33
|
+
case "groupEnd":
|
|
34
|
+
console.groupEnd();
|
|
35
|
+
break;
|
|
36
|
+
// ... handle other entry types
|
|
37
|
+
}
|
|
17
38
|
},
|
|
18
39
|
});
|
|
19
40
|
```
|
|
20
41
|
|
|
21
|
-
|
|
42
|
+
### Simple Console Handler
|
|
43
|
+
|
|
44
|
+
For basic use cases where you just want to route output to console methods:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { setupConsole, simpleConsoleHandler } from "@ricsam/isolate-console";
|
|
48
|
+
|
|
49
|
+
const handle = await setupConsole(
|
|
50
|
+
context,
|
|
51
|
+
simpleConsoleHandler({
|
|
52
|
+
log: (...args) => console.log("[sandbox]", ...args),
|
|
53
|
+
warn: (...args) => console.warn("[sandbox]", ...args),
|
|
54
|
+
error: (...args) => console.error("[sandbox]", ...args),
|
|
55
|
+
info: (...args) => console.info("[sandbox]", ...args),
|
|
56
|
+
debug: (...args) => console.debug("[sandbox]", ...args),
|
|
57
|
+
})
|
|
58
|
+
);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## ConsoleEntry Types
|
|
62
|
+
|
|
63
|
+
The `ConsoleEntry` discriminated union type includes all possible console events:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
type ConsoleEntry =
|
|
67
|
+
// Standard output (log, warn, error, info, debug)
|
|
68
|
+
| { type: "output"; level: "log" | "warn" | "error" | "info" | "debug"; args: unknown[]; groupDepth: number }
|
|
69
|
+
|
|
70
|
+
// console.dir()
|
|
71
|
+
| { type: "dir"; value: unknown; groupDepth: number }
|
|
72
|
+
|
|
73
|
+
// console.table()
|
|
74
|
+
| { type: "table"; data: unknown; columns?: string[]; groupDepth: number }
|
|
75
|
+
|
|
76
|
+
// console.timeEnd() - timer completed
|
|
77
|
+
| { type: "time"; label: string; duration: number; groupDepth: number }
|
|
78
|
+
|
|
79
|
+
// console.timeLog() - timer checkpoint
|
|
80
|
+
| { type: "timeLog"; label: string; duration: number; args: unknown[]; groupDepth: number }
|
|
81
|
+
|
|
82
|
+
// console.count()
|
|
83
|
+
| { type: "count"; label: string; count: number; groupDepth: number }
|
|
84
|
+
|
|
85
|
+
// console.countReset()
|
|
86
|
+
| { type: "countReset"; label: string; groupDepth: number }
|
|
87
|
+
|
|
88
|
+
// console.assert() - failed assertion
|
|
89
|
+
| { type: "assert"; args: unknown[]; groupDepth: number }
|
|
90
|
+
|
|
91
|
+
// console.group() or console.groupCollapsed()
|
|
92
|
+
| { type: "group"; label: string; collapsed: boolean; groupDepth: number }
|
|
93
|
+
|
|
94
|
+
// console.groupEnd()
|
|
95
|
+
| { type: "groupEnd"; groupDepth: number }
|
|
96
|
+
|
|
97
|
+
// console.clear()
|
|
98
|
+
| { type: "clear" }
|
|
99
|
+
|
|
100
|
+
// console.trace()
|
|
101
|
+
| { type: "trace"; args: unknown[]; stack: string; groupDepth: number };
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Each entry includes `groupDepth` (except `clear`) which indicates the current nesting level of console groups. This allows you to render output with proper indentation without tracking state yourself.
|
|
105
|
+
|
|
106
|
+
## Injected Globals
|
|
107
|
+
|
|
22
108
|
- `console.log`, `console.warn`, `console.error`, `console.debug`, `console.info`
|
|
23
109
|
- `console.trace`, `console.dir`, `console.table`
|
|
24
110
|
- `console.time`, `console.timeEnd`, `console.timeLog`
|
|
@@ -26,7 +112,7 @@ const handle = await setupConsole(context, {
|
|
|
26
112
|
- `console.group`, `console.groupCollapsed`, `console.groupEnd`
|
|
27
113
|
- `console.assert`, `console.clear`
|
|
28
114
|
|
|
29
|
-
|
|
115
|
+
## Usage in Isolate
|
|
30
116
|
|
|
31
117
|
```javascript
|
|
32
118
|
// Basic logging
|
|
@@ -54,16 +140,23 @@ console.log("Age: 30");
|
|
|
54
140
|
console.groupEnd();
|
|
55
141
|
```
|
|
56
142
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
|
60
|
-
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
143
|
+
## Entry Types Reference
|
|
144
|
+
|
|
145
|
+
| Entry Type | Description | Key Properties |
|
|
146
|
+
|------------|-------------|----------------|
|
|
147
|
+
| `output` | Standard logging (log, warn, error, info, debug) | `level`, `args` |
|
|
148
|
+
| `dir` | Object inspection | `value` |
|
|
149
|
+
| `table` | Tabular data display | `data`, `columns?` |
|
|
150
|
+
| `time` | Timer completion (timeEnd) | `label`, `duration` |
|
|
151
|
+
| `timeLog` | Timer checkpoint | `label`, `duration`, `args` |
|
|
152
|
+
| `count` | Counter increment | `label`, `count` |
|
|
153
|
+
| `countReset` | Counter reset | `label` |
|
|
154
|
+
| `assert` | Failed assertion | `args` |
|
|
155
|
+
| `group` | Group start | `label`, `collapsed` |
|
|
156
|
+
| `groupEnd` | Group end | - |
|
|
157
|
+
| `clear` | Console clear | - |
|
|
158
|
+
| `trace` | Stack trace | `args`, `stack` |
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
MIT
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -43,31 +43,76 @@ var __export = (target, all) => {
|
|
|
43
43
|
// packages/console/src/index.ts
|
|
44
44
|
var exports_src = {};
|
|
45
45
|
__export(exports_src, {
|
|
46
|
+
simpleConsoleHandler: () => simpleConsoleHandler,
|
|
46
47
|
setupConsole: () => setupConsole
|
|
47
48
|
});
|
|
48
49
|
module.exports = __toCommonJS(exports_src);
|
|
49
50
|
var import_isolated_vm = __toESM(require("isolated-vm"));
|
|
51
|
+
function simpleConsoleHandler(callbacks) {
|
|
52
|
+
return {
|
|
53
|
+
onEntry: (entry) => {
|
|
54
|
+
if (entry.type === "output") {
|
|
55
|
+
callbacks[entry.level]?.(...entry.args);
|
|
56
|
+
} else if (entry.type === "assert") {
|
|
57
|
+
callbacks.error?.("Assertion failed:", ...entry.args);
|
|
58
|
+
} else if (entry.type === "trace") {
|
|
59
|
+
callbacks.log?.(...entry.args, `
|
|
60
|
+
` + entry.stack);
|
|
61
|
+
} else if (entry.type === "dir") {
|
|
62
|
+
callbacks.log?.(entry.value);
|
|
63
|
+
} else if (entry.type === "table") {
|
|
64
|
+
callbacks.log?.(entry.data);
|
|
65
|
+
} else if (entry.type === "time") {
|
|
66
|
+
callbacks.log?.(`${entry.label}: ${entry.duration.toFixed(2)}ms`);
|
|
67
|
+
} else if (entry.type === "timeLog") {
|
|
68
|
+
callbacks.log?.(`${entry.label}: ${entry.duration.toFixed(2)}ms`, ...entry.args);
|
|
69
|
+
} else if (entry.type === "count") {
|
|
70
|
+
callbacks.log?.(`${entry.label}: ${entry.count}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
50
75
|
async function setupConsole(context, options) {
|
|
51
76
|
const opts = options ?? {};
|
|
52
77
|
const timers = new Map;
|
|
53
78
|
const counters = new Map;
|
|
54
79
|
let groupDepth = 0;
|
|
55
80
|
const global = context.global;
|
|
56
|
-
const logLevels = [
|
|
57
|
-
"log",
|
|
58
|
-
"warn",
|
|
59
|
-
"error",
|
|
60
|
-
"debug",
|
|
61
|
-
"info",
|
|
62
|
-
"trace",
|
|
63
|
-
"dir",
|
|
64
|
-
"table"
|
|
65
|
-
];
|
|
81
|
+
const logLevels = ["log", "warn", "error", "debug", "info"];
|
|
66
82
|
for (const level of logLevels) {
|
|
67
83
|
global.setSync(`__console_${level}`, new import_isolated_vm.default.Callback((...args) => {
|
|
68
|
-
opts.
|
|
84
|
+
opts.onEntry?.({
|
|
85
|
+
type: "output",
|
|
86
|
+
level,
|
|
87
|
+
args,
|
|
88
|
+
groupDepth
|
|
89
|
+
});
|
|
69
90
|
}));
|
|
70
91
|
}
|
|
92
|
+
global.setSync("__console_dir", new import_isolated_vm.default.Callback((value) => {
|
|
93
|
+
opts.onEntry?.({
|
|
94
|
+
type: "dir",
|
|
95
|
+
value,
|
|
96
|
+
groupDepth
|
|
97
|
+
});
|
|
98
|
+
}));
|
|
99
|
+
global.setSync("__console_table", new import_isolated_vm.default.Callback((data, columns) => {
|
|
100
|
+
opts.onEntry?.({
|
|
101
|
+
type: "table",
|
|
102
|
+
data,
|
|
103
|
+
columns,
|
|
104
|
+
groupDepth
|
|
105
|
+
});
|
|
106
|
+
}));
|
|
107
|
+
global.setSync("__console_trace", new import_isolated_vm.default.Callback((...args) => {
|
|
108
|
+
const stack = new Error().stack ?? "";
|
|
109
|
+
opts.onEntry?.({
|
|
110
|
+
type: "trace",
|
|
111
|
+
args,
|
|
112
|
+
stack,
|
|
113
|
+
groupDepth
|
|
114
|
+
});
|
|
115
|
+
}));
|
|
71
116
|
global.setSync("__console_time", new import_isolated_vm.default.Callback((label) => {
|
|
72
117
|
const l = label ?? "default";
|
|
73
118
|
timers.set(l, performance.now());
|
|
@@ -78,7 +123,12 @@ async function setupConsole(context, options) {
|
|
|
78
123
|
if (start !== undefined) {
|
|
79
124
|
const duration = performance.now() - start;
|
|
80
125
|
timers.delete(l);
|
|
81
|
-
opts.
|
|
126
|
+
opts.onEntry?.({
|
|
127
|
+
type: "time",
|
|
128
|
+
label: l,
|
|
129
|
+
duration,
|
|
130
|
+
groupDepth
|
|
131
|
+
});
|
|
82
132
|
}
|
|
83
133
|
}));
|
|
84
134
|
global.setSync("__console_timeLog", new import_isolated_vm.default.Callback((label, ...args) => {
|
|
@@ -86,42 +136,74 @@ async function setupConsole(context, options) {
|
|
|
86
136
|
const start = timers.get(l);
|
|
87
137
|
if (start !== undefined) {
|
|
88
138
|
const duration = performance.now() - start;
|
|
89
|
-
opts.
|
|
139
|
+
opts.onEntry?.({
|
|
140
|
+
type: "timeLog",
|
|
141
|
+
label: l,
|
|
142
|
+
duration,
|
|
143
|
+
args,
|
|
144
|
+
groupDepth
|
|
145
|
+
});
|
|
90
146
|
}
|
|
91
147
|
}));
|
|
92
148
|
global.setSync("__console_count", new import_isolated_vm.default.Callback((label) => {
|
|
93
149
|
const l = label ?? "default";
|
|
94
150
|
const count = (counters.get(l) ?? 0) + 1;
|
|
95
151
|
counters.set(l, count);
|
|
96
|
-
opts.
|
|
152
|
+
opts.onEntry?.({
|
|
153
|
+
type: "count",
|
|
154
|
+
label: l,
|
|
155
|
+
count,
|
|
156
|
+
groupDepth
|
|
157
|
+
});
|
|
97
158
|
}));
|
|
98
159
|
global.setSync("__console_countReset", new import_isolated_vm.default.Callback((label) => {
|
|
99
160
|
const l = label ?? "default";
|
|
100
161
|
counters.delete(l);
|
|
101
|
-
opts.
|
|
162
|
+
opts.onEntry?.({
|
|
163
|
+
type: "countReset",
|
|
164
|
+
label: l,
|
|
165
|
+
groupDepth
|
|
166
|
+
});
|
|
102
167
|
}));
|
|
103
168
|
global.setSync("__console_group", new import_isolated_vm.default.Callback((label) => {
|
|
104
169
|
const l = label ?? "default";
|
|
170
|
+
opts.onEntry?.({
|
|
171
|
+
type: "group",
|
|
172
|
+
label: l,
|
|
173
|
+
collapsed: false,
|
|
174
|
+
groupDepth
|
|
175
|
+
});
|
|
105
176
|
groupDepth++;
|
|
106
|
-
opts.onGroup?.(l, false);
|
|
107
177
|
}));
|
|
108
178
|
global.setSync("__console_groupCollapsed", new import_isolated_vm.default.Callback((label) => {
|
|
109
179
|
const l = label ?? "default";
|
|
180
|
+
opts.onEntry?.({
|
|
181
|
+
type: "group",
|
|
182
|
+
label: l,
|
|
183
|
+
collapsed: true,
|
|
184
|
+
groupDepth
|
|
185
|
+
});
|
|
110
186
|
groupDepth++;
|
|
111
|
-
opts.onGroup?.(l, true);
|
|
112
187
|
}));
|
|
113
188
|
global.setSync("__console_groupEnd", new import_isolated_vm.default.Callback(() => {
|
|
114
189
|
if (groupDepth > 0) {
|
|
115
190
|
groupDepth--;
|
|
116
191
|
}
|
|
117
|
-
opts.
|
|
192
|
+
opts.onEntry?.({
|
|
193
|
+
type: "groupEnd",
|
|
194
|
+
groupDepth
|
|
195
|
+
});
|
|
118
196
|
}));
|
|
119
197
|
global.setSync("__console_clear", new import_isolated_vm.default.Callback(() => {
|
|
120
|
-
opts.
|
|
198
|
+
opts.onEntry?.({ type: "clear" });
|
|
121
199
|
}));
|
|
122
200
|
global.setSync("__console_assert", new import_isolated_vm.default.Callback((condition, ...args) => {
|
|
123
201
|
if (!condition) {
|
|
124
|
-
opts.
|
|
202
|
+
opts.onEntry?.({
|
|
203
|
+
type: "assert",
|
|
204
|
+
args,
|
|
205
|
+
groupDepth
|
|
206
|
+
});
|
|
125
207
|
}
|
|
126
208
|
}));
|
|
127
209
|
context.evalSync(`
|
|
@@ -170,4 +252,4 @@ async function setupConsole(context, options) {
|
|
|
170
252
|
}
|
|
171
253
|
})
|
|
172
254
|
|
|
173
|
-
//# debugId=
|
|
255
|
+
//# debugId=2521806AC72E527C64756E2164756E21
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import ivm from \"isolated-vm\";\n\nexport interface ConsoleOptions {\n onLog?: (level: string, ...args: unknown[]) => void;\n onTime?: (label: string, duration: number) => void;\n onTimeLog?: (label: string, duration: number, ...args: unknown[]) => void;\n onCount?: (label: string, count: number) => void;\n onCountReset?: (label: string) => void;\n onGroup?: (label: string, collapsed: boolean) => void;\n onGroupEnd?: () => void;\n onClear?: () => void;\n onAssert?: (condition: boolean, ...args: unknown[]) => void;\n}\n\nexport interface ConsoleHandle {\n dispose(): void;\n reset(): void;\n getTimers(): Map<string, number>;\n getCounters(): Map<string, number>;\n getGroupDepth(): number;\n}\n\n/**\n * Setup console API in an isolated-vm context\n *\n * Injects console.log, console.warn, console.error, console.info, console.debug,\n * console.trace, console.dir, console.table, console.time, console.timeEnd,\n * console.timeLog, console.count, console.countReset, console.group,\n * console.groupCollapsed, console.groupEnd, console.clear, console.assert\n *\n * @example\n * const handle = await setupConsole(context, {\n * onLog: (level, ...args) => console.log(`[${level}]`, ...args)\n * });\n */\nexport async function setupConsole(\n context: ivm.Context,\n options?: ConsoleOptions\n): Promise<ConsoleHandle> {\n const opts = options ?? {};\n\n // State management\n const timers = new Map<string, number>();\n const counters = new Map<string, number>();\n let groupDepth = 0;\n\n const global = context.global;\n\n // Log-level methods\n const logLevels = [\n \"log\",\n \"warn\",\n \"error\",\n \"debug\",\n \"info\",\n \"trace\",\n \"dir\",\n \"table\",\n ];\n\n for (const level of logLevels) {\n global.setSync(\n `__console_${level}`,\n new ivm.Callback((...args: unknown[]) => {\n opts.onLog?.(level, ...args);\n })\n );\n }\n\n // Timing methods\n global.setSync(\n \"__console_time\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n timers.set(l, performance.now());\n })\n );\n\n global.setSync(\n \"__console_timeEnd\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n const start = timers.get(l);\n if (start !== undefined) {\n const duration = performance.now() - start;\n timers.delete(l);\n opts.onTime?.(l, duration);\n }\n })\n );\n\n global.setSync(\n \"__console_timeLog\",\n new ivm.Callback((label?: string, ...args: unknown[]) => {\n const l = label ?? \"default\";\n const start = timers.get(l);\n if (start !== undefined) {\n const duration = performance.now() - start;\n opts.onTimeLog?.(l, duration, ...args);\n }\n })\n );\n\n // Counting methods\n global.setSync(\n \"__console_count\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n const count = (counters.get(l) ?? 0) + 1;\n counters.set(l, count);\n opts.onCount?.(l, count);\n })\n );\n\n global.setSync(\n \"__console_countReset\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n counters.delete(l);\n opts.onCountReset?.(l);\n })\n );\n\n // Grouping methods\n global.setSync(\n \"__console_group\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n groupDepth++;\n opts.onGroup?.(l, false);\n })\n );\n\n global.setSync(\n \"__console_groupCollapsed\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n groupDepth++;\n opts.onGroup?.(l, true);\n })\n );\n\n global.setSync(\n \"__console_groupEnd\",\n new ivm.Callback(() => {\n if (groupDepth > 0) {\n groupDepth--;\n }\n opts.onGroupEnd?.();\n })\n );\n\n // Other methods\n global.setSync(\n \"__console_clear\",\n new ivm.Callback(() => {\n opts.onClear?.();\n })\n );\n\n global.setSync(\n \"__console_assert\",\n new ivm.Callback((condition: boolean, ...args: unknown[]) => {\n if (!condition) {\n opts.onAssert?.(condition, ...args);\n }\n })\n );\n\n // Inject console object\n context.evalSync(`\n globalThis.console = {\n log: __console_log,\n warn: __console_warn,\n error: __console_error,\n debug: __console_debug,\n info: __console_info,\n trace: __console_trace,\n dir: __console_dir,\n table: __console_table,\n time: __console_time,\n timeEnd: __console_timeEnd,\n timeLog: __console_timeLog,\n count: __console_count,\n countReset: __console_countReset,\n group: __console_group,\n groupCollapsed: __console_groupCollapsed,\n groupEnd: __console_groupEnd,\n clear: __console_clear,\n assert: __console_assert,\n };\n `);\n\n return {\n dispose() {\n timers.clear();\n counters.clear();\n groupDepth = 0;\n },\n reset() {\n timers.clear();\n counters.clear();\n groupDepth = 0;\n },\n getTimers() {\n return new Map(timers);\n },\n getCounters() {\n return new Map(counters);\n },\n getGroupDepth() {\n return groupDepth;\n },\n };\n}\n"
|
|
5
|
+
"import ivm from \"isolated-vm\";\n\n/**\n * Console entry types for structured console output.\n * Each entry type captures the specific data needed to render like DevTools.\n */\nexport type ConsoleEntry =\n | {\n type: \"output\";\n level: \"log\" | \"warn\" | \"error\" | \"info\" | \"debug\";\n args: unknown[];\n groupDepth: number;\n }\n | {\n /** Browser console output (from Playwright page, not sandbox) */\n type: \"browserOutput\";\n level: string;\n args: unknown[];\n timestamp: number;\n }\n | { type: \"dir\"; value: unknown; groupDepth: number }\n | { type: \"table\"; data: unknown; columns?: string[]; groupDepth: number }\n | { type: \"time\"; label: string; duration: number; groupDepth: number }\n | {\n type: \"timeLog\";\n label: string;\n duration: number;\n args: unknown[];\n groupDepth: number;\n }\n | { type: \"count\"; label: string; count: number; groupDepth: number }\n | { type: \"countReset\"; label: string; groupDepth: number }\n | { type: \"assert\"; args: unknown[]; groupDepth: number }\n | {\n type: \"group\";\n label: string;\n collapsed: boolean;\n groupDepth: number;\n }\n | { type: \"groupEnd\"; groupDepth: number }\n | { type: \"clear\" }\n | { type: \"trace\"; args: unknown[]; stack: string; groupDepth: number };\n\n/**\n * Console options with a single structured callback.\n */\nexport interface ConsoleOptions {\n /**\n * Callback invoked for each console operation.\n * Receives a structured entry with all data needed to render the output.\n */\n onEntry?: (entry: ConsoleEntry) => void;\n}\n\n/**\n * Console handle for accessing internal state.\n */\nexport interface ConsoleHandle {\n dispose(): void;\n reset(): void;\n getTimers(): Map<string, number>;\n getCounters(): Map<string, number>;\n getGroupDepth(): number;\n}\n\n/**\n * Simple console callback interface for basic usage.\n */\nexport interface SimpleConsoleCallbacks {\n log?: (...args: unknown[]) => void;\n warn?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n info?: (...args: unknown[]) => void;\n debug?: (...args: unknown[]) => void;\n}\n\n/**\n * Helper to create ConsoleOptions from simple callbacks.\n * Routes log-level outputs to the appropriate callback and handles assertions.\n *\n * @example\n * ```typescript\n * const runtime = await createRuntime({\n * console: simpleConsoleHandler({\n * log: (...args) => console.log('[sandbox]', ...args),\n * warn: (...args) => console.warn('[sandbox]', ...args),\n * error: (...args) => console.error('[sandbox]', ...args),\n * })\n * });\n * ```\n */\nexport function simpleConsoleHandler(\n callbacks: SimpleConsoleCallbacks\n): ConsoleOptions {\n return {\n onEntry: (entry) => {\n if (entry.type === \"output\") {\n callbacks[entry.level]?.(...entry.args);\n } else if (entry.type === \"assert\") {\n callbacks.error?.(\"Assertion failed:\", ...entry.args);\n } else if (entry.type === \"trace\") {\n callbacks.log?.(...entry.args, \"\\n\" + entry.stack);\n } else if (entry.type === \"dir\") {\n callbacks.log?.(entry.value);\n } else if (entry.type === \"table\") {\n callbacks.log?.(entry.data);\n } else if (entry.type === \"time\") {\n callbacks.log?.(`${entry.label}: ${entry.duration.toFixed(2)}ms`);\n } else if (entry.type === \"timeLog\") {\n callbacks.log?.(\n `${entry.label}: ${entry.duration.toFixed(2)}ms`,\n ...entry.args\n );\n } else if (entry.type === \"count\") {\n callbacks.log?.(`${entry.label}: ${entry.count}`);\n }\n // group, groupEnd, groupEnd, countReset, clear are silently ignored\n },\n };\n}\n\n/**\n * Setup console API in an isolated-vm context\n *\n * Injects console.log, console.warn, console.error, console.info, console.debug,\n * console.trace, console.dir, console.table, console.time, console.timeEnd,\n * console.timeLog, console.count, console.countReset, console.group,\n * console.groupCollapsed, console.groupEnd, console.clear, console.assert\n *\n * @example\n * const handle = await setupConsole(context, {\n * onEntry: (entry) => {\n * if (entry.type === 'output') {\n * console.log(`[${entry.level}]`, ...entry.args);\n * }\n * }\n * });\n */\nexport async function setupConsole(\n context: ivm.Context,\n options?: ConsoleOptions\n): Promise<ConsoleHandle> {\n const opts = options ?? {};\n\n // State management\n const timers = new Map<string, number>();\n const counters = new Map<string, number>();\n let groupDepth = 0;\n\n const global = context.global;\n\n // Log-level methods (output type)\n const logLevels = [\"log\", \"warn\", \"error\", \"debug\", \"info\"] as const;\n\n for (const level of logLevels) {\n global.setSync(\n `__console_${level}`,\n new ivm.Callback((...args: unknown[]) => {\n opts.onEntry?.({\n type: \"output\",\n level,\n args,\n groupDepth,\n });\n })\n );\n }\n\n // dir method\n global.setSync(\n \"__console_dir\",\n new ivm.Callback((value: unknown) => {\n opts.onEntry?.({\n type: \"dir\",\n value,\n groupDepth,\n });\n })\n );\n\n // table method\n global.setSync(\n \"__console_table\",\n new ivm.Callback((data: unknown, columns?: string[]) => {\n opts.onEntry?.({\n type: \"table\",\n data,\n columns,\n groupDepth,\n });\n })\n );\n\n // trace method (includes stack)\n global.setSync(\n \"__console_trace\",\n new ivm.Callback((...args: unknown[]) => {\n const stack = new Error().stack ?? \"\";\n opts.onEntry?.({\n type: \"trace\",\n args,\n stack,\n groupDepth,\n });\n })\n );\n\n // Timing methods\n global.setSync(\n \"__console_time\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n timers.set(l, performance.now());\n })\n );\n\n global.setSync(\n \"__console_timeEnd\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n const start = timers.get(l);\n if (start !== undefined) {\n const duration = performance.now() - start;\n timers.delete(l);\n opts.onEntry?.({\n type: \"time\",\n label: l,\n duration,\n groupDepth,\n });\n }\n })\n );\n\n global.setSync(\n \"__console_timeLog\",\n new ivm.Callback((label?: string, ...args: unknown[]) => {\n const l = label ?? \"default\";\n const start = timers.get(l);\n if (start !== undefined) {\n const duration = performance.now() - start;\n opts.onEntry?.({\n type: \"timeLog\",\n label: l,\n duration,\n args,\n groupDepth,\n });\n }\n })\n );\n\n // Counting methods\n global.setSync(\n \"__console_count\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n const count = (counters.get(l) ?? 0) + 1;\n counters.set(l, count);\n opts.onEntry?.({\n type: \"count\",\n label: l,\n count,\n groupDepth,\n });\n })\n );\n\n global.setSync(\n \"__console_countReset\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n counters.delete(l);\n opts.onEntry?.({\n type: \"countReset\",\n label: l,\n groupDepth,\n });\n })\n );\n\n // Grouping methods\n global.setSync(\n \"__console_group\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n opts.onEntry?.({\n type: \"group\",\n label: l,\n collapsed: false,\n groupDepth,\n });\n groupDepth++;\n })\n );\n\n global.setSync(\n \"__console_groupCollapsed\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n opts.onEntry?.({\n type: \"group\",\n label: l,\n collapsed: true,\n groupDepth,\n });\n groupDepth++;\n })\n );\n\n global.setSync(\n \"__console_groupEnd\",\n new ivm.Callback(() => {\n if (groupDepth > 0) {\n groupDepth--;\n }\n opts.onEntry?.({\n type: \"groupEnd\",\n groupDepth,\n });\n })\n );\n\n // Other methods\n global.setSync(\n \"__console_clear\",\n new ivm.Callback(() => {\n opts.onEntry?.({ type: \"clear\" });\n })\n );\n\n global.setSync(\n \"__console_assert\",\n new ivm.Callback((condition: boolean, ...args: unknown[]) => {\n if (!condition) {\n opts.onEntry?.({\n type: \"assert\",\n args,\n groupDepth,\n });\n }\n })\n );\n\n // Inject console object\n context.evalSync(`\n globalThis.console = {\n log: __console_log,\n warn: __console_warn,\n error: __console_error,\n debug: __console_debug,\n info: __console_info,\n trace: __console_trace,\n dir: __console_dir,\n table: __console_table,\n time: __console_time,\n timeEnd: __console_timeEnd,\n timeLog: __console_timeLog,\n count: __console_count,\n countReset: __console_countReset,\n group: __console_group,\n groupCollapsed: __console_groupCollapsed,\n groupEnd: __console_groupEnd,\n clear: __console_clear,\n assert: __console_assert,\n };\n `);\n\n return {\n dispose() {\n timers.clear();\n counters.clear();\n groupDepth = 0;\n },\n reset() {\n timers.clear();\n counters.clear();\n groupDepth = 0;\n },\n getTimers() {\n return new Map(timers);\n },\n getCounters() {\n return new Map(counters);\n },\n getGroupDepth() {\n return groupDepth;\n },\n };\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "2521806AC72E527C64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/cjs/package.json
CHANGED
package/dist/mjs/index.mjs
CHANGED
|
@@ -1,27 +1,71 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/console/src/index.ts
|
|
3
3
|
import ivm from "isolated-vm";
|
|
4
|
+
function simpleConsoleHandler(callbacks) {
|
|
5
|
+
return {
|
|
6
|
+
onEntry: (entry) => {
|
|
7
|
+
if (entry.type === "output") {
|
|
8
|
+
callbacks[entry.level]?.(...entry.args);
|
|
9
|
+
} else if (entry.type === "assert") {
|
|
10
|
+
callbacks.error?.("Assertion failed:", ...entry.args);
|
|
11
|
+
} else if (entry.type === "trace") {
|
|
12
|
+
callbacks.log?.(...entry.args, `
|
|
13
|
+
` + entry.stack);
|
|
14
|
+
} else if (entry.type === "dir") {
|
|
15
|
+
callbacks.log?.(entry.value);
|
|
16
|
+
} else if (entry.type === "table") {
|
|
17
|
+
callbacks.log?.(entry.data);
|
|
18
|
+
} else if (entry.type === "time") {
|
|
19
|
+
callbacks.log?.(`${entry.label}: ${entry.duration.toFixed(2)}ms`);
|
|
20
|
+
} else if (entry.type === "timeLog") {
|
|
21
|
+
callbacks.log?.(`${entry.label}: ${entry.duration.toFixed(2)}ms`, ...entry.args);
|
|
22
|
+
} else if (entry.type === "count") {
|
|
23
|
+
callbacks.log?.(`${entry.label}: ${entry.count}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
4
28
|
async function setupConsole(context, options) {
|
|
5
29
|
const opts = options ?? {};
|
|
6
30
|
const timers = new Map;
|
|
7
31
|
const counters = new Map;
|
|
8
32
|
let groupDepth = 0;
|
|
9
33
|
const global = context.global;
|
|
10
|
-
const logLevels = [
|
|
11
|
-
"log",
|
|
12
|
-
"warn",
|
|
13
|
-
"error",
|
|
14
|
-
"debug",
|
|
15
|
-
"info",
|
|
16
|
-
"trace",
|
|
17
|
-
"dir",
|
|
18
|
-
"table"
|
|
19
|
-
];
|
|
34
|
+
const logLevels = ["log", "warn", "error", "debug", "info"];
|
|
20
35
|
for (const level of logLevels) {
|
|
21
36
|
global.setSync(`__console_${level}`, new ivm.Callback((...args) => {
|
|
22
|
-
opts.
|
|
37
|
+
opts.onEntry?.({
|
|
38
|
+
type: "output",
|
|
39
|
+
level,
|
|
40
|
+
args,
|
|
41
|
+
groupDepth
|
|
42
|
+
});
|
|
23
43
|
}));
|
|
24
44
|
}
|
|
45
|
+
global.setSync("__console_dir", new ivm.Callback((value) => {
|
|
46
|
+
opts.onEntry?.({
|
|
47
|
+
type: "dir",
|
|
48
|
+
value,
|
|
49
|
+
groupDepth
|
|
50
|
+
});
|
|
51
|
+
}));
|
|
52
|
+
global.setSync("__console_table", new ivm.Callback((data, columns) => {
|
|
53
|
+
opts.onEntry?.({
|
|
54
|
+
type: "table",
|
|
55
|
+
data,
|
|
56
|
+
columns,
|
|
57
|
+
groupDepth
|
|
58
|
+
});
|
|
59
|
+
}));
|
|
60
|
+
global.setSync("__console_trace", new ivm.Callback((...args) => {
|
|
61
|
+
const stack = new Error().stack ?? "";
|
|
62
|
+
opts.onEntry?.({
|
|
63
|
+
type: "trace",
|
|
64
|
+
args,
|
|
65
|
+
stack,
|
|
66
|
+
groupDepth
|
|
67
|
+
});
|
|
68
|
+
}));
|
|
25
69
|
global.setSync("__console_time", new ivm.Callback((label) => {
|
|
26
70
|
const l = label ?? "default";
|
|
27
71
|
timers.set(l, performance.now());
|
|
@@ -32,7 +76,12 @@ async function setupConsole(context, options) {
|
|
|
32
76
|
if (start !== undefined) {
|
|
33
77
|
const duration = performance.now() - start;
|
|
34
78
|
timers.delete(l);
|
|
35
|
-
opts.
|
|
79
|
+
opts.onEntry?.({
|
|
80
|
+
type: "time",
|
|
81
|
+
label: l,
|
|
82
|
+
duration,
|
|
83
|
+
groupDepth
|
|
84
|
+
});
|
|
36
85
|
}
|
|
37
86
|
}));
|
|
38
87
|
global.setSync("__console_timeLog", new ivm.Callback((label, ...args) => {
|
|
@@ -40,42 +89,74 @@ async function setupConsole(context, options) {
|
|
|
40
89
|
const start = timers.get(l);
|
|
41
90
|
if (start !== undefined) {
|
|
42
91
|
const duration = performance.now() - start;
|
|
43
|
-
opts.
|
|
92
|
+
opts.onEntry?.({
|
|
93
|
+
type: "timeLog",
|
|
94
|
+
label: l,
|
|
95
|
+
duration,
|
|
96
|
+
args,
|
|
97
|
+
groupDepth
|
|
98
|
+
});
|
|
44
99
|
}
|
|
45
100
|
}));
|
|
46
101
|
global.setSync("__console_count", new ivm.Callback((label) => {
|
|
47
102
|
const l = label ?? "default";
|
|
48
103
|
const count = (counters.get(l) ?? 0) + 1;
|
|
49
104
|
counters.set(l, count);
|
|
50
|
-
opts.
|
|
105
|
+
opts.onEntry?.({
|
|
106
|
+
type: "count",
|
|
107
|
+
label: l,
|
|
108
|
+
count,
|
|
109
|
+
groupDepth
|
|
110
|
+
});
|
|
51
111
|
}));
|
|
52
112
|
global.setSync("__console_countReset", new ivm.Callback((label) => {
|
|
53
113
|
const l = label ?? "default";
|
|
54
114
|
counters.delete(l);
|
|
55
|
-
opts.
|
|
115
|
+
opts.onEntry?.({
|
|
116
|
+
type: "countReset",
|
|
117
|
+
label: l,
|
|
118
|
+
groupDepth
|
|
119
|
+
});
|
|
56
120
|
}));
|
|
57
121
|
global.setSync("__console_group", new ivm.Callback((label) => {
|
|
58
122
|
const l = label ?? "default";
|
|
123
|
+
opts.onEntry?.({
|
|
124
|
+
type: "group",
|
|
125
|
+
label: l,
|
|
126
|
+
collapsed: false,
|
|
127
|
+
groupDepth
|
|
128
|
+
});
|
|
59
129
|
groupDepth++;
|
|
60
|
-
opts.onGroup?.(l, false);
|
|
61
130
|
}));
|
|
62
131
|
global.setSync("__console_groupCollapsed", new ivm.Callback((label) => {
|
|
63
132
|
const l = label ?? "default";
|
|
133
|
+
opts.onEntry?.({
|
|
134
|
+
type: "group",
|
|
135
|
+
label: l,
|
|
136
|
+
collapsed: true,
|
|
137
|
+
groupDepth
|
|
138
|
+
});
|
|
64
139
|
groupDepth++;
|
|
65
|
-
opts.onGroup?.(l, true);
|
|
66
140
|
}));
|
|
67
141
|
global.setSync("__console_groupEnd", new ivm.Callback(() => {
|
|
68
142
|
if (groupDepth > 0) {
|
|
69
143
|
groupDepth--;
|
|
70
144
|
}
|
|
71
|
-
opts.
|
|
145
|
+
opts.onEntry?.({
|
|
146
|
+
type: "groupEnd",
|
|
147
|
+
groupDepth
|
|
148
|
+
});
|
|
72
149
|
}));
|
|
73
150
|
global.setSync("__console_clear", new ivm.Callback(() => {
|
|
74
|
-
opts.
|
|
151
|
+
opts.onEntry?.({ type: "clear" });
|
|
75
152
|
}));
|
|
76
153
|
global.setSync("__console_assert", new ivm.Callback((condition, ...args) => {
|
|
77
154
|
if (!condition) {
|
|
78
|
-
opts.
|
|
155
|
+
opts.onEntry?.({
|
|
156
|
+
type: "assert",
|
|
157
|
+
args,
|
|
158
|
+
groupDepth
|
|
159
|
+
});
|
|
79
160
|
}
|
|
80
161
|
}));
|
|
81
162
|
context.evalSync(`
|
|
@@ -123,7 +204,8 @@ async function setupConsole(context, options) {
|
|
|
123
204
|
};
|
|
124
205
|
}
|
|
125
206
|
export {
|
|
207
|
+
simpleConsoleHandler,
|
|
126
208
|
setupConsole
|
|
127
209
|
};
|
|
128
210
|
|
|
129
|
-
//# debugId=
|
|
211
|
+
//# debugId=763E37163F3CD31764756E2164756E21
|
package/dist/mjs/index.mjs.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import ivm from \"isolated-vm\";\n\nexport interface ConsoleOptions {\n onLog?: (level: string, ...args: unknown[]) => void;\n onTime?: (label: string, duration: number) => void;\n onTimeLog?: (label: string, duration: number, ...args: unknown[]) => void;\n onCount?: (label: string, count: number) => void;\n onCountReset?: (label: string) => void;\n onGroup?: (label: string, collapsed: boolean) => void;\n onGroupEnd?: () => void;\n onClear?: () => void;\n onAssert?: (condition: boolean, ...args: unknown[]) => void;\n}\n\nexport interface ConsoleHandle {\n dispose(): void;\n reset(): void;\n getTimers(): Map<string, number>;\n getCounters(): Map<string, number>;\n getGroupDepth(): number;\n}\n\n/**\n * Setup console API in an isolated-vm context\n *\n * Injects console.log, console.warn, console.error, console.info, console.debug,\n * console.trace, console.dir, console.table, console.time, console.timeEnd,\n * console.timeLog, console.count, console.countReset, console.group,\n * console.groupCollapsed, console.groupEnd, console.clear, console.assert\n *\n * @example\n * const handle = await setupConsole(context, {\n * onLog: (level, ...args) => console.log(`[${level}]`, ...args)\n * });\n */\nexport async function setupConsole(\n context: ivm.Context,\n options?: ConsoleOptions\n): Promise<ConsoleHandle> {\n const opts = options ?? {};\n\n // State management\n const timers = new Map<string, number>();\n const counters = new Map<string, number>();\n let groupDepth = 0;\n\n const global = context.global;\n\n // Log-level methods\n const logLevels = [\n \"log\",\n \"warn\",\n \"error\",\n \"debug\",\n \"info\",\n \"trace\",\n \"dir\",\n \"table\",\n ];\n\n for (const level of logLevels) {\n global.setSync(\n `__console_${level}`,\n new ivm.Callback((...args: unknown[]) => {\n opts.onLog?.(level, ...args);\n })\n );\n }\n\n // Timing methods\n global.setSync(\n \"__console_time\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n timers.set(l, performance.now());\n })\n );\n\n global.setSync(\n \"__console_timeEnd\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n const start = timers.get(l);\n if (start !== undefined) {\n const duration = performance.now() - start;\n timers.delete(l);\n opts.onTime?.(l, duration);\n }\n })\n );\n\n global.setSync(\n \"__console_timeLog\",\n new ivm.Callback((label?: string, ...args: unknown[]) => {\n const l = label ?? \"default\";\n const start = timers.get(l);\n if (start !== undefined) {\n const duration = performance.now() - start;\n opts.onTimeLog?.(l, duration, ...args);\n }\n })\n );\n\n // Counting methods\n global.setSync(\n \"__console_count\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n const count = (counters.get(l) ?? 0) + 1;\n counters.set(l, count);\n opts.onCount?.(l, count);\n })\n );\n\n global.setSync(\n \"__console_countReset\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n counters.delete(l);\n opts.onCountReset?.(l);\n })\n );\n\n // Grouping methods\n global.setSync(\n \"__console_group\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n groupDepth++;\n opts.onGroup?.(l, false);\n })\n );\n\n global.setSync(\n \"__console_groupCollapsed\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n groupDepth++;\n opts.onGroup?.(l, true);\n })\n );\n\n global.setSync(\n \"__console_groupEnd\",\n new ivm.Callback(() => {\n if (groupDepth > 0) {\n groupDepth--;\n }\n opts.onGroupEnd?.();\n })\n );\n\n // Other methods\n global.setSync(\n \"__console_clear\",\n new ivm.Callback(() => {\n opts.onClear?.();\n })\n );\n\n global.setSync(\n \"__console_assert\",\n new ivm.Callback((condition: boolean, ...args: unknown[]) => {\n if (!condition) {\n opts.onAssert?.(condition, ...args);\n }\n })\n );\n\n // Inject console object\n context.evalSync(`\n globalThis.console = {\n log: __console_log,\n warn: __console_warn,\n error: __console_error,\n debug: __console_debug,\n info: __console_info,\n trace: __console_trace,\n dir: __console_dir,\n table: __console_table,\n time: __console_time,\n timeEnd: __console_timeEnd,\n timeLog: __console_timeLog,\n count: __console_count,\n countReset: __console_countReset,\n group: __console_group,\n groupCollapsed: __console_groupCollapsed,\n groupEnd: __console_groupEnd,\n clear: __console_clear,\n assert: __console_assert,\n };\n `);\n\n return {\n dispose() {\n timers.clear();\n counters.clear();\n groupDepth = 0;\n },\n reset() {\n timers.clear();\n counters.clear();\n groupDepth = 0;\n },\n getTimers() {\n return new Map(timers);\n },\n getCounters() {\n return new Map(counters);\n },\n getGroupDepth() {\n return groupDepth;\n },\n };\n}\n"
|
|
5
|
+
"import ivm from \"isolated-vm\";\n\n/**\n * Console entry types for structured console output.\n * Each entry type captures the specific data needed to render like DevTools.\n */\nexport type ConsoleEntry =\n | {\n type: \"output\";\n level: \"log\" | \"warn\" | \"error\" | \"info\" | \"debug\";\n args: unknown[];\n groupDepth: number;\n }\n | {\n /** Browser console output (from Playwright page, not sandbox) */\n type: \"browserOutput\";\n level: string;\n args: unknown[];\n timestamp: number;\n }\n | { type: \"dir\"; value: unknown; groupDepth: number }\n | { type: \"table\"; data: unknown; columns?: string[]; groupDepth: number }\n | { type: \"time\"; label: string; duration: number; groupDepth: number }\n | {\n type: \"timeLog\";\n label: string;\n duration: number;\n args: unknown[];\n groupDepth: number;\n }\n | { type: \"count\"; label: string; count: number; groupDepth: number }\n | { type: \"countReset\"; label: string; groupDepth: number }\n | { type: \"assert\"; args: unknown[]; groupDepth: number }\n | {\n type: \"group\";\n label: string;\n collapsed: boolean;\n groupDepth: number;\n }\n | { type: \"groupEnd\"; groupDepth: number }\n | { type: \"clear\" }\n | { type: \"trace\"; args: unknown[]; stack: string; groupDepth: number };\n\n/**\n * Console options with a single structured callback.\n */\nexport interface ConsoleOptions {\n /**\n * Callback invoked for each console operation.\n * Receives a structured entry with all data needed to render the output.\n */\n onEntry?: (entry: ConsoleEntry) => void;\n}\n\n/**\n * Console handle for accessing internal state.\n */\nexport interface ConsoleHandle {\n dispose(): void;\n reset(): void;\n getTimers(): Map<string, number>;\n getCounters(): Map<string, number>;\n getGroupDepth(): number;\n}\n\n/**\n * Simple console callback interface for basic usage.\n */\nexport interface SimpleConsoleCallbacks {\n log?: (...args: unknown[]) => void;\n warn?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n info?: (...args: unknown[]) => void;\n debug?: (...args: unknown[]) => void;\n}\n\n/**\n * Helper to create ConsoleOptions from simple callbacks.\n * Routes log-level outputs to the appropriate callback and handles assertions.\n *\n * @example\n * ```typescript\n * const runtime = await createRuntime({\n * console: simpleConsoleHandler({\n * log: (...args) => console.log('[sandbox]', ...args),\n * warn: (...args) => console.warn('[sandbox]', ...args),\n * error: (...args) => console.error('[sandbox]', ...args),\n * })\n * });\n * ```\n */\nexport function simpleConsoleHandler(\n callbacks: SimpleConsoleCallbacks\n): ConsoleOptions {\n return {\n onEntry: (entry) => {\n if (entry.type === \"output\") {\n callbacks[entry.level]?.(...entry.args);\n } else if (entry.type === \"assert\") {\n callbacks.error?.(\"Assertion failed:\", ...entry.args);\n } else if (entry.type === \"trace\") {\n callbacks.log?.(...entry.args, \"\\n\" + entry.stack);\n } else if (entry.type === \"dir\") {\n callbacks.log?.(entry.value);\n } else if (entry.type === \"table\") {\n callbacks.log?.(entry.data);\n } else if (entry.type === \"time\") {\n callbacks.log?.(`${entry.label}: ${entry.duration.toFixed(2)}ms`);\n } else if (entry.type === \"timeLog\") {\n callbacks.log?.(\n `${entry.label}: ${entry.duration.toFixed(2)}ms`,\n ...entry.args\n );\n } else if (entry.type === \"count\") {\n callbacks.log?.(`${entry.label}: ${entry.count}`);\n }\n // group, groupEnd, groupEnd, countReset, clear are silently ignored\n },\n };\n}\n\n/**\n * Setup console API in an isolated-vm context\n *\n * Injects console.log, console.warn, console.error, console.info, console.debug,\n * console.trace, console.dir, console.table, console.time, console.timeEnd,\n * console.timeLog, console.count, console.countReset, console.group,\n * console.groupCollapsed, console.groupEnd, console.clear, console.assert\n *\n * @example\n * const handle = await setupConsole(context, {\n * onEntry: (entry) => {\n * if (entry.type === 'output') {\n * console.log(`[${entry.level}]`, ...entry.args);\n * }\n * }\n * });\n */\nexport async function setupConsole(\n context: ivm.Context,\n options?: ConsoleOptions\n): Promise<ConsoleHandle> {\n const opts = options ?? {};\n\n // State management\n const timers = new Map<string, number>();\n const counters = new Map<string, number>();\n let groupDepth = 0;\n\n const global = context.global;\n\n // Log-level methods (output type)\n const logLevels = [\"log\", \"warn\", \"error\", \"debug\", \"info\"] as const;\n\n for (const level of logLevels) {\n global.setSync(\n `__console_${level}`,\n new ivm.Callback((...args: unknown[]) => {\n opts.onEntry?.({\n type: \"output\",\n level,\n args,\n groupDepth,\n });\n })\n );\n }\n\n // dir method\n global.setSync(\n \"__console_dir\",\n new ivm.Callback((value: unknown) => {\n opts.onEntry?.({\n type: \"dir\",\n value,\n groupDepth,\n });\n })\n );\n\n // table method\n global.setSync(\n \"__console_table\",\n new ivm.Callback((data: unknown, columns?: string[]) => {\n opts.onEntry?.({\n type: \"table\",\n data,\n columns,\n groupDepth,\n });\n })\n );\n\n // trace method (includes stack)\n global.setSync(\n \"__console_trace\",\n new ivm.Callback((...args: unknown[]) => {\n const stack = new Error().stack ?? \"\";\n opts.onEntry?.({\n type: \"trace\",\n args,\n stack,\n groupDepth,\n });\n })\n );\n\n // Timing methods\n global.setSync(\n \"__console_time\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n timers.set(l, performance.now());\n })\n );\n\n global.setSync(\n \"__console_timeEnd\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n const start = timers.get(l);\n if (start !== undefined) {\n const duration = performance.now() - start;\n timers.delete(l);\n opts.onEntry?.({\n type: \"time\",\n label: l,\n duration,\n groupDepth,\n });\n }\n })\n );\n\n global.setSync(\n \"__console_timeLog\",\n new ivm.Callback((label?: string, ...args: unknown[]) => {\n const l = label ?? \"default\";\n const start = timers.get(l);\n if (start !== undefined) {\n const duration = performance.now() - start;\n opts.onEntry?.({\n type: \"timeLog\",\n label: l,\n duration,\n args,\n groupDepth,\n });\n }\n })\n );\n\n // Counting methods\n global.setSync(\n \"__console_count\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n const count = (counters.get(l) ?? 0) + 1;\n counters.set(l, count);\n opts.onEntry?.({\n type: \"count\",\n label: l,\n count,\n groupDepth,\n });\n })\n );\n\n global.setSync(\n \"__console_countReset\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n counters.delete(l);\n opts.onEntry?.({\n type: \"countReset\",\n label: l,\n groupDepth,\n });\n })\n );\n\n // Grouping methods\n global.setSync(\n \"__console_group\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n opts.onEntry?.({\n type: \"group\",\n label: l,\n collapsed: false,\n groupDepth,\n });\n groupDepth++;\n })\n );\n\n global.setSync(\n \"__console_groupCollapsed\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n opts.onEntry?.({\n type: \"group\",\n label: l,\n collapsed: true,\n groupDepth,\n });\n groupDepth++;\n })\n );\n\n global.setSync(\n \"__console_groupEnd\",\n new ivm.Callback(() => {\n if (groupDepth > 0) {\n groupDepth--;\n }\n opts.onEntry?.({\n type: \"groupEnd\",\n groupDepth,\n });\n })\n );\n\n // Other methods\n global.setSync(\n \"__console_clear\",\n new ivm.Callback(() => {\n opts.onEntry?.({ type: \"clear\" });\n })\n );\n\n global.setSync(\n \"__console_assert\",\n new ivm.Callback((condition: boolean, ...args: unknown[]) => {\n if (!condition) {\n opts.onEntry?.({\n type: \"assert\",\n args,\n groupDepth,\n });\n }\n })\n );\n\n // Inject console object\n context.evalSync(`\n globalThis.console = {\n log: __console_log,\n warn: __console_warn,\n error: __console_error,\n debug: __console_debug,\n info: __console_info,\n trace: __console_trace,\n dir: __console_dir,\n table: __console_table,\n time: __console_time,\n timeEnd: __console_timeEnd,\n timeLog: __console_timeLog,\n count: __console_count,\n countReset: __console_countReset,\n group: __console_group,\n groupCollapsed: __console_groupCollapsed,\n groupEnd: __console_groupEnd,\n clear: __console_clear,\n assert: __console_assert,\n };\n `);\n\n return {\n dispose() {\n timers.clear();\n counters.clear();\n groupDepth = 0;\n },\n reset() {\n timers.clear();\n counters.clear();\n groupDepth = 0;\n },\n getTimers() {\n return new Map(timers);\n },\n getCounters() {\n return new Map(counters);\n },\n getGroupDepth() {\n return groupDepth;\n },\n };\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;AAAA;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "763E37163F3CD31764756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/mjs/package.json
CHANGED
package/dist/types/index.d.ts
CHANGED
|
@@ -1,15 +1,81 @@
|
|
|
1
1
|
import ivm from "isolated-vm";
|
|
2
|
+
/**
|
|
3
|
+
* Console entry types for structured console output.
|
|
4
|
+
* Each entry type captures the specific data needed to render like DevTools.
|
|
5
|
+
*/
|
|
6
|
+
export type ConsoleEntry = {
|
|
7
|
+
type: "output";
|
|
8
|
+
level: "log" | "warn" | "error" | "info" | "debug";
|
|
9
|
+
args: unknown[];
|
|
10
|
+
groupDepth: number;
|
|
11
|
+
} | {
|
|
12
|
+
/** Browser console output (from Playwright page, not sandbox) */
|
|
13
|
+
type: "browserOutput";
|
|
14
|
+
level: string;
|
|
15
|
+
args: unknown[];
|
|
16
|
+
timestamp: number;
|
|
17
|
+
} | {
|
|
18
|
+
type: "dir";
|
|
19
|
+
value: unknown;
|
|
20
|
+
groupDepth: number;
|
|
21
|
+
} | {
|
|
22
|
+
type: "table";
|
|
23
|
+
data: unknown;
|
|
24
|
+
columns?: string[];
|
|
25
|
+
groupDepth: number;
|
|
26
|
+
} | {
|
|
27
|
+
type: "time";
|
|
28
|
+
label: string;
|
|
29
|
+
duration: number;
|
|
30
|
+
groupDepth: number;
|
|
31
|
+
} | {
|
|
32
|
+
type: "timeLog";
|
|
33
|
+
label: string;
|
|
34
|
+
duration: number;
|
|
35
|
+
args: unknown[];
|
|
36
|
+
groupDepth: number;
|
|
37
|
+
} | {
|
|
38
|
+
type: "count";
|
|
39
|
+
label: string;
|
|
40
|
+
count: number;
|
|
41
|
+
groupDepth: number;
|
|
42
|
+
} | {
|
|
43
|
+
type: "countReset";
|
|
44
|
+
label: string;
|
|
45
|
+
groupDepth: number;
|
|
46
|
+
} | {
|
|
47
|
+
type: "assert";
|
|
48
|
+
args: unknown[];
|
|
49
|
+
groupDepth: number;
|
|
50
|
+
} | {
|
|
51
|
+
type: "group";
|
|
52
|
+
label: string;
|
|
53
|
+
collapsed: boolean;
|
|
54
|
+
groupDepth: number;
|
|
55
|
+
} | {
|
|
56
|
+
type: "groupEnd";
|
|
57
|
+
groupDepth: number;
|
|
58
|
+
} | {
|
|
59
|
+
type: "clear";
|
|
60
|
+
} | {
|
|
61
|
+
type: "trace";
|
|
62
|
+
args: unknown[];
|
|
63
|
+
stack: string;
|
|
64
|
+
groupDepth: number;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Console options with a single structured callback.
|
|
68
|
+
*/
|
|
2
69
|
export interface ConsoleOptions {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
onGroup?: (label: string, collapsed: boolean) => void;
|
|
9
|
-
onGroupEnd?: () => void;
|
|
10
|
-
onClear?: () => void;
|
|
11
|
-
onAssert?: (condition: boolean, ...args: unknown[]) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Callback invoked for each console operation.
|
|
72
|
+
* Receives a structured entry with all data needed to render the output.
|
|
73
|
+
*/
|
|
74
|
+
onEntry?: (entry: ConsoleEntry) => void;
|
|
12
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Console handle for accessing internal state.
|
|
78
|
+
*/
|
|
13
79
|
export interface ConsoleHandle {
|
|
14
80
|
dispose(): void;
|
|
15
81
|
reset(): void;
|
|
@@ -17,6 +83,32 @@ export interface ConsoleHandle {
|
|
|
17
83
|
getCounters(): Map<string, number>;
|
|
18
84
|
getGroupDepth(): number;
|
|
19
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Simple console callback interface for basic usage.
|
|
88
|
+
*/
|
|
89
|
+
export interface SimpleConsoleCallbacks {
|
|
90
|
+
log?: (...args: unknown[]) => void;
|
|
91
|
+
warn?: (...args: unknown[]) => void;
|
|
92
|
+
error?: (...args: unknown[]) => void;
|
|
93
|
+
info?: (...args: unknown[]) => void;
|
|
94
|
+
debug?: (...args: unknown[]) => void;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Helper to create ConsoleOptions from simple callbacks.
|
|
98
|
+
* Routes log-level outputs to the appropriate callback and handles assertions.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const runtime = await createRuntime({
|
|
103
|
+
* console: simpleConsoleHandler({
|
|
104
|
+
* log: (...args) => console.log('[sandbox]', ...args),
|
|
105
|
+
* warn: (...args) => console.warn('[sandbox]', ...args),
|
|
106
|
+
* error: (...args) => console.error('[sandbox]', ...args),
|
|
107
|
+
* })
|
|
108
|
+
* });
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export declare function simpleConsoleHandler(callbacks: SimpleConsoleCallbacks): ConsoleOptions;
|
|
20
112
|
/**
|
|
21
113
|
* Setup console API in an isolated-vm context
|
|
22
114
|
*
|
|
@@ -27,7 +119,11 @@ export interface ConsoleHandle {
|
|
|
27
119
|
*
|
|
28
120
|
* @example
|
|
29
121
|
* const handle = await setupConsole(context, {
|
|
30
|
-
*
|
|
122
|
+
* onEntry: (entry) => {
|
|
123
|
+
* if (entry.type === 'output') {
|
|
124
|
+
* console.log(`[${entry.level}]`, ...entry.args);
|
|
125
|
+
* }
|
|
126
|
+
* }
|
|
31
127
|
* });
|
|
32
128
|
*/
|
|
33
129
|
export declare function setupConsole(context: ivm.Context, options?: ConsoleOptions): Promise<ConsoleHandle>;
|