create-specra 0.2.2 → 0.2.5
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 +84 -8
- package/dist/{api-client-4XZPF7GL.js → api-client-VHQARPDT.js} +3 -3
- package/dist/chunk-5765WX4D.js +192 -0
- package/dist/chunk-5765WX4D.js.map +1 -0
- package/dist/{chunk-CIM73PDF.js → chunk-72RDEJR2.js} +2 -2
- package/dist/chunk-SQ2MMFUZ.js +102 -0
- package/dist/chunk-SQ2MMFUZ.js.map +1 -0
- package/dist/cli.js +7 -7
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-ETWFNB4Z.js → deploy-V4JO2D6B.js} +32 -6
- package/dist/deploy-V4JO2D6B.js.map +1 -0
- package/dist/{doctor-IFELWGQB.js → doctor-ICALAJ4N.js} +41 -2
- package/dist/doctor-ICALAJ4N.js.map +1 -0
- package/dist/index.js +40 -107
- package/dist/index.js.map +1 -1
- package/dist/{login-DRPP77G4.js → login-UG3WU7DY.js} +17 -11
- package/dist/login-UG3WU7DY.js.map +1 -0
- package/dist/{logout-UJFYUAQC.js → logout-WJKHJZT6.js} +2 -2
- package/dist/{logs-K2CSCKOE.js → logs-BLUJPWNO.js} +3 -3
- package/dist/{projects-NORBBC4D.js → projects-LJ57GK3D.js} +3 -3
- package/package.json +1 -1
- package/templates/book-docs/.env.sample +1 -0
- package/templates/book-docs/package.json +2 -2
- package/templates/book-docs/src/app.css +80 -1
- package/templates/book-docs/src/routes/+layout.server.ts +3 -0
- package/templates/book-docs/src/routes/docs/[version]/+layout.server.ts +31 -0
- package/templates/book-docs/src/routes/docs/[version]/[...slug]/+page.server.ts +9 -14
- package/templates/book-docs/src/routes/docs/[version]/[...slug]/+page.svelte +40 -3
- package/templates/book-docs/svelte.config.js +6 -1
- package/templates/jbrains-docs/.env.sample +1 -0
- package/templates/jbrains-docs/package.json +2 -2
- package/templates/jbrains-docs/src/app.css +80 -1
- package/templates/jbrains-docs/src/routes/+layout.server.ts +3 -0
- package/templates/jbrains-docs/src/routes/docs/[version]/+layout.server.ts +31 -0
- package/templates/jbrains-docs/src/routes/docs/[version]/[...slug]/+page.server.ts +9 -14
- package/templates/jbrains-docs/src/routes/docs/[version]/[...slug]/+page.svelte +40 -3
- package/templates/jbrains-docs/svelte.config.js +6 -1
- package/templates/minimal/.env.sample +1 -0
- package/templates/minimal/package.json +1 -1
- package/templates/minimal/src/app.css +80 -1
- package/templates/minimal/src/routes/+layout.server.ts +1 -1
- package/templates/minimal/src/routes/docs/[version]/+layout.server.ts +31 -0
- package/templates/minimal/src/routes/docs/[version]/[...slug]/+page.server.ts +8 -13
- package/templates/minimal/src/routes/docs/[version]/[...slug]/+page.svelte +40 -3
- package/templates/minimal/svelte.config.js +1 -1
- package/dist/chunk-ATRUBLRX.js +0 -102
- package/dist/chunk-ATRUBLRX.js.map +0 -1
- package/dist/deploy-ETWFNB4Z.js.map +0 -1
- package/dist/doctor-IFELWGQB.js.map +0 -1
- package/dist/login-DRPP77G4.js.map +0 -1
- /package/dist/{api-client-4XZPF7GL.js.map → api-client-VHQARPDT.js.map} +0 -0
- /package/dist/{chunk-CIM73PDF.js.map → chunk-72RDEJR2.js.map} +0 -0
- /package/dist/{logout-UJFYUAQC.js.map → logout-WJKHJZT6.js.map} +0 -0
- /package/dist/{logs-K2CSCKOE.js.map → logs-BLUJPWNO.js.map} +0 -0
- /package/dist/{projects-NORBBC4D.js.map → projects-LJ57GK3D.js.map} +0 -0
package/README.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
The fastest way to create a new Specra documentation site. Scaffold a complete documentation project with a single command.
|
|
4
4
|
|
|
5
|
+
## What is Specra?
|
|
6
|
+
|
|
7
|
+
Specra is a modern documentation library for SvelteKit that provides:
|
|
8
|
+
- Multi-version documentation support
|
|
9
|
+
- API reference generation
|
|
10
|
+
- Full-text search
|
|
11
|
+
- MDX-powered content
|
|
12
|
+
- Beautiful UI components
|
|
13
|
+
|
|
14
|
+
The official Specra site ([specra-docs](https://specra-docs.com)) also offers a SaaS platform with paid tiers (Starter, Pro, Enterprise) including authentication, Stripe/M-Pesa billing, and a user dashboard. The CLI scaffolds free, self-hosted documentation sites — no billing features are included in generated projects.
|
|
15
|
+
|
|
5
16
|
## Usage
|
|
6
17
|
|
|
7
18
|
### With npx (recommended)
|
|
@@ -142,16 +153,81 @@ Once your project is created, you can:
|
|
|
142
153
|
|
|
143
154
|
4. Customize your site in `specra.config.json`
|
|
144
155
|
|
|
145
|
-
##
|
|
156
|
+
## Deployment
|
|
146
157
|
|
|
147
|
-
Specra
|
|
148
|
-
- Multi-version documentation support
|
|
149
|
-
- API reference generation
|
|
150
|
-
- Full-text search
|
|
151
|
-
- MDX-powered content
|
|
152
|
-
- Beautiful UI components
|
|
158
|
+
Specra projects are standard SvelteKit apps, so you can deploy anywhere SvelteKit runs.
|
|
153
159
|
|
|
154
|
-
|
|
160
|
+
### Static Hosting (Vercel, Netlify, Cloudflare Pages)
|
|
161
|
+
|
|
162
|
+
Install the appropriate SvelteKit adapter:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
# Vercel
|
|
166
|
+
npm install -D @sveltejs/adapter-vercel
|
|
167
|
+
|
|
168
|
+
# Netlify
|
|
169
|
+
npm install -D @sveltejs/adapter-netlify
|
|
170
|
+
|
|
171
|
+
# Cloudflare Pages
|
|
172
|
+
npm install -D @sveltejs/adapter-cloudflare
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Update `svelte.config.js` to use the adapter:
|
|
176
|
+
|
|
177
|
+
```js
|
|
178
|
+
import adapter from '@sveltejs/adapter-vercel'; // or adapter-netlify, etc.
|
|
179
|
+
|
|
180
|
+
export default {
|
|
181
|
+
kit: {
|
|
182
|
+
adapter: adapter()
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Then push to your Git provider — the platform handles the rest.
|
|
188
|
+
|
|
189
|
+
### Node Server (VPS, Docker, Railway)
|
|
190
|
+
|
|
191
|
+
Use `@sveltejs/adapter-node` (included by default):
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
npm run build
|
|
195
|
+
node build
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The server listens on port 3000 by default. Configure with environment variables:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
PORT=8080 HOST=0.0.0.0 node build
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Static Site Generation
|
|
205
|
+
|
|
206
|
+
For fully static docs with no server needed:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
npm install -D @sveltejs/adapter-static
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Update `svelte.config.js`:
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
import adapter from '@sveltejs/adapter-static';
|
|
216
|
+
|
|
217
|
+
export default {
|
|
218
|
+
kit: {
|
|
219
|
+
adapter: adapter({
|
|
220
|
+
fallback: '404.html'
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
npm run build
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Upload the `build/` directory to any static host (GitHub Pages, S3, etc.).
|
|
155
231
|
|
|
156
232
|
## Learn More
|
|
157
233
|
|
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
apiRequest,
|
|
5
5
|
apiUpload,
|
|
6
6
|
formatError
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-72RDEJR2.js";
|
|
8
|
+
import "./chunk-5765WX4D.js";
|
|
9
9
|
export {
|
|
10
10
|
ApiError,
|
|
11
11
|
apiRequest,
|
|
12
12
|
apiUpload,
|
|
13
13
|
formatError
|
|
14
14
|
};
|
|
15
|
-
//# sourceMappingURL=api-client-
|
|
15
|
+
//# sourceMappingURL=api-client-VHQARPDT.js.map
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/config.ts
|
|
4
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from "fs";
|
|
5
|
+
import { join, resolve } from "path";
|
|
6
|
+
import { homedir } from "os";
|
|
7
|
+
var GLOBAL_CONFIG_DIR = join(homedir(), ".specra");
|
|
8
|
+
var GLOBAL_CONFIG_FILE = join(GLOBAL_CONFIG_DIR, "config.json");
|
|
9
|
+
var DEFAULT_TOKEN_ENV = "SPECRA_TOKEN";
|
|
10
|
+
var DEFAULT_GLOBAL_CONFIG = {
|
|
11
|
+
apiUrl: "https://specra-docs.com"
|
|
12
|
+
};
|
|
13
|
+
function getEnvFilePath(dir) {
|
|
14
|
+
return join(resolve(dir || "."), ".env");
|
|
15
|
+
}
|
|
16
|
+
function readEnvFile(dir) {
|
|
17
|
+
const envPath = getEnvFilePath(dir);
|
|
18
|
+
try {
|
|
19
|
+
const content = readFileSync(envPath, "utf-8");
|
|
20
|
+
const env = {};
|
|
21
|
+
for (const line of content.split("\n")) {
|
|
22
|
+
const trimmed = line.trim();
|
|
23
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
24
|
+
const eqIdx = trimmed.indexOf("=");
|
|
25
|
+
if (eqIdx === -1) continue;
|
|
26
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
27
|
+
const value = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, "");
|
|
28
|
+
env[key] = value;
|
|
29
|
+
}
|
|
30
|
+
return env;
|
|
31
|
+
} catch {
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function writeEnvVar(key, value, dir) {
|
|
36
|
+
const envPath = getEnvFilePath(dir);
|
|
37
|
+
let content = "";
|
|
38
|
+
try {
|
|
39
|
+
content = readFileSync(envPath, "utf-8");
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
42
|
+
const lines = content.split("\n");
|
|
43
|
+
let found = false;
|
|
44
|
+
for (let i = 0; i < lines.length; i++) {
|
|
45
|
+
if (lines[i].trim().startsWith(`${key}=`)) {
|
|
46
|
+
lines[i] = `${key}=${value}`;
|
|
47
|
+
found = true;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!found) {
|
|
52
|
+
if (lines.length > 0 && lines[lines.length - 1] !== "") {
|
|
53
|
+
lines.push("");
|
|
54
|
+
}
|
|
55
|
+
lines.push(`${key}=${value}`);
|
|
56
|
+
}
|
|
57
|
+
writeFileSync(envPath, lines.join("\n") + "\n");
|
|
58
|
+
}
|
|
59
|
+
function removeEnvVar(key, dir) {
|
|
60
|
+
const envPath = getEnvFilePath(dir);
|
|
61
|
+
try {
|
|
62
|
+
const content = readFileSync(envPath, "utf-8");
|
|
63
|
+
const lines = content.split("\n").filter((line) => !line.trim().startsWith(`${key}=`));
|
|
64
|
+
writeFileSync(envPath, lines.join("\n"));
|
|
65
|
+
} catch {
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function ensureGitignore(dir) {
|
|
69
|
+
const gitignorePath = join(resolve(dir || "."), ".gitignore");
|
|
70
|
+
try {
|
|
71
|
+
let content = "";
|
|
72
|
+
try {
|
|
73
|
+
content = readFileSync(gitignorePath, "utf-8");
|
|
74
|
+
} catch {
|
|
75
|
+
}
|
|
76
|
+
if (!content.split("\n").some((line) => line.trim() === ".env")) {
|
|
77
|
+
const newline = content && !content.endsWith("\n") ? "\n" : "";
|
|
78
|
+
writeFileSync(gitignorePath, content + newline + ".env\n");
|
|
79
|
+
}
|
|
80
|
+
} catch {
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function getGlobalConfig() {
|
|
84
|
+
try {
|
|
85
|
+
const raw = readFileSync(GLOBAL_CONFIG_FILE, "utf-8");
|
|
86
|
+
return { ...DEFAULT_GLOBAL_CONFIG, ...JSON.parse(raw) };
|
|
87
|
+
} catch {
|
|
88
|
+
return DEFAULT_GLOBAL_CONFIG;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function saveGlobalConfig(config) {
|
|
92
|
+
mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
93
|
+
const current = getGlobalConfig();
|
|
94
|
+
const merged = { ...current, ...config };
|
|
95
|
+
writeFileSync(GLOBAL_CONFIG_FILE, JSON.stringify(merged, null, 2));
|
|
96
|
+
}
|
|
97
|
+
function clearGlobalToken() {
|
|
98
|
+
const config = getGlobalConfig();
|
|
99
|
+
delete config.token;
|
|
100
|
+
mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
101
|
+
writeFileSync(GLOBAL_CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
102
|
+
}
|
|
103
|
+
function getLocalConfigPath(dir) {
|
|
104
|
+
return join(resolve(dir || "."), "specra.config.json");
|
|
105
|
+
}
|
|
106
|
+
function readLocalConfig(dir) {
|
|
107
|
+
const configPath = getLocalConfigPath(dir);
|
|
108
|
+
try {
|
|
109
|
+
return JSON.parse(readFileSync(configPath, "utf-8"));
|
|
110
|
+
} catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function getLocalToken(dir) {
|
|
115
|
+
const config = readLocalConfig(dir);
|
|
116
|
+
if (!config?.auth) return void 0;
|
|
117
|
+
if (config.auth.tokenEnv) {
|
|
118
|
+
const envName = config.auth.tokenEnv;
|
|
119
|
+
if (process.env[envName]) return process.env[envName];
|
|
120
|
+
const envVars = readEnvFile(dir);
|
|
121
|
+
return envVars[envName];
|
|
122
|
+
}
|
|
123
|
+
if (config.auth.source === "global") {
|
|
124
|
+
return getGlobalConfig().token;
|
|
125
|
+
}
|
|
126
|
+
return config.auth.token;
|
|
127
|
+
}
|
|
128
|
+
function saveLocalToken(token, dir) {
|
|
129
|
+
const configPath = getLocalConfigPath(dir);
|
|
130
|
+
if (!existsSync(configPath)) {
|
|
131
|
+
throw new Error(`specra.config.json not found in ${resolve(dir || ".")}. Are you in a Specra project?`);
|
|
132
|
+
}
|
|
133
|
+
writeEnvVar(DEFAULT_TOKEN_ENV, token, dir);
|
|
134
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
135
|
+
config.auth = { tokenEnv: DEFAULT_TOKEN_ENV };
|
|
136
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
137
|
+
ensureGitignore(dir);
|
|
138
|
+
}
|
|
139
|
+
function clearLocalToken(dir) {
|
|
140
|
+
removeEnvVar(DEFAULT_TOKEN_ENV, dir);
|
|
141
|
+
const configPath = getLocalConfigPath(dir);
|
|
142
|
+
if (!existsSync(configPath)) return;
|
|
143
|
+
try {
|
|
144
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
145
|
+
if (config.auth) {
|
|
146
|
+
delete config.auth;
|
|
147
|
+
}
|
|
148
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
149
|
+
} catch {
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function getToken(dir) {
|
|
153
|
+
return getLocalToken(dir) || getGlobalConfig().token;
|
|
154
|
+
}
|
|
155
|
+
function getConfig() {
|
|
156
|
+
return getGlobalConfig();
|
|
157
|
+
}
|
|
158
|
+
function isAuthenticated(dir) {
|
|
159
|
+
return !!getToken(dir);
|
|
160
|
+
}
|
|
161
|
+
function saveToken(token, options) {
|
|
162
|
+
if (options?.global) {
|
|
163
|
+
saveGlobalConfig({ token });
|
|
164
|
+
const configPath = getLocalConfigPath(options?.dir);
|
|
165
|
+
if (existsSync(configPath)) {
|
|
166
|
+
try {
|
|
167
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
168
|
+
config.auth = { source: "global" };
|
|
169
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
saveLocalToken(token, options?.dir);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function clearToken(options) {
|
|
178
|
+
if (options?.global) {
|
|
179
|
+
clearGlobalToken();
|
|
180
|
+
} else {
|
|
181
|
+
clearLocalToken(options?.dir);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export {
|
|
186
|
+
getToken,
|
|
187
|
+
getConfig,
|
|
188
|
+
isAuthenticated,
|
|
189
|
+
saveToken,
|
|
190
|
+
clearToken
|
|
191
|
+
};
|
|
192
|
+
//# sourceMappingURL=chunk-5765WX4D.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from 'fs'\nimport { join, resolve } from 'path'\nimport { homedir } from 'os'\n\n// Global config: ~/.specra/config.json\nconst GLOBAL_CONFIG_DIR = join(homedir(), '.specra')\nconst GLOBAL_CONFIG_FILE = join(GLOBAL_CONFIG_DIR, 'config.json')\n\nconst DEFAULT_TOKEN_ENV = 'SPECRA_TOKEN'\n\ninterface GlobalConfig {\n apiUrl: string\n token?: string\n defaultProject?: string\n}\n\nconst DEFAULT_GLOBAL_CONFIG: GlobalConfig = {\n apiUrl: 'https://specra-docs.com',\n}\n\n// --------------- .env file helpers ---------------\n\nfunction getEnvFilePath(dir?: string): string {\n return join(resolve(dir || '.'), '.env')\n}\n\nfunction readEnvFile(dir?: string): Record<string, string> {\n const envPath = getEnvFilePath(dir)\n try {\n const content = readFileSync(envPath, 'utf-8')\n const env: Record<string, string> = {}\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#')) continue\n const eqIdx = trimmed.indexOf('=')\n if (eqIdx === -1) continue\n const key = trimmed.slice(0, eqIdx).trim()\n const value = trimmed.slice(eqIdx + 1).trim().replace(/^[\"']|[\"']$/g, '')\n env[key] = value\n }\n return env\n } catch {\n return {}\n }\n}\n\nfunction writeEnvVar(key: string, value: string, dir?: string) {\n const envPath = getEnvFilePath(dir)\n let content = ''\n try {\n content = readFileSync(envPath, 'utf-8')\n } catch {\n // file doesn't exist yet\n }\n\n const lines = content.split('\\n')\n let found = false\n for (let i = 0; i < lines.length; i++) {\n if (lines[i].trim().startsWith(`${key}=`)) {\n lines[i] = `${key}=${value}`\n found = true\n break\n }\n }\n\n if (!found) {\n // Ensure trailing newline before appending\n if (lines.length > 0 && lines[lines.length - 1] !== '') {\n lines.push('')\n }\n lines.push(`${key}=${value}`)\n }\n\n writeFileSync(envPath, lines.join('\\n') + '\\n')\n}\n\nfunction removeEnvVar(key: string, dir?: string) {\n const envPath = getEnvFilePath(dir)\n try {\n const content = readFileSync(envPath, 'utf-8')\n const lines = content.split('\\n').filter(line => !line.trim().startsWith(`${key}=`))\n writeFileSync(envPath, lines.join('\\n'))\n } catch {\n // file doesn't exist, nothing to remove\n }\n}\n\nfunction ensureGitignore(dir?: string) {\n const gitignorePath = join(resolve(dir || '.'), '.gitignore')\n try {\n let content = ''\n try {\n content = readFileSync(gitignorePath, 'utf-8')\n } catch {\n // no .gitignore yet\n }\n if (!content.split('\\n').some(line => line.trim() === '.env')) {\n const newline = content && !content.endsWith('\\n') ? '\\n' : ''\n writeFileSync(gitignorePath, content + newline + '.env\\n')\n }\n } catch {\n // ignore\n }\n}\n\n// --------------- Global config ---------------\n\nexport function getGlobalConfig(): GlobalConfig {\n try {\n const raw = readFileSync(GLOBAL_CONFIG_FILE, 'utf-8')\n return { ...DEFAULT_GLOBAL_CONFIG, ...JSON.parse(raw) }\n } catch {\n return DEFAULT_GLOBAL_CONFIG\n }\n}\n\nexport function saveGlobalConfig(config: Partial<GlobalConfig>) {\n mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true })\n const current = getGlobalConfig()\n const merged = { ...current, ...config }\n writeFileSync(GLOBAL_CONFIG_FILE, JSON.stringify(merged, null, 2))\n}\n\nexport function clearGlobalToken() {\n const config = getGlobalConfig()\n delete config.token\n mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true })\n writeFileSync(GLOBAL_CONFIG_FILE, JSON.stringify(config, null, 2))\n}\n\n// --------------- Local config (specra.config.json) ---------------\n\nfunction getLocalConfigPath(dir?: string): string {\n return join(resolve(dir || '.'), 'specra.config.json')\n}\n\nfunction readLocalConfig(dir?: string): Record<string, any> | null {\n const configPath = getLocalConfigPath(dir)\n try {\n return JSON.parse(readFileSync(configPath, 'utf-8'))\n } catch {\n return null\n }\n}\n\nexport function getLocalToken(dir?: string): string | undefined {\n const config = readLocalConfig(dir)\n if (!config?.auth) return undefined\n\n // Env var reference: auth.tokenEnv → read from process.env, then .env file\n if (config.auth.tokenEnv) {\n const envName = config.auth.tokenEnv\n if (process.env[envName]) return process.env[envName]\n const envVars = readEnvFile(dir)\n return envVars[envName]\n }\n\n // Global reference: auth.source === \"global\" → read from ~/.specra/config.json\n if (config.auth.source === 'global') {\n return getGlobalConfig().token\n }\n\n // Legacy: direct auth.token (backwards compat for existing projects)\n return config.auth.token\n}\n\nexport function saveLocalToken(token: string, dir?: string) {\n const configPath = getLocalConfigPath(dir)\n if (!existsSync(configPath)) {\n throw new Error(`specra.config.json not found in ${resolve(dir || '.')}. Are you in a Specra project?`)\n }\n\n // Save the actual token to .env\n writeEnvVar(DEFAULT_TOKEN_ENV, token, dir)\n\n // Point specra.config.json at the env var (never store raw token)\n const config = JSON.parse(readFileSync(configPath, 'utf-8'))\n config.auth = { tokenEnv: DEFAULT_TOKEN_ENV }\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n')\n\n // Make sure .env is gitignored\n ensureGitignore(dir)\n}\n\nexport function clearLocalToken(dir?: string) {\n // Remove token from .env\n removeEnvVar(DEFAULT_TOKEN_ENV, dir)\n\n // Clean up auth section from specra.config.json\n const configPath = getLocalConfigPath(dir)\n if (!existsSync(configPath)) return\n try {\n const config = JSON.parse(readFileSync(configPath, 'utf-8'))\n if (config.auth) {\n delete config.auth\n }\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n')\n } catch {\n // ignore parse errors\n }\n}\n\n// --------------- Unified accessors ---------------\n\n/** Get token: checks local specra.config.json first, then global ~/.specra/config.json */\nexport function getToken(dir?: string): string | undefined {\n return getLocalToken(dir) || getGlobalConfig().token\n}\n\n/** Get the API URL from global config */\nexport function getConfig(): GlobalConfig {\n return getGlobalConfig()\n}\n\nexport function isAuthenticated(dir?: string): boolean {\n return !!getToken(dir)\n}\n\n/** Save token to local .env (default) or global ~/.specra/config.json */\nexport function saveToken(token: string, options?: { global?: boolean; dir?: string }) {\n if (options?.global) {\n saveGlobalConfig({ token })\n // If specra.config.json exists locally, point it at global\n const configPath = getLocalConfigPath(options?.dir)\n if (existsSync(configPath)) {\n try {\n const config = JSON.parse(readFileSync(configPath, 'utf-8'))\n config.auth = { source: 'global' }\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n')\n } catch {\n // ignore\n }\n }\n } else {\n saveLocalToken(token, options?.dir)\n }\n}\n\n/** Clear token from local .env (default) or global config */\nexport function clearToken(options?: { global?: boolean; dir?: string }) {\n if (options?.global) {\n clearGlobalToken()\n } else {\n clearLocalToken(options?.dir)\n }\n}\n\n// Legacy exports for backwards compat\nexport function saveConfig(config: Partial<GlobalConfig>) {\n saveGlobalConfig(config)\n}\n\nexport function clearConfig() {\n if (existsSync(GLOBAL_CONFIG_FILE)) {\n unlinkSync(GLOBAL_CONFIG_FILE)\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
getConfig,
|
|
4
4
|
getToken
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-5765WX4D.js";
|
|
6
6
|
|
|
7
7
|
// src/api-client.ts
|
|
8
8
|
var ApiError = class extends Error {
|
|
@@ -91,4 +91,4 @@ export {
|
|
|
91
91
|
apiRequest,
|
|
92
92
|
apiUpload
|
|
93
93
|
};
|
|
94
|
-
//# sourceMappingURL=chunk-
|
|
94
|
+
//# sourceMappingURL=chunk-72RDEJR2.js.map
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/utils.ts
|
|
4
|
+
import validateNpmPackageName from "validate-npm-package-name";
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
function validateProjectName(name) {
|
|
9
|
+
const validation = validateNpmPackageName(name);
|
|
10
|
+
if (validation.validForNewPackages) {
|
|
11
|
+
return { valid: true };
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
valid: false,
|
|
15
|
+
problems: [
|
|
16
|
+
...validation.errors || [],
|
|
17
|
+
...validation.warnings || []
|
|
18
|
+
]
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function isWriteable(directory) {
|
|
22
|
+
try {
|
|
23
|
+
fs.accessSync(directory, fs.constants.W_OK);
|
|
24
|
+
return true;
|
|
25
|
+
} catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function isFolderEmpty(path2) {
|
|
30
|
+
const files = fs.readdirSync(path2);
|
|
31
|
+
return files.length === 0 || files.length === 1 && files[0] === ".git";
|
|
32
|
+
}
|
|
33
|
+
function getPackageManagerCommand(packageManager) {
|
|
34
|
+
switch (packageManager) {
|
|
35
|
+
case "yarn":
|
|
36
|
+
return {
|
|
37
|
+
install: "yarn install",
|
|
38
|
+
run: (script) => `yarn ${script}`
|
|
39
|
+
};
|
|
40
|
+
case "pnpm":
|
|
41
|
+
return {
|
|
42
|
+
install: "pnpm install",
|
|
43
|
+
run: (script) => `pnpm ${script}`
|
|
44
|
+
};
|
|
45
|
+
case "npm":
|
|
46
|
+
default:
|
|
47
|
+
return {
|
|
48
|
+
install: "npm install",
|
|
49
|
+
run: (script) => `npm run ${script}`
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function detectPackageManager(dir) {
|
|
54
|
+
const configPath = path.join(dir, "specra.config.json");
|
|
55
|
+
try {
|
|
56
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
57
|
+
if (config.packageManager) return config.packageManager;
|
|
58
|
+
} catch {
|
|
59
|
+
}
|
|
60
|
+
if (fs.existsSync(path.join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
61
|
+
if (fs.existsSync(path.join(dir, "yarn.lock"))) return "yarn";
|
|
62
|
+
return "npm";
|
|
63
|
+
}
|
|
64
|
+
function tryGitInit(root) {
|
|
65
|
+
try {
|
|
66
|
+
execSync("git --version", { stdio: "ignore" });
|
|
67
|
+
execSync("git init", { cwd: root, stdio: "ignore" });
|
|
68
|
+
execSync("git add -A", { cwd: root, stdio: "ignore" });
|
|
69
|
+
execSync('git commit -m "Initial commit from create-specra"', {
|
|
70
|
+
cwd: root,
|
|
71
|
+
stdio: "ignore"
|
|
72
|
+
});
|
|
73
|
+
return true;
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function copyRecursive(src, dest) {
|
|
79
|
+
const stat = fs.statSync(src);
|
|
80
|
+
if (stat.isDirectory()) {
|
|
81
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
82
|
+
const entries = fs.readdirSync(src);
|
|
83
|
+
for (const entry of entries) {
|
|
84
|
+
const srcPath = path.join(src, entry);
|
|
85
|
+
const destPath = path.join(dest, entry);
|
|
86
|
+
copyRecursive(srcPath, destPath);
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
fs.copyFileSync(src, dest);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export {
|
|
94
|
+
validateProjectName,
|
|
95
|
+
isWriteable,
|
|
96
|
+
isFolderEmpty,
|
|
97
|
+
getPackageManagerCommand,
|
|
98
|
+
detectPackageManager,
|
|
99
|
+
tryGitInit,
|
|
100
|
+
copyRecursive
|
|
101
|
+
};
|
|
102
|
+
//# sourceMappingURL=chunk-SQ2MMFUZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts"],"sourcesContent":["import validateNpmPackageName from 'validate-npm-package-name'\nimport { execSync } from 'child_process'\nimport fs from 'fs'\nimport path from 'path'\n\nexport function validateProjectName(name: string) {\n const validation = validateNpmPackageName(name)\n\n if (validation.validForNewPackages) {\n return { valid: true }\n }\n\n return {\n valid: false,\n problems: [\n ...(validation.errors || []),\n ...(validation.warnings || []),\n ],\n }\n}\n\nexport function isWriteable(directory: string): boolean {\n try {\n fs.accessSync(directory, fs.constants.W_OK)\n return true\n } catch {\n return false\n }\n}\n\nexport function isFolderEmpty(path: string): boolean {\n const files = fs.readdirSync(path)\n return files.length === 0 || (files.length === 1 && files[0] === '.git')\n}\n\nexport function getPackageManagerCommand(packageManager: string): {\n install: string\n run: (script: string) => string\n} {\n switch (packageManager) {\n case 'yarn':\n return {\n install: 'yarn install',\n run: (script) => `yarn ${script}`,\n }\n case 'pnpm':\n return {\n install: 'pnpm install',\n run: (script) => `pnpm ${script}`,\n }\n case 'npm':\n default:\n return {\n install: 'npm install',\n run: (script) => `npm run ${script}`,\n }\n }\n}\n\nexport function detectPackageManager(dir: string): string {\n // 1. Check specra.config.json for explicit setting\n const configPath = path.join(dir, 'specra.config.json')\n try {\n const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n if (config.packageManager) return config.packageManager\n } catch {\n // ignore\n }\n\n // 2. Detect from lockfiles\n if (fs.existsSync(path.join(dir, 'pnpm-lock.yaml'))) return 'pnpm'\n if (fs.existsSync(path.join(dir, 'yarn.lock'))) return 'yarn'\n return 'npm'\n}\n\nexport function tryGitInit(root: string): boolean {\n try {\n execSync('git --version', { stdio: 'ignore' })\n execSync('git init', { cwd: root, stdio: 'ignore' })\n execSync('git add -A', { cwd: root, stdio: 'ignore' })\n execSync('git commit -m \"Initial commit from create-specra\"', {\n cwd: root,\n stdio: 'ignore',\n })\n return true\n } catch {\n return false\n }\n}\n\nexport function copyRecursive(src: string, dest: string) {\n const stat = fs.statSync(src)\n\n if (stat.isDirectory()) {\n fs.mkdirSync(dest, { recursive: true })\n const entries = fs.readdirSync(src)\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry)\n const destPath = path.join(dest, entry)\n copyRecursive(srcPath, destPath)\n }\n } else {\n fs.copyFileSync(src, dest)\n }\n}\n"],"mappings":";;;AAAA,OAAO,4BAA4B;AACnC,SAAS,gBAAgB;AACzB,OAAO,QAAQ;AACf,OAAO,UAAU;AAEV,SAAS,oBAAoB,MAAc;AAChD,QAAM,aAAa,uBAAuB,IAAI;AAE9C,MAAI,WAAW,qBAAqB;AAClC,WAAO,EAAE,OAAO,KAAK;AAAA,EACvB;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,MACR,GAAI,WAAW,UAAU,CAAC;AAAA,MAC1B,GAAI,WAAW,YAAY,CAAC;AAAA,IAC9B;AAAA,EACF;AACF;AAEO,SAAS,YAAY,WAA4B;AACtD,MAAI;AACF,OAAG,WAAW,WAAW,GAAG,UAAU,IAAI;AAC1C,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,cAAcA,OAAuB;AACnD,QAAM,QAAQ,GAAG,YAAYA,KAAI;AACjC,SAAO,MAAM,WAAW,KAAM,MAAM,WAAW,KAAK,MAAM,CAAC,MAAM;AACnE;AAEO,SAAS,yBAAyB,gBAGvC;AACA,UAAQ,gBAAgB;AAAA,IACtB,KAAK;AACH,aAAO;AAAA,QACL,SAAS;AAAA,QACT,KAAK,CAAC,WAAW,QAAQ,MAAM;AAAA,MACjC;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,SAAS;AAAA,QACT,KAAK,CAAC,WAAW,QAAQ,MAAM;AAAA,MACjC;AAAA,IACF,KAAK;AAAA,IACL;AACE,aAAO;AAAA,QACL,SAAS;AAAA,QACT,KAAK,CAAC,WAAW,WAAW,MAAM;AAAA,MACpC;AAAA,EACJ;AACF;AAEO,SAAS,qBAAqB,KAAqB;AAExD,QAAM,aAAa,KAAK,KAAK,KAAK,oBAAoB;AACtD,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,GAAG,aAAa,YAAY,OAAO,CAAC;AAC9D,QAAI,OAAO,eAAgB,QAAO,OAAO;AAAA,EAC3C,QAAQ;AAAA,EAER;AAGA,MAAI,GAAG,WAAW,KAAK,KAAK,KAAK,gBAAgB,CAAC,EAAG,QAAO;AAC5D,MAAI,GAAG,WAAW,KAAK,KAAK,KAAK,WAAW,CAAC,EAAG,QAAO;AACvD,SAAO;AACT;AAEO,SAAS,WAAW,MAAuB;AAChD,MAAI;AACF,aAAS,iBAAiB,EAAE,OAAO,SAAS,CAAC;AAC7C,aAAS,YAAY,EAAE,KAAK,MAAM,OAAO,SAAS,CAAC;AACnD,aAAS,cAAc,EAAE,KAAK,MAAM,OAAO,SAAS,CAAC;AACrD,aAAS,qDAAqD;AAAA,MAC5D,KAAK;AAAA,MACL,OAAO;AAAA,IACT,CAAC;AACD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,cAAc,KAAa,MAAc;AACvD,QAAM,OAAO,GAAG,SAAS,GAAG;AAE5B,MAAI,KAAK,YAAY,GAAG;AACtB,OAAG,UAAU,MAAM,EAAE,WAAW,KAAK,CAAC;AACtC,UAAM,UAAU,GAAG,YAAY,GAAG;AAElC,eAAW,SAAS,SAAS;AAC3B,YAAM,UAAU,KAAK,KAAK,KAAK,KAAK;AACpC,YAAM,WAAW,KAAK,KAAK,MAAM,KAAK;AACtC,oBAAc,SAAS,QAAQ;AAAA,IACjC;AAAA,EACF,OAAO;AACL,OAAG,aAAa,KAAK,IAAI;AAAA,EAC3B;AACF;","names":["path"]}
|
package/dist/cli.js
CHANGED
|
@@ -9,27 +9,27 @@ var { version } = require2("../package.json");
|
|
|
9
9
|
var program = new Command();
|
|
10
10
|
program.name("specra").description("Specra CLI - Deploy and manage your documentation sites").version(version);
|
|
11
11
|
program.command("login").description("Authenticate with your Specra account").option("-g, --global", "Store credentials in ~/.specra/ instead of local specra.config.json").action(async (options) => {
|
|
12
|
-
const { login } = await import("./login-
|
|
12
|
+
const { login } = await import("./login-UG3WU7DY.js");
|
|
13
13
|
await login(options);
|
|
14
14
|
});
|
|
15
15
|
program.command("logout").description("Clear stored credentials").option("-g, --global", "Clear credentials from ~/.specra/ instead of local specra.config.json").action(async (options) => {
|
|
16
|
-
const { logout } = await import("./logout-
|
|
16
|
+
const { logout } = await import("./logout-WJKHJZT6.js");
|
|
17
17
|
await logout(options);
|
|
18
18
|
});
|
|
19
|
-
program.command("deploy").description("Deploy your docs project").option("-p, --project <id>", "Project ID to deploy to").option("-d, --dir <directory>", "Docs directory to deploy", ".").action(async (options) => {
|
|
20
|
-
const { deploy } = await import("./deploy-
|
|
19
|
+
program.command("deploy").description("Deploy your docs project").option("-p, --project <id>", "Project ID to deploy to").option("-d, --dir <directory>", "Docs directory to deploy", ".").option("-v, --verbose", "Show detailed build output and logs").action(async (options) => {
|
|
20
|
+
const { deploy } = await import("./deploy-V4JO2D6B.js");
|
|
21
21
|
await deploy(options);
|
|
22
22
|
});
|
|
23
23
|
program.command("projects").description("List your projects").action(async () => {
|
|
24
|
-
const { projects } = await import("./projects-
|
|
24
|
+
const { projects } = await import("./projects-LJ57GK3D.js");
|
|
25
25
|
await projects();
|
|
26
26
|
});
|
|
27
27
|
program.command("logs").description("View deployment logs").argument("<projectId>", "Project ID").option("--deployment <id>", "Specific deployment ID").action(async (projectId, options) => {
|
|
28
|
-
const { logs } = await import("./logs-
|
|
28
|
+
const { logs } = await import("./logs-BLUJPWNO.js");
|
|
29
29
|
await logs(projectId, options);
|
|
30
30
|
});
|
|
31
31
|
program.command("doctor").description("Check specra.config.json for issues").option("-d, --dir <directory>", "Project directory to check", ".").action(async (options) => {
|
|
32
|
-
const { doctor } = await import("./doctor-
|
|
32
|
+
const { doctor } = await import("./doctor-ICALAJ4N.js");
|
|
33
33
|
await doctor(options);
|
|
34
34
|
});
|
|
35
35
|
program.parse();
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander'\nimport pc from 'picocolors'\nimport { createRequire } from 'module'\n\nconst require = createRequire(import.meta.url)\nconst { version } = require('../package.json')\n\nconst program = new Command()\n\nprogram\n .name('specra')\n .description('Specra CLI - Deploy and manage your documentation sites')\n .version(version)\n\nprogram\n .command('login')\n .description('Authenticate with your Specra account')\n .option('-g, --global', 'Store credentials in ~/.specra/ instead of local specra.config.json')\n .action(async (options) => {\n const { login } = await import('./commands/login.js')\n await login(options)\n })\n\nprogram\n .command('logout')\n .description('Clear stored credentials')\n .option('-g, --global', 'Clear credentials from ~/.specra/ instead of local specra.config.json')\n .action(async (options) => {\n const { logout } = await import('./commands/logout.js')\n await logout(options)\n })\n\nprogram\n .command('deploy')\n .description('Deploy your docs project')\n .option('-p, --project <id>', 'Project ID to deploy to')\n .option('-d, --dir <directory>', 'Docs directory to deploy', '.')\n .action(async (options) => {\n const { deploy } = await import('./commands/deploy.js')\n await deploy(options)\n })\n\nprogram\n .command('projects')\n .description('List your projects')\n .action(async () => {\n const { projects } = await import('./commands/projects.js')\n await projects()\n })\n\nprogram\n .command('logs')\n .description('View deployment logs')\n .argument('<projectId>', 'Project ID')\n .option('--deployment <id>', 'Specific deployment ID')\n .action(async (projectId: string, options) => {\n const { logs } = await import('./commands/logs.js')\n await logs(projectId, options)\n })\n\nprogram\n .command('doctor')\n .description('Check specra.config.json for issues')\n .option('-d, --dir <directory>', 'Project directory to check', '.')\n .action(async (options) => {\n const { doctor } = await import('./commands/doctor.js')\n await doctor(options)\n })\n\nprogram.parse()\n\n// Handle unhandled rejections\nprocess.on('unhandledRejection', (err) => {\n console.error(pc.red('Error:'), err)\n process.exit(1)\n})\n"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,OAAO,QAAQ;AACf,SAAS,qBAAqB;AAE9B,IAAMA,WAAU,cAAc,YAAY,GAAG;AAC7C,IAAM,EAAE,QAAQ,IAAIA,SAAQ,iBAAiB;AAE7C,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,QAAQ,EACb,YAAY,yDAAyD,EACrE,QAAQ,OAAO;AAElB,QACG,QAAQ,OAAO,EACf,YAAY,uCAAuC,EACnD,OAAO,gBAAgB,qEAAqE,EAC5F,OAAO,OAAO,YAAY;AACzB,QAAM,EAAE,MAAM,IAAI,MAAM,OAAO,qBAAqB;AACpD,QAAM,MAAM,OAAO;AACrB,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,0BAA0B,EACtC,OAAO,gBAAgB,uEAAuE,EAC9F,OAAO,OAAO,YAAY;AACzB,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,sBAAsB;AACtD,QAAM,OAAO,OAAO;AACtB,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,0BAA0B,EACtC,OAAO,sBAAsB,yBAAyB,EACtD,OAAO,yBAAyB,4BAA4B,GAAG,EAC/D,OAAO,OAAO,YAAY;AACzB,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,sBAAsB;AACtD,QAAM,OAAO,OAAO;AACtB,CAAC;AAEH,QACG,QAAQ,UAAU,EAClB,YAAY,oBAAoB,EAChC,OAAO,YAAY;AAClB,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,wBAAwB;AAC1D,QAAM,SAAS;AACjB,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,sBAAsB,EAClC,SAAS,eAAe,YAAY,EACpC,OAAO,qBAAqB,wBAAwB,EACpD,OAAO,OAAO,WAAmB,YAAY;AAC5C,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,oBAAoB;AAClD,QAAM,KAAK,WAAW,OAAO;AAC/B,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,qCAAqC,EACjD,OAAO,yBAAyB,8BAA8B,GAAG,EACjE,OAAO,OAAO,YAAY;AACzB,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,sBAAsB;AACtD,QAAM,OAAO,OAAO;AACtB,CAAC;AAEH,QAAQ,MAAM;AAGd,QAAQ,GAAG,sBAAsB,CAAC,QAAQ;AACxC,UAAQ,MAAM,GAAG,IAAI,QAAQ,GAAG,GAAG;AACnC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["require"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander'\nimport pc from 'picocolors'\nimport { createRequire } from 'module'\n\nconst require = createRequire(import.meta.url)\nconst { version } = require('../package.json')\n\nconst program = new Command()\n\nprogram\n .name('specra')\n .description('Specra CLI - Deploy and manage your documentation sites')\n .version(version)\n\nprogram\n .command('login')\n .description('Authenticate with your Specra account')\n .option('-g, --global', 'Store credentials in ~/.specra/ instead of local specra.config.json')\n .action(async (options) => {\n const { login } = await import('./commands/login.js')\n await login(options)\n })\n\nprogram\n .command('logout')\n .description('Clear stored credentials')\n .option('-g, --global', 'Clear credentials from ~/.specra/ instead of local specra.config.json')\n .action(async (options) => {\n const { logout } = await import('./commands/logout.js')\n await logout(options)\n })\n\nprogram\n .command('deploy')\n .description('Deploy your docs project')\n .option('-p, --project <id>', 'Project ID to deploy to')\n .option('-d, --dir <directory>', 'Docs directory to deploy', '.')\n .option('-v, --verbose', 'Show detailed build output and logs')\n .action(async (options) => {\n const { deploy } = await import('./commands/deploy.js')\n await deploy(options)\n })\n\nprogram\n .command('projects')\n .description('List your projects')\n .action(async () => {\n const { projects } = await import('./commands/projects.js')\n await projects()\n })\n\nprogram\n .command('logs')\n .description('View deployment logs')\n .argument('<projectId>', 'Project ID')\n .option('--deployment <id>', 'Specific deployment ID')\n .action(async (projectId: string, options) => {\n const { logs } = await import('./commands/logs.js')\n await logs(projectId, options)\n })\n\nprogram\n .command('doctor')\n .description('Check specra.config.json for issues')\n .option('-d, --dir <directory>', 'Project directory to check', '.')\n .action(async (options) => {\n const { doctor } = await import('./commands/doctor.js')\n await doctor(options)\n })\n\nprogram.parse()\n\n// Handle unhandled rejections\nprocess.on('unhandledRejection', (err) => {\n console.error(pc.red('Error:'), err)\n process.exit(1)\n})\n"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,OAAO,QAAQ;AACf,SAAS,qBAAqB;AAE9B,IAAMA,WAAU,cAAc,YAAY,GAAG;AAC7C,IAAM,EAAE,QAAQ,IAAIA,SAAQ,iBAAiB;AAE7C,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,QAAQ,EACb,YAAY,yDAAyD,EACrE,QAAQ,OAAO;AAElB,QACG,QAAQ,OAAO,EACf,YAAY,uCAAuC,EACnD,OAAO,gBAAgB,qEAAqE,EAC5F,OAAO,OAAO,YAAY;AACzB,QAAM,EAAE,MAAM,IAAI,MAAM,OAAO,qBAAqB;AACpD,QAAM,MAAM,OAAO;AACrB,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,0BAA0B,EACtC,OAAO,gBAAgB,uEAAuE,EAC9F,OAAO,OAAO,YAAY;AACzB,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,sBAAsB;AACtD,QAAM,OAAO,OAAO;AACtB,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,0BAA0B,EACtC,OAAO,sBAAsB,yBAAyB,EACtD,OAAO,yBAAyB,4BAA4B,GAAG,EAC/D,OAAO,iBAAiB,qCAAqC,EAC7D,OAAO,OAAO,YAAY;AACzB,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,sBAAsB;AACtD,QAAM,OAAO,OAAO;AACtB,CAAC;AAEH,QACG,QAAQ,UAAU,EAClB,YAAY,oBAAoB,EAChC,OAAO,YAAY;AAClB,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,wBAAwB;AAC1D,QAAM,SAAS;AACjB,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,sBAAsB,EAClC,SAAS,eAAe,YAAY,EACpC,OAAO,qBAAqB,wBAAwB,EACpD,OAAO,OAAO,WAAmB,YAAY;AAC5C,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,oBAAoB;AAClD,QAAM,KAAK,WAAW,OAAO;AAC/B,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,qCAAqC,EACjD,OAAO,yBAAyB,8BAA8B,GAAG,EACjE,OAAO,OAAO,YAAY;AACzB,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,sBAAsB;AACtD,QAAM,OAAO,OAAO;AACtB,CAAC;AAEH,QAAQ,MAAM;AAGd,QAAQ,GAAG,sBAAsB,CAAC,QAAQ;AACxC,UAAQ,MAAM,GAAG,IAAI,QAAQ,GAAG,GAAG;AACnC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["require"]}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
detectPackageManager,
|
|
4
|
+
getPackageManagerCommand
|
|
5
|
+
} from "./chunk-SQ2MMFUZ.js";
|
|
2
6
|
import {
|
|
3
7
|
apiRequest,
|
|
4
8
|
apiUpload,
|
|
5
9
|
formatError
|
|
6
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-72RDEJR2.js";
|
|
7
11
|
import {
|
|
8
12
|
getConfig,
|
|
9
13
|
isAuthenticated
|
|
10
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-5765WX4D.js";
|
|
11
15
|
|
|
12
16
|
// src/commands/deploy.ts
|
|
13
17
|
import pc from "picocolors";
|
|
@@ -100,16 +104,35 @@ async function deploy(options) {
|
|
|
100
104
|
}
|
|
101
105
|
projectId = response.project;
|
|
102
106
|
}
|
|
107
|
+
const verbose = options.verbose ?? false;
|
|
108
|
+
if (verbose) {
|
|
109
|
+
console.log(pc.dim(`Project ID: ${projectId}`));
|
|
110
|
+
console.log(pc.dim(`Directory: ${dir}`));
|
|
111
|
+
}
|
|
103
112
|
const spinner = ora("Building project...").start();
|
|
104
113
|
try {
|
|
105
114
|
const buildDir = join(dir, "build");
|
|
106
115
|
const { execSync } = await import("child_process");
|
|
116
|
+
const pm = detectPackageManager(dir);
|
|
117
|
+
const pmCmd = getPackageManagerCommand(pm);
|
|
118
|
+
if (verbose) {
|
|
119
|
+
spinner.stop();
|
|
120
|
+
console.log(pc.dim(`Package manager: ${pm}`));
|
|
121
|
+
console.log(pc.dim(`Running: ${pmCmd.run("build")}`));
|
|
122
|
+
console.log();
|
|
123
|
+
}
|
|
107
124
|
try {
|
|
108
|
-
execSync("
|
|
125
|
+
execSync(pmCmd.run("build"), { cwd: dir, stdio: verbose ? "inherit" : "pipe" });
|
|
109
126
|
} catch (err) {
|
|
110
|
-
|
|
111
|
-
|
|
127
|
+
if (!verbose) {
|
|
128
|
+
const stderr = err instanceof Error && "stderr" in err ? err.stderr?.toString() : "";
|
|
129
|
+
throw new Error(`Build failed:
|
|
112
130
|
${stderr}`);
|
|
131
|
+
}
|
|
132
|
+
throw new Error("Build failed. See output above.");
|
|
133
|
+
}
|
|
134
|
+
if (verbose) {
|
|
135
|
+
spinner.start();
|
|
113
136
|
}
|
|
114
137
|
if (!existsSync2(buildDir)) {
|
|
115
138
|
throw new Error(
|
|
@@ -119,6 +142,9 @@ ${stderr}`);
|
|
|
119
142
|
spinner.text = "Packaging build output...";
|
|
120
143
|
const archive = await createArchive(buildDir);
|
|
121
144
|
spinner.text = `Uploading (${(archive.length / 1024).toFixed(0)}KB)...`;
|
|
145
|
+
if (verbose) {
|
|
146
|
+
console.log(pc.dim(`Archive size: ${(archive.length / 1024).toFixed(1)}KB`));
|
|
147
|
+
}
|
|
122
148
|
let commitSha;
|
|
123
149
|
try {
|
|
124
150
|
commitSha = execSync("git rev-parse HEAD", { cwd: dir }).toString().trim();
|
|
@@ -150,4 +176,4 @@ ${stderr}`);
|
|
|
150
176
|
export {
|
|
151
177
|
deploy
|
|
152
178
|
};
|
|
153
|
-
//# sourceMappingURL=deploy-
|
|
179
|
+
//# sourceMappingURL=deploy-V4JO2D6B.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/deploy.ts","../src/archive.ts"],"sourcesContent":["import pc from 'picocolors'\nimport ora from 'ora'\nimport { createArchive } from '../archive.js'\nimport { apiUpload, apiRequest, formatError } from '../api-client.js'\nimport { isAuthenticated, getConfig } from '../config.js'\nimport { existsSync, readFileSync } from 'fs'\nimport { join, resolve } from 'path'\nimport { detectPackageManager, getPackageManagerCommand } from '../utils.js'\n\ninterface DeployOptions {\n project?: string\n dir: string\n verbose?: boolean\n}\n\nexport async function deploy(options: DeployOptions) {\n if (!isAuthenticated()) {\n console.error(pc.red('Not authenticated. Run `specra login` first.'))\n process.exit(1)\n }\n\n const dir = resolve(options.dir)\n let projectId = options.project\n\n // If no project specified, try to read from specra.config.json\n if (!projectId) {\n const configPath = join(dir, 'specra.config.json')\n if (existsSync(configPath)) {\n try {\n const config = JSON.parse(readFileSync(configPath, 'utf-8'))\n projectId = config.projectId\n } catch {\n // ignore\n }\n }\n }\n\n if (!projectId) {\n // List projects and ask user to pick\n let projects: Array<{ id: string; name: string; subdomain: string }>\n try {\n projects = await apiRequest<Array<{ id: string; name: string; subdomain: string }>>(\n '/api/projects'\n )\n } catch (err) {\n console.error(pc.red(formatError('Failed to fetch projects', err)))\n process.exit(1)\n }\n\n if (projects.length === 0) {\n console.error(\n pc.red('No projects found. Create one at https://specra-docs.com/dashboard/projects/new')\n )\n process.exit(1)\n }\n\n console.log(pc.bold('Select a project to deploy to:'))\n projects.forEach((p, i) => {\n console.log(` ${pc.dim(`${i + 1}.`)} ${p.name} ${pc.dim(`(${p.subdomain}.docs.specra.dev)`)}`)\n })\n\n const prompts = await import('prompts')\n const response = await prompts.default({\n type: 'select',\n name: 'project',\n message: 'Project',\n choices: projects.map((p) => ({\n title: p.name,\n value: p.id,\n description: `${p.subdomain}.docs.specra.dev`,\n })),\n })\n\n if (!response.project) {\n console.log('Aborted.')\n process.exit(1)\n }\n\n projectId = response.project\n }\n\n const verbose = options.verbose ?? false\n\n if (verbose) {\n console.log(pc.dim(`Project ID: ${projectId}`))\n console.log(pc.dim(`Directory: ${dir}`))\n }\n\n const spinner = ora('Building project...').start()\n\n try {\n // 1. Build the project locally\n const buildDir = join(dir, 'build')\n const { execSync } = await import('child_process')\n\n const pm = detectPackageManager(dir)\n const pmCmd = getPackageManagerCommand(pm)\n\n if (verbose) {\n spinner.stop()\n console.log(pc.dim(`Package manager: ${pm}`))\n console.log(pc.dim(`Running: ${pmCmd.run('build')}`))\n console.log()\n }\n\n try {\n execSync(pmCmd.run('build'), { cwd: dir, stdio: verbose ? 'inherit' : 'pipe' })\n } catch (err) {\n if (!verbose) {\n const stderr = err instanceof Error && 'stderr' in err\n ? (err as { stderr: Buffer }).stderr?.toString()\n : ''\n throw new Error(`Build failed:\\n${stderr}`)\n }\n throw new Error('Build failed. See output above.')\n }\n\n if (verbose) {\n spinner.start()\n }\n\n if (!existsSync(buildDir)) {\n throw new Error(\n 'Build output not found. Expected a `build/` directory.\\n' +\n 'Make sure your project uses @sveltejs/adapter-static.'\n )\n }\n\n // 2. Archive the build output\n spinner.text = 'Packaging build output...'\n const archive = await createArchive(buildDir)\n spinner.text = `Uploading (${(archive.length / 1024).toFixed(0)}KB)...`\n\n if (verbose) {\n console.log(pc.dim(`Archive size: ${(archive.length / 1024).toFixed(1)}KB`))\n }\n\n // 3. Get git commit SHA if available\n let commitSha: string | undefined\n try {\n commitSha = execSync('git rev-parse HEAD', { cwd: dir })\n .toString()\n .trim()\n } catch {\n // not a git repo\n }\n\n // 4. Upload as pre-built\n const result = await apiUpload(\n `/api/projects/${projectId}/deploy`,\n archive,\n {\n 'X-Deploy-Trigger': 'CLI',\n 'X-Pre-Built': 'true',\n ...(commitSha ? { 'X-Commit-Sha': commitSha } : {}),\n }\n ) as { deploymentId: string }\n\n spinner.succeed(pc.green('Deployed!'))\n console.log()\n console.log(` Deployment ID: ${pc.cyan(result.deploymentId)}`)\n\n const config = getConfig()\n console.log(\n ` View status: ${pc.dim(`${config.apiUrl}/dashboard/projects/${projectId}/deployments`)}`\n )\n console.log()\n } catch (err) {\n spinner.fail(pc.red('Deploy failed'))\n console.error(pc.red(formatError('', err)))\n process.exit(1)\n }\n}\n","import * as tar from 'tar'\nimport { existsSync, statSync } from 'fs'\nimport { resolve } from 'path'\n\nexport async function createArchive(dir: string): Promise<Buffer> {\n const absDir = resolve(dir)\n\n if (!existsSync(absDir)) {\n throw new Error(`Directory not found: ${absDir}`)\n }\n\n if (!statSync(absDir).isDirectory()) {\n throw new Error(`Not a directory: ${absDir}`)\n }\n\n const chunks: Buffer[] = []\n\n const stream = tar.create(\n {\n gzip: true,\n cwd: absDir,\n },\n ['.']\n )\n\n for await (const chunk of stream) {\n chunks.push(chunk as Buffer)\n }\n\n const result = Buffer.concat(chunks)\n if (result.length === 0) {\n throw new Error('Archive is empty — no files found in the build output')\n }\n\n return result\n}\n"],"mappings":"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","names":["existsSync","resolve","resolve","existsSync"]}
|