@nudojs/env 0.1.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/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@nudojs/env",
3
+ "version": "0.1.0",
4
+ "description": "ES standard, Web platform, and Node.js API type definitions for the Nudo inference engine",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "exports": {
8
+ "./es": "./src/es.ts",
9
+ "./web": "./src/web.ts",
10
+ "./node": "./src/node.ts"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/nudojs/nudo.git",
15
+ "directory": "packages/env"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public",
19
+ "provenance": true,
20
+ "registry": "https://registry.npmjs.org"
21
+ },
22
+ "dependencies": {
23
+ "@nudojs/core": "workspace:*"
24
+ },
25
+ "scripts": {
26
+ "build": "tsup src/es.ts src/web.ts src/node.ts --format esm --dts"
27
+ }
28
+ }
package/src/es.ts ADDED
@@ -0,0 +1,252 @@
1
+ import { type TypeValue, type SigImpl, T } from "@nudojs/core";
2
+
3
+ export type EnvDefinition = {
4
+ globals: Record<string, TypeValue>;
5
+ modules?: Record<string, Record<string, TypeValue>>;
6
+ };
7
+
8
+ function litNum(tv: TypeValue): number | undefined {
9
+ return tv.kind === "literal" && typeof tv.value === "number" ? tv.value : undefined;
10
+ }
11
+
12
+ function litStr(tv: TypeValue): string | undefined {
13
+ return tv.kind === "literal" && typeof tv.value === "string" ? tv.value : undefined;
14
+ }
15
+
16
+ function numImpl1(fn: (a: number) => number): SigImpl {
17
+ return (args) => {
18
+ const a = litNum(args[0]);
19
+ return a !== undefined ? T.literal(fn(a)) : undefined;
20
+ };
21
+ }
22
+
23
+ function numImpl2(fn: (a: number, b: number) => number): SigImpl {
24
+ return (args) => {
25
+ const a = litNum(args[0]);
26
+ const b = litNum(args[1]);
27
+ return a !== undefined && b !== undefined ? T.literal(fn(a, b)) : undefined;
28
+ };
29
+ }
30
+
31
+ function strToStrImpl(fn: (s: string) => string): SigImpl {
32
+ return (args) => {
33
+ const s = litStr(args[0]);
34
+ return s !== undefined ? T.literal(fn(s)) : undefined;
35
+ };
36
+ }
37
+
38
+ export function defineEnv(): EnvDefinition {
39
+ const voidFn = T.fnSig([T.unknown], T.undefined);
40
+
41
+ const consoleMethods: Record<string, TypeValue> = {};
42
+ for (const name of ["log", "error", "warn", "info", "debug", "trace", "dir", "table", "time", "timeEnd", "timeLog", "clear", "count", "countReset", "group", "groupCollapsed", "groupEnd", "assert"]) {
43
+ consoleMethods[name] = voidFn;
44
+ }
45
+
46
+ const jsonStringifyImpl: SigImpl = (args) => {
47
+ const v = args[0];
48
+ if (v.kind === "literal") {
49
+ try {
50
+ const result = JSON.stringify(v.value);
51
+ return result === undefined ? T.undefined : T.literal(result);
52
+ } catch { /* fallback */ }
53
+ }
54
+ return undefined;
55
+ };
56
+
57
+ const parseIntImpl: SigImpl = (args) => {
58
+ const s = litStr(args[0]);
59
+ const radix = args[1] !== undefined ? litNum(args[1]) : 10;
60
+ if (s !== undefined && radix !== undefined) {
61
+ const result = parseInt(s, radix);
62
+ return Number.isNaN(result) ? T.literal(NaN) : T.literal(result);
63
+ }
64
+ return undefined;
65
+ };
66
+
67
+ const parseFloatImpl: SigImpl = (args) => {
68
+ const s = litStr(args[0]);
69
+ if (s !== undefined) {
70
+ const result = parseFloat(s);
71
+ return T.literal(result);
72
+ }
73
+ return undefined;
74
+ };
75
+
76
+ const isNaNImpl: SigImpl = (args) => {
77
+ const v = args[0];
78
+ if (v.kind === "literal" && typeof v.value === "number") return T.literal(Number.isNaN(v.value));
79
+ return undefined;
80
+ };
81
+
82
+ const isFiniteImpl: SigImpl = (args) => {
83
+ const v = args[0];
84
+ if (v.kind === "literal" && typeof v.value === "number") return T.literal(Number.isFinite(v.value));
85
+ return undefined;
86
+ };
87
+
88
+ return {
89
+ globals: {
90
+ // --- JSON ---
91
+ JSON: T.object({
92
+ parse: T.fnSig([T.string], T.unknown, T.instanceOf("SyntaxError")),
93
+ stringify: T.fnSig([T.unknown], T.union(T.string, T.undefined), T.never, jsonStringifyImpl),
94
+ }),
95
+
96
+ // --- Math ---
97
+ Math: T.object({
98
+ abs: T.fnSig([T.number], T.number, T.never, numImpl1(Math.abs)),
99
+ ceil: T.fnSig([T.number], T.number, T.never, numImpl1(Math.ceil)),
100
+ floor: T.fnSig([T.number], T.number, T.never, numImpl1(Math.floor)),
101
+ round: T.fnSig([T.number], T.number, T.never, numImpl1(Math.round)),
102
+ trunc: T.fnSig([T.number], T.number, T.never, numImpl1(Math.trunc)),
103
+ sign: T.fnSig([T.number], T.number, T.never, numImpl1(Math.sign)),
104
+ max: T.fnSig([T.number, T.number], T.number, T.never, numImpl2(Math.max)),
105
+ min: T.fnSig([T.number, T.number], T.number, T.never, numImpl2(Math.min)),
106
+ pow: T.fnSig([T.number, T.number], T.number, T.never, numImpl2(Math.pow)),
107
+ sqrt: T.fnSig([T.number], T.number, T.never, numImpl1(Math.sqrt)),
108
+ cbrt: T.fnSig([T.number], T.number, T.never, numImpl1(Math.cbrt)),
109
+ log: T.fnSig([T.number], T.number, T.never, numImpl1(Math.log)),
110
+ log2: T.fnSig([T.number], T.number, T.never, numImpl1(Math.log2)),
111
+ log10: T.fnSig([T.number], T.number, T.never, numImpl1(Math.log10)),
112
+ exp: T.fnSig([T.number], T.number, T.never, numImpl1(Math.exp)),
113
+ random: T.fnSig([], T.number),
114
+ sin: T.fnSig([T.number], T.number, T.never, numImpl1(Math.sin)),
115
+ cos: T.fnSig([T.number], T.number, T.never, numImpl1(Math.cos)),
116
+ tan: T.fnSig([T.number], T.number, T.never, numImpl1(Math.tan)),
117
+ asin: T.fnSig([T.number], T.number, T.never, numImpl1(Math.asin)),
118
+ acos: T.fnSig([T.number], T.number, T.never, numImpl1(Math.acos)),
119
+ atan: T.fnSig([T.number], T.number, T.never, numImpl1(Math.atan)),
120
+ atan2: T.fnSig([T.number, T.number], T.number, T.never, numImpl2(Math.atan2)),
121
+ hypot: T.fnSig([T.number, T.number], T.number, T.never, numImpl2(Math.hypot)),
122
+ clz32: T.fnSig([T.number], T.number, T.never, numImpl1(Math.clz32)),
123
+ imul: T.fnSig([T.number, T.number], T.number, T.never, numImpl2(Math.imul)),
124
+ fround: T.fnSig([T.number], T.number, T.never, numImpl1(Math.fround)),
125
+ PI: T.number,
126
+ E: T.number,
127
+ LN2: T.number,
128
+ LN10: T.number,
129
+ LOG2E: T.number,
130
+ LOG10E: T.number,
131
+ SQRT2: T.number,
132
+ SQRT1_2: T.number,
133
+ }),
134
+
135
+ // --- Number ---
136
+ Number: T.object({
137
+ isFinite: T.fnSig([T.unknown], T.boolean, T.never, isFiniteImpl),
138
+ isInteger: T.fnSig([T.unknown], T.boolean, T.never, (args) => {
139
+ const v = args[0];
140
+ if (v.kind === "literal" && typeof v.value === "number") return T.literal(Number.isInteger(v.value));
141
+ return undefined;
142
+ }),
143
+ isNaN: T.fnSig([T.unknown], T.boolean, T.never, isNaNImpl),
144
+ isSafeInteger: T.fnSig([T.unknown], T.boolean, T.never, (args) => {
145
+ const v = args[0];
146
+ if (v.kind === "literal" && typeof v.value === "number") return T.literal(Number.isSafeInteger(v.value));
147
+ return undefined;
148
+ }),
149
+ parseFloat: T.fnSig([T.string], T.number, T.never, parseFloatImpl),
150
+ parseInt: T.fnSig([T.string], T.number, T.never, parseIntImpl),
151
+ MAX_SAFE_INTEGER: T.number,
152
+ MIN_SAFE_INTEGER: T.number,
153
+ MAX_VALUE: T.number,
154
+ MIN_VALUE: T.number,
155
+ POSITIVE_INFINITY: T.number,
156
+ NEGATIVE_INFINITY: T.number,
157
+ NaN: T.number,
158
+ EPSILON: T.number,
159
+ }),
160
+
161
+ // --- Boolean ---
162
+ Boolean: T.fnSig([T.unknown], T.boolean, T.never, (args) => {
163
+ const v = args[0];
164
+ if (v.kind === "literal") return T.literal(Boolean(v.value));
165
+ return undefined;
166
+ }),
167
+
168
+ // --- String ---
169
+ String: T.fnSig([T.unknown], T.string, T.never, (args) => {
170
+ const v = args[0];
171
+ if (v.kind === "literal" && v.value !== null && v.value !== undefined) return T.literal(String(v.value));
172
+ return undefined;
173
+ }),
174
+
175
+ // --- Array ---
176
+ Array: T.object({
177
+ isArray: T.fnSig([T.unknown], T.boolean, T.never, (args) => {
178
+ const v = args[0];
179
+ if (v.kind === "array" || v.kind === "tuple") return T.literal(true);
180
+ if (v.kind === "literal" || v.kind === "primitive" || v.kind === "object") return T.literal(false);
181
+ return undefined;
182
+ }),
183
+ from: T.fnSig([T.unknown], T.array(T.unknown)),
184
+ of: T.fnSig([T.unknown], T.array(T.unknown)),
185
+ }),
186
+
187
+ // --- console ---
188
+ console: T.object(consoleMethods),
189
+
190
+ // --- Global functions ---
191
+ parseInt: T.fnSig([T.string, T.number], T.number, T.never, parseIntImpl),
192
+ parseFloat: T.fnSig([T.string], T.number, T.never, parseFloatImpl),
193
+ isNaN: T.fnSig([T.unknown], T.boolean, T.never, isNaNImpl),
194
+ isFinite: T.fnSig([T.unknown], T.boolean, T.never, isFiniteImpl),
195
+ encodeURI: T.fnSig([T.string], T.string, T.never, strToStrImpl(encodeURI)),
196
+ decodeURI: T.fnSig([T.string], T.string, T.instanceOf("URIError"), strToStrImpl(decodeURI)),
197
+ encodeURIComponent: T.fnSig([T.string], T.string, T.never, strToStrImpl(encodeURIComponent)),
198
+ decodeURIComponent: T.fnSig([T.string], T.string, T.instanceOf("URIError"), strToStrImpl(decodeURIComponent)),
199
+
200
+ // --- Error constructors ---
201
+ Error: T.fnSig([T.string], T.instanceOf("Error")),
202
+ TypeError: T.fnSig([T.string], T.instanceOf("TypeError")),
203
+ RangeError: T.fnSig([T.string], T.instanceOf("RangeError")),
204
+ SyntaxError: T.fnSig([T.string], T.instanceOf("SyntaxError")),
205
+ ReferenceError: T.fnSig([T.string], T.instanceOf("ReferenceError")),
206
+ URIError: T.fnSig([T.string], T.instanceOf("URIError")),
207
+
208
+ // --- Promise ---
209
+ Promise: T.object({
210
+ resolve: T.fnSig([T.unknown], T.promise(T.unknown), T.never, (args) => T.promise(args[0])),
211
+ reject: T.fnSig([T.unknown], T.promise(T.never)),
212
+ all: T.fnSig([T.array(T.promise(T.unknown))], T.promise(T.array(T.unknown))),
213
+ allSettled: T.fnSig([T.array(T.promise(T.unknown))], T.promise(T.array(T.unknown))),
214
+ race: T.fnSig([T.array(T.promise(T.unknown))], T.promise(T.unknown)),
215
+ any: T.fnSig([T.array(T.promise(T.unknown))], T.promise(T.unknown)),
216
+ }),
217
+
218
+ // --- Date ---
219
+ Date: T.object({
220
+ now: T.fnSig([], T.number),
221
+ parse: T.fnSig([T.string], T.number),
222
+ UTC: T.fnSig([T.number, T.number], T.number),
223
+ }),
224
+
225
+ // --- Symbol ---
226
+ Symbol: T.fnSig([T.string], T.symbol),
227
+
228
+ // --- Reflect ---
229
+ Reflect: T.object({
230
+ apply: T.fnSig([T.unknown, T.unknown, T.array(T.unknown)], T.unknown),
231
+ construct: T.fnSig([T.unknown, T.array(T.unknown)], T.unknown),
232
+ defineProperty: T.fnSig([T.unknown, T.string, T.unknown], T.boolean),
233
+ deleteProperty: T.fnSig([T.unknown, T.string], T.boolean),
234
+ get: T.fnSig([T.unknown, T.string], T.unknown),
235
+ getOwnPropertyDescriptor: T.fnSig([T.unknown, T.string], T.union(T.unknown, T.undefined)),
236
+ getPrototypeOf: T.fnSig([T.unknown], T.union(T.unknown, T.null)),
237
+ has: T.fnSig([T.unknown, T.string], T.boolean),
238
+ isExtensible: T.fnSig([T.unknown], T.boolean),
239
+ ownKeys: T.fnSig([T.unknown], T.array(T.string)),
240
+ preventExtensions: T.fnSig([T.unknown], T.boolean),
241
+ set: T.fnSig([T.unknown, T.string, T.unknown], T.boolean),
242
+ setPrototypeOf: T.fnSig([T.unknown, T.unknown], T.boolean),
243
+ }),
244
+
245
+ // --- globalThis ---
246
+ globalThis: T.unknown,
247
+ undefined: T.undefined,
248
+ NaN: T.number,
249
+ Infinity: T.number,
250
+ },
251
+ };
252
+ }
package/src/node.ts ADDED
@@ -0,0 +1,386 @@
1
+ import { type TypeValue, type SigImpl, T } from "@nudojs/core";
2
+ import { type EnvDefinition, defineEnv as defineEsEnv } from "./es.ts";
3
+ import nodePath from "node:path";
4
+
5
+ export type { EnvDefinition };
6
+
7
+ function litStr(tv: TypeValue): string | undefined {
8
+ return tv.kind === "literal" && typeof tv.value === "string" ? tv.value : undefined;
9
+ }
10
+
11
+ function allLitStr(args: TypeValue[]): string[] | undefined {
12
+ const result: string[] = [];
13
+ for (const a of args) {
14
+ const s = litStr(a);
15
+ if (s === undefined) return undefined;
16
+ result.push(s);
17
+ }
18
+ return result;
19
+ }
20
+
21
+ export function defineEnv(): EnvDefinition {
22
+ const esEnv = defineEsEnv();
23
+
24
+ const BufferInstance = T.instanceOf("Buffer", {
25
+ toString: T.fnSig([T.string], T.string),
26
+ toJSON: T.fnSig([], T.object({ type: T.string, data: T.array(T.number) })),
27
+ length: T.number,
28
+ slice: T.fnSig([T.number, T.number], T.instanceOf("Buffer")),
29
+ copy: T.fnSig([T.unknown, T.number, T.number, T.number], T.number),
30
+ write: T.fnSig([T.string, T.number, T.number, T.string], T.number),
31
+ readUInt8: T.fnSig([T.number], T.number),
32
+ readUInt16BE: T.fnSig([T.number], T.number),
33
+ readUInt16LE: T.fnSig([T.number], T.number),
34
+ readUInt32BE: T.fnSig([T.number], T.number),
35
+ readUInt32LE: T.fnSig([T.number], T.number),
36
+ readInt8: T.fnSig([T.number], T.number),
37
+ readInt16BE: T.fnSig([T.number], T.number),
38
+ readInt16LE: T.fnSig([T.number], T.number),
39
+ readInt32BE: T.fnSig([T.number], T.number),
40
+ readInt32LE: T.fnSig([T.number], T.number),
41
+ includes: T.fnSig([T.union(T.string, T.number)], T.boolean),
42
+ indexOf: T.fnSig([T.union(T.string, T.number)], T.number),
43
+ fill: T.fnSig([T.union(T.string, T.number)], T.instanceOf("Buffer")),
44
+ equals: T.fnSig([T.instanceOf("Buffer")], T.boolean),
45
+ compare: T.fnSig([T.instanceOf("Buffer")], T.number),
46
+ subarray: T.fnSig([T.number, T.number], T.instanceOf("Buffer")),
47
+ });
48
+
49
+ // --- fs module ---
50
+ const fsModule: Record<string, TypeValue> = {
51
+ readFileSync: T.fnSig([T.string, T.union(T.string, T.object({}))], T.union(T.string, BufferInstance)),
52
+ writeFileSync: T.fnSig([T.string, T.union(T.string, BufferInstance)], T.undefined),
53
+ appendFileSync: T.fnSig([T.string, T.union(T.string, BufferInstance)], T.undefined),
54
+ existsSync: T.fnSig([T.string], T.boolean),
55
+ mkdirSync: T.fnSig([T.string, T.unknown], T.union(T.string, T.undefined)),
56
+ rmdirSync: T.fnSig([T.string], T.undefined),
57
+ rmSync: T.fnSig([T.string, T.unknown], T.undefined),
58
+ unlinkSync: T.fnSig([T.string], T.undefined),
59
+ renameSync: T.fnSig([T.string, T.string], T.undefined),
60
+ copyFileSync: T.fnSig([T.string, T.string], T.undefined),
61
+ statSync: T.fnSig([T.string], T.object({
62
+ isFile: T.fnSig([], T.boolean),
63
+ isDirectory: T.fnSig([], T.boolean),
64
+ isSymbolicLink: T.fnSig([], T.boolean),
65
+ size: T.number,
66
+ mtime: T.unknown,
67
+ ctime: T.unknown,
68
+ atime: T.unknown,
69
+ birthtime: T.unknown,
70
+ mode: T.number,
71
+ uid: T.number,
72
+ gid: T.number,
73
+ })),
74
+ readdirSync: T.fnSig([T.string, T.unknown], T.array(T.union(T.string, T.unknown))),
75
+ realpathSync: T.fnSig([T.string], T.string),
76
+ readlinkSync: T.fnSig([T.string], T.string),
77
+ symlinkSync: T.fnSig([T.string, T.string], T.undefined),
78
+ chmodSync: T.fnSig([T.string, T.number], T.undefined),
79
+ chownSync: T.fnSig([T.string, T.number, T.number], T.undefined),
80
+ accessSync: T.fnSig([T.string, T.number], T.undefined),
81
+ readFile: T.fnSig([T.string, T.unknown], T.promise(T.union(T.string, BufferInstance))),
82
+ writeFile: T.fnSig([T.string, T.union(T.string, BufferInstance)], T.promise(T.undefined)),
83
+ mkdir: T.fnSig([T.string, T.unknown], T.promise(T.union(T.string, T.undefined))),
84
+ rm: T.fnSig([T.string, T.unknown], T.promise(T.undefined)),
85
+ stat: T.fnSig([T.string], T.promise(T.unknown)),
86
+ readdir: T.fnSig([T.string, T.unknown], T.promise(T.array(T.unknown))),
87
+ access: T.fnSig([T.string, T.number], T.promise(T.undefined)),
88
+ };
89
+
90
+ // --- path module ---
91
+ const strImpl1 = (fn: (a: string) => string): SigImpl => (args) => {
92
+ const a = litStr(args[0]);
93
+ return a !== undefined ? T.literal(fn(a)) : undefined;
94
+ };
95
+
96
+ const pathModule: Record<string, TypeValue> = {
97
+ join: T.fnSig([T.string, T.string], T.string, T.never, (args) => {
98
+ const strs = allLitStr(args);
99
+ return strs ? T.literal(nodePath.join(...strs)) : undefined;
100
+ }),
101
+ resolve: T.fnSig([T.string], T.string, T.never, (args) => {
102
+ const strs = allLitStr(args);
103
+ return strs ? T.literal(nodePath.resolve(...strs)) : undefined;
104
+ }),
105
+ dirname: T.fnSig([T.string], T.string, T.never, strImpl1(nodePath.dirname)),
106
+ basename: T.fnSig([T.string, T.string], T.string, T.never, (args) => {
107
+ const p = litStr(args[0]);
108
+ if (p === undefined) return undefined;
109
+ const ext = args[1] !== undefined ? litStr(args[1]) : undefined;
110
+ return T.literal(ext !== undefined ? nodePath.basename(p, ext) : nodePath.basename(p));
111
+ }),
112
+ extname: T.fnSig([T.string], T.string, T.never, strImpl1(nodePath.extname)),
113
+ relative: T.fnSig([T.string, T.string], T.string, T.never, (args) => {
114
+ const from = litStr(args[0]);
115
+ const to = litStr(args[1]);
116
+ return from !== undefined && to !== undefined ? T.literal(nodePath.relative(from, to)) : undefined;
117
+ }),
118
+ normalize: T.fnSig([T.string], T.string, T.never, strImpl1(nodePath.normalize)),
119
+ isAbsolute: T.fnSig([T.string], T.boolean, T.never, (args) => {
120
+ const p = litStr(args[0]);
121
+ return p !== undefined ? T.literal(nodePath.isAbsolute(p)) : undefined;
122
+ }),
123
+ parse: T.fnSig([T.string], T.object({
124
+ root: T.string,
125
+ dir: T.string,
126
+ base: T.string,
127
+ ext: T.string,
128
+ name: T.string,
129
+ }), T.never, (args) => {
130
+ const p = litStr(args[0]);
131
+ if (p === undefined) return undefined;
132
+ const parsed = nodePath.parse(p);
133
+ return T.object({
134
+ root: T.literal(parsed.root),
135
+ dir: T.literal(parsed.dir),
136
+ base: T.literal(parsed.base),
137
+ ext: T.literal(parsed.ext),
138
+ name: T.literal(parsed.name),
139
+ });
140
+ }),
141
+ format: T.fnSig([T.object({})], T.string),
142
+ sep: T.string,
143
+ delimiter: T.string,
144
+ posix: T.unknown,
145
+ win32: T.unknown,
146
+ };
147
+
148
+ // --- os module ---
149
+ const osModule: Record<string, TypeValue> = {
150
+ platform: T.fnSig([], T.string),
151
+ arch: T.fnSig([], T.string),
152
+ type: T.fnSig([], T.string),
153
+ release: T.fnSig([], T.string),
154
+ hostname: T.fnSig([], T.string),
155
+ homedir: T.fnSig([], T.string),
156
+ tmpdir: T.fnSig([], T.string),
157
+ cpus: T.fnSig([], T.array(T.object({
158
+ model: T.string,
159
+ speed: T.number,
160
+ }))),
161
+ totalmem: T.fnSig([], T.number),
162
+ freemem: T.fnSig([], T.number),
163
+ uptime: T.fnSig([], T.number),
164
+ loadavg: T.fnSig([], T.tuple([T.number, T.number, T.number])),
165
+ networkInterfaces: T.fnSig([], T.unknown),
166
+ userInfo: T.fnSig([], T.object({
167
+ username: T.string,
168
+ uid: T.number,
169
+ gid: T.number,
170
+ shell: T.union(T.string, T.null),
171
+ homedir: T.string,
172
+ })),
173
+ EOL: T.string,
174
+ };
175
+
176
+ // --- url module ---
177
+ const nodeUrlObj = T.object({
178
+ href: T.string,
179
+ origin: T.string,
180
+ protocol: T.string,
181
+ username: T.string,
182
+ password: T.string,
183
+ host: T.string,
184
+ hostname: T.string,
185
+ port: T.string,
186
+ pathname: T.string,
187
+ search: T.string,
188
+ hash: T.string,
189
+ toString: T.fnSig([], T.string),
190
+ toJSON: T.fnSig([], T.string),
191
+ });
192
+
193
+ const urlModule: Record<string, TypeValue> = {
194
+ URL: T.fnSig([T.string, T.string], nodeUrlObj, T.instanceOf("TypeError"), (args) => {
195
+ const href = litStr(args[0]);
196
+ const base = args[1] !== undefined ? litStr(args[1]) : undefined;
197
+ if (href === undefined) return undefined;
198
+ try {
199
+ const url = base !== undefined ? new URL(href, base) : new URL(href);
200
+ return T.object({
201
+ href: T.literal(url.href),
202
+ origin: T.literal(url.origin),
203
+ protocol: T.literal(url.protocol),
204
+ username: T.literal(url.username),
205
+ password: T.literal(url.password),
206
+ host: T.literal(url.host),
207
+ hostname: T.literal(url.hostname),
208
+ port: T.literal(url.port),
209
+ pathname: T.literal(url.pathname),
210
+ search: T.literal(url.search),
211
+ hash: T.literal(url.hash),
212
+ toString: T.fnSig([], T.string, T.never, () => T.literal(url.href)),
213
+ toJSON: T.fnSig([], T.string, T.never, () => T.literal(url.href)),
214
+ });
215
+ } catch { return undefined; }
216
+ }),
217
+ URLSearchParams: T.fnSig([T.unknown], T.object({
218
+ get: T.fnSig([T.string], T.union(T.string, T.null)),
219
+ has: T.fnSig([T.string], T.boolean),
220
+ set: T.fnSig([T.string, T.string], T.undefined),
221
+ append: T.fnSig([T.string, T.string], T.undefined),
222
+ delete: T.fnSig([T.string], T.undefined),
223
+ toString: T.fnSig([], T.string),
224
+ })),
225
+ fileURLToPath: T.fnSig([T.string], T.string, T.never, strImpl1((s) => {
226
+ try { return new URL(s).pathname; } catch { return s; }
227
+ })),
228
+ pathToFileURL: T.fnSig([T.string], T.object({ href: T.string }), T.never, (args) => {
229
+ const p = litStr(args[0]);
230
+ if (p === undefined) return undefined;
231
+ try {
232
+ const href = `file://${p.startsWith("/") ? "" : "/"}${p}`;
233
+ return T.object({ href: T.literal(href) });
234
+ } catch { return undefined; }
235
+ }),
236
+ format: T.fnSig([T.unknown], T.string),
237
+ };
238
+
239
+ // --- crypto module ---
240
+ const cryptoModule: Record<string, TypeValue> = {
241
+ randomBytes: T.fnSig([T.number], BufferInstance),
242
+ randomUUID: T.fnSig([], T.string),
243
+ randomInt: T.fnSig([T.number, T.number], T.number),
244
+ createHash: T.fnSig([T.string], T.object({
245
+ update: T.fnSig([T.union(T.string, BufferInstance)], T.unknown),
246
+ digest: T.fnSig([T.string], T.union(T.string, BufferInstance)),
247
+ })),
248
+ createHmac: T.fnSig([T.string, T.union(T.string, BufferInstance)], T.object({
249
+ update: T.fnSig([T.union(T.string, BufferInstance)], T.unknown),
250
+ digest: T.fnSig([T.string], T.union(T.string, BufferInstance)),
251
+ })),
252
+ createCipheriv: T.fnSig([T.string, T.unknown, T.unknown], T.unknown),
253
+ createDecipheriv: T.fnSig([T.string, T.unknown, T.unknown], T.unknown),
254
+ pbkdf2Sync: T.fnSig([T.string, T.string, T.number, T.number, T.string], BufferInstance),
255
+ scryptSync: T.fnSig([T.string, T.string, T.number], BufferInstance),
256
+ timingSafeEqual: T.fnSig([BufferInstance, BufferInstance], T.boolean),
257
+ };
258
+
259
+ // --- child_process module ---
260
+ const childProcessModule: Record<string, TypeValue> = {
261
+ execSync: T.fnSig([T.string, T.unknown], T.union(T.string, BufferInstance)),
262
+ execFileSync: T.fnSig([T.string, T.array(T.string), T.unknown], T.union(T.string, BufferInstance)),
263
+ spawnSync: T.fnSig([T.string, T.array(T.string), T.unknown], T.object({
264
+ status: T.union(T.number, T.null),
265
+ stdout: T.union(T.string, BufferInstance),
266
+ stderr: T.union(T.string, BufferInstance),
267
+ error: T.union(T.instanceOf("Error"), T.undefined),
268
+ })),
269
+ exec: T.fnSig([T.string, T.unknown], T.unknown),
270
+ spawn: T.fnSig([T.string, T.array(T.string), T.unknown], T.unknown),
271
+ fork: T.fnSig([T.string, T.array(T.string), T.unknown], T.unknown),
272
+ };
273
+
274
+ // --- util module ---
275
+ const utilModule: Record<string, TypeValue> = {
276
+ promisify: T.fnSig([T.unknown], T.unknown),
277
+ inspect: T.fnSig([T.unknown, T.unknown], T.string),
278
+ format: T.fnSig([T.string], T.string),
279
+ types: T.object({
280
+ isDate: T.fnSig([T.unknown], T.boolean),
281
+ isRegExp: T.fnSig([T.unknown], T.boolean),
282
+ isPromise: T.fnSig([T.unknown], T.boolean),
283
+ isArrayBuffer: T.fnSig([T.unknown], T.boolean),
284
+ isTypedArray: T.fnSig([T.unknown], T.boolean),
285
+ }),
286
+ TextEncoder: T.fnSig([], T.object({
287
+ encode: T.fnSig([T.string], T.unknown),
288
+ })),
289
+ TextDecoder: T.fnSig([T.string], T.object({
290
+ decode: T.fnSig([T.unknown], T.string),
291
+ })),
292
+ };
293
+
294
+ const nodeGlobals: Record<string, TypeValue> = {
295
+ process: T.object({
296
+ env: T.object({}),
297
+ argv: T.array(T.string),
298
+ argv0: T.string,
299
+ execArgv: T.array(T.string),
300
+ execPath: T.string,
301
+ cwd: T.fnSig([], T.string),
302
+ chdir: T.fnSig([T.string], T.undefined),
303
+ exit: T.fnSig([T.number], T.never),
304
+ pid: T.number,
305
+ ppid: T.number,
306
+ platform: T.string,
307
+ arch: T.string,
308
+ version: T.string,
309
+ versions: T.object({}),
310
+ stdout: T.object({ write: T.fnSig([T.string], T.boolean) }),
311
+ stderr: T.object({ write: T.fnSig([T.string], T.boolean) }),
312
+ stdin: T.object({ on: T.fnSig([T.string, T.unknown], T.unknown) }),
313
+ hrtime: T.object({
314
+ bigint: T.fnSig([], T.bigint),
315
+ }),
316
+ memoryUsage: T.fnSig([], T.object({
317
+ rss: T.number,
318
+ heapTotal: T.number,
319
+ heapUsed: T.number,
320
+ external: T.number,
321
+ arrayBuffers: T.number,
322
+ })),
323
+ cpuUsage: T.fnSig([], T.object({ user: T.number, system: T.number })),
324
+ uptime: T.fnSig([], T.number),
325
+ nextTick: T.fnSig([T.unknown], T.undefined),
326
+ on: T.fnSig([T.string, T.unknown], T.unknown),
327
+ once: T.fnSig([T.string, T.unknown], T.unknown),
328
+ off: T.fnSig([T.string, T.unknown], T.unknown),
329
+ emit: T.fnSig([T.string], T.boolean),
330
+ }),
331
+
332
+ Buffer: T.object({
333
+ from: T.fnSig([T.union(T.string, T.array(T.number))], BufferInstance),
334
+ alloc: T.fnSig([T.number], BufferInstance),
335
+ allocUnsafe: T.fnSig([T.number], BufferInstance),
336
+ isBuffer: T.fnSig([T.unknown], T.boolean),
337
+ byteLength: T.fnSig([T.union(T.string, BufferInstance)], T.number),
338
+ concat: T.fnSig([T.array(BufferInstance)], BufferInstance),
339
+ compare: T.fnSig([BufferInstance, BufferInstance], T.number),
340
+ }),
341
+
342
+ __dirname: T.string,
343
+ __filename: T.string,
344
+
345
+ setTimeout: T.fnSig([T.unknown, T.number], T.unknown),
346
+ setInterval: T.fnSig([T.unknown, T.number], T.unknown),
347
+ setImmediate: T.fnSig([T.unknown], T.unknown),
348
+ clearTimeout: T.fnSig([T.unknown], T.undefined),
349
+ clearInterval: T.fnSig([T.unknown], T.undefined),
350
+ clearImmediate: T.fnSig([T.unknown], T.undefined),
351
+ queueMicrotask: T.fnSig([T.unknown], T.undefined),
352
+
353
+ structuredClone: T.fnSig([T.unknown], T.unknown),
354
+ };
355
+
356
+ const modules: Record<string, Record<string, TypeValue>> = {
357
+ fs: fsModule,
358
+ "node:fs": fsModule,
359
+ "node:fs/promises": {
360
+ readFile: fsModule.readFile,
361
+ writeFile: fsModule.writeFile,
362
+ mkdir: fsModule.mkdir,
363
+ rm: fsModule.rm,
364
+ stat: fsModule.stat,
365
+ readdir: fsModule.readdir,
366
+ access: fsModule.access,
367
+ },
368
+ path: pathModule,
369
+ "node:path": pathModule,
370
+ os: osModule,
371
+ "node:os": osModule,
372
+ url: urlModule,
373
+ "node:url": urlModule,
374
+ crypto: cryptoModule,
375
+ "node:crypto": cryptoModule,
376
+ child_process: childProcessModule,
377
+ "node:child_process": childProcessModule,
378
+ util: utilModule,
379
+ "node:util": utilModule,
380
+ };
381
+
382
+ return {
383
+ globals: { ...esEnv.globals, ...nodeGlobals },
384
+ modules,
385
+ };
386
+ }
package/src/web.ts ADDED
@@ -0,0 +1,316 @@
1
+ import { type TypeValue, type SigImpl, T } from "@nudojs/core";
2
+ import { type EnvDefinition, defineEnv as defineEsEnv } from "./es.ts";
3
+
4
+ export type { EnvDefinition };
5
+
6
+ function litStr(tv: TypeValue): string | undefined {
7
+ return tv.kind === "literal" && typeof tv.value === "string" ? tv.value : undefined;
8
+ }
9
+
10
+ function makeURLObj(url: URL): TypeValue {
11
+ return T.object({
12
+ href: T.literal(url.href),
13
+ origin: T.literal(url.origin),
14
+ protocol: T.literal(url.protocol),
15
+ username: T.literal(url.username),
16
+ password: T.literal(url.password),
17
+ host: T.literal(url.host),
18
+ hostname: T.literal(url.hostname),
19
+ port: T.literal(url.port),
20
+ pathname: T.literal(url.pathname),
21
+ search: T.literal(url.search),
22
+ searchParams: T.object({
23
+ append: T.fnSig([T.string, T.string], T.undefined),
24
+ delete: T.fnSig([T.string], T.undefined),
25
+ get: T.fnSig([T.string], T.union(T.string, T.null)),
26
+ getAll: T.fnSig([T.string], T.array(T.string)),
27
+ has: T.fnSig([T.string], T.boolean),
28
+ set: T.fnSig([T.string, T.string], T.undefined),
29
+ sort: T.fnSig([], T.undefined),
30
+ toString: T.fnSig([], T.string, T.never, () => T.literal(url.searchParams.toString())),
31
+ entries: T.fnSig([], T.unknown),
32
+ keys: T.fnSig([], T.unknown),
33
+ values: T.fnSig([], T.unknown),
34
+ forEach: T.fnSig([T.unknown], T.undefined),
35
+ size: T.literal(url.searchParams.size),
36
+ }),
37
+ hash: T.literal(url.hash),
38
+ toString: T.fnSig([], T.string, T.never, () => T.literal(url.href)),
39
+ toJSON: T.fnSig([], T.string, T.never, () => T.literal(url.href)),
40
+ });
41
+ }
42
+
43
+ export function defineEnv(): EnvDefinition {
44
+ const esEnv = defineEsEnv();
45
+
46
+ const Headers = T.object({
47
+ append: T.fnSig([T.string, T.string], T.undefined),
48
+ delete: T.fnSig([T.string], T.undefined),
49
+ get: T.fnSig([T.string], T.union(T.string, T.null)),
50
+ has: T.fnSig([T.string], T.boolean),
51
+ set: T.fnSig([T.string, T.string], T.undefined),
52
+ forEach: T.fnSig([T.unknown], T.undefined),
53
+ entries: T.fnSig([], T.unknown),
54
+ keys: T.fnSig([], T.unknown),
55
+ values: T.fnSig([], T.unknown),
56
+ });
57
+
58
+ const Body = {
59
+ json: T.fnSig([], T.promise(T.unknown)),
60
+ text: T.fnSig([], T.promise(T.string)),
61
+ arrayBuffer: T.fnSig([], T.promise(T.unknown)),
62
+ blob: T.fnSig([], T.promise(T.unknown)),
63
+ formData: T.fnSig([], T.promise(T.unknown)),
64
+ clone: T.fnSig([], T.unknown),
65
+ ok: T.boolean,
66
+ status: T.number,
67
+ statusText: T.string,
68
+ headers: Headers,
69
+ url: T.string,
70
+ redirected: T.boolean,
71
+ type: T.string,
72
+ bodyUsed: T.boolean,
73
+ };
74
+
75
+ const Response = T.object(Body);
76
+
77
+ const Request = T.object({
78
+ ...Body,
79
+ method: T.string,
80
+ url: T.string,
81
+ headers: Headers,
82
+ body: T.union(T.unknown, T.null),
83
+ mode: T.string,
84
+ credentials: T.string,
85
+ cache: T.string,
86
+ redirect: T.string,
87
+ referrer: T.string,
88
+ integrity: T.string,
89
+ signal: T.unknown,
90
+ clone: T.fnSig([], T.unknown),
91
+ });
92
+
93
+ const URLSearchParams = T.object({
94
+ append: T.fnSig([T.string, T.string], T.undefined),
95
+ delete: T.fnSig([T.string], T.undefined),
96
+ get: T.fnSig([T.string], T.union(T.string, T.null)),
97
+ getAll: T.fnSig([T.string], T.array(T.string)),
98
+ has: T.fnSig([T.string], T.boolean),
99
+ set: T.fnSig([T.string, T.string], T.undefined),
100
+ sort: T.fnSig([], T.undefined),
101
+ toString: T.fnSig([], T.string),
102
+ entries: T.fnSig([], T.unknown),
103
+ keys: T.fnSig([], T.unknown),
104
+ values: T.fnSig([], T.unknown),
105
+ forEach: T.fnSig([T.unknown], T.undefined),
106
+ size: T.number,
107
+ });
108
+
109
+ const URLObj = T.object({
110
+ href: T.string,
111
+ origin: T.string,
112
+ protocol: T.string,
113
+ username: T.string,
114
+ password: T.string,
115
+ host: T.string,
116
+ hostname: T.string,
117
+ port: T.string,
118
+ pathname: T.string,
119
+ search: T.string,
120
+ searchParams: URLSearchParams,
121
+ hash: T.string,
122
+ toString: T.fnSig([], T.string),
123
+ toJSON: T.fnSig([], T.string),
124
+ });
125
+
126
+ const AbortController = T.object({
127
+ signal: T.unknown,
128
+ abort: T.fnSig([], T.undefined),
129
+ });
130
+
131
+ const Storage = T.object({
132
+ getItem: T.fnSig([T.string], T.union(T.string, T.null)),
133
+ setItem: T.fnSig([T.string, T.string], T.undefined),
134
+ removeItem: T.fnSig([T.string], T.undefined),
135
+ clear: T.fnSig([], T.undefined),
136
+ key: T.fnSig([T.number], T.union(T.string, T.null)),
137
+ length: T.number,
138
+ });
139
+
140
+ const EventTarget = T.object({
141
+ addEventListener: T.fnSig([T.string, T.unknown], T.undefined),
142
+ removeEventListener: T.fnSig([T.string, T.unknown], T.undefined),
143
+ dispatchEvent: T.fnSig([T.unknown], T.boolean),
144
+ });
145
+
146
+ const webGlobals: Record<string, TypeValue> = {
147
+ // --- Fetch API ---
148
+ fetch: T.fnSig([T.union(T.string, Request)], T.promise(Response)),
149
+ Request: T.fnSig([T.string, T.unknown], Request),
150
+ Response: T.object({
151
+ json: T.fnSig([T.unknown], Response),
152
+ redirect: T.fnSig([T.string, T.number], Response),
153
+ error: T.fnSig([], Response),
154
+ }),
155
+ Headers: T.fnSig([T.unknown], Headers),
156
+
157
+ // --- URL ---
158
+ URL: T.fnSig([T.string, T.string], URLObj, T.instanceOf("TypeError"), (args) => {
159
+ const href = litStr(args[0]);
160
+ const base = args[1] !== undefined ? litStr(args[1]) : undefined;
161
+ if (href === undefined) return undefined;
162
+ try {
163
+ const url = base !== undefined ? new URL(href, base) : new URL(href);
164
+ return makeURLObj(url);
165
+ } catch { return undefined; }
166
+ }),
167
+ URLSearchParams: T.fnSig([T.unknown], URLSearchParams),
168
+
169
+ // --- Timers ---
170
+ setTimeout: T.fnSig([T.unknown, T.number], T.number),
171
+ setInterval: T.fnSig([T.unknown, T.number], T.number),
172
+ clearTimeout: T.fnSig([T.number], T.undefined),
173
+ clearInterval: T.fnSig([T.number], T.undefined),
174
+ queueMicrotask: T.fnSig([T.unknown], T.undefined),
175
+ requestAnimationFrame: T.fnSig([T.unknown], T.number),
176
+ cancelAnimationFrame: T.fnSig([T.number], T.undefined),
177
+
178
+ // --- Abort ---
179
+ AbortController: T.fnSig([], AbortController),
180
+ AbortSignal: T.object({
181
+ abort: T.fnSig([], T.unknown),
182
+ timeout: T.fnSig([T.number], T.unknown),
183
+ }),
184
+
185
+ // --- Encoding ---
186
+ atob: T.fnSig([T.string], T.string, T.never, (args) => {
187
+ const s = litStr(args[0]);
188
+ if (s === undefined) return undefined;
189
+ try { return T.literal(atob(s)); } catch { return undefined; }
190
+ }),
191
+ btoa: T.fnSig([T.string], T.string, T.never, (args) => {
192
+ const s = litStr(args[0]);
193
+ if (s === undefined) return undefined;
194
+ try { return T.literal(btoa(s)); } catch { return undefined; }
195
+ }),
196
+ TextEncoder: T.fnSig([], T.object({
197
+ encode: T.fnSig([T.string], T.unknown),
198
+ encodeInto: T.fnSig([T.string, T.unknown], T.unknown),
199
+ })),
200
+ TextDecoder: T.fnSig([T.string], T.object({
201
+ decode: T.fnSig([T.unknown], T.string),
202
+ encoding: T.string,
203
+ fatal: T.boolean,
204
+ ignoreBOM: T.boolean,
205
+ })),
206
+
207
+ // --- Storage ---
208
+ localStorage: Storage,
209
+ sessionStorage: Storage,
210
+
211
+ // --- DOM (minimal) ---
212
+ document: T.object({
213
+ getElementById: T.fnSig([T.string], T.union(T.unknown, T.null)),
214
+ querySelector: T.fnSig([T.string], T.union(T.unknown, T.null)),
215
+ querySelectorAll: T.fnSig([T.string], T.unknown),
216
+ createElement: T.fnSig([T.string], T.unknown),
217
+ createTextNode: T.fnSig([T.string], T.unknown),
218
+ body: T.unknown,
219
+ head: T.unknown,
220
+ documentElement: T.unknown,
221
+ title: T.string,
222
+ cookie: T.string,
223
+ readyState: T.string,
224
+ addEventListener: T.fnSig([T.string, T.unknown], T.undefined),
225
+ removeEventListener: T.fnSig([T.string, T.unknown], T.undefined),
226
+ }),
227
+
228
+ // --- Window ---
229
+ window: T.unknown,
230
+ self: T.unknown,
231
+ navigator: T.object({
232
+ userAgent: T.string,
233
+ language: T.string,
234
+ languages: T.array(T.string),
235
+ onLine: T.boolean,
236
+ platform: T.string,
237
+ clipboard: T.object({
238
+ readText: T.fnSig([], T.promise(T.string)),
239
+ writeText: T.fnSig([T.string], T.promise(T.undefined)),
240
+ }),
241
+ }),
242
+ location: T.object({
243
+ href: T.string,
244
+ origin: T.string,
245
+ protocol: T.string,
246
+ host: T.string,
247
+ hostname: T.string,
248
+ port: T.string,
249
+ pathname: T.string,
250
+ search: T.string,
251
+ hash: T.string,
252
+ assign: T.fnSig([T.string], T.undefined),
253
+ replace: T.fnSig([T.string], T.undefined),
254
+ reload: T.fnSig([], T.undefined),
255
+ }),
256
+ history: T.object({
257
+ length: T.number,
258
+ state: T.unknown,
259
+ back: T.fnSig([], T.undefined),
260
+ forward: T.fnSig([], T.undefined),
261
+ go: T.fnSig([T.number], T.undefined),
262
+ pushState: T.fnSig([T.unknown, T.string, T.string], T.undefined),
263
+ replaceState: T.fnSig([T.unknown, T.string, T.string], T.undefined),
264
+ }),
265
+
266
+ // --- Events ---
267
+ EventTarget: T.fnSig([], EventTarget),
268
+ Event: T.fnSig([T.string, T.unknown], T.object({
269
+ type: T.string,
270
+ target: T.union(T.unknown, T.null),
271
+ currentTarget: T.union(T.unknown, T.null),
272
+ bubbles: T.boolean,
273
+ cancelable: T.boolean,
274
+ defaultPrevented: T.boolean,
275
+ preventDefault: T.fnSig([], T.undefined),
276
+ stopPropagation: T.fnSig([], T.undefined),
277
+ stopImmediatePropagation: T.fnSig([], T.undefined),
278
+ })),
279
+ CustomEvent: T.fnSig([T.string, T.unknown], T.unknown),
280
+
281
+ // --- Structured clone ---
282
+ structuredClone: T.fnSig([T.unknown], T.unknown),
283
+
284
+ // --- Performance ---
285
+ performance: T.object({
286
+ now: T.fnSig([], T.number),
287
+ mark: T.fnSig([T.string], T.undefined),
288
+ measure: T.fnSig([T.string, T.string, T.string], T.unknown),
289
+ getEntriesByName: T.fnSig([T.string], T.array(T.unknown)),
290
+ getEntriesByType: T.fnSig([T.string], T.array(T.unknown)),
291
+ clearMarks: T.fnSig([], T.undefined),
292
+ clearMeasures: T.fnSig([], T.undefined),
293
+ timeOrigin: T.number,
294
+ }),
295
+
296
+ // --- Crypto ---
297
+ crypto: T.object({
298
+ randomUUID: T.fnSig([], T.string),
299
+ getRandomValues: T.fnSig([T.unknown], T.unknown),
300
+ subtle: T.object({
301
+ digest: T.fnSig([T.string, T.unknown], T.promise(T.unknown)),
302
+ encrypt: T.fnSig([T.unknown, T.unknown, T.unknown], T.promise(T.unknown)),
303
+ decrypt: T.fnSig([T.unknown, T.unknown, T.unknown], T.promise(T.unknown)),
304
+ sign: T.fnSig([T.unknown, T.unknown, T.unknown], T.promise(T.unknown)),
305
+ verify: T.fnSig([T.unknown, T.unknown, T.unknown, T.unknown], T.promise(T.boolean)),
306
+ generateKey: T.fnSig([T.unknown, T.boolean, T.array(T.string)], T.promise(T.unknown)),
307
+ importKey: T.fnSig([T.string, T.unknown, T.unknown, T.boolean, T.array(T.string)], T.promise(T.unknown)),
308
+ exportKey: T.fnSig([T.string, T.unknown], T.promise(T.unknown)),
309
+ }),
310
+ }),
311
+ };
312
+
313
+ return {
314
+ globals: { ...esEnv.globals, ...webGlobals },
315
+ };
316
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src"],
8
+ "references": [
9
+ { "path": "../core" }
10
+ ]
11
+ }