fake-node 0.1.1 → 0.3.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 speedydelete
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ ## fake-node
2
+
3
+ A version of node that works in the browser.
package/lib/index.d.ts ADDED
@@ -0,0 +1,59 @@
1
+ export declare class Process {
2
+ fakeNode: FakeNode;
3
+ pid: number;
4
+ priority: number;
5
+ uid: number;
6
+ gid: number;
7
+ groups: number[];
8
+ cwd: string;
9
+ umask: number;
10
+ argv: string[];
11
+ argv0: string;
12
+ execArgv: string[];
13
+ execArgv0: string;
14
+ path: string;
15
+ module: false | string;
16
+ code: string;
17
+ constructor(fakeNode: FakeNode, { path, code, module }: {
18
+ path?: string;
19
+ code: string;
20
+ module?: false | string;
21
+ });
22
+ get env(): {
23
+ [key: string]: string;
24
+ };
25
+ run(): void;
26
+ }
27
+ export declare class FakeNode {
28
+ version: string;
29
+ static nextId: number;
30
+ id: number;
31
+ globalName: string;
32
+ globalenv: {
33
+ [key: string]: string;
34
+ };
35
+ modules: Map<string, unknown>;
36
+ globals: {
37
+ [key: string]: unknown;
38
+ };
39
+ processes: Map<number, Process>;
40
+ nextPid: number;
41
+ window: Window;
42
+ errorCallbacks: (Function | undefined)[];
43
+ constructor();
44
+ require(module: string): unknown;
45
+ getGlobals(pid: number): object;
46
+ getenv(pid: number): {
47
+ [key: string]: string;
48
+ };
49
+ run(code: string): void;
50
+ addModule(name: string, code: string): void;
51
+ addModuleFromValue(name: string, module: unknown): void;
52
+ getUserFromUID(uid: number | string): string;
53
+ getUserFromGID(gid: number | string): string;
54
+ getUIDFromUser(user: string | number): number;
55
+ getGIDFromGroup(group: string | number): number;
56
+ onError(error: Error): void;
57
+ addErrorCallback(callback: Function): number;
58
+ removeErrorCallback(callbackID: number): void;
59
+ }
@@ -37,35 +37,48 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.FakeNode = exports.Process = void 0;
40
- const assert_1 = __importDefault(require("assert"));
41
- const module_buffer = __importStar(require("buffer"));
42
- // @ts-ignore
43
- const module_path = __importStar(require("path"));
44
- const module_punycode = __importStar(require("punycode"));
45
- const module_querystring = __importStar(require("querystring"));
46
- // @ts-ignore
47
- const module_readline = __importStar(require("readline"));
48
- // @ts-ignore
49
- const module_stream = __importStar(require("stream"));
50
- // @ts-ignore
51
- const module_string_decoder = __importStar(require("string_decoder"));
52
- const module_test = __importStar(require("test"));
53
- // @ts-ignore
54
- const module_url = __importStar(require("url"));
55
- // @ts-ignore
56
- const module_util = __importStar(require("util"));
40
+ const module_os = __importStar(require("./os"));
41
+ const module_process = __importStar(require("./process"));
42
+ const module_punycode = __importStar(require("punycode/"));
43
+ const module_querystring = __importStar(require("./querystring"));
57
44
  const web_only_globals_json_1 = __importDefault(require("./web_only_globals.json"));
58
- // todo: properly implement eval
59
- const ES_GLOBALS = { Infinity, NaN, undefined, eval, isFinite, isNaN, parseFloat, parseInt, decodeURI, decodeURIComponent, encodeURI, encodeURIComponent, escape, unescape, Object, Function, Boolean, Symbol, Error, AggregateError, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, Number, BigInt, Math, Date, String, RegExp, Array, Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, BigInt64Array, BigUint64Array, Float32Array, Float64Array, Map, Set, WeakMap, WeakSet, ArrayBuffer, SharedArrayBuffer, DataView, Atomics, JSON, WeakRef, FinalizationRegistry, Promise, Reflect, Proxy, Intl };
60
- const NODE_AND_WEB_GLOBALS = { AbortController, Blob, ByteLengthQueuingStrategy, atob, BroadcastChannel, btoa, clearInterval, clearTimeout, CloseEvent, CompressionStream, console, CountQueuingStrategy, Crypto, crypto, CryptoKey, CustomEvent, DecompressionStream, Event, EventSource, EventTarget, fetch, FormData, Headers, localStorage, MessageChannel, MessageEvent, MessagePort, Navigator, navigator, PerformanceEntry, PerformanceMark, PerformanceMeasure, PerformanceObserver, PerformanceObserverEntryList, performance, queueMicrotask, ReadableByteStreamController, Response, Request, sessionStorage, setInterval, setTimeout, Storage, structuredClone, SubtleCrypto, DOMException, TextDecoder, TextDecoderStream, TextEncoder, TextEncoderStream, TransformStreamDefaultController, URL, URLSearchParams, WebAssembly, WebSocket, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter };
45
+ const DEFAULT_GLOBALS = Object.defineProperties({}, Object.fromEntries(web_only_globals_json_1.default.map((name) => [name, { get() { throw new ReferenceError(`${name} is not defined`); } }])));
46
+ const BUILTIN_MODULES = [
47
+ ['os', module_os],
48
+ ['process', module_process],
49
+ ['querystring', module_querystring],
50
+ ['punycode', module_punycode],
51
+ ];
52
+ const DEFAULT_ENV = {
53
+ PATH: '/usr/local/bin:/usr/bin:/bin',
54
+ SHLVL: '1',
55
+ SHELL: '/bin/bash',
56
+ TERM: 'none',
57
+ PS1: '',
58
+ PS2: '> ',
59
+ HISTFILE: '~/.bash_history',
60
+ EDITOR: 'vim',
61
+ VISUAL: 'vim',
62
+ LANG: 'en_US.utf8',
63
+ HOSTNAME: 'fake-node',
64
+ TMPDIR: '/tmp',
65
+ };
61
66
  class Process {
62
67
  fakeNode;
63
68
  pid;
69
+ priority = 0;
70
+ uid = 0;
71
+ gid = 0;
72
+ groups = [];
73
+ cwd;
74
+ umask = 0o6440;
64
75
  argv = [];
65
76
  argv0 = '';
77
+ execArgv = [];
78
+ execArgv0 = '/usr/bin/local/node';
79
+ path;
66
80
  module;
67
81
  code;
68
- path;
69
82
  constructor(fakeNode, { path = '', code, module }) {
70
83
  this.fakeNode = fakeNode;
71
84
  this.pid = fakeNode.nextPid;
@@ -73,12 +86,16 @@ class Process {
73
86
  fakeNode.processes.set(this.pid, this);
74
87
  this.code = code;
75
88
  this.path = path;
89
+ this.cwd = path.split('/').slice(0, -1).join('/');
76
90
  this.module = module ?? false;
77
91
  }
92
+ get env() {
93
+ return this.fakeNode.getenv(this.pid);
94
+ }
78
95
  run() {
79
96
  let code;
80
97
  if (this.module) {
81
- code = `with(${this.fakeNode.globalName}.getGlobals(${this.pid})){__fakeNode_process__.fakeNode.modules.set('${this.module},(function(){${this.code};return module.exports;})());}`;
98
+ code = `with(${this.fakeNode.globalName}.getGlobals(${this.pid})){__fakeNode__.modules.set('${this.module},(function(){${this.code};return module.exports;})());}`;
82
99
  }
83
100
  else {
84
101
  code = `with(${this.fakeNode.globalName}.getGlobals(${this.pid})){(function(){${this.code}})();}`;
@@ -90,55 +107,39 @@ class Process {
90
107
  }
91
108
  exports.Process = Process;
92
109
  class FakeNode {
110
+ version = '0.3.0';
93
111
  static nextId = 0;
94
112
  id;
95
113
  globalName;
114
+ globalenv = DEFAULT_ENV;
96
115
  modules = new Map();
97
- builtinModules = new Map([
98
- ['assert', assert_1.default],
99
- ['buffer', module_buffer],
100
- ['path', module_path],
101
- ['punycode', module_punycode],
102
- ['querystring', module_querystring],
103
- ['readline', module_readline],
104
- ['stream', module_stream],
105
- ['string_decoder', module_string_decoder],
106
- ['test', module_test],
107
- ['url', module_url],
108
- ['util', module_util],
109
- ]);
110
116
  globals;
111
117
  processes = new Map();
112
118
  nextPid = 3;
113
119
  window = window;
120
+ errorCallbacks = [];
114
121
  constructor() {
115
122
  this.id = FakeNode.nextId;
116
123
  FakeNode.nextId++;
117
124
  this.globalName = '__fakeNode_' + this.id + '__';
118
125
  // @ts-ignore
119
126
  globalThis[this.globalName] = this;
120
- this.globals = { require: this.require, Buffer: module_buffer.Buffer };
121
- Object.assign(this.globals, ES_GLOBALS);
122
- for (const name of web_only_globals_json_1.default) {
123
- Object.defineProperty(this.globals, name, { get: () => { throw new ReferenceError(`${name} is not defined`); } });
127
+ this.globals = { __fakeNode__: this };
128
+ Object.assign(this.globals, DEFAULT_GLOBALS);
129
+ window.addEventListener('error', ({ error }) => this.onError(error));
130
+ window.addEventListener('unhandledrejection', ({ reason }) => reason instanceof Error ? this.onError(reason) : this.onError(new Error(String(reason))));
131
+ for (const [name, module] of BUILTIN_MODULES) {
132
+ this.addModuleFromValue(name, module);
133
+ this.addModuleFromValue('node:' + name, module);
134
+ this.addModuleFromValue('fake-node:' + name, module);
124
135
  }
125
- Object.assign(this.globals, NODE_AND_WEB_GLOBALS);
126
136
  }
127
137
  require(module) {
128
- if (module.startsWith('fake-node:')) {
129
- module = module.slice('fake-node:'.length);
130
- }
131
- else if (module.startsWith('node:')) {
132
- module = module.slice('node:'.length);
133
- }
134
138
  if (this.modules.has(module)) {
135
139
  return this.modules.get(module);
136
140
  }
137
- else if (this.builtinModules.has(module)) {
138
- return this.builtinModules.get(module);
139
- }
140
141
  else {
141
- throw new Error(`cannot find module '${name}'`);
142
+ throw new Error(`cannot find module '${module}'`);
142
143
  }
143
144
  }
144
145
  getGlobals(pid) {
@@ -146,10 +147,12 @@ class FakeNode {
146
147
  if (process === undefined) {
147
148
  throw new TypeError(`nonexistent PID in FakeNode.getGlobals call: ${pid}. If you do not know why this occured, it is probably a bug in fake-node. Please report it at https://github.com/speedydelete/fake-node/issues.`);
148
149
  }
149
- let scope = Object.create(this.globals);
150
+ let scope = {};
151
+ Object.assign(scope, this.globals);
150
152
  scope.global = scope;
151
153
  scope.globalThis = scope;
152
154
  scope.__fakeNode_process__ = process;
155
+ scope.require = this.require.bind(this);
153
156
  if (process.path !== '') {
154
157
  const pathParts = process.path.split('/');
155
158
  scope.__dirname = pathParts.slice(0, -1).join('/');
@@ -157,14 +160,76 @@ class FakeNode {
157
160
  }
158
161
  if (process.module !== false) {
159
162
  scope.module = {
160
- exports: {}
163
+ exports: {},
161
164
  };
165
+ // @ts-ignore
162
166
  scope.exports = scope.module.exports;
163
167
  }
164
168
  return scope;
165
169
  }
170
+ getenv(pid) {
171
+ let env = Object.create(this.globalenv);
172
+ const process = this.processes.get(pid);
173
+ if (process === undefined) {
174
+ throw new TypeError(`invalid PID: ${pid}`);
175
+ }
176
+ env.USER = this.getUserFromUID(process.uid);
177
+ return env;
178
+ }
166
179
  run(code) {
167
180
  (new Process(this, { code, path: '/' })).run();
168
181
  }
182
+ addModule(name, code) {
183
+ (new Process(this, { code, path: '/', module: name })).run();
184
+ }
185
+ addModuleFromValue(name, module) {
186
+ this.modules.set(name, module);
187
+ }
188
+ getUserFromUID(uid) {
189
+ if (typeof uid === 'string') {
190
+ return uid;
191
+ }
192
+ else {
193
+ return 'root';
194
+ }
195
+ }
196
+ getUserFromGID(gid) {
197
+ if (typeof gid === 'string') {
198
+ return gid;
199
+ }
200
+ else {
201
+ return 'root';
202
+ }
203
+ }
204
+ getUIDFromUser(user) {
205
+ if (typeof user === 'number') {
206
+ return user;
207
+ }
208
+ else {
209
+ return 0;
210
+ }
211
+ }
212
+ getGIDFromGroup(group) {
213
+ if (typeof group === 'number') {
214
+ return group;
215
+ }
216
+ else {
217
+ return 0;
218
+ }
219
+ }
220
+ onError(error) {
221
+ for (const callback of this.errorCallbacks) {
222
+ if (callback !== undefined) {
223
+ callback(error);
224
+ }
225
+ }
226
+ }
227
+ addErrorCallback(callback) {
228
+ this.errorCallbacks.push(callback);
229
+ return this.errorCallbacks.length - 1;
230
+ }
231
+ removeErrorCallback(callbackID) {
232
+ this.errorCallbacks[callbackID] = undefined;
233
+ }
169
234
  }
170
235
  exports.FakeNode = FakeNode;
package/lib/os.d.ts ADDED
@@ -0,0 +1,191 @@
1
+ export declare const EOL = "\n";
2
+ export declare function availableParallelism(): number;
3
+ export declare function arch(): string;
4
+ declare enum signals {
5
+ SIGHUP = 1,
6
+ SIGINT = 2,
7
+ SIGQUIT = 3,
8
+ SIGILL = 4,
9
+ SIGTRAP = 5,
10
+ SIGABRT = 6,
11
+ SIGIOT = 6,
12
+ SIGBUS = 7,
13
+ SIGFPE = 8,
14
+ SIGKILL = 9,
15
+ SIGUSR1 = 10,
16
+ SIGUSR2 = 11,
17
+ SIGSEGV = 12,
18
+ SIGPIPE = 13,
19
+ SIGALRM = 14,
20
+ SIGTERM = 15,
21
+ SIGCHLD = 16,
22
+ SIGSTKFLT = 17,
23
+ SIGCONT = 18,
24
+ SIGSTOP = 19,
25
+ SIGTSTP = 20,
26
+ SIGBREAK = 21,
27
+ SIGTTIN = 22,
28
+ SIGTTOU = 23,
29
+ SIGURG = 24,
30
+ SIGXCPU = 25,
31
+ SIGXFSZ = 26,
32
+ SIGVTALRM = 27,
33
+ SIGPROF = 28,
34
+ SIGWINCH = 29,
35
+ SIGIO = 30,
36
+ SIGPOLL = 30,
37
+ SIGLOST = 31,
38
+ SIGPWR = 32,
39
+ SIGINFO = 32,
40
+ SIGSYS = 33,
41
+ SIGUNUSED = 33
42
+ }
43
+ declare enum errno {
44
+ E2BIG = 0,
45
+ EACCES = 1,
46
+ EADDRINUSE = 2,
47
+ EADDRNONOTAVAIL = 3,
48
+ EAFNOSUPPORT = 4,
49
+ EAGAIN = 5,
50
+ EALREADY = 6,
51
+ EBADF = 7,
52
+ EBADMSG = 8,
53
+ EBUSY = 9,
54
+ ECANCELED = 10,
55
+ ECHILD = 11,
56
+ ECONNABORTED = 12,
57
+ ECONNREFUSED = 13,
58
+ ECONNRESET = 14,
59
+ EDEADLK = 15,
60
+ EDESTADDRREQ = 16,
61
+ EDOM = 17,
62
+ EDQUOT = 18,
63
+ EEXIST = 19,
64
+ EFAULT = 20,
65
+ EFBIG = 21,
66
+ EHOSTUNREACH = 22,
67
+ EIDRM = 23,
68
+ EILSEQ = 24,
69
+ EINPROGRESS = 25,
70
+ EINTR = 26,
71
+ EINVAL = 27,
72
+ EIO = 28,
73
+ EISCONN = 29,
74
+ EISDIR = 30,
75
+ ELOOP = 31,
76
+ EMFILE = 32,
77
+ EMLINK = 33,
78
+ EMGSIZE = 34,
79
+ EMULTIHOP = 35,
80
+ ENAMETOOLONG = 36,
81
+ ENETDOWN = 37,
82
+ ENETRESET = 38,
83
+ ENETUNREACH = 39,
84
+ ENFILE = 40,
85
+ ENOBUFS = 41,
86
+ ENODATA = 42,
87
+ ENODEV = 43,
88
+ ENOENT = 44,
89
+ ENOEXEC = 45,
90
+ ENOLCK = 46,
91
+ ENOLINK = 47,
92
+ ENOMEM = 48,
93
+ ENOMSG = 49,
94
+ ENOPROTOOPT = 50,
95
+ ENOSPC = 51,
96
+ ENOSR = 52,
97
+ ENOSTR = 53,
98
+ ENOSYS = 54,
99
+ ENOTCONN = 55,
100
+ ENOTDIR = 56,
101
+ ENOTEMPTY = 57,
102
+ ENOTSOCK = 58,
103
+ ENOTSUP = 59,
104
+ ENOTTY = 60,
105
+ ENXIO = 61,
106
+ EOPNOTSUPP = 62,
107
+ EOVERFLOW = 63,
108
+ EPERM = 64,
109
+ EPIPE = 65,
110
+ EPROTO = 66,
111
+ EPROTONOSUPPORT = 67,
112
+ EPROTOTYPE = 68,
113
+ ERANGE = 69,
114
+ EROFS = 70,
115
+ ESPIPE = 71,
116
+ ESRCH = 72,
117
+ ESTALE = 73,
118
+ ETIME = 74,
119
+ ETIMEDOUT = 75,
120
+ ETXTBSY = 76,
121
+ EWOULDBLOCK = 77,
122
+ EXDEV = 78
123
+ }
124
+ declare enum dlopen {
125
+ RTLD_LAZY = 1,
126
+ RTLD_NOW = 2,
127
+ RTLD_GLOBAL = 3,
128
+ RTLD_LOCAL = 4,
129
+ RTLD_DEEPBIND = 5
130
+ }
131
+ declare enum priority {
132
+ PRIORITY_LOW = 1,
133
+ PRIORITY_BELOW_NORMAL = 2,
134
+ PRIORITY_NORMAL = 3,
135
+ PRIORITY_ABOVE_NORMAL = 4,
136
+ PRIORITY_HIGH = 5,
137
+ PRIORITY_HIGHEST = 6
138
+ }
139
+ export declare const constants: {
140
+ signals: typeof signals;
141
+ errno: typeof errno;
142
+ dlopen: typeof dlopen;
143
+ priority: typeof priority;
144
+ };
145
+ export declare function cpus(): {
146
+ model: string;
147
+ speed: number;
148
+ times: {
149
+ user: number;
150
+ nice: number;
151
+ sys: number;
152
+ idle: number;
153
+ irq: number;
154
+ };
155
+ }[];
156
+ export declare const devNull = "/dev/null";
157
+ export declare function endianness(): string;
158
+ export declare function freemem(): number;
159
+ export declare function getPriority(pid?: number): number;
160
+ export declare function homedir(): string;
161
+ export declare function hostname(): string;
162
+ export declare function loadavg(): [number, number, number];
163
+ export declare function machine(): string;
164
+ export declare function networkInterfaces(): {
165
+ [key: string]: {
166
+ address: string;
167
+ netmask: string;
168
+ family: 'IPV4' | 'IPV6';
169
+ mac: string;
170
+ internal: boolean;
171
+ scopeid: number;
172
+ cidr: string;
173
+ };
174
+ };
175
+ export declare function platform(): string;
176
+ export declare function release(): string;
177
+ export declare function setPriority(priority: number): void;
178
+ export declare function setPriority(pid: number, priority: number): void;
179
+ export declare function tmpdir(): string;
180
+ export declare function totalmem(): number;
181
+ export declare function type(): string;
182
+ export declare function uptime(): number;
183
+ export declare function userInfo(): {
184
+ username: string;
185
+ uid: number;
186
+ gid: number;
187
+ shell: string;
188
+ homedir: string;
189
+ };
190
+ export declare function version(): string;
191
+ export {};