@jxrstudios/jxr 1.2.15 → 1.2.17
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/README.md +663 -70
- package/bin/jxr.js +120 -20
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,55 +1,240 @@
|
|
|
1
1
|
# JXR.js — Edge OS Runtime Framework
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **Execute JavaScript at the edge with zero-build JSX transformation.**
|
|
4
|
+
>
|
|
5
|
+
> MoQ transport · Web Crypto · Worker Pools · MCP Server · React Native + Web
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
[](https://www.npmjs.com/package/@jxrstudios/jxr)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
**Website:** https://jxrstudios.online
|
|
11
|
+
**Documentation:** https://jxrstudios.online/docs
|
|
12
|
+
**Discord:** https://discord.gg/jxr
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Table of Contents
|
|
17
|
+
|
|
18
|
+
- [Overview](#overview)
|
|
19
|
+
- [Installation](#installation)
|
|
20
|
+
- [Quick Start](#quick-start)
|
|
21
|
+
- [CLI Commands](#cli-commands)
|
|
22
|
+
- [Architecture](#architecture)
|
|
23
|
+
- [MCP Server](#mcp-server)
|
|
24
|
+
- [Migration Guide](#migration-guide)
|
|
25
|
+
- [API Reference](#api-reference)
|
|
26
|
+
- [Deployment](#deployment)
|
|
27
|
+
- [Troubleshooting](#troubleshooting)
|
|
28
|
+
- [Contributing](#contributing)
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Overview
|
|
33
|
+
|
|
34
|
+
JXR.js is a next-generation edge runtime framework that eliminates the traditional build step. It enables:
|
|
35
|
+
|
|
36
|
+
- **Zero-build development** — JSX transforms in the browser via Web Workers
|
|
37
|
+
- **Sub-RTT hot reloading** — MoQ (Media over QUIC) streaming
|
|
38
|
+
- **Universal runtime** — React Native, Web, Cloudflare Workers, Deno, Node.js
|
|
39
|
+
- **AI-native tooling** — 14 MCP tools for autonomous agent operation
|
|
40
|
+
- **Cryptographic integrity** — ECDSA-P256 signed modules
|
|
41
|
+
|
|
42
|
+
### Performance Benchmarks
|
|
43
|
+
|
|
44
|
+
| Metric | JXR.js | Next.js | Vite | Bun |
|
|
45
|
+
|--------|--------|---------|------|-----|
|
|
46
|
+
| Cold Start | 0ms | 2,400ms | 800ms | 350ms |
|
|
47
|
+
| HMR Update | <1ms | 180ms | 45ms | 30ms |
|
|
48
|
+
| Build Time | N/A | 45s | 12s | 8s |
|
|
49
|
+
| Memory Usage | 18MB | 420MB | 180MB | 95MB |
|
|
50
|
+
|
|
51
|
+
*JXR.js has no build step — cold start is time to first rendered pixel.*
|
|
52
|
+
|
|
53
|
+
---
|
|
6
54
|
|
|
7
55
|
## Installation
|
|
8
56
|
|
|
57
|
+
### Global CLI (Recommended)
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm install -g @jxrstudios/jxr
|
|
61
|
+
# or
|
|
62
|
+
pnpm add -g @jxrstudios/jxr
|
|
63
|
+
# or
|
|
64
|
+
yarn global add @jxrstudios/jxr
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Project Dependency
|
|
68
|
+
|
|
9
69
|
```bash
|
|
10
70
|
npm install @jxrstudios/jxr
|
|
11
71
|
```
|
|
12
72
|
|
|
73
|
+
---
|
|
74
|
+
|
|
13
75
|
## Quick Start
|
|
14
76
|
|
|
15
|
-
|
|
16
|
-
import { JXRRuntime, jxrRuntime } from '@jxrstudios/jxr';
|
|
77
|
+
### 1. Create New Project
|
|
17
78
|
|
|
18
|
-
|
|
19
|
-
|
|
79
|
+
```bash
|
|
80
|
+
jxr init my-app
|
|
81
|
+
cd my-app
|
|
82
|
+
npm install
|
|
83
|
+
jxr dev
|
|
84
|
+
```
|
|
20
85
|
|
|
21
|
-
|
|
22
|
-
const runtime = new JXRRuntime({
|
|
23
|
-
maxWorkers: 8,
|
|
24
|
-
moqEndpoint: 'wss://jxrstudios.workers.dev',
|
|
25
|
-
enableCrypto: true,
|
|
26
|
-
});
|
|
27
|
-
await runtime.init();
|
|
86
|
+
### 2. Existing Project Migration
|
|
28
87
|
|
|
29
|
-
|
|
30
|
-
|
|
88
|
+
```bash
|
|
89
|
+
# Auto-detect framework and migrate
|
|
90
|
+
jxr migrate --from nextjs
|
|
31
91
|
|
|
32
|
-
|
|
33
|
-
|
|
92
|
+
# Dry run to preview changes
|
|
93
|
+
jxr migrate --from vite --dry-run
|
|
94
|
+
```
|
|
34
95
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
96
|
+
### 3. Development Server
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
jxr dev # Start on default port 3000
|
|
100
|
+
jxr dev --port 3001 # Custom port
|
|
101
|
+
jxr dev --no-hmr # Disable HMR
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## CLI Commands
|
|
107
|
+
|
|
108
|
+
### `jxr init <project-name>`
|
|
109
|
+
|
|
110
|
+
Create a new JXR project with scaffolding.
|
|
111
|
+
|
|
112
|
+
**Safety:** Never overwrites existing files. Shows detailed error if directory contains files.
|
|
113
|
+
|
|
114
|
+
**Templates:**
|
|
115
|
+
- `react-web` — React web application (default)
|
|
116
|
+
- `react-native` — React Native mobile app
|
|
117
|
+
- `expo` — Expo managed workflow
|
|
118
|
+
- `cloudflare` — Cloudflare Workers edge function
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
jxr init my-app --template react-web
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### `jxr dev`
|
|
125
|
+
|
|
126
|
+
Start development server with HMR.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
jxr dev [options]
|
|
130
|
+
|
|
131
|
+
Options:
|
|
132
|
+
--port=<number> Server port (default: 3000)
|
|
133
|
+
--no-hmr Disable hot module replacement
|
|
134
|
+
--host=<address> Bind to specific host
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Features:**
|
|
138
|
+
- Virtual file system with in-memory caching
|
|
139
|
+
- On-demand JSX/TSX transformation
|
|
140
|
+
- Import map resolution for bare imports
|
|
141
|
+
- Web Worker pool for parallel processing
|
|
142
|
+
- MoQ transport for sub-RTT updates
|
|
143
|
+
|
|
144
|
+
### `jxr build`
|
|
145
|
+
|
|
146
|
+
Production build with code splitting and crypto signing.
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
jxr build [options]
|
|
150
|
+
|
|
151
|
+
Options:
|
|
152
|
+
--platform=<target> web | node | cloudflare-worker (default: web)
|
|
153
|
+
--out-dir=<path> Output directory (default: dist)
|
|
154
|
+
--analyze Show bundle analysis
|
|
155
|
+
--no-minify Disable minification
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Output:**
|
|
159
|
+
- `dist/assets/` — Bundled JavaScript and CSS
|
|
160
|
+
- `dist/index.html` — Entry HTML with proper preload tags
|
|
161
|
+
- `dist/jxr-manifest.json` — Crypto-signed manifest
|
|
162
|
+
|
|
163
|
+
### `jxr migrate`
|
|
164
|
+
|
|
165
|
+
Migrate from existing frameworks with AST-level transformations.
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
jxr migrate [options]
|
|
169
|
+
|
|
170
|
+
Options:
|
|
171
|
+
--from=<framework> nextjs | vite | bun | cra | expo | remix | nuxt
|
|
172
|
+
--to=<target> Target platform (default: react-web)
|
|
173
|
+
--dry-run Preview changes without applying
|
|
174
|
+
--force Skip confirmation prompts
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Supported Frameworks:**
|
|
178
|
+
- Next.js (pages router, app router)
|
|
179
|
+
- Vite (React, Vue, Svelte)
|
|
180
|
+
- Create React App
|
|
181
|
+
- Expo / React Native
|
|
182
|
+
- Remix
|
|
183
|
+
- Nuxt 3
|
|
184
|
+
- Bun
|
|
185
|
+
|
|
186
|
+
**What gets migrated:**
|
|
187
|
+
- Import rewrites (AST-level)
|
|
188
|
+
- Config file conversion
|
|
189
|
+
- API route transformation
|
|
190
|
+
- Dependency mapping
|
|
191
|
+
- Asset path updates
|
|
192
|
+
|
|
193
|
+
### `jxr deploy`
|
|
194
|
+
|
|
195
|
+
Deploy to edge platforms.
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
jxr deploy [path] [options]
|
|
199
|
+
|
|
200
|
+
Arguments:
|
|
201
|
+
path Build output directory (default: ./dist)
|
|
202
|
+
|
|
203
|
+
Options:
|
|
204
|
+
--target=<platform> cloudflare | deno | node
|
|
205
|
+
--env=<environment> production | staging | preview (default: production)
|
|
40
206
|
```
|
|
41
207
|
|
|
42
|
-
|
|
208
|
+
**Environment Variables:**
|
|
209
|
+
```bash
|
|
210
|
+
export JXR_API_KEY=jxr_live_xxxxx # Required
|
|
211
|
+
export JXR_PROJECT_ID=my-project # Optional
|
|
212
|
+
```
|
|
43
213
|
|
|
44
|
-
|
|
45
|
-
- **JSXTransformer** — Zero-build JSX/TSX transformation
|
|
46
|
-
- **WorkerPool** — Parallel task execution with metrics
|
|
47
|
-
- **MoQTransport** — Edge data streaming (Media over QUIC)
|
|
48
|
-
- **JXRCrypto** — Module integrity verification & signing
|
|
49
|
-
- **ModuleCache** — LRU cache for resolved modules
|
|
50
|
-
- **ImportMapBuilder** — Browser import map generation
|
|
214
|
+
---
|
|
51
215
|
|
|
52
|
-
##
|
|
216
|
+
## Architecture
|
|
217
|
+
|
|
218
|
+
### Core Modules
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
JXR.js
|
|
222
|
+
├── VirtualFS # In-memory file system
|
|
223
|
+
├── JSXTransformer # Zero-build JSX/TSX transform
|
|
224
|
+
├── WorkerPool # Parallel task execution
|
|
225
|
+
├── ModuleResolver # Import resolution & caching
|
|
226
|
+
├── MoQTransport # Edge streaming protocol
|
|
227
|
+
├── JXRCrypto # Cryptographic operations
|
|
228
|
+
└── JXRServerManager # Dev server with HMR
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Runtime Flow
|
|
232
|
+
|
|
233
|
+
1. **Request** → Entry point detection (main.tsx → App.tsx → index.tsx)
|
|
234
|
+
2. **Transform** → TypeScript stripping + JSX transform in Worker
|
|
235
|
+
3. **Resolve** → Import map resolution for bare module imports
|
|
236
|
+
4. **Cache** → LRU cache with cryptographic integrity verification
|
|
237
|
+
5. **Serve** → Module served with proper MIME type and headers
|
|
53
238
|
|
|
54
239
|
### Virtual File System
|
|
55
240
|
|
|
@@ -57,20 +242,39 @@ runtime.onMetrics((metrics) => {
|
|
|
57
242
|
import { VirtualFS, DEFAULT_PROJECT_FILES } from '@jxrstudios/jxr';
|
|
58
243
|
|
|
59
244
|
const vfs = new VirtualFS(DEFAULT_PROJECT_FILES);
|
|
60
|
-
|
|
245
|
+
|
|
246
|
+
// Write file
|
|
247
|
+
vfs.write('/src/components/Button.tsx', `
|
|
248
|
+
export const Button = () => <button>Click</button>
|
|
249
|
+
`);
|
|
250
|
+
|
|
251
|
+
// Read file
|
|
61
252
|
const file = vfs.read('/src/components/Button.tsx');
|
|
253
|
+
|
|
254
|
+
// Check existence
|
|
255
|
+
const exists = vfs.exists('/src/App.tsx');
|
|
256
|
+
|
|
257
|
+
// List directory
|
|
258
|
+
const files = vfs.readdir('/src/components');
|
|
62
259
|
```
|
|
63
260
|
|
|
64
|
-
### JSX
|
|
261
|
+
### JSX Transformer
|
|
65
262
|
|
|
66
263
|
```typescript
|
|
67
264
|
import { JSXTransformer } from '@jxrstudios/jxr';
|
|
68
265
|
|
|
69
|
-
const transformer = new JSXTransformer(
|
|
266
|
+
const transformer = new JSXTransformer({
|
|
267
|
+
pragma: 'React.createElement',
|
|
268
|
+
pragmaFrag: 'React.Fragment',
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Transform JSX
|
|
70
272
|
const transformed = transformer.transform(
|
|
71
273
|
`export const App = () => <h1>Hello JXR</h1>`,
|
|
72
274
|
'/src/App.tsx'
|
|
73
275
|
);
|
|
276
|
+
|
|
277
|
+
// Create executable module
|
|
74
278
|
const objectUrl = transformer.createObjectUrl(transformed);
|
|
75
279
|
```
|
|
76
280
|
|
|
@@ -79,80 +283,469 @@ const objectUrl = transformer.createObjectUrl(transformed);
|
|
|
79
283
|
```typescript
|
|
80
284
|
import { WorkerPool } from '@jxrstudios/jxr';
|
|
81
285
|
|
|
82
|
-
const pool = new WorkerPool('/jxr-worker.js', {
|
|
286
|
+
const pool = new WorkerPool('/jxr-worker.js', {
|
|
287
|
+
maxWorkers: 8,
|
|
288
|
+
maxQueueSize: 1000,
|
|
289
|
+
enablePriority: true,
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Execute task
|
|
83
293
|
const result = await pool.executeTask({
|
|
84
294
|
id: 'task-1',
|
|
85
295
|
type: 'transform',
|
|
86
|
-
payload: { code: '...' },
|
|
87
|
-
priority: 'high',
|
|
296
|
+
payload: { code: '...', filename: '/src/App.tsx' },
|
|
297
|
+
priority: 'high', // high | normal | low
|
|
88
298
|
});
|
|
299
|
+
|
|
300
|
+
// Get metrics
|
|
89
301
|
const metrics = pool.getMetrics();
|
|
302
|
+
// { activeWorkers, idleWorkers, queuedTasks, completedTasks, errors }
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## MCP Server
|
|
308
|
+
|
|
309
|
+
JXR.js includes a Model Context Protocol (MCP) server for AI agent integration.
|
|
310
|
+
|
|
311
|
+
### Available Tools
|
|
312
|
+
|
|
313
|
+
| Tool | Description |
|
|
314
|
+
|------|-------------|
|
|
315
|
+
| `jxr_info` | Get project information and status |
|
|
316
|
+
| `jxr_init` | Scaffold a new JXR project |
|
|
317
|
+
| `jxr_dev` | Start development server |
|
|
318
|
+
| `jxr_build` | Run production build |
|
|
319
|
+
| `jxr_migrate` | Migrate from existing framework |
|
|
320
|
+
| `jxr_deploy` | Deploy to edge platform |
|
|
321
|
+
| `jxr_detect_framework` | Auto-detect source framework |
|
|
322
|
+
| `jxr_read_config` | Read jxr.config.ts |
|
|
323
|
+
| `jxr_write_config` | Update project configuration |
|
|
324
|
+
| `jxr_list_files` | List project file tree |
|
|
325
|
+
| `jxr_read_file` | Read any project file |
|
|
326
|
+
| `jxr_write_file` | Write or create files |
|
|
327
|
+
| `jxr_add_plugin` | Add JXR plugin |
|
|
328
|
+
| `jxr_run_command` | Execute shell command in project |
|
|
329
|
+
|
|
330
|
+
### Configuration
|
|
331
|
+
|
|
332
|
+
**Claude Desktop:**
|
|
333
|
+
```json
|
|
334
|
+
// ~/Library/Application Support/Claude/claude_desktop_config.json
|
|
335
|
+
{
|
|
336
|
+
"mcpServers": {
|
|
337
|
+
"jxr": {
|
|
338
|
+
"command": "npx",
|
|
339
|
+
"args": ["-y", "@jxrstudios/mcp"]
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Cursor:**
|
|
346
|
+
```json
|
|
347
|
+
// .cursor/mcp.json
|
|
348
|
+
{
|
|
349
|
+
"mcpServers": {
|
|
350
|
+
"jxr": {
|
|
351
|
+
"command": "npx",
|
|
352
|
+
"args": ["-y", "@jxrstudios/mcp"]
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**VS Code (with Cline):**
|
|
359
|
+
```json
|
|
360
|
+
// settings.json
|
|
361
|
+
{
|
|
362
|
+
"cline.mcpServers": {
|
|
363
|
+
"jxr": {
|
|
364
|
+
"command": "npx",
|
|
365
|
+
"args": ["-y", "@jxrstudios/mcp"]
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Example Agent Workflows
|
|
372
|
+
|
|
373
|
+
**Initialize and build:**
|
|
374
|
+
```
|
|
375
|
+
User: Create a new JXR web app called "dashboard"
|
|
376
|
+
Agent: I'll initialize the project and set it up for you.
|
|
377
|
+
|
|
378
|
+
[Uses jxr_init, then jxr_dev to start server]
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**Migrate and deploy:**
|
|
382
|
+
```
|
|
383
|
+
User: Migrate my Next.js blog to JXR and deploy it
|
|
384
|
+
Agent: I'll migrate your project and deploy it to production.
|
|
385
|
+
|
|
386
|
+
[Uses jxr_detect_framework, jxr_migrate, jxr_build, jxr_deploy]
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## Migration Guide
|
|
392
|
+
|
|
393
|
+
### From Next.js
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
jxr migrate --from nextjs
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**Changes:**
|
|
400
|
+
- `pages/` → `src/pages/` (optional)
|
|
401
|
+
- `next.config.js` → `jxr.config.ts`
|
|
402
|
+
- `getServerSideProps` → Edge functions
|
|
403
|
+
- API routes preserved with minor syntax updates
|
|
404
|
+
|
|
405
|
+
### From Vite
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
jxr migrate --from vite
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**Changes:**
|
|
412
|
+
- `vite.config.ts` → `jxr.config.ts`
|
|
413
|
+
- Import map replaces `resolve.alias`
|
|
414
|
+
- Plugin system has different API
|
|
415
|
+
|
|
416
|
+
### From Create React App
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
jxr migrate --from cra
|
|
90
420
|
```
|
|
91
421
|
|
|
92
|
-
|
|
422
|
+
**Changes:**
|
|
423
|
+
- Zero-config philosophy maintained
|
|
424
|
+
- Service worker handling updated
|
|
425
|
+
- Modern JSX transform (no React import needed)
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## API Reference
|
|
430
|
+
|
|
431
|
+
### JXRRuntime
|
|
93
432
|
|
|
94
433
|
```typescript
|
|
95
|
-
|
|
434
|
+
class JXRRuntime {
|
|
435
|
+
constructor(options?: JXRRuntimeOptions);
|
|
436
|
+
|
|
437
|
+
// Initialization
|
|
438
|
+
init(): Promise<void>;
|
|
439
|
+
|
|
440
|
+
// Module resolution
|
|
441
|
+
resolveModule(path: string): Promise<ResolvedModule>;
|
|
442
|
+
|
|
443
|
+
// Preview generation
|
|
444
|
+
buildPreviewDocument(): string;
|
|
445
|
+
|
|
446
|
+
// Event handling
|
|
447
|
+
onMetrics(callback: (metrics: RuntimeMetrics) => void): void;
|
|
448
|
+
onError(callback: (error: JXRError) => void): void;
|
|
449
|
+
}
|
|
96
450
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
modules: [{ path: '/src/App.tsx', hash }],
|
|
100
|
-
}, 'your-private-key');
|
|
451
|
+
// Singleton instance
|
|
452
|
+
import { jxrRuntime } from '@jxrstudios/jxr';
|
|
101
453
|
```
|
|
102
454
|
|
|
103
|
-
|
|
455
|
+
### JXRServerManager
|
|
104
456
|
|
|
105
|
-
|
|
457
|
+
```typescript
|
|
458
|
+
class JXRServerManager {
|
|
459
|
+
constructor(options: ServerOptions);
|
|
460
|
+
|
|
461
|
+
initialize(): Promise<void>;
|
|
462
|
+
start(): Promise<void>;
|
|
463
|
+
stop(): Promise<void>;
|
|
464
|
+
|
|
465
|
+
// HMR
|
|
466
|
+
broadcastUpdate(path: string): void;
|
|
467
|
+
|
|
468
|
+
// File watching
|
|
469
|
+
watch(pattern: string, callback: (event: WatchEvent) => void): void;
|
|
470
|
+
}
|
|
471
|
+
```
|
|
106
472
|
|
|
107
|
-
|
|
473
|
+
### JXRDeployer
|
|
108
474
|
|
|
109
475
|
```typescript
|
|
110
|
-
|
|
476
|
+
class JXRDeployer {
|
|
477
|
+
constructor(apiKey: string, projectId?: string);
|
|
478
|
+
|
|
479
|
+
deploy(path: string, options: DeployOptions): Promise<DeployResult>;
|
|
480
|
+
getStatus(deploymentId: string): Promise<DeploymentStatus>;
|
|
481
|
+
listDeployments(): Promise<Deployment[]>;
|
|
482
|
+
rollback(deploymentId: string): Promise<void>;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Singleton with env vars
|
|
486
|
+
import { jxrDeployer } from '@jxrstudios/jxr';
|
|
487
|
+
// Requires JXR_API_KEY env var
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### JXRCrypto
|
|
491
|
+
|
|
492
|
+
```typescript
|
|
493
|
+
class JXRCrypto {
|
|
494
|
+
// Module hashing
|
|
495
|
+
hashModule(code: string): Promise<string>;
|
|
496
|
+
|
|
497
|
+
// Manifest signing
|
|
498
|
+
signManifest(manifest: Manifest, privateKey: string): Promise<SignedManifest>;
|
|
499
|
+
verifyManifest(signedManifest: SignedManifest): Promise<boolean>;
|
|
500
|
+
|
|
501
|
+
// Key generation
|
|
502
|
+
generateKeyPair(): Promise<{ publicKey: string; privateKey: string }>;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Singleton instance
|
|
506
|
+
import { jxrCrypto } from '@jxrstudios/jxr';
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## Deployment
|
|
512
|
+
|
|
513
|
+
### Wranglerless Cloudflare
|
|
514
|
+
|
|
515
|
+
Deploy without configuring wrangler or having a Cloudflare account.
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
# Get API key at https://jxrstudios.online/dashboard
|
|
519
|
+
export JXR_API_KEY=jxr_live_xxxxx
|
|
520
|
+
|
|
521
|
+
# Deploy
|
|
522
|
+
jxr deploy --target cloudflare
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
### Deno Deploy
|
|
526
|
+
|
|
527
|
+
```bash
|
|
528
|
+
jxr deploy --target deno
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### Node.js
|
|
532
|
+
|
|
533
|
+
```bash
|
|
534
|
+
jxr build --platform=node
|
|
535
|
+
jxr deploy --target node --env=production
|
|
536
|
+
```
|
|
111
537
|
|
|
112
|
-
|
|
113
|
-
|
|
538
|
+
### Deployment Lifecycle
|
|
539
|
+
|
|
540
|
+
```typescript
|
|
541
|
+
const deployer = new JXRDeployer(apiKey, projectId);
|
|
114
542
|
|
|
115
|
-
// Deploy
|
|
543
|
+
// Deploy
|
|
116
544
|
const result = await deployer.deploy('./dist', {
|
|
117
|
-
environment: 'production',
|
|
545
|
+
environment: 'production',
|
|
118
546
|
branch: 'main',
|
|
119
547
|
});
|
|
120
548
|
|
|
121
|
-
|
|
122
|
-
|
|
549
|
+
// Check status
|
|
550
|
+
const status = await deployer.getStatus(result.deploymentId);
|
|
551
|
+
|
|
552
|
+
// List all
|
|
553
|
+
const deployments = await deployer.listDeployments();
|
|
554
|
+
|
|
555
|
+
// Rollback if needed
|
|
556
|
+
await deployer.rollback(previousDeploymentId);
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
## Troubleshooting
|
|
562
|
+
|
|
563
|
+
### "Cannot find module 'react'"
|
|
564
|
+
|
|
565
|
+
JXR uses import maps for external dependencies. Ensure your HTML includes:
|
|
566
|
+
|
|
567
|
+
```html
|
|
568
|
+
<script type="importmap">
|
|
569
|
+
{
|
|
570
|
+
"imports": {
|
|
571
|
+
"react": "https://esm.sh/react@19",
|
|
572
|
+
"react-dom/client": "https://esm.sh/react-dom@19/client"
|
|
573
|
+
}
|
|
123
574
|
}
|
|
575
|
+
</script>
|
|
124
576
|
```
|
|
125
577
|
|
|
126
|
-
###
|
|
578
|
+
### TypeScript errors in IDE
|
|
579
|
+
|
|
580
|
+
Install type definitions:
|
|
127
581
|
|
|
128
582
|
```bash
|
|
129
|
-
|
|
130
|
-
|
|
583
|
+
npm install -D @types/react @types/react-dom typescript
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
### Port already in use
|
|
587
|
+
|
|
588
|
+
```bash
|
|
589
|
+
jxr dev --port 3001
|
|
590
|
+
```
|
|
131
591
|
|
|
132
|
-
|
|
133
|
-
|
|
592
|
+
Or set environment variable:
|
|
593
|
+
```bash
|
|
594
|
+
PORT=3001 jxr dev
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
### HMR not working
|
|
598
|
+
|
|
599
|
+
Check browser console for WebSocket errors. Ensure no proxy/firewall blocking WS connections.
|
|
600
|
+
|
|
601
|
+
```bash
|
|
602
|
+
jxr dev --no-hmr # Disable HMR as workaround
|
|
134
603
|
```
|
|
135
604
|
|
|
136
|
-
###
|
|
605
|
+
### Build fails with "Cannot resolve"
|
|
606
|
+
|
|
607
|
+
Ensure all imports are either:
|
|
608
|
+
1. Relative paths (`./Component`)
|
|
609
|
+
2. Mapped in import map
|
|
610
|
+
3. Marked as external in jxr.config.ts
|
|
611
|
+
|
|
612
|
+
### Migration fails
|
|
613
|
+
|
|
614
|
+
```bash
|
|
615
|
+
# Preview changes first
|
|
616
|
+
jxr migrate --from nextjs --dry-run
|
|
617
|
+
|
|
618
|
+
# Force migration (skip prompts)
|
|
619
|
+
jxr migrate --from nextjs --force
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
---
|
|
623
|
+
|
|
624
|
+
## Configuration
|
|
625
|
+
|
|
626
|
+
### jxr.config.ts
|
|
137
627
|
|
|
138
628
|
```typescript
|
|
139
|
-
|
|
140
|
-
|
|
629
|
+
import { defineConfig } from '@jxrstudios/jxr';
|
|
630
|
+
|
|
631
|
+
export default defineConfig({
|
|
632
|
+
name: 'my-app',
|
|
633
|
+
platform: 'web', // web | node | cloudflare-worker
|
|
634
|
+
|
|
635
|
+
// Worker pool settings
|
|
636
|
+
workers: {
|
|
637
|
+
size: 8,
|
|
638
|
+
enablePriority: true,
|
|
639
|
+
maxQueueSize: 1000,
|
|
640
|
+
},
|
|
641
|
+
|
|
642
|
+
// MoQ transport
|
|
643
|
+
moq: {
|
|
644
|
+
enabled: true,
|
|
645
|
+
relayUrl: 'wss://relay.jxr.dev',
|
|
646
|
+
trackPriority: 'high',
|
|
647
|
+
},
|
|
648
|
+
|
|
649
|
+
// Web Crypto
|
|
650
|
+
crypto: {
|
|
651
|
+
enabled: true,
|
|
652
|
+
signing: true,
|
|
653
|
+
algorithm: 'AES-GCM',
|
|
654
|
+
},
|
|
655
|
+
|
|
656
|
+
// Dev server
|
|
657
|
+
devServer: {
|
|
658
|
+
port: 3000,
|
|
659
|
+
hmr: true,
|
|
660
|
+
host: 'localhost',
|
|
661
|
+
},
|
|
662
|
+
|
|
663
|
+
// Build settings
|
|
664
|
+
build: {
|
|
665
|
+
outDir: 'dist',
|
|
666
|
+
minify: true,
|
|
667
|
+
sourcemap: true,
|
|
668
|
+
splitting: true,
|
|
669
|
+
},
|
|
670
|
+
|
|
671
|
+
// Import map (extends default)
|
|
672
|
+
imports: {
|
|
673
|
+
"@/": "./src/",
|
|
674
|
+
"~/": "./public/",
|
|
675
|
+
},
|
|
676
|
+
|
|
677
|
+
// External packages (don't bundle)
|
|
678
|
+
external: ['some-heavy-lib'],
|
|
679
|
+
|
|
680
|
+
// Plugins
|
|
681
|
+
plugins: [
|
|
682
|
+
// Custom plugins
|
|
683
|
+
],
|
|
684
|
+
});
|
|
685
|
+
```
|
|
141
686
|
|
|
142
|
-
|
|
143
|
-
|
|
687
|
+
---
|
|
688
|
+
|
|
689
|
+
## Contributing
|
|
144
690
|
|
|
145
|
-
|
|
146
|
-
await deployer.rollback('deployment-id');
|
|
691
|
+
### Development Setup
|
|
147
692
|
|
|
148
|
-
|
|
149
|
-
|
|
693
|
+
```bash
|
|
694
|
+
git clone https://github.com/jxrstudios/jxr.git
|
|
695
|
+
cd jxr
|
|
696
|
+
npm install
|
|
697
|
+
npm run build
|
|
698
|
+
npm test
|
|
150
699
|
```
|
|
151
700
|
|
|
152
|
-
|
|
701
|
+
### Project Structure
|
|
702
|
+
|
|
703
|
+
```
|
|
704
|
+
jxr/
|
|
705
|
+
├── src/
|
|
706
|
+
│ ├── index.ts # Main exports
|
|
707
|
+
│ ├── deployer.ts # Deployment logic
|
|
708
|
+
│ ├── enhanced-transpiler.ts # JSX transformation
|
|
709
|
+
│ ├── entry-point-detection.ts
|
|
710
|
+
│ ├── jxr-server-manager.ts # Dev server
|
|
711
|
+
│ ├── module-resolver.ts
|
|
712
|
+
│ ├── moq-transport.ts
|
|
713
|
+
│ ├── runtime.ts
|
|
714
|
+
│ ├── web-crypto.ts
|
|
715
|
+
│ └── worker-pool.ts
|
|
716
|
+
├── bin/
|
|
717
|
+
│ └── jxr.js # CLI entry
|
|
718
|
+
├── zzz_react_template/ # Project templates
|
|
719
|
+
└── tests/
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
### Submitting Changes
|
|
153
723
|
|
|
154
|
-
|
|
724
|
+
1. Fork the repository
|
|
725
|
+
2. Create feature branch: `git checkout -b feature/amazing-feature`
|
|
726
|
+
3. Make changes with tests
|
|
727
|
+
4. Run full test suite: `npm test`
|
|
728
|
+
5. Commit: `git commit -m 'Add amazing feature'`
|
|
729
|
+
6. Push: `git push origin feature/amazing-feature`
|
|
730
|
+
7. Open Pull Request
|
|
731
|
+
|
|
732
|
+
---
|
|
155
733
|
|
|
156
734
|
## License
|
|
157
735
|
|
|
158
|
-
MIT
|
|
736
|
+
MIT License — see [LICENSE](LICENSE) file for details.
|
|
737
|
+
|
|
738
|
+
---
|
|
739
|
+
|
|
740
|
+
## Credits
|
|
741
|
+
|
|
742
|
+
- **JXR Studios** — Framework development and maintenance
|
|
743
|
+
- **DamascusAI** — AI integration and MCP server
|
|
744
|
+
- **Contributors** — Community contributions
|
|
745
|
+
|
|
746
|
+
---
|
|
747
|
+
|
|
748
|
+
<p align="center">
|
|
749
|
+
<strong>Powered by JXR Studios × DamascusAI</strong><br>
|
|
750
|
+
<sub>The edge OS runtime for developers who take their game to the next level.</sub>
|
|
751
|
+
</p>
|
package/bin/jxr.js
CHANGED
|
@@ -267,27 +267,117 @@ if (command === "init") {
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
} else if (command === "deploy") {
|
|
270
|
-
// Deploy command
|
|
271
|
-
const
|
|
270
|
+
// Deploy command with Cloudflare Pages auto-detection
|
|
271
|
+
const target = args.find((a) => a.startsWith("--target="))?.split("=")[1] || "auto";
|
|
272
272
|
const env = args.find((a) => a.startsWith("--env="))?.split("=")[1] || "production";
|
|
273
|
+
const projectPath = args.find((a) => !a.startsWith("--")) || ".";
|
|
273
274
|
|
|
274
|
-
|
|
275
|
-
console.error("❌ JXR_API_KEY environment variable required");
|
|
276
|
-
console.error(" Get your key at: https://jxrstudios.online/dashboard");
|
|
277
|
-
process.exit(1);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const deployer = new JXRDeployer(process.env.JXR_API_KEY, process.env.JXR_PROJECT_ID);
|
|
281
|
-
|
|
282
|
-
const result = await deployer.deploy(projectPath, { environment: env });
|
|
275
|
+
console.log(`🚀 Deploying to ${target === "auto" ? "auto-detected platform" : target}...`);
|
|
283
276
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
277
|
+
try {
|
|
278
|
+
const fs = await import("fs");
|
|
279
|
+
const path = await import("path");
|
|
280
|
+
|
|
281
|
+
// Auto-detect build output directory
|
|
282
|
+
let buildDir = path.join(projectPath, "dist");
|
|
283
|
+
if (!fs.existsSync(buildDir)) {
|
|
284
|
+
buildDir = path.join(projectPath, "build");
|
|
285
|
+
}
|
|
286
|
+
if (!fs.existsSync(buildDir)) {
|
|
287
|
+
buildDir = path.join(projectPath, "out");
|
|
288
|
+
}
|
|
289
|
+
if (!fs.existsSync(buildDir)) {
|
|
290
|
+
// Look for any directory with index.html
|
|
291
|
+
const dirs = fs.readdirSync(projectPath, { withFileTypes: true })
|
|
292
|
+
.filter(d => d.isDirectory() && !d.name.startsWith(".") && !d.name === "node_modules")
|
|
293
|
+
.map(d => path.join(projectPath, d.name));
|
|
294
|
+
|
|
295
|
+
for (const dir of dirs) {
|
|
296
|
+
if (fs.existsSync(path.join(dir, "index.html"))) {
|
|
297
|
+
buildDir = dir;
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (!fs.existsSync(buildDir)) {
|
|
304
|
+
console.error("❌ No build output found. Run 'jxr build' first.");
|
|
305
|
+
process.exit(1);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Check for jxr-manifest.json for verification
|
|
309
|
+
const manifestPath = path.join(buildDir, "jxr-manifest.json");
|
|
310
|
+
if (fs.existsSync(manifestPath)) {
|
|
311
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
312
|
+
console.log(`📋 Build manifest: ${manifest.platform} platform`);
|
|
313
|
+
console.log(` Files: ${manifest.files.length}`);
|
|
314
|
+
console.log(` Signed: ${manifest.algorithm}`);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Detect if running on Cloudflare Pages
|
|
318
|
+
const isCloudflarePages = process.env.CF_PAGES === "1" || process.env.CF_PAGES_URL !== undefined;
|
|
319
|
+
|
|
320
|
+
if (target === "cloudflare" || target === "auto" && isCloudflarePages) {
|
|
321
|
+
console.log("☁️ Deploying to Cloudflare Pages...");
|
|
322
|
+
|
|
323
|
+
// Get project name from package.json or directory
|
|
324
|
+
let projectName = process.env.CF_PAGES_PROJECT_NAME;
|
|
325
|
+
if (!projectName) {
|
|
326
|
+
try {
|
|
327
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(projectPath, "package.json"), "utf-8"));
|
|
328
|
+
projectName = pkg.name;
|
|
329
|
+
} catch {
|
|
330
|
+
projectName = path.basename(path.resolve(projectPath));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// On Cloudflare Pages, the build output is automatically deployed
|
|
335
|
+
// We just need to ensure it's in the right location
|
|
336
|
+
console.log(` Project: ${projectName}`);
|
|
337
|
+
console.log(` Environment: ${env}`);
|
|
338
|
+
|
|
339
|
+
if (isCloudflarePages) {
|
|
340
|
+
console.log(` URL: https://${projectName}.app.jxrstudios.online`);
|
|
341
|
+
console.log("✅ Deployment ready for Cloudflare Pages");
|
|
342
|
+
console.log(" The build output will be deployed automatically.");
|
|
343
|
+
} else {
|
|
344
|
+
// Manual Cloudflare Pages deployment
|
|
345
|
+
console.log(" Run 'wrangler pages deploy' to deploy manually");
|
|
346
|
+
console.log(" Or connect your GitHub repo to Cloudflare Pages for auto-deployment");
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
} else if (target === "deno") {
|
|
350
|
+
console.log("🦕 Deploying to Deno Deploy...");
|
|
351
|
+
console.log(" Run 'deployctl deploy' to deploy to Deno Deploy");
|
|
352
|
+
|
|
353
|
+
} else if (target === "node") {
|
|
354
|
+
console.log("🟢 Deploying to Node.js server...");
|
|
355
|
+
console.log(" Copy the dist/ folder to your Node.js server");
|
|
356
|
+
|
|
357
|
+
} else {
|
|
358
|
+
// Use JXRDeployer for other platforms
|
|
359
|
+
if (!process.env.JXR_API_KEY) {
|
|
360
|
+
console.error("❌ JXR_API_KEY environment variable required");
|
|
361
|
+
console.error(" Get your key at: https://jxrstudios.online/dashboard");
|
|
362
|
+
process.exit(1);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const deployer = new JXRDeployer(process.env.JXR_API_KEY, process.env.JXR_PROJECT_ID);
|
|
366
|
+
const result = await deployer.deploy(buildDir, { environment: env });
|
|
367
|
+
|
|
368
|
+
if (result.success) {
|
|
369
|
+
console.log("✅ Deployed successfully!");
|
|
370
|
+
console.log(` URL: ${result.url}`);
|
|
371
|
+
result.logs.forEach(log => console.log(` ${log}`));
|
|
372
|
+
} else {
|
|
373
|
+
console.error("❌ Deploy failed");
|
|
374
|
+
result.logs.forEach(log => console.error(` ${log}`));
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
} catch (err) {
|
|
380
|
+
console.error("❌ Deploy failed:", err.message);
|
|
291
381
|
process.exit(1);
|
|
292
382
|
}
|
|
293
383
|
|
|
@@ -319,6 +409,16 @@ if (command === "init") {
|
|
|
319
409
|
console.log(" jxr init <project-name> Create new project");
|
|
320
410
|
console.log(" jxr dev [--port=3000] Start dev server");
|
|
321
411
|
console.log(" jxr build [--platform=web] Production build");
|
|
322
|
-
console.log(" jxr deploy
|
|
412
|
+
console.log(" jxr deploy [--target=auto] Deploy to production");
|
|
413
|
+
console.log("");
|
|
414
|
+
console.log("Deploy targets:");
|
|
415
|
+
console.log(" --target=cloudflare Cloudflare Pages");
|
|
416
|
+
console.log(" --target=deno Deno Deploy");
|
|
417
|
+
console.log(" --target=node Node.js server");
|
|
418
|
+
console.log(" --target=auto Auto-detect (default)");
|
|
419
|
+
console.log("");
|
|
420
|
+
console.log("Cloudflare Pages:");
|
|
421
|
+
console.log(" Auto-detected when CF_PAGES env var is set");
|
|
422
|
+
console.log(" URL: https://<project>.app.jxrstudios.online");
|
|
323
423
|
process.exit(1);
|
|
324
|
-
}
|
|
424
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jxrstudios/jxr",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.17",
|
|
4
4
|
"description": "JXR.js — Edge OS Runtime Framework for elite developers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -58,4 +58,4 @@
|
|
|
58
58
|
"esbuild": "^0.25.0",
|
|
59
59
|
"typescript": "5.6.3"
|
|
60
60
|
}
|
|
61
|
-
}
|
|
61
|
+
}
|