@marsengine/mars-client 1.0.0 → 1.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 +22 -12
- package/publish_attempt_3.txt +0 -0
- package/publish_log.txt +0 -0
- package/publish_root_attempt.txt +0 -0
- package/src/index.ts +71 -61
- package/tsconfig.json +25 -5
- package/README.md +0 -61
- package/dist/index.d.ts +0 -25
- package/dist/index.js +0 -68
package/package.json
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marsengine/mars-client",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "React-friendly client for MARS Engine",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
7
14
|
"scripts": {
|
|
8
|
-
"build": "
|
|
15
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
16
|
+
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
17
|
+
"typecheck": "tsc --noEmit"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@marsengine/engine": "file:../engine"
|
|
9
21
|
},
|
|
10
|
-
"keywords": [
|
|
11
|
-
"mars",
|
|
12
|
-
"webcontainer",
|
|
13
|
-
"client"
|
|
14
|
-
],
|
|
15
|
-
"author": "MARS Team",
|
|
16
|
-
"license": "MIT",
|
|
17
22
|
"devDependencies": {
|
|
23
|
+
"react": "^18.2.0",
|
|
24
|
+
"tsup": "^8.0.1",
|
|
18
25
|
"typescript": "^5.3.3"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"react": ">=18.0.0"
|
|
19
29
|
}
|
|
20
30
|
}
|
|
Binary file
|
package/publish_log.txt
ADDED
|
Binary file
|
|
Binary file
|
package/src/index.ts
CHANGED
|
@@ -1,77 +1,87 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
import { MarsEngine, type IMarsEngine } from '@marsengine/engine';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
|
-
* MARS
|
|
3
|
-
* This is the lightweight "Messenger" library that customers install.
|
|
4
|
-
* It contains NO engine logic, only a bridge to the hosted runtime.
|
|
5
|
+
* Hook to use MARS Engine in a React component
|
|
5
6
|
*/
|
|
7
|
+
export function useMarsEngine() {
|
|
8
|
+
const [engine, setEngine] = useState<IMarsEngine | null>(null);
|
|
9
|
+
const [isBooting, setIsBooting] = useState(false);
|
|
10
|
+
const [error, setError] = useState<Error | null>(null);
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
this.iframe = document.createElement('iframe');
|
|
22
|
-
this.iframe.src = this.runtimeUrl;
|
|
23
|
-
this.iframe.style.display = 'none';
|
|
24
|
-
this.iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
|
|
12
|
+
const boot = useCallback(async (options = {}) => {
|
|
13
|
+
setIsBooting(true);
|
|
14
|
+
setError(null);
|
|
15
|
+
try {
|
|
16
|
+
const instance = await MarsEngine.boot(options);
|
|
17
|
+
setEngine(instance);
|
|
18
|
+
return instance;
|
|
19
|
+
} catch (err: any) {
|
|
20
|
+
setError(err);
|
|
21
|
+
throw err;
|
|
22
|
+
} finally {
|
|
23
|
+
setIsBooting(false);
|
|
24
|
+
}
|
|
25
|
+
}, []);
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this.iframe!.contentWindow!.postMessage(
|
|
29
|
-
{ type: 'MARS_HANDSHAKE' },
|
|
30
|
-
this.runtimeUrl,
|
|
31
|
-
[this.channel.port2]
|
|
32
|
-
);
|
|
27
|
+
return { engine, isBooting, error, boot };
|
|
28
|
+
}
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Messenger for remote control of MARS Engine
|
|
32
|
+
* Useful for iframe-to-iframe communication
|
|
33
|
+
*/
|
|
34
|
+
export class MarsMessenger {
|
|
35
|
+
private engine: IMarsEngine;
|
|
39
36
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
constructor(engine: IMarsEngine) {
|
|
38
|
+
this.engine = engine;
|
|
39
|
+
this.setupListeners();
|
|
43
40
|
}
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (!this.port) throw new Error('Engine not booted');
|
|
50
|
-
|
|
51
|
-
const requestId = Math.random().toString(36).substring(7);
|
|
52
|
-
this.port.postMessage({ type: 'MARS_CALL', requestId, method, args });
|
|
42
|
+
private setupListeners() {
|
|
43
|
+
window.addEventListener('message', async (event) => {
|
|
44
|
+
const { type, payload, id } = event.data;
|
|
45
|
+
if (!type || !type.startsWith('MARS_')) return;
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
try {
|
|
48
|
+
let result;
|
|
49
|
+
switch (type) {
|
|
50
|
+
case 'MARS_MOUNT':
|
|
51
|
+
result = await this.engine.mount(payload.tree, payload.target);
|
|
52
|
+
break;
|
|
53
|
+
case 'MARS_SPAWN':
|
|
54
|
+
const process = await this.engine.spawn(payload.command, payload.args, payload.options);
|
|
55
|
+
// Handle process streaming back to caller
|
|
56
|
+
this.handleProcess(process, id);
|
|
57
|
+
return;
|
|
58
|
+
case 'MARS_WRITE_FILE':
|
|
59
|
+
result = await this.engine.fs.writeFile(payload.path, payload.contents);
|
|
60
|
+
break;
|
|
61
|
+
case 'MARS_READ_FILE':
|
|
62
|
+
result = await this.engine.fs.readFile(payload.path, payload.encoding);
|
|
63
|
+
break;
|
|
59
64
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
|
|
66
|
+
window.parent.postMessage({ id, result }, '*');
|
|
67
|
+
} catch (err: any) {
|
|
68
|
+
window.parent.postMessage({ id, error: err.message }, '*');
|
|
69
|
+
}
|
|
63
70
|
});
|
|
64
71
|
}
|
|
65
72
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
private handleProcess(process: any, id: string) {
|
|
74
|
+
process.output.pipeTo(new WritableStream({
|
|
75
|
+
write(chunk) {
|
|
76
|
+
window.parent.postMessage({ id, type: 'STDOUT', chunk }, '*');
|
|
77
|
+
}
|
|
78
|
+
}));
|
|
70
79
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
readFile: (path: string) => this.call('fs.readFile', [path]),
|
|
75
|
-
};
|
|
80
|
+
process.exit.then((code: number) => {
|
|
81
|
+
window.parent.postMessage({ id, type: 'EXIT', code }, '*');
|
|
82
|
+
});
|
|
76
83
|
}
|
|
77
84
|
}
|
|
85
|
+
|
|
86
|
+
export { MarsEngine };
|
|
87
|
+
export type { IMarsEngine };
|
package/tsconfig.json
CHANGED
|
@@ -1,10 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"target": "
|
|
4
|
-
"module": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": [
|
|
7
|
+
"DOM",
|
|
8
|
+
"DOM.Iterable",
|
|
9
|
+
"ESNext"
|
|
10
|
+
],
|
|
11
|
+
"allowJs": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"allowSyntheticDefaultImports": true,
|
|
15
|
+
"strict": true,
|
|
16
|
+
"forceConsistentCasingInFileNames": true,
|
|
17
|
+
"noFallthroughCasesInSwitch": true,
|
|
18
|
+
"resolveJsonModule": true,
|
|
19
|
+
"isolatedModules": true,
|
|
20
|
+
"noEmit": true,
|
|
21
|
+
"jsx": "react-jsx",
|
|
22
|
+
"baseUrl": ".",
|
|
23
|
+
"paths": {
|
|
24
|
+
"@marsengine/engine": [
|
|
25
|
+
"../engine/src/index.ts"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
8
28
|
},
|
|
9
29
|
"include": [
|
|
10
30
|
"src"
|
package/README.md
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# @yakreentechnologies/mars-client
|
|
2
|
-
|
|
3
|
-
The official client for the **MARS Engine** - The Enterprise-Grade WebContainer Replacement.
|
|
4
|
-
|
|
5
|
-
This lightweight library allows you to connect to a hosted MARS Engine runtime and control a full Node.js environment directly from the browser.
|
|
6
|
-
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
* 🚀 **Zero-Copy I/O**: Blazing fast communication with the engine.
|
|
10
|
-
* 🔒 **Secure Sandbox**: Runs code in a hidden, isolated iframe.
|
|
11
|
-
* 📦 **Drop-in Replacement**: API compatible with WebContainer.
|
|
12
|
-
* ⚡ **Vibe Coding Ready**: Optimized for AI-driven development.
|
|
13
|
-
|
|
14
|
-
## Installation
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npm install @marsengine/mars-client
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Usage
|
|
21
|
-
|
|
22
|
-
### 1. Boot the Engine
|
|
23
|
-
|
|
24
|
-
```typescript
|
|
25
|
-
import { MarsEngineMessenger } from '@marsengine/mars-client';
|
|
26
|
-
|
|
27
|
-
// Initialize the engine (pointing to your hosted runtime)
|
|
28
|
-
const engine = new MarsEngineMessenger('https://engine.yourdomain.com');
|
|
29
|
-
|
|
30
|
-
await engine.boot();
|
|
31
|
-
console.log('MARS Engine is ready! 🚀');
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### 2. Run a Command
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
// Run 'npm install' inside the browser
|
|
38
|
-
const process = await engine.spawn('npm', ['install']);
|
|
39
|
-
|
|
40
|
-
// Stream the output to your terminal
|
|
41
|
-
process.output.pipeTo(new WritableStream({
|
|
42
|
-
write(chunk) {
|
|
43
|
-
console.log(chunk);
|
|
44
|
-
}
|
|
45
|
-
}));
|
|
46
|
-
|
|
47
|
-
await process.exit;
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### 3. Write a File
|
|
51
|
-
|
|
52
|
-
```typescript
|
|
53
|
-
await engine.fs.writeFile('/src/App.tsx', `
|
|
54
|
-
import React from 'react';
|
|
55
|
-
export default () => <h1>Hello from MARS! 🪐</h1>;
|
|
56
|
-
`);
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## License
|
|
60
|
-
|
|
61
|
-
MIT
|
package/dist/index.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MARS Messenger (Public API)
|
|
3
|
-
* This is the lightweight "Messenger" library that customers install.
|
|
4
|
-
* It contains NO engine logic, only a bridge to the hosted runtime.
|
|
5
|
-
*/
|
|
6
|
-
export declare class MarsEngineMessenger {
|
|
7
|
-
private runtimeUrl;
|
|
8
|
-
private iframe;
|
|
9
|
-
private channel;
|
|
10
|
-
private port;
|
|
11
|
-
constructor(runtimeUrl?: string);
|
|
12
|
-
/**
|
|
13
|
-
* Boot the engine by creating a hidden iframe to the hosted runtime.
|
|
14
|
-
*/
|
|
15
|
-
boot(): Promise<void>;
|
|
16
|
-
/**
|
|
17
|
-
* Proxy call to the hosted engine.
|
|
18
|
-
*/
|
|
19
|
-
call(method: string, args: any[]): Promise<any>;
|
|
20
|
-
spawn(command: string, args: string[]): Promise<any>;
|
|
21
|
-
get fs(): {
|
|
22
|
-
writeFile: (path: string, content: any) => Promise<any>;
|
|
23
|
-
readFile: (path: string) => Promise<any>;
|
|
24
|
-
};
|
|
25
|
-
}
|
package/dist/index.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* MARS Messenger (Public API)
|
|
4
|
-
* This is the lightweight "Messenger" library that customers install.
|
|
5
|
-
* It contains NO engine logic, only a bridge to the hosted runtime.
|
|
6
|
-
*/
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.MarsEngineMessenger = void 0;
|
|
9
|
-
class MarsEngineMessenger {
|
|
10
|
-
constructor(runtimeUrl = 'https://runtime.mars.ai') {
|
|
11
|
-
this.runtimeUrl = runtimeUrl;
|
|
12
|
-
this.iframe = null;
|
|
13
|
-
this.port = null;
|
|
14
|
-
this.channel = new MessageChannel();
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Boot the engine by creating a hidden iframe to the hosted runtime.
|
|
18
|
-
*/
|
|
19
|
-
async boot() {
|
|
20
|
-
return new Promise((resolve, reject) => {
|
|
21
|
-
this.iframe = document.createElement('iframe');
|
|
22
|
-
this.iframe.src = this.runtimeUrl;
|
|
23
|
-
this.iframe.style.display = 'none';
|
|
24
|
-
this.iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
|
|
25
|
-
this.iframe.onload = () => {
|
|
26
|
-
// Handshake: Send our MessagePort to the hosted runtime
|
|
27
|
-
this.iframe.contentWindow.postMessage({ type: 'MARS_HANDSHAKE' }, this.runtimeUrl, [this.channel.port2]);
|
|
28
|
-
this.port = this.channel.port1;
|
|
29
|
-
this.port.onmessage = (event) => {
|
|
30
|
-
if (event.data.type === 'MARS_READY')
|
|
31
|
-
resolve();
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
this.iframe.onerror = reject;
|
|
35
|
-
document.body.appendChild(this.iframe);
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Proxy call to the hosted engine.
|
|
40
|
-
*/
|
|
41
|
-
async call(method, args) {
|
|
42
|
-
if (!this.port)
|
|
43
|
-
throw new Error('Engine not booted');
|
|
44
|
-
const requestId = Math.random().toString(36).substring(7);
|
|
45
|
-
this.port.postMessage({ type: 'MARS_CALL', requestId, method, args });
|
|
46
|
-
return new Promise((resolve) => {
|
|
47
|
-
const handler = (event) => {
|
|
48
|
-
if (event.data.requestId === requestId) {
|
|
49
|
-
this.port.removeEventListener('message', handler);
|
|
50
|
-
resolve(event.data.result);
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
this.port.addEventListener('message', handler);
|
|
54
|
-
this.port.start();
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
// Public API Proxies
|
|
58
|
-
async spawn(command, args) {
|
|
59
|
-
return this.call('spawn', [command, args]);
|
|
60
|
-
}
|
|
61
|
-
get fs() {
|
|
62
|
-
return {
|
|
63
|
-
writeFile: (path, content) => this.call('fs.writeFile', [path, content]),
|
|
64
|
-
readFile: (path) => this.call('fs.readFile', [path]),
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
exports.MarsEngineMessenger = MarsEngineMessenger;
|