editor-sdk 0.1.0 → 0.1.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/README.md CHANGED
@@ -1,68 +1,71 @@
1
1
  # 3D Editor SDK
2
2
 
3
- The secure runtime SDK for determining, fetching, and rendering components from the 3D Component Registry.
3
+ The official SDK and CLI for the 3D Component Registry.
4
4
 
5
- ## Installation
5
+ ## 📦 Features
6
6
 
7
- ```bash
8
- npm install editor-sdk-secure-demo
9
- # or
10
- pnpm add editor-sdk-secure-demo
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
- *> Note: Ensure you are using the version that matches your registry configuration.*
13
+ ## 🛠️ CLI Usage (For Developers)
14
14
 
15
- ## Features
15
+ Use the CLI to install components from the registry into your Next.js project.
16
16
 
17
- - **Secure Loading**: Fetches signed URLs for assets, ensuring they are not publicly exposable.
18
- - **Domain Locking**: Validates the request origin against the allowed domains list.
19
- - **Caching**: Smart caching of model URLs in `localStorage` to minimize API costs and latency.
20
- - **Dev Mode**: Shows a "DEV MODE: SECURE" badge when running on localhost.
17
+ ### 1. Login
18
+ Authenticate with your registry API key.
19
+ ```bash
20
+ npx editor-sdk login
21
+ ```
21
22
 
22
- ## Usage
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
- This SDK is primarily used by the code generated via the CLI (`npx 3d-editor add`).
33
+ ---
25
34
 
26
- ### Manual Usage
35
+ ## 📚 Library Usage (For Components)
27
36
 
28
- If you want to manually secure-load a scene:
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-secure-demo';
40
+ import { SecureScene } from 'editor-sdk';
32
41
 
33
- function MyComponent() {
42
+ export default function My3DComponent() {
34
43
  return (
35
- <div style={{ width: '100vw', height: '100vh' }}>
36
- <Canvas>
37
- <SecureScene
38
- id="your-component-id"
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
- ## CLI Authentication
48
-
49
- To install **Private Components** from the registry, you must be authenticated in your terminal.
50
-
51
- ### How to Login
52
-
53
- 1. **Obtain an API Key**:
54
- * *Self-Hosted*: Check your database `ApiKey` table or ask your administrator.
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
- 2. **Run Login Command**:
58
- ```bash
59
- npx 3d-editor login
60
- ```
61
+ ---
61
62
 
62
- 3. **Enter Key**:
63
- Paste your API key when prompted. It will be saved securely to `~/.3d-editor/config.json`.
63
+ ## 🔧 Troubleshooting
64
64
 
65
- ### Troubleshooting
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
- - **401 Unauthorized**: Run `npx 3d-editor login` again.
68
- - **403 Forbidden**: Your domain might not be whitelisted. Check the Project settings in the Editor.
69
+ ### "Unauthorized"
70
+ * **Cause**: CLI session expired or invalid key.
71
+ * **Fix**: Run `npx editor-sdk login` again.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
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.0",
3
+ "version": "0.1.1",
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
  }