titanpl 7.0.0 → 7.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.
Files changed (54) hide show
  1. package/package.json +1 -1
  2. package/packages/cli/package.json +4 -4
  3. package/packages/cli/src/commands/build-ext.js +17 -4
  4. package/packages/engine-darwin-arm64/package.json +1 -1
  5. package/packages/engine-linux-x64/package.json +1 -1
  6. package/packages/engine-win32-x64/bin/titan-server.exe +0 -0
  7. package/packages/engine-win32-x64/package.json +1 -1
  8. package/packages/native/index.d.ts +27 -0
  9. package/packages/native/index.js +1 -0
  10. package/packages/native/package.json +1 -1
  11. package/packages/native/t.native.d.ts +99 -3
  12. package/packages/packet/package.json +1 -1
  13. package/packages/route/package.json +1 -1
  14. package/packages/sdk/package.json +1 -1
  15. package/templates/extension/README_WASM.md +38 -0
  16. package/templates/extension/package.json +2 -2
  17. package/templates/js/package.json +7 -7
  18. package/templates/rust-js/package.json +4 -4
  19. package/templates/rust-ts/package.json +4 -4
  20. package/templates/ts/package.json +7 -7
  21. package/packages/core-source/LICENSE +0 -15
  22. package/packages/core-source/README.md +0 -128
  23. package/packages/core-source/V8_SERIALIZATION.md +0 -125
  24. package/packages/core-source/configure.js +0 -50
  25. package/packages/core-source/globals.d.ts +0 -2238
  26. package/packages/core-source/index.d.ts +0 -515
  27. package/packages/core-source/index.js +0 -639
  28. package/packages/core-source/jsconfig.json +0 -12
  29. package/packages/core-source/mkctx.config.json +0 -7
  30. package/packages/core-source/native/Cargo.lock +0 -1559
  31. package/packages/core-source/native/Cargo.toml +0 -30
  32. package/packages/core-source/native/src/crypto_impl.rs +0 -139
  33. package/packages/core-source/native/src/lib.rs +0 -702
  34. package/packages/core-source/native/src/storage_impl.rs +0 -73
  35. package/packages/core-source/native/src/v8_impl.rs +0 -93
  36. package/packages/core-source/package-lock.json +0 -1464
  37. package/packages/core-source/package.json +0 -53
  38. package/packages/core-source/tests/buffer.test.js +0 -78
  39. package/packages/core-source/tests/cookies.test.js +0 -117
  40. package/packages/core-source/tests/crypto.test.js +0 -142
  41. package/packages/core-source/tests/fs.test.js +0 -176
  42. package/packages/core-source/tests/ls.test.js +0 -149
  43. package/packages/core-source/tests/net.test.js +0 -84
  44. package/packages/core-source/tests/os.test.js +0 -81
  45. package/packages/core-source/tests/path.test.js +0 -102
  46. package/packages/core-source/tests/response.test.js +0 -146
  47. package/packages/core-source/tests/session.test.js +0 -110
  48. package/packages/core-source/tests/setup.js +0 -325
  49. package/packages/core-source/tests/time.test.js +0 -57
  50. package/packages/core-source/tests/url.test.js +0 -82
  51. package/packages/core-source/titan-ext.d.ts +0 -2
  52. package/packages/core-source/titan.json +0 -9
  53. package/packages/core-source/vitest.config.js +0 -8
  54. package/templates/extension/README.md +0 -69
@@ -1,325 +0,0 @@
1
- /**
2
- * tests/setup.js
3
- *
4
- * Emulates Rust native functions for testing.
5
- * Equivalent to what @t8n/micro-gravity/setup would do.
6
- *
7
- * MOCKED:
8
- * - DB (PostgreSQL connection) - No way to test without a real DB
9
- *
10
- * EMULATED (JS implementation that simulates Rust behavior):
11
- * - fs_* (uses Node.js fs)
12
- * - crypto_* (uses Node.js crypto)
13
- * - ls_* (uses in-memory Map)
14
- * - session_* (uses in-memory Map)
15
- * - os_*, net_*, proc_*, time_*, path_cwd
16
- */
17
-
18
- import { vi } from 'vitest';
19
- import * as nodeFs from 'node:fs';
20
- import * as nodePath from 'node:path';
21
- import * as nodeCrypto from 'node:crypto';
22
- import * as nodeOs from 'node:os';
23
-
24
- // In-memory storage for ls and session
25
- const localStorage = new Map();
26
- const sessionStorage = new Map();
27
-
28
- // Initialize global `t` object with native functions
29
- globalThis.t = globalThis.t || {};
30
- globalThis.t["@titanpl/core"] = globalThis.t["@titanpl/core"] || {};
31
- globalThis.t.native = globalThis.t.native || {};
32
- globalThis.t.core = globalThis.t.core || {};
33
-
34
- const ext = globalThis.t["@titanpl/core"];
35
-
36
- // ============================================
37
- // FILE SYSTEM - Emulation using Node.js fs
38
- // ============================================
39
-
40
- ext.fs_read_file = (path) => {
41
- try {
42
- return nodeFs.readFileSync(path, 'utf-8');
43
- } catch (e) {
44
- return `ERROR: ${e.message}`;
45
- }
46
- };
47
-
48
- ext.fs_write_file = (path, content) => {
49
- nodeFs.writeFileSync(path, content, 'utf-8');
50
- };
51
-
52
- ext.fs_readdir = (path) => {
53
- try {
54
- return JSON.stringify(nodeFs.readdirSync(path));
55
- } catch {
56
- return '[]';
57
- }
58
- };
59
-
60
- ext.fs_mkdir = (path) => {
61
- nodeFs.mkdirSync(path, { recursive: true });
62
- };
63
-
64
- ext.fs_exists = (path) => {
65
- return nodeFs.existsSync(path);
66
- };
67
-
68
- ext.fs_stat = (path) => {
69
- try {
70
- const stat = nodeFs.statSync(path);
71
- return JSON.stringify({
72
- size: stat.size,
73
- isFile: stat.isFile(),
74
- isDir: stat.isDirectory(),
75
- modified: stat.mtimeMs
76
- });
77
- } catch {
78
- return '{}';
79
- }
80
- };
81
-
82
- ext.fs_remove = (path) => {
83
- try {
84
- const stat = nodeFs.statSync(path);
85
- if (stat.isDirectory()) {
86
- nodeFs.rmSync(path, { recursive: true });
87
- } else {
88
- nodeFs.unlinkSync(path);
89
- }
90
- } catch { }
91
- };
92
-
93
- ext.path_cwd = () => process.cwd();
94
-
95
- // ============================================
96
- // CRYPTO - Emulation using Node.js crypto
97
- // ============================================
98
-
99
- ext.crypto_hash = (algo, data) => {
100
- try {
101
- const hash = nodeCrypto.createHash(algo);
102
- hash.update(data);
103
- return hash.digest('hex');
104
- } catch (e) {
105
- return `ERROR: ${e.message}`;
106
- }
107
- };
108
-
109
- ext.crypto_random_bytes = (size) => {
110
- return nodeCrypto.randomBytes(size).toString('hex');
111
- };
112
-
113
- ext.crypto_uuid = () => {
114
- return nodeCrypto.randomUUID();
115
- };
116
-
117
- ext.crypto_encrypt = (algo, jsonArgs) => {
118
- try {
119
- const { key, plaintext } = JSON.parse(jsonArgs);
120
- const keyBuffer = Buffer.alloc(32);
121
- Buffer.from(key).copy(keyBuffer);
122
- const iv = nodeCrypto.randomBytes(12);
123
- const cipher = nodeCrypto.createCipheriv('aes-256-gcm', keyBuffer, iv);
124
- let encrypted = cipher.update(plaintext, 'utf8', 'hex');
125
- encrypted += cipher.final('hex');
126
- const authTag = cipher.getAuthTag().toString('hex');
127
- return iv.toString('hex') + ':' + authTag + ':' + encrypted;
128
- } catch (e) {
129
- return `ERROR: ${e.message}`;
130
- }
131
- };
132
-
133
- ext.crypto_decrypt = (algo, jsonArgs) => {
134
- try {
135
- const { key, ciphertext } = JSON.parse(jsonArgs);
136
- const [ivHex, authTagHex, encrypted] = ciphertext.split(':');
137
- const keyBuffer = Buffer.alloc(32);
138
- Buffer.from(key).copy(keyBuffer);
139
- const iv = Buffer.from(ivHex, 'hex');
140
- const authTag = Buffer.from(authTagHex, 'hex');
141
- const decipher = nodeCrypto.createDecipheriv('aes-256-gcm', keyBuffer, iv);
142
- decipher.setAuthTag(authTag);
143
- let decrypted = decipher.update(encrypted, 'hex', 'utf8');
144
- decrypted += decipher.final('utf8');
145
- return decrypted;
146
- } catch (e) {
147
- return `ERROR: ${e.message}`;
148
- }
149
- };
150
-
151
- ext.crypto_hash_keyed = (algo, jsonArgs) => {
152
- try {
153
- const { key, message } = JSON.parse(jsonArgs);
154
- const hmac = nodeCrypto.createHmac(algo === 'sha256' ? 'sha256' : 'sha512', key);
155
- hmac.update(message);
156
- return hmac.digest('hex');
157
- } catch (e) {
158
- return `ERROR: ${e.message}`;
159
- }
160
- };
161
-
162
- ext.crypto_compare = (a, b) => {
163
- return nodeCrypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
164
- };
165
-
166
- // ============================================
167
- // LOCAL STORAGE - In-memory emulation
168
- // ============================================
169
-
170
- ext.ls_get = (key) => {
171
- return localStorage.get(key) || '';
172
- };
173
-
174
- ext.ls_set = (key, value) => {
175
- localStorage.set(key, value);
176
- };
177
-
178
- ext.ls_remove = (key) => {
179
- localStorage.delete(key);
180
- };
181
-
182
- ext.ls_clear = () => {
183
- localStorage.clear();
184
- };
185
-
186
- ext.ls_keys = () => {
187
- return JSON.stringify([...localStorage.keys()]);
188
- };
189
-
190
- // Simplified V8 serialization (uses JSON as fallback)
191
- ext.serialize = (value) => {
192
- try {
193
- const json = JSON.stringify(value);
194
- return new TextEncoder().encode(json);
195
- } catch {
196
- return null;
197
- }
198
- };
199
-
200
- ext.deserialize = (bytes) => {
201
- try {
202
- const json = new TextDecoder().decode(bytes);
203
- return JSON.parse(json);
204
- } catch {
205
- return null;
206
- }
207
- };
208
-
209
- // ============================================
210
- // SESSION - In-memory emulation
211
- // ============================================
212
-
213
- ext.session_get = (sid, key) => {
214
- return sessionStorage.get(`${sid}:${key}`) || '';
215
- };
216
-
217
- ext.session_set = (sid, jsonArgs) => {
218
- const { key, value } = JSON.parse(jsonArgs);
219
- sessionStorage.set(`${sid}:${key}`, value);
220
- };
221
-
222
- ext.session_delete = (sid, key) => {
223
- sessionStorage.delete(`${sid}:${key}`);
224
- };
225
-
226
- ext.session_clear = (sid) => {
227
- for (const key of sessionStorage.keys()) {
228
- if (key.startsWith(`${sid}:`)) {
229
- sessionStorage.delete(key);
230
- }
231
- }
232
- };
233
-
234
- // ============================================
235
- // OS - Emulation using Node.js os
236
- // ============================================
237
-
238
- ext.os_info = () => {
239
- return JSON.stringify({
240
- platform: nodeOs.platform(),
241
- cpus: nodeOs.cpus().length,
242
- totalMemory: nodeOs.totalmem(),
243
- freeMemory: nodeOs.freemem(),
244
- tmpdir: nodeOs.tmpdir()
245
- });
246
- };
247
-
248
- // ============================================
249
- // NET - Basic emulation
250
- // ============================================
251
-
252
- ext.net_resolve = (hostname) => {
253
- return JSON.stringify(['127.0.0.1']);
254
- };
255
-
256
- ext.net_ip = () => {
257
- const interfaces = nodeOs.networkInterfaces();
258
- for (const name of Object.keys(interfaces)) {
259
- for (const iface of interfaces[name]) {
260
- if (iface.family === 'IPv4' && !iface.internal) {
261
- return iface.address;
262
- }
263
- }
264
- }
265
- return '127.0.0.1';
266
- };
267
-
268
- // ============================================
269
- // PROC - Basic emulation
270
- // ============================================
271
-
272
- ext.proc_info = () => {
273
- return JSON.stringify({
274
- pid: process.pid,
275
- uptime: process.uptime()
276
- });
277
- };
278
-
279
- ext.proc_run = (jsonArgs) => {
280
- return JSON.stringify({ ok: false, error: 'Disabled in tests' });
281
- };
282
-
283
- ext.proc_kill = (pid) => {
284
- return false;
285
- };
286
-
287
- ext.proc_list = () => {
288
- return JSON.stringify([]);
289
- };
290
-
291
- // ============================================
292
- // TIME
293
- // ============================================
294
-
295
- ext.time_sleep = (ms) => {
296
- const end = Date.now() + ms;
297
- while (Date.now() < end) { }
298
- };
299
-
300
- // ============================================
301
- // DATABASE - MOCK (only real mock)
302
- // ============================================
303
-
304
- globalThis.t.db = {
305
- connect: vi.fn().mockReturnValue({
306
- query: vi.fn().mockResolvedValue({ rows: [] }),
307
- execute: vi.fn().mockResolvedValue({ rowCount: 0 }),
308
- close: vi.fn()
309
- })
310
- };
311
-
312
- // ============================================
313
- // Helpers to clear state between tests
314
- // ============================================
315
-
316
- export function clearStorage() {
317
- localStorage.clear();
318
- sessionStorage.clear();
319
- }
320
-
321
- import { beforeEach } from 'vitest';
322
-
323
- beforeEach(() => {
324
- clearStorage();
325
- });
@@ -1,57 +0,0 @@
1
- /**
2
- * tests/time.test.js
3
- *
4
- * Tests for the time module
5
- * time.now() - Pure JS (Date.now())
6
- * time.sleep() - Native emulated
7
- */
8
- import { describe, it, expect } from 'vitest';
9
- import { time } from '../index.js';
10
-
11
- describe('time', () => {
12
- describe('now()', () => {
13
- it('should return current timestamp', () => {
14
- const before = Date.now();
15
- const result = time.now();
16
- const after = Date.now();
17
-
18
- expect(result).toBeGreaterThanOrEqual(before);
19
- expect(result).toBeLessThanOrEqual(after);
20
- });
21
-
22
- it('should return number', () => {
23
- expect(typeof time.now()).toBe('number');
24
- });
25
-
26
- it('should increment over time', async () => {
27
- const first = time.now();
28
- await new Promise(r => setTimeout(r, 10));
29
- const second = time.now();
30
-
31
- expect(second).toBeGreaterThan(first);
32
- });
33
- });
34
-
35
- describe('sleep()', () => {
36
- it('should pause execution', () => {
37
- const start = Date.now();
38
- time.sleep(50);
39
- const elapsed = Date.now() - start;
40
-
41
- // Should have passed at least 40ms (margin of error)
42
- expect(elapsed).toBeGreaterThanOrEqual(40);
43
- });
44
-
45
- it('should accept small values', () => {
46
- expect(() => time.sleep(1)).not.toThrow();
47
- });
48
-
49
- it('should handle 0ms', () => {
50
- const start = Date.now();
51
- time.sleep(0);
52
- const elapsed = Date.now() - start;
53
-
54
- expect(elapsed).toBeLessThan(100);
55
- });
56
- });
57
- });
@@ -1,82 +0,0 @@
1
- /**
2
- * tests/url.test.js
3
- *
4
- * Tests for the url module
5
- * Pure JS API - uses native URL and URLSearchParams
6
- */
7
- import { describe, it, expect } from 'vitest';
8
- import { url } from '../index.js';
9
-
10
- describe('url', () => {
11
- describe('parse()', () => {
12
- it('should parse complete URL', () => {
13
- const parsed = url.parse('https://example.com:8080/path?query=value#hash');
14
-
15
- expect(parsed.protocol).toBe('https:');
16
- expect(parsed.hostname).toBe('example.com');
17
- expect(parsed.port).toBe('8080');
18
- expect(parsed.pathname).toBe('/path');
19
- expect(parsed.search).toBe('?query=value');
20
- expect(parsed.hash).toBe('#hash');
21
- });
22
-
23
- it('should parse simple URL', () => {
24
- const parsed = url.parse('https://example.com');
25
-
26
- expect(parsed.hostname).toBe('example.com');
27
- expect(parsed.pathname).toBe('/');
28
- });
29
-
30
- it('should return null for invalid URL', () => {
31
- expect(url.parse('not-a-url')).toBeNull();
32
- expect(url.parse('')).toBeNull();
33
- });
34
-
35
- it('should handle query params', () => {
36
- const parsed = url.parse('https://api.example.com/search?q=test&page=1');
37
-
38
- expect(parsed.searchParams.get('q')).toBe('test');
39
- expect(parsed.searchParams.get('page')).toBe('1');
40
- });
41
-
42
- it('should handle URLs with authentication', () => {
43
- const parsed = url.parse('https://user:pass@example.com/path');
44
-
45
- expect(parsed.username).toBe('user');
46
- expect(parsed.password).toBe('pass');
47
- });
48
- });
49
-
50
- describe('SearchParams', () => {
51
- it('should create URLSearchParams instance', () => {
52
- const params = new url.SearchParams('foo=bar&baz=qux');
53
-
54
- expect(params.get('foo')).toBe('bar');
55
- expect(params.get('baz')).toBe('qux');
56
- });
57
-
58
- it('should serialize to string', () => {
59
- const params = new url.SearchParams();
60
- params.append('key', 'value');
61
- params.append('another', 'test');
62
-
63
- expect(params.toString()).toContain('key=value');
64
- expect(params.toString()).toContain('another=test');
65
- });
66
-
67
- it('should handle encoded values', () => {
68
- const params = new url.SearchParams();
69
- params.set('message', 'Hello World!');
70
-
71
- expect(params.toString()).toContain('Hello');
72
- });
73
-
74
- it('should iterate over entries', () => {
75
- const params = new url.SearchParams('a=1&b=2&c=3');
76
- const entries = [...params.entries()];
77
-
78
- expect(entries).toHaveLength(3);
79
- expect(entries[0]).toEqual(['a', '1']);
80
- });
81
- });
82
- });
@@ -1,2 +0,0 @@
1
- // titan-ext.d.ts
2
- /// <reference path="./globals.d.ts" />
@@ -1,9 +0,0 @@
1
- {
2
- "name": "@titanpl/core",
3
- "type": "native",
4
- "entry": "index.js",
5
- "native": {
6
- "windows": "native/target/release/titan_core.dll",
7
- "linux": "native/target/release/libtitan_core.so"
8
- }
9
- }
@@ -1,8 +0,0 @@
1
- // vitest.config.ts
2
- import { defineConfig } from 'vitest/config';
3
-
4
- export default defineConfig({
5
- test: {
6
- setupFiles: ['@tgrv/microgravity/setup'],
7
- }
8
- });
@@ -1,69 +0,0 @@
1
- # Titan Extension Template
2
-
3
- This template provides a starting point for building native extensions for Titan.
4
-
5
- ## Directory Structure
6
-
7
- - `index.js`: The JavaScript entry point for your extension. It runs within the Titan runtime.
8
- - `index.d.ts`: TypeScript definitions for your extension. This ensures users get autocompletion when using your extension.
9
- - `native/`: (Optional) Rust source code for native high-performance logic.
10
- - `titan.json`: Configuration file defining your extension's native ABI (if using Rust).
11
-
12
- ## Type Definitions (`index.d.ts`)
13
-
14
- The `index.d.ts` file is crucial for Developer Experience (DX). It allows Titan projects to "see" your extension's API on the global `t` object.
15
-
16
- ### How it works
17
-
18
- Titan uses **Declaration Merging** to extend the global `Titan.Runtime` interface. When a user installs your extension, this file acts as a plugin to their TypeScript environment.
19
-
20
- ### Customizing Types
21
-
22
- Edit `index.d.ts` to match the API you expose in `index.js`.
23
-
24
- **Example:**
25
-
26
- If your `index.js` looks like this:
27
-
28
- ```javascript
29
- // index.js
30
- t.ext.my_cool_ext = {
31
- greet: (name) => `Hello, ${name}!`,
32
- compute: (x) => x * 2
33
- };
34
- ```
35
-
36
- Your `index.d.ts` should look like this:
37
-
38
- ```typescript
39
- // index.d.ts
40
- declare global {
41
- namespace Titan {
42
- interface Runtime {
43
- "my-cool-ext": {
44
- /**
45
- * Sends a greeting.
46
- */
47
- greet(name: string): string;
48
-
49
- /**
50
- * Computes a value.
51
- */
52
- compute(x: number): number;
53
- }
54
- }
55
- }
56
- }
57
- export { };
58
- ```
59
-
60
- ## Native Bindings (Rust)
61
-
62
- If your extension requires native performance or system access, use the `native/` directory.
63
- 1. Define functions in `native/src/lib.rs`.
64
- 2. Map them in `titan.json`.
65
- 3. Call them from `index.js` using `Titan.native.invoke(...)` (or the helper provided in the template).
66
-
67
- ---
68
-
69
- **Important Note:** Currently, Titan Planet and its entire package ecosystem are only for Windows. The Linux version is in development (dev only) for the new architecture and will be launched later.