editor-sdk 0.1.0 → 0.1.2
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 +48 -45
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +172 -0
- package/package.json +12 -1
package/README.md
CHANGED
|
@@ -1,68 +1,71 @@
|
|
|
1
1
|
# 3D Editor SDK
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The official SDK and CLI for the 3D Component Registry.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 📦 Features
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
- **Runtime Library**: Securely load and render 3D components with `SecureScene`.
|
|
8
|
+
- **CLI Tool**: Install components directly into your project with `npx editor-sdk`.
|
|
9
|
+
- **Security**: Built-in domain locking, signed URL fetching, and local caching.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## 🛠️ CLI Usage (For Developers)
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Use the CLI to install components from the registry into your Next.js project.
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
17
|
+
### 1. Login
|
|
18
|
+
Authenticate with your registry API key.
|
|
19
|
+
```bash
|
|
20
|
+
npx editor-sdk login
|
|
21
|
+
```
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
### 2. Add Component
|
|
24
|
+
Fetch a component by its ID.
|
|
25
|
+
```bash
|
|
26
|
+
npx editor-sdk add <component-id> --host <registry-url>
|
|
27
|
+
```
|
|
28
|
+
*Example:*
|
|
29
|
+
```bash
|
|
30
|
+
npx editor-sdk add my-scene-123 --host http://localhost:3000
|
|
31
|
+
```
|
|
23
32
|
|
|
24
|
-
|
|
33
|
+
---
|
|
25
34
|
|
|
26
|
-
|
|
35
|
+
## 📚 Library Usage (For Components)
|
|
27
36
|
|
|
28
|
-
|
|
37
|
+
The CLI generates components that use this library under the hood. You typically won't write this code manually, but here is how it works:
|
|
29
38
|
|
|
30
39
|
```tsx
|
|
31
|
-
import { SecureScene } from 'editor-sdk
|
|
40
|
+
import { SecureScene } from 'editor-sdk';
|
|
32
41
|
|
|
33
|
-
function
|
|
42
|
+
export default function My3DComponent() {
|
|
34
43
|
return (
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
registryUrl="https://your-registry-api.com"
|
|
40
|
-
/>
|
|
41
|
-
</Canvas>
|
|
42
|
-
</div>
|
|
44
|
+
<SecureScene
|
|
45
|
+
id="my-scene-123"
|
|
46
|
+
registryUrl="http://localhost:3000"
|
|
47
|
+
/>
|
|
43
48
|
);
|
|
44
49
|
}
|
|
45
50
|
```
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
* *Development*: If you are running the registry locally, you can currently use any non-empty string (e.g., `dev-token`) as the system accepts preshared keys for testing.
|
|
52
|
+
### Props
|
|
53
|
+
| Prop | Type | Description |
|
|
54
|
+
|------|------|-------------|
|
|
55
|
+
| `id` | `string` | The unique ID of the component in the registry. |
|
|
56
|
+
| `registryUrl` | `string` | Base URL of the registry (e.g. `https://api.myregistry.com`). |
|
|
57
|
+
| `token` | `string` | (Optional) Auth token for private components. |
|
|
58
|
+
| `onLoad` | `() => void` | Callback when the model finishes loading. |
|
|
59
|
+
| `onError` | `(err) => void` | Callback if loading fails. |
|
|
56
60
|
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
npx 3d-editor login
|
|
60
|
-
```
|
|
61
|
+
---
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
Paste your API key when prompted. It will be saved securely to `~/.3d-editor/config.json`.
|
|
63
|
+
## 🔧 Troubleshooting
|
|
64
64
|
|
|
65
|
-
###
|
|
65
|
+
### "403 Forbidden"
|
|
66
|
+
* **Cause**: You might be trying to publish a version that already exists.
|
|
67
|
+
* **Fix**: Update the `version` in `package.json`.
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
### "Unauthorized"
|
|
70
|
+
* **Cause**: CLI session expired or invalid key.
|
|
71
|
+
* **Fix**: Run `npx editor-sdk login` again.
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import fetch from 'node-fetch';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import prompts from 'prompts';
|
|
8
|
+
import { execSync } from 'child_process';
|
|
9
|
+
import os from 'os';
|
|
10
|
+
const program = new Command();
|
|
11
|
+
const CONFIG_DIR = path.join(os.homedir(), '.3d-editor');
|
|
12
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
13
|
+
// Helper to save config
|
|
14
|
+
function saveConfig(data) {
|
|
15
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
16
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2));
|
|
19
|
+
}
|
|
20
|
+
// Helper to load config
|
|
21
|
+
function loadConfig() {
|
|
22
|
+
if (!fs.existsSync(CONFIG_FILE))
|
|
23
|
+
return {};
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
program
|
|
32
|
+
.name('3d-editor')
|
|
33
|
+
.description('CLI to install 3D components from the registry')
|
|
34
|
+
.version('1.0.0');
|
|
35
|
+
// Login Command
|
|
36
|
+
program
|
|
37
|
+
.command('login')
|
|
38
|
+
.description('Authenticate with the 3D Editor Registry')
|
|
39
|
+
.action(async () => {
|
|
40
|
+
console.log(chalk.blue('🔐 Authenticating with 3D Editor...'));
|
|
41
|
+
const response = await prompts({
|
|
42
|
+
type: 'password',
|
|
43
|
+
name: 'apiKey',
|
|
44
|
+
message: 'Enter your API Key:',
|
|
45
|
+
validate: value => value.length < 5 ? 'API Key seems too short' : true
|
|
46
|
+
});
|
|
47
|
+
if (response.apiKey) {
|
|
48
|
+
saveConfig({ apiKey: response.apiKey });
|
|
49
|
+
console.log(chalk.green('✓ Logged in successfully!'));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.log(chalk.yellow('Login cancelled.'));
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
// Add Command
|
|
56
|
+
program
|
|
57
|
+
.command('add <componentId>')
|
|
58
|
+
.description('Add a component by ID')
|
|
59
|
+
.option('-p, --package', 'Install as a node_module package', false)
|
|
60
|
+
.option('--host <url>', 'Registry Host URL', 'http://localhost:3000') // Default to local for dev
|
|
61
|
+
.action(async (componentId, options) => {
|
|
62
|
+
try {
|
|
63
|
+
const config = loadConfig();
|
|
64
|
+
const apiKey = config.apiKey;
|
|
65
|
+
if (!apiKey) {
|
|
66
|
+
console.warn(chalk.yellow('⚠ You are not logged in. Public components only.'));
|
|
67
|
+
console.warn(chalk.yellow('Run `npx 3d-editor login` to access private components.'));
|
|
68
|
+
}
|
|
69
|
+
let registryUrl = '';
|
|
70
|
+
let idFromArg = componentId;
|
|
71
|
+
if (componentId.startsWith('http://') || componentId.startsWith('https://')) {
|
|
72
|
+
registryUrl = componentId;
|
|
73
|
+
// Extract ID from URL for fallback naming (last segment)
|
|
74
|
+
const parts = componentId.split('/');
|
|
75
|
+
idFromArg = parts[parts.length - 1] || 'component';
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
registryUrl = `${options.host}/api/registry/${componentId}`;
|
|
79
|
+
}
|
|
80
|
+
console.log(chalk.blue(`📦 Fetching component from ${registryUrl}...`));
|
|
81
|
+
const res = await fetch(registryUrl, {
|
|
82
|
+
headers: apiKey ? { 'Authorization': `Bearer ${apiKey}` } : {}
|
|
83
|
+
});
|
|
84
|
+
if (!res.ok) {
|
|
85
|
+
if (res.status === 404)
|
|
86
|
+
throw new Error(`Component '${componentId}' not found.`);
|
|
87
|
+
if (res.status === 401)
|
|
88
|
+
throw new Error(`Unauthorized. Please login.`);
|
|
89
|
+
throw new Error(`Registry Error: ${res.statusText}`);
|
|
90
|
+
}
|
|
91
|
+
const data = await res.json();
|
|
92
|
+
const { name, id } = data; // We don't need assets/code/etc anymore for the shell
|
|
93
|
+
console.log(chalk.green(`✓ Found component: ${name || id}`));
|
|
94
|
+
// 1. Check for Core SDK
|
|
95
|
+
console.log(chalk.blue('Checking for editor-sdk...'));
|
|
96
|
+
const packageJsonPath = path.join(process.cwd(), 'package.json');
|
|
97
|
+
let needsSdk = true;
|
|
98
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
99
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
100
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
101
|
+
if (allDeps['editor-sdk']) {
|
|
102
|
+
needsSdk = false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (needsSdk) {
|
|
106
|
+
const { install } = await prompts({
|
|
107
|
+
type: 'confirm',
|
|
108
|
+
name: 'install',
|
|
109
|
+
message: componentId === 'editor-sdk' ? 'Install SDK?' : `This component requires editor-sdk. Install it now?`,
|
|
110
|
+
initial: true
|
|
111
|
+
});
|
|
112
|
+
if (install) {
|
|
113
|
+
// Use 'editor-sdk' as that is the package name
|
|
114
|
+
console.log(chalk.blue('Installing editor-sdk...'));
|
|
115
|
+
execSync('npm install editor-sdk', { stdio: 'inherit' });
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
console.warn(chalk.yellow('⚠ Component may not work without editor-sdk'));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// 2. Generate Shell Component
|
|
122
|
+
let targetDir = '';
|
|
123
|
+
let targetFile = '';
|
|
124
|
+
const componentName = name || `Component${id}`;
|
|
125
|
+
if (options.package) {
|
|
126
|
+
// Install to node_modules (Legacy support or library mode)
|
|
127
|
+
// ... omitted for brevity/focus on src implementation for now
|
|
128
|
+
// Re-using logic roughly
|
|
129
|
+
const nodeModulesDir = path.join(process.cwd(), 'node_modules');
|
|
130
|
+
targetDir = path.join(nodeModulesDir, componentName);
|
|
131
|
+
targetFile = path.join(targetDir, 'index.tsx');
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
// Install to src/components
|
|
135
|
+
const srcDir = path.join(process.cwd(), 'src');
|
|
136
|
+
const hasSrc = fs.existsSync(srcDir);
|
|
137
|
+
const componentsDir = hasSrc
|
|
138
|
+
? path.join(srcDir, 'components')
|
|
139
|
+
: path.join(process.cwd(), 'components');
|
|
140
|
+
targetDir = componentsDir;
|
|
141
|
+
targetFile = path.join(targetDir, `${componentName}.tsx`);
|
|
142
|
+
}
|
|
143
|
+
if (!fs.existsSync(targetDir) && !targetFile.endsWith('.tsx')) {
|
|
144
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
145
|
+
}
|
|
146
|
+
else if (!fs.existsSync(path.dirname(targetFile))) {
|
|
147
|
+
fs.mkdirSync(path.dirname(targetFile), { recursive: true });
|
|
148
|
+
}
|
|
149
|
+
// The Shell Code
|
|
150
|
+
const shellCode = `import React from 'react';
|
|
151
|
+
import { SecureScene } from 'editor-sdk';
|
|
152
|
+
|
|
153
|
+
export default function ${componentName}(props: any) {
|
|
154
|
+
return (
|
|
155
|
+
<SecureScene
|
|
156
|
+
id="${id}"
|
|
157
|
+
registryUrl="${options.host}"
|
|
158
|
+
{...props}
|
|
159
|
+
/>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
`;
|
|
163
|
+
fs.writeFileSync(targetFile, shellCode);
|
|
164
|
+
console.log(chalk.green(`✓ Created ${targetFile}`));
|
|
165
|
+
console.log(`\nUsage:\nimport ${componentName} from '@/components/${componentName}';\n\n<${componentName} />`);
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
console.error(chalk.red('Error:'), error.message);
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
program.parse();
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "editor-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"editor-sdk": "./dist/cli.js"
|
|
9
|
+
},
|
|
7
10
|
"scripts": {
|
|
8
11
|
"build": "tsc",
|
|
9
12
|
"dev": "tsc --watch"
|
|
@@ -15,12 +18,20 @@
|
|
|
15
18
|
"react-dom": ">=18.0.0",
|
|
16
19
|
"three": ">=0.160.0"
|
|
17
20
|
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"commander": "^11.1.0",
|
|
23
|
+
"node-fetch": "^3.3.2",
|
|
24
|
+
"chalk": "^4.1.2",
|
|
25
|
+
"prompts": "^2.4.2"
|
|
26
|
+
},
|
|
18
27
|
"files": [
|
|
19
28
|
"dist"
|
|
20
29
|
],
|
|
21
30
|
"devDependencies": {
|
|
22
31
|
"@types/react": "^18.3.27",
|
|
23
32
|
"@types/three": "^0.160.0",
|
|
33
|
+
"@types/node": "^20.0.0",
|
|
34
|
+
"@types/prompts": "^2.4.9",
|
|
24
35
|
"typescript": "^5.9.3"
|
|
25
36
|
}
|
|
26
37
|
}
|