@titanpl/core 1.0.1 → 2.0.1

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/index.js CHANGED
@@ -1,250 +1,555 @@
1
- // Titan Core Library
2
- // Provides standard library features using native bindings.
3
-
4
- // Native bindings are expected to be available globally or via t.native
5
- // adjusting based on typical Titan behavior.
6
- // We bind them to local variables for cleaner usage.
7
-
8
- const native_fs_read_file = globalThis.fs_read_file;
9
- const native_fs_write_file = globalThis.fs_write_file;
10
- const native_fs_readdir = globalThis.fs_readdir;
11
- const native_fs_mkdir = globalThis.fs_mkdir;
12
- const native_fs_exists = globalThis.fs_exists;
13
- const native_fs_stat = globalThis.fs_stat;
14
- const native_fs_remove = globalThis.fs_remove;
15
- const native_path_cwd = globalThis.path_cwd;
16
- const native_crypto_hash = globalThis.crypto_hash;
17
- const native_crypto_random_bytes = globalThis.crypto_random_bytes;
18
- const native_crypto_uuid = globalThis.crypto_uuid;
19
- const native_os_info = globalThis.os_info;
20
- const native_net_resolve = globalThis.net_resolve;
21
- const native_net_ip = globalThis.net_ip;
22
- const native_proc_info = globalThis.proc_info;
23
- const native_time_sleep = globalThis.time_sleep;
24
-
25
- // --- FS ---
26
- const fs = {
27
- readFile: (path) => {
28
- if (!native_fs_read_file) throw new Error("Native fs_read_file not found");
29
- return native_fs_read_file(path);
30
- },
31
- writeFile: (path, content) => {
32
- if (!native_fs_write_file) throw new Error("Native fs_write_file not found");
33
- native_fs_write_file(path, content);
34
- },
35
- readdir: (path) => {
36
- if (!native_fs_readdir) throw new Error("Native fs_readdir not found");
37
- return JSON.parse(native_fs_readdir(path));
38
- },
39
- mkdir: (path) => {
40
- if (!native_fs_mkdir) throw new Error("Native fs_mkdir not found");
41
- native_fs_mkdir(path);
42
- },
43
- exists: (path) => {
44
- if (!native_fs_exists) throw new Error("Native fs_exists not found");
45
- return native_fs_exists(path);
46
- },
47
- stat: (path) => {
48
- if (!native_fs_stat) throw new Error("Native fs_stat not found");
49
- return JSON.parse(native_fs_stat(path));
50
- },
51
- remove: (path) => {
52
- if (!native_fs_remove) throw new Error("Native fs_remove not found");
53
- native_fs_remove(path);
54
- }
55
- };
56
-
57
- // --- Path ---
58
- // Basic implementation for POSIX-like paths (Titan mostly runs on servers/containers)
59
- const path = {
60
- join: (...args) => {
61
- return args
62
- .map((part, i) => {
63
- if (i === 0) return part.trim().replace(/[\/]*$/g, '');
64
- return part.trim().replace(/(^[\/]*|[\/]*$)/g, '');
65
- })
66
- .filter(x => x.length)
67
- .join('/');
68
- },
69
- resolve: (...args) => {
70
- let resolved = '';
71
- for (let arg of args) {
72
- resolved = path.join(resolved, arg);
73
- }
74
- if (!resolved.startsWith('/') && native_path_cwd) {
75
- resolved = path.join(native_path_cwd(), resolved);
76
- }
77
- return resolved;
78
- },
79
- extname: (p) => {
80
- const parts = p.split('.');
81
- return parts.length > 1 && !p.startsWith('.') ? '.' + parts.pop() : '';
82
- },
83
- dirname: (p) => {
84
- const parts = p.split('/');
85
- parts.pop();
86
- return parts.join('/') || '.';
87
- },
88
- basename: (p) => p.split('/').pop()
89
- };
90
-
91
- // --- Crypto ---
92
- const crypto = {
93
- hash: (algo, data) => native_crypto_hash(algo, data),
94
- randomBytes: (size) => native_crypto_random_bytes(size),
95
- uuid: () => native_crypto_uuid(),
96
- base64: {
97
- encode: (str) => btoa(str), // Boa supports btoa/atob
98
- decode: (str) => atob(str),
99
- },
100
- compare: (a, b) => {
101
- if (a.length !== b.length) return false;
102
- // Constant time comparison not guaranteed here in JS easily without specialized tricks
103
- let mismatch = 0;
104
- for (let i = 0; i < a.length; ++i) {
105
- mismatch |= (a.charCodeAt(i) ^ b.charCodeAt(i));
106
- }
107
- return mismatch === 0;
108
- }
109
- };
110
-
111
- // --- OS ---
112
- const os = {
113
- platform: () => {
114
- const info = JSON.parse(native_os_info());
115
- return info.platform;
116
- },
117
- cpus: () => {
118
- const info = JSON.parse(native_os_info());
119
- return info.cpus;
120
- },
121
- totalMemory: () => {
122
- const info = JSON.parse(native_os_info());
123
- return info.totalMemory;
124
- },
125
- freeMemory: () => {
126
- const info = JSON.parse(native_os_info());
127
- return info.freeMemory;
128
- },
129
- tmpdir: () => '/tmp' // Default for now, generic
130
- };
131
-
132
- // --- Net ---
133
- const net = {
134
- resolveDNS: (hostname) => JSON.parse(native_net_resolve(hostname)),
135
- ip: () => native_net_ip(),
136
- ping: (host) => {
137
- // Mock ping or simple verify
138
- return true;
139
- }
140
- };
141
-
142
- // --- Proc ---
143
- // Memoize static info if needed, but here we call native
144
- const proc = {
145
- pid: () => {
146
- const info = JSON.parse(native_proc_info());
147
- return info.pid;
148
- },
149
- uptime: () => {
150
- const info = JSON.parse(native_proc_info());
151
- return info.uptime;
152
- },
153
- memory: () => {
154
- // Optional: return full memory usage if possible
155
- return {};
156
- }
157
- };
158
-
159
- // --- Time ---
160
- const time = {
161
- sleep: (ms) => native_time_sleep(ms),
162
- now: () => Date.now(),
163
- timestamp: () => new Date().toISOString()
164
- };
165
-
166
- // --- URL ---
167
- // Simple URLSearchParams polyfill for V8 runtime
168
- class TitanURLSearchParams {
169
- constructor(init = '') {
170
- this._params = {};
171
- if (typeof init === 'string') {
172
- const query = init.startsWith('?') ? init.slice(1) : init;
173
- query.split('&').forEach(pair => {
174
- const [key, value] = pair.split('=').map(decodeURIComponent);
175
- if (key) this._params[key] = value || '';
176
- });
177
- } else if (typeof init === 'object') {
178
- Object.assign(this._params, init);
179
- }
180
- }
181
- get(key) { return this._params[key] || null; }
182
- set(key, value) { this._params[key] = String(value); }
183
- has(key) { return key in this._params; }
184
- delete(key) { delete this._params[key]; }
185
- toString() {
186
- return Object.entries(this._params)
187
- .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
188
- .join('&');
189
- }
190
- entries() { return Object.entries(this._params); }
191
- keys() { return Object.keys(this._params); }
192
- values() { return Object.values(this._params); }
193
- }
194
-
195
- const url = {
196
- parse: (str) => {
197
- // Basic URL parsing if native URL is available
198
- if (typeof URL !== 'undefined') {
199
- return new URL(str);
200
- }
201
- // Simple fallback parser
202
- const match = str.match(/^(https?:)\/\/([^/:]+)(?::(\d+))?(\/[^?#]*)?(\?[^#]*)?(#.*)?$/);
203
- if (!match) throw new Error('Invalid URL');
204
- return {
205
- protocol: match[1],
206
- hostname: match[2],
207
- port: match[3] || '',
208
- pathname: match[4] || '/',
209
- search: match[5] || '',
210
- hash: match[6] || ''
211
- };
212
- },
213
- format: (obj) => obj.toString ? obj.toString() : String(obj),
214
- SearchParams: TitanURLSearchParams
215
- };
216
-
217
-
218
- // Create the main core export object (following titan-valid pattern)
219
- const core = {
220
- fs,
221
- path,
222
- crypto,
223
- os,
224
- net,
225
- proc,
226
- time,
227
- url
228
- };
229
-
230
-
231
- t.fs = fs;
232
- t.path = path;
233
- t.crypto = crypto;
234
- t.os = os;
235
- t.net = net;
236
- t.proc = proc;
237
- t.time = time;
238
- t.url = url;
239
-
240
- // Attach core as unified namespace (main access point)
241
- t.core = core;
242
-
243
- // Register as extension under multiple names for compatibility
244
- t["titan-core"] = core;
245
- t["@titanpl/core"] = core;
246
-
247
- // Also register in t.exts
248
- if (!t.exts) t.exts = {};
249
- t.exts["titan-core"] = core;
1
+ const b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
2
+
3
+ function local_btoa(input) {
4
+ let str = String(input);
5
+ let output = '';
6
+
7
+ for (let i = 0; i < str.length; i += 3) {
8
+ const char1 = str.charCodeAt(i);
9
+ const char2 = str.charCodeAt(i + 1);
10
+ const char3 = str.charCodeAt(i + 2);
11
+
12
+ const enc1 = char1 >> 2;
13
+ const enc2 = ((char1 & 3) << 4) | (char2 >> 4);
14
+ let enc3 = ((char2 & 15) << 2) | (char3 >> 6);
15
+ let enc4 = char3 & 63;
16
+
17
+ if (isNaN(char2)) {
18
+ enc3 = enc4 = 64;
19
+ } else if (isNaN(char3)) {
20
+ enc4 = 64;
21
+ }
22
+
23
+ output += b64chars.charAt(enc1) + b64chars.charAt(enc2);
24
+ output += (enc3 === 64) ? '=' : b64chars.charAt(enc3);
25
+ output += (enc4 === 64) ? '=' : b64chars.charAt(enc4);
26
+ }
27
+
28
+ return output;
29
+ }
30
+
31
+ function local_atob(input) {
32
+ // Remove whitespace and padding '='
33
+ let str = String(input).replace(/[\t\n\f\r =]/g, "");
34
+ let output = '';
35
+
36
+ for (let i = 0; i < str.length; i += 4) {
37
+ const c1Str = str.charAt(i);
38
+ const c2Str = str.charAt(i + 1);
39
+ const c3Str = str.charAt(i + 2);
40
+ const c4Str = str.charAt(i + 3);
41
+
42
+ const e1 = b64chars.indexOf(c1Str);
43
+ const e2 = c2Str ? b64chars.indexOf(c2Str) : -1;
44
+ const e3 = c3Str ? b64chars.indexOf(c3Str) : -1;
45
+ const e4 = c4Str ? b64chars.indexOf(c4Str) : -1;
46
+
47
+ // e1 and e2 are required
48
+ if (e1 < 0 || e2 < 0) continue;
49
+
50
+ // Shift and mask to reconstruct bytes
51
+ const c1 = (e1 << 2) | (e2 >> 4);
52
+ output += String.fromCharCode(c1);
53
+
54
+ if (e3 !== -1) {
55
+ const c2 = ((e2 & 15) << 4) | (e3 >> 2);
56
+ output += String.fromCharCode(c2);
57
+ }
58
+ if (e4 !== -1) {
59
+ const c3 = ((e3 & 3) << 6) | e4;
60
+ output += String.fromCharCode(c3);
61
+ }
62
+ }
63
+
64
+ return output;
65
+ }
66
+
67
+ function local_utf8_encode(str) {
68
+ let result = [];
69
+ for (let i = 0; i < str.length; i++) {
70
+ let c = str.charCodeAt(i);
71
+ if (c < 0x80) { result.push(c); }
72
+ else if (c < 0x800) {
73
+ result.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f));
74
+ }
75
+ else if (c < 0xd800 || c >= 0xe000) {
76
+ result.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f));
77
+ }
78
+ else {
79
+ i++;
80
+ c = 0x10000 + (((c & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff));
81
+ result.push(0xf0 | (c >> 18), 0x80 | ((c >> 12) & 0x3f), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f));
82
+ }
83
+ }
84
+ return new Uint8Array(result);
85
+ }
86
+
87
+ function local_utf8_decode(bytes) {
88
+ let str = "";
89
+ let i = 0;
90
+ while (i < bytes.length) {
91
+ let c = bytes[i++];
92
+ if (c > 127) {
93
+ if (c > 191 && c < 224) {
94
+ c = ((c & 31) << 6) | (bytes[i++] & 63);
95
+ } else if (c > 223 && c < 240) {
96
+ c = ((c & 15) << 12) | ((bytes[i++] & 63) << 6) | (bytes[i++] & 63);
97
+ } else if (c > 239 && c < 248) {
98
+ c = ((c & 7) << 18) | ((bytes[i++] & 63) << 12) | ((bytes[i++] & 63) << 6) | (bytes[i++] & 63);
99
+ }
100
+ }
101
+ if (c <= 0xffff) str += String.fromCharCode(c);
102
+ else if (c <= 0x10ffff) {
103
+ c -= 0x10000;
104
+ str += String.fromCharCode(c >> 10 | 0xd800) + String.fromCharCode(c & 0x3ff | 0xdc00);
105
+ }
106
+ }
107
+ return str;
108
+ }
109
+
110
+
111
+ // Native bindings are loaded by the runtime into t["@titanpl/core"]
112
+ const natives = t["@titanpl/core"] || {};
113
+
114
+
115
+ // Native Function bindings
116
+ const native_fs_read_file = natives.fs_read_file;
117
+ const native_fs_write_file = natives.fs_write_file;
118
+ const native_fs_readdir = natives.fs_readdir;
119
+ const native_fs_mkdir = natives.fs_mkdir;
120
+ const native_fs_exists = natives.fs_exists;
121
+ const native_fs_stat = natives.fs_stat;
122
+ const native_fs_remove = natives.fs_remove;
123
+ const native_path_cwd = natives.path_cwd;
124
+
125
+ const native_crypto_hash = natives.crypto_hash;
126
+ const native_crypto_random_bytes = natives.crypto_random_bytes;
127
+ const native_crypto_uuid = natives.crypto_uuid;
128
+ const native_crypto_encrypt = natives.crypto_encrypt;
129
+ const native_crypto_decrypt = natives.crypto_decrypt;
130
+ const native_crypto_hash_keyed = natives.crypto_hash_keyed;
131
+ const native_crypto_compare = natives.crypto_compare;
132
+
133
+ const native_os_info = natives.os_info;
134
+ const native_net_resolve = natives.net_resolve;
135
+ const native_net_ip = natives.net_ip;
136
+ const native_proc_info = natives.proc_info;
137
+ const native_time_sleep = natives.time_sleep;
138
+
139
+ const native_ls_get = natives.ls_get;
140
+ const native_ls_set = natives.ls_set;
141
+ const native_ls_remove = natives.ls_remove;
142
+ const native_ls_clear = natives.ls_clear;
143
+ const native_ls_keys = natives.ls_keys;
144
+
145
+ const native_session_get = natives.session_get;
146
+ const native_session_set = natives.session_set;
147
+ const native_session_delete = natives.session_delete;
148
+ const native_session_clear = natives.session_clear;
149
+
150
+ // --- FS ---
151
+ /** File System module */
152
+ const fs = {
153
+ /** Reads file content as UTF-8 string */
154
+ readFile: (path) => {
155
+ if (!native_fs_read_file) throw new Error("Native fs_read_file not found");
156
+ const res = native_fs_read_file(path);
157
+ if (res && res.startsWith("ERROR:")) throw new Error(res);
158
+ return res;
159
+ },
160
+ /** Writes content to file */
161
+ writeFile: (path, content) => {
162
+ if (!native_fs_write_file) throw new Error("Native fs_write_file not found");
163
+ native_fs_write_file(path, content);
164
+ },
165
+ /** Reads directory contents */
166
+ readdir: (path) => {
167
+ if (!native_fs_readdir) throw new Error("Native fs_readdir not found");
168
+ const res = native_fs_readdir(path);
169
+ try {
170
+ return JSON.parse(res);
171
+ } catch (e) {
172
+ return [];
173
+ }
174
+ },
175
+ /** Creates direction recursively */
176
+ mkdir: (path) => {
177
+ if (!native_fs_mkdir) throw new Error("Native fs_mkdir not found");
178
+ native_fs_mkdir(path);
179
+ },
180
+ /** Checks if path exists */
181
+ exists: (path) => {
182
+ if (!native_fs_exists) throw new Error("Native fs_exists not found");
183
+ return native_fs_exists(path);
184
+ },
185
+ /** Returns file stats */
186
+ stat: (path) => {
187
+ if (!native_fs_stat) throw new Error("Native fs_stat not found");
188
+ const res = native_fs_stat(path);
189
+ try {
190
+ return JSON.parse(res);
191
+ } catch (e) {
192
+ return {};
193
+ }
194
+ },
195
+ /** Removes file or directory */
196
+ remove: (path) => {
197
+ if (!native_fs_remove) throw new Error("Native fs_remove not found");
198
+ native_fs_remove(path);
199
+ }
200
+ };
201
+
202
+ // --- Path ---
203
+ /** Path manipulation module */
204
+ const path = {
205
+ join: (...args) => {
206
+ return args
207
+ .map((part, i) => {
208
+ if (!part) return '';
209
+ let p = part.replace(/\\/g, '/');
210
+ if (i === 0) return p.trim().replace(/[\/]*$/g, '');
211
+ return p.trim().replace(/(^[\/]*|[\/]*$)/g, '');
212
+ })
213
+ .filter(x => x.length)
214
+ .join('/');
215
+ },
216
+ resolve: (...args) => {
217
+ let resolved = '';
218
+ for (let arg of args) {
219
+ resolved = path.join(resolved, arg);
220
+ }
221
+ if (!resolved.startsWith('/')) {
222
+ const isWindowsAbs = /^[a-zA-Z]:\\/.test(resolved) || resolved.startsWith('\\');
223
+ if (!isWindowsAbs && native_path_cwd) {
224
+ const cwd = native_path_cwd();
225
+ if (cwd) {
226
+ resolved = path.join(cwd, resolved);
227
+ }
228
+ }
229
+ }
230
+ return resolved;
231
+ },
232
+ extname: (p) => {
233
+ const parts = p.split('.');
234
+ return parts.length > 1 && !p.startsWith('.') ? '.' + parts.pop() : '';
235
+ },
236
+ dirname: (p) => {
237
+ const parts = p.split('/');
238
+ parts.pop();
239
+ return parts.join('/') || '.';
240
+ },
241
+ basename: (p) => p.split('/').pop()
242
+ };
243
+
244
+ // --- Crypto ---
245
+ /** Cryptography module */
246
+ const crypto = {
247
+ hash: (algo, data) => native_crypto_hash ? native_crypto_hash(algo, data) : "",
248
+ randomBytes: (size) => native_crypto_random_bytes ? native_crypto_random_bytes(size) : "",
249
+ uuid: () => native_crypto_uuid ? native_crypto_uuid() : "",
250
+ base64: {
251
+ encode: (str) => local_btoa(str),
252
+ decode: (str) => local_atob(str),
253
+ },
254
+ // Extended API
255
+ /** Encrypts data using AES-256-GCM. Returns Base64 string. */
256
+ encrypt: (algorithm, key, plaintext) => {
257
+ if (!native_crypto_encrypt) throw new Error("Native crypto_encrypt not found");
258
+ const res = native_crypto_encrypt(algorithm, JSON.stringify({ key, plaintext }));
259
+ if (res.startsWith("ERROR:")) throw new Error(res.substring(6));
260
+ return res;
261
+ },
262
+ /** Decrypts data using AES-256-GCM. Returns plaintext string. */
263
+ decrypt: (algorithm, key, ciphertext) => {
264
+ if (!native_crypto_decrypt) throw new Error("Native crypto_decrypt not found");
265
+ const res = native_crypto_decrypt(algorithm, JSON.stringify({ key, ciphertext }));
266
+ if (res.startsWith("ERROR:")) throw new Error(res.substring(6));
267
+ return res;
268
+ },
269
+ /** Computes HMAC-SHA256/512. Returns Hex string. */
270
+ hashKeyed: (algorithm, key, message) => {
271
+ if (!native_crypto_hash_keyed) throw new Error("Native crypto_hash_keyed not found");
272
+ const res = native_crypto_hash_keyed(algorithm, JSON.stringify({ key, message }));
273
+ if (res.startsWith("ERROR:")) throw new Error(res.substring(6));
274
+ return res;
275
+ },
276
+ /** Constant-time string comparison */
277
+ compare: (a, b) => {
278
+ if (native_crypto_compare) return native_crypto_compare(a, b);
279
+ // Fallback insecure
280
+ if (a.length !== b.length) return false;
281
+ let mismatch = 0;
282
+ for (let i = 0; i < a.length; ++i) {
283
+ mismatch |= (a.charCodeAt(i) ^ b.charCodeAt(i));
284
+ }
285
+ return mismatch === 0;
286
+ }
287
+ };
288
+
289
+ // --- Buffer ---
290
+ // Helper for hex
291
+ function hexToBytes(hex) {
292
+ const bytes = new Uint8Array(hex.length / 2);
293
+ for (let i = 0; i < bytes.length; i++) {
294
+ bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
295
+ }
296
+ return bytes;
297
+ }
298
+ function bytesToHex(bytes) {
299
+ return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
300
+ }
301
+
302
+ /** Buffer utility module */
303
+ const buffer = {
304
+ /** Creates Uint8Array from Base64 string */
305
+ fromBase64: (str) => {
306
+ const binary = local_atob(str);
307
+ const bytes = new Uint8Array(binary.length);
308
+ for (let i = 0; i < binary.length; i++) {
309
+ bytes[i] = binary.charCodeAt(i);
310
+ }
311
+ return bytes;
312
+ },
313
+ /** encoded Uint8Array or String to Base64 string */
314
+ toBase64: (bytes) => {
315
+ let binary = '';
316
+ if (typeof bytes === 'string') {
317
+ return local_btoa(bytes);
318
+ }
319
+ // Uint8Array
320
+ const len = bytes.byteLength;
321
+ for (let i = 0; i < len; i++) {
322
+ binary += String.fromCharCode(bytes[i]);
323
+ }
324
+ return local_btoa(binary);
325
+ },
326
+ /** Creates Uint8Array from Hex string */
327
+ fromHex: (str) => hexToBytes(str),
328
+ /** Encodes bytes to Hex string */
329
+ toHex: (bytes) => {
330
+ if (typeof bytes === 'string') {
331
+ return bytesToHex(local_utf8_encode(bytes));
332
+ }
333
+ return bytesToHex(bytes);
334
+ },
335
+ /** Creates Uint8Array from UTF-8 string */
336
+ fromUtf8: (str) => local_utf8_encode(str),
337
+ /** Decodes bytes to UTF-8 string */
338
+ toUtf8: (bytes) => local_utf8_decode(bytes)
339
+ };
340
+
341
+ // --- Local Storage ---
342
+ /** Persistent Local Storage */
343
+ const ls = {
344
+ get: (key) => native_ls_get ? native_ls_get(key) || null : null,
345
+ set: (key, value) => native_ls_set && native_ls_set(key, value),
346
+ remove: (key) => native_ls_remove && native_ls_remove(key),
347
+ clear: () => native_ls_clear && native_ls_clear(),
348
+ keys: () => {
349
+ if (!native_ls_keys) return [];
350
+ try {
351
+ return JSON.parse(native_ls_keys());
352
+ } catch (e) { return []; }
353
+ }
354
+ };
355
+
356
+ // --- Sessions ---
357
+ /** Server-side Session Management */
358
+ const session = {
359
+ get: (sessionId, key) => native_session_get ? native_session_get(sessionId, key) || null : null,
360
+ set: (sessionId, key, value) => native_session_set && native_session_set(sessionId, JSON.stringify({ key, value })),
361
+ delete: (sessionId, key) => native_session_delete && native_session_delete(sessionId, key),
362
+ clear: (sessionId) => native_session_clear && native_session_clear(sessionId)
363
+ };
364
+
365
+
366
+ // --- Cookies ---
367
+ /** HTTP Cookie Utilities */
368
+ const cookies = {
369
+ /** Parses cookie from request headers */
370
+ get: (req, name) => {
371
+ if (!req || !req.headers) return null;
372
+ const cookieHeader = req.headers.cookie;
373
+ if (!cookieHeader) return null;
374
+ const cookies = cookieHeader.split(';');
375
+ for (let c of cookies) {
376
+ const [k, v] = c.trim().split('=');
377
+ if (k === name) return decodeURIComponent(v);
378
+ }
379
+ return null;
380
+ },
381
+ /** Sets Set-Cookie header on response */
382
+ set: (res, name, value, options = {}) => {
383
+ if (!res || !res.setHeader) return;
384
+ let cookie = `${name}=${encodeURIComponent(value)}`;
385
+ if (options.maxAge) cookie += `; Max-Age=${options.maxAge}`;
386
+ if (options.path) cookie += `; Path=${options.path}`;
387
+ if (options.httpOnly) cookie += `; HttpOnly`;
388
+ if (options.secure) cookie += `; Secure`;
389
+ if (options.sameSite) cookie += `; SameSite=${options.sameSite}`;
390
+
391
+ let prev = res.getHeader ? res.getHeader('Set-Cookie') : null;
392
+ if (prev) {
393
+ if (Array.isArray(prev)) {
394
+ prev.push(cookie);
395
+ res.setHeader('Set-Cookie', prev);
396
+ } else {
397
+ res.setHeader('Set-Cookie', [prev, cookie]);
398
+ }
399
+ } else {
400
+ res.setHeader('Set-Cookie', cookie);
401
+ }
402
+ },
403
+ /** Deletes cookie by setting maxAge=0 */
404
+ delete: (res, name) => {
405
+ cookies.set(res, name, "", { maxAge: 0, path: '/' });
406
+ }
407
+ };
408
+
409
+ // --- OS ---
410
+ const os = {
411
+ platform: () => {
412
+ if (!native_os_info) return "unknown";
413
+ const info = JSON.parse(native_os_info());
414
+ return info.platform;
415
+ },
416
+ cpus: () => {
417
+ if (!native_os_info) return 1;
418
+ const info = JSON.parse(native_os_info());
419
+ return info.cpus;
420
+ },
421
+ totalMemory: () => {
422
+ if (!native_os_info) return 0;
423
+ const info = JSON.parse(native_os_info());
424
+ return info.totalMemory;
425
+ },
426
+ freeMemory: () => {
427
+ if (!native_os_info) return 0;
428
+ const info = JSON.parse(native_os_info());
429
+ return info.freeMemory;
430
+ },
431
+ tmpdir: () => '/tmp'
432
+ };
433
+
434
+ // --- Net ---
435
+ const net = {
436
+ resolveDNS: (hostname) => {
437
+ if (!native_net_resolve) return [];
438
+ return JSON.parse(native_net_resolve(hostname));
439
+ },
440
+ ip: () => native_net_ip ? native_net_ip() : "127.0.0.1",
441
+ ping: (host) => true
442
+ };
443
+
444
+ // --- Proc ---
445
+ const proc = {
446
+ pid: () => {
447
+ if (!native_proc_info) return 0;
448
+ const info = JSON.parse(native_proc_info());
449
+ return info.pid;
450
+ },
451
+ uptime: () => {
452
+ if (!native_proc_info) return 0;
453
+ const info = JSON.parse(native_proc_info());
454
+ return info.uptime;
455
+ },
456
+ memory: () => ({})
457
+ };
458
+
459
+ // --- Time ---
460
+ const time = {
461
+ sleep: (ms) => {
462
+ if (native_time_sleep) native_time_sleep(ms);
463
+ },
464
+ now: () => Date.now(),
465
+ timestamp: () => new Date().toISOString()
466
+ };
467
+
468
+ // --- URL ---
469
+ class TitanURLSearchParams {
470
+ constructor(init = '') {
471
+ this._params = {};
472
+ if (typeof init === 'string') {
473
+ const query = init.startsWith('?') ? init.slice(1) : init;
474
+ query.split('&').forEach(pair => {
475
+ const [key, value] = pair.split('=').map(decodeURIComponent);
476
+ if (key) this._params[key] = value || '';
477
+ });
478
+ } else if (typeof init === 'object') {
479
+ Object.assign(this._params, init);
480
+ }
481
+ }
482
+ get(key) { return this._params[key] || null; }
483
+ set(key, value) { this._params[key] = String(value); }
484
+ has(key) { return key in this._params; }
485
+ delete(key) { delete this._params[key]; }
486
+ toString() {
487
+ return Object.entries(this._params)
488
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
489
+ .join('&');
490
+ }
491
+ entries() { return Object.entries(this._params); }
492
+ keys() { return Object.keys(this._params); }
493
+ values() { return Object.values(this._params); }
494
+ }
495
+
496
+ const url = {
497
+ parse: (str) => {
498
+ if (typeof URL !== 'undefined') {
499
+ return new URL(str);
500
+ }
501
+ const match = str.match(/^(https?:)\/\/([^/:]+)(?::(\d+))?(\/[^?#]*)?(\?[^#]*)?(#.*)?$/);
502
+ if (!match) throw new Error('Invalid URL');
503
+ return {
504
+ protocol: match[1],
505
+ hostname: match[2],
506
+ port: match[3] || '',
507
+ pathname: match[4] || '/',
508
+ search: match[5] || '',
509
+ hash: match[6] || ''
510
+ };
511
+ },
512
+ format: (obj) => obj.toString ? obj.toString() : String(obj),
513
+ SearchParams: TitanURLSearchParams
514
+ };
515
+
516
+ // Create the main core export object (following titan-valid pattern)
517
+ const core = {
518
+ fs,
519
+ path,
520
+ crypto,
521
+ os,
522
+ net,
523
+ proc,
524
+ time,
525
+ url,
526
+ buffer, // t.core.buffer
527
+ };
528
+
529
+ t.fs = fs;
530
+ t.path = path;
531
+ t.crypto = crypto;
532
+ t.os = os;
533
+ t.net = net;
534
+ t.proc = proc;
535
+ t.time = time;
536
+ t.url = url;
537
+
538
+ // New Global Modules
539
+ t.buffer = buffer;
540
+ t.ls = ls;
541
+ t.localStorage = ls;
542
+ t.session = session;
543
+ t.cookies = cookies;
544
+
545
+ // Attach core as unified namespace (main access point)
546
+ t.core = core;
547
+
548
+ // Register as extension under multiple names for compatibility
549
+ t["titan-core"] = core;
550
+ t["@titanpl/core"] = core;
551
+
552
+ // Also register in t.exts
553
+ if (!t.exts) t.exts = {};
554
+ t.exts["titan-core"] = core;
250
555
  t.exts["@titanpl/core"] = core;