specra-cli 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.MD +33 -0
- package/README.md +246 -0
- package/dist/api-client-VHQARPDT.js +15 -0
- package/dist/api-client-VHQARPDT.js.map +1 -0
- package/dist/chunk-5765WX4D.js +192 -0
- package/dist/chunk-5765WX4D.js.map +1 -0
- package/dist/chunk-72RDEJR2.js +94 -0
- package/dist/chunk-72RDEJR2.js.map +1 -0
- package/dist/chunk-SQ2MMFUZ.js +102 -0
- package/dist/chunk-SQ2MMFUZ.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +242 -0
- package/dist/cli.js.map +1 -0
- package/dist/deploy-V4JO2D6B.js +179 -0
- package/dist/deploy-V4JO2D6B.js.map +1 -0
- package/dist/doctor-ICALAJ4N.js +309 -0
- package/dist/doctor-ICALAJ4N.js.map +1 -0
- package/dist/login-UG3WU7DY.js +92 -0
- package/dist/login-UG3WU7DY.js.map +1 -0
- package/dist/logout-WJKHJZT6.js +24 -0
- package/dist/logout-WJKHJZT6.js.map +1 -0
- package/dist/logs-BLUJPWNO.js +77 -0
- package/dist/logs-BLUJPWNO.js.map +1 -0
- package/dist/projects-LJ57GK3D.js +49 -0
- package/dist/projects-LJ57GK3D.js.map +1 -0
- package/package.json +50 -0
- package/templates/book-docs/.env.sample +1 -0
- package/templates/book-docs/docs/v1.0.0/concepts.mdx +89 -0
- package/templates/book-docs/docs/v1.0.0/content/_category_.json +7 -0
- package/templates/book-docs/docs/v1.0.0/content/formatting.mdx +128 -0
- package/templates/book-docs/docs/v1.0.0/content/reusable-content.mdx +116 -0
- package/templates/book-docs/docs/v1.0.0/content/structure.mdx +92 -0
- package/templates/book-docs/docs/v1.0.0/customization/_category_.json +7 -0
- package/templates/book-docs/docs/v1.0.0/customization/branding.mdx +115 -0
- package/templates/book-docs/docs/v1.0.0/customization/themes.mdx +81 -0
- package/templates/book-docs/docs/v1.0.0/introduction.mdx +38 -0
- package/templates/book-docs/docs/v1.0.0/quickstart.mdx +112 -0
- package/templates/book-docs/docs/v2.0.0/concepts.mdx +89 -0
- package/templates/book-docs/docs/v2.0.0/content/_category_.json +7 -0
- package/templates/book-docs/docs/v2.0.0/content/formatting.mdx +128 -0
- package/templates/book-docs/docs/v2.0.0/content/reusable-content.mdx +116 -0
- package/templates/book-docs/docs/v2.0.0/content/structure.mdx +92 -0
- package/templates/book-docs/docs/v2.0.0/customization/_category_.json +7 -0
- package/templates/book-docs/docs/v2.0.0/customization/branding.mdx +115 -0
- package/templates/book-docs/docs/v2.0.0/customization/themes.mdx +81 -0
- package/templates/book-docs/docs/v2.0.0/introduction.mdx +39 -0
- package/templates/book-docs/docs/v2.0.0/quickstart.mdx +112 -0
- package/templates/book-docs/gitignore +7 -0
- package/templates/book-docs/package.json +28 -0
- package/templates/book-docs/postcss.config.mjs +8 -0
- package/templates/book-docs/public/api-specs/openapi-example.json +259 -0
- package/templates/book-docs/public/api-specs/postman-example.json +205 -0
- package/templates/book-docs/public/api-specs/test-api.json +256 -0
- package/templates/book-docs/public/api-specs/users-api.json +264 -0
- package/templates/book-docs/specra.config.json +77 -0
- package/templates/book-docs/src/app.css +86 -0
- package/templates/book-docs/src/app.html +17 -0
- package/templates/book-docs/src/params/product.ts +7 -0
- package/templates/book-docs/src/routes/+layout.server.ts +14 -0
- package/templates/book-docs/src/routes/+layout.svelte +21 -0
- package/templates/book-docs/src/routes/+page.server.ts +9 -0
- package/templates/book-docs/src/routes/docs/[product=product]/[version]/+layout.server.ts +40 -0
- package/templates/book-docs/src/routes/docs/[product=product]/[version]/+page.server.ts +24 -0
- package/templates/book-docs/src/routes/docs/[product=product]/[version]/[...slug]/+page.server.ts +131 -0
- package/templates/book-docs/src/routes/docs/[product=product]/[version]/[...slug]/+page.svelte +180 -0
- package/templates/book-docs/src/routes/docs/[version]/+layout.server.ts +42 -0
- package/templates/book-docs/src/routes/docs/[version]/+page.server.ts +27 -0
- package/templates/book-docs/src/routes/docs/[version]/[...slug]/+page.server.ts +106 -0
- package/templates/book-docs/src/routes/docs/[version]/[...slug]/+page.svelte +172 -0
- package/templates/book-docs/static/favicon.svg +4 -0
- package/templates/book-docs/svelte.config.js +13 -0
- package/templates/book-docs/tsconfig.json +12 -0
- package/templates/book-docs/vite.config.ts +6 -0
- package/templates/jbrains-docs/.env.sample +1 -0
- package/templates/jbrains-docs/docs/v1.0.0/advanced/_category_.json +8 -0
- package/templates/jbrains-docs/docs/v1.0.0/advanced/async.mdx +95 -0
- package/templates/jbrains-docs/docs/v1.0.0/advanced/generics.mdx +126 -0
- package/templates/jbrains-docs/docs/v1.0.0/basics/_category_.json +8 -0
- package/templates/jbrains-docs/docs/v1.0.0/basics/control-flow.mdx +106 -0
- package/templates/jbrains-docs/docs/v1.0.0/basics/syntax.mdx +129 -0
- package/templates/jbrains-docs/docs/v1.0.0/basics/types.mdx +135 -0
- package/templates/jbrains-docs/docs/v1.0.0/getting-started.mdx +111 -0
- package/templates/jbrains-docs/docs/v1.0.0/home.mdx +37 -0
- package/templates/jbrains-docs/docs/v1.0.0/tools/_category_.json +8 -0
- package/templates/jbrains-docs/docs/v1.0.0/tools/build-tools.mdx +165 -0
- package/templates/jbrains-docs/docs/v1.0.0/tools/testing.mdx +112 -0
- package/templates/jbrains-docs/docs/v2.0.0/advanced/_category_.json +8 -0
- package/templates/jbrains-docs/docs/v2.0.0/advanced/async.mdx +95 -0
- package/templates/jbrains-docs/docs/v2.0.0/advanced/generics.mdx +126 -0
- package/templates/jbrains-docs/docs/v2.0.0/basics/_category_.json +8 -0
- package/templates/jbrains-docs/docs/v2.0.0/basics/control-flow.mdx +106 -0
- package/templates/jbrains-docs/docs/v2.0.0/basics/syntax.mdx +129 -0
- package/templates/jbrains-docs/docs/v2.0.0/basics/types.mdx +135 -0
- package/templates/jbrains-docs/docs/v2.0.0/getting-started.mdx +111 -0
- package/templates/jbrains-docs/docs/v2.0.0/home.mdx +37 -0
- package/templates/jbrains-docs/docs/v2.0.0/tools/_category_.json +8 -0
- package/templates/jbrains-docs/docs/v2.0.0/tools/build-tools.mdx +165 -0
- package/templates/jbrains-docs/docs/v2.0.0/tools/testing.mdx +112 -0
- package/templates/jbrains-docs/gitignore +7 -0
- package/templates/jbrains-docs/package.json +28 -0
- package/templates/jbrains-docs/postcss.config.mjs +8 -0
- package/templates/jbrains-docs/public/api-specs/openapi-example.json +259 -0
- package/templates/jbrains-docs/public/api-specs/postman-example.json +205 -0
- package/templates/jbrains-docs/public/api-specs/test-api.json +256 -0
- package/templates/jbrains-docs/public/api-specs/users-api.json +264 -0
- package/templates/jbrains-docs/specra.config.json +80 -0
- package/templates/jbrains-docs/src/app.css +86 -0
- package/templates/jbrains-docs/src/app.html +17 -0
- package/templates/jbrains-docs/src/params/product.ts +7 -0
- package/templates/jbrains-docs/src/routes/+layout.server.ts +14 -0
- package/templates/jbrains-docs/src/routes/+layout.svelte +21 -0
- package/templates/jbrains-docs/src/routes/+page.server.ts +9 -0
- package/templates/jbrains-docs/src/routes/docs/[product=product]/[version]/+layout.server.ts +40 -0
- package/templates/jbrains-docs/src/routes/docs/[product=product]/[version]/+page.server.ts +24 -0
- package/templates/jbrains-docs/src/routes/docs/[product=product]/[version]/[...slug]/+page.server.ts +131 -0
- package/templates/jbrains-docs/src/routes/docs/[product=product]/[version]/[...slug]/+page.svelte +180 -0
- package/templates/jbrains-docs/src/routes/docs/[version]/+layout.server.ts +42 -0
- package/templates/jbrains-docs/src/routes/docs/[version]/+page.server.ts +27 -0
- package/templates/jbrains-docs/src/routes/docs/[version]/[...slug]/+page.server.ts +106 -0
- package/templates/jbrains-docs/src/routes/docs/[version]/[...slug]/+page.svelte +172 -0
- package/templates/jbrains-docs/static/favicon.svg +4 -0
- package/templates/jbrains-docs/svelte.config.js +13 -0
- package/templates/jbrains-docs/tsconfig.json +12 -0
- package/templates/jbrains-docs/vite.config.ts +6 -0
- package/templates/minimal/.env.sample +1 -0
- package/templates/minimal/docs/v1.0.0/about.mdx +57 -0
- package/templates/minimal/docs/v1.0.0/components/_category_.json +8 -0
- package/templates/minimal/docs/v1.0.0/components/callout.mdx +83 -0
- package/templates/minimal/docs/v1.0.0/components/code-block.mdx +103 -0
- package/templates/minimal/docs/v1.0.0/components/index.mdx +8 -0
- package/templates/minimal/docs/v1.0.0/components/tabs.mdx +92 -0
- package/templates/minimal/docs/v1.0.0/configuration.mdx +322 -0
- package/templates/minimal/docs/v1.0.0/features.mdx +197 -0
- package/templates/minimal/docs/v1.0.0/getting-started.mdx +183 -0
- package/templates/minimal/docs/v2.0.0/about.mdx +57 -0
- package/templates/minimal/docs/v2.0.0/components/_category_.json +8 -0
- package/templates/minimal/docs/v2.0.0/components/callout.mdx +83 -0
- package/templates/minimal/docs/v2.0.0/components/code-block.mdx +103 -0
- package/templates/minimal/docs/v2.0.0/components/index.mdx +8 -0
- package/templates/minimal/docs/v2.0.0/components/tabs.mdx +92 -0
- package/templates/minimal/docs/v2.0.0/configuration.mdx +322 -0
- package/templates/minimal/docs/v2.0.0/features.mdx +197 -0
- package/templates/minimal/docs/v2.0.0/getting-started.mdx +183 -0
- package/templates/minimal/gitignore +7 -0
- package/templates/minimal/package.json +29 -0
- package/templates/minimal/postcss.config.mjs +8 -0
- package/templates/minimal/specra.config.json +91 -0
- package/templates/minimal/src/app.css +86 -0
- package/templates/minimal/src/app.html +17 -0
- package/templates/minimal/src/hooks.server.ts +8 -0
- package/templates/minimal/src/params/product.ts +7 -0
- package/templates/minimal/src/routes/+error.svelte +10 -0
- package/templates/minimal/src/routes/+layout.server.ts +14 -0
- package/templates/minimal/src/routes/+layout.svelte +21 -0
- package/templates/minimal/src/routes/+page.server.ts +9 -0
- package/templates/minimal/src/routes/+page.svelte +149 -0
- package/templates/minimal/src/routes/docs/[product=product]/[version]/+layout.server.ts +40 -0
- package/templates/minimal/src/routes/docs/[product=product]/[version]/+page.server.ts +24 -0
- package/templates/minimal/src/routes/docs/[product=product]/[version]/[...slug]/+page.server.ts +131 -0
- package/templates/minimal/src/routes/docs/[product=product]/[version]/[...slug]/+page.svelte +180 -0
- package/templates/minimal/src/routes/docs/[version]/+layout.server.ts +42 -0
- package/templates/minimal/src/routes/docs/[version]/+page.server.ts +27 -0
- package/templates/minimal/src/routes/docs/[version]/[...slug]/+page.server.ts +106 -0
- package/templates/minimal/src/routes/docs/[version]/[...slug]/+page.svelte +172 -0
- package/templates/minimal/static/api-specs/openapi-example.json +259 -0
- package/templates/minimal/static/api-specs/postman-example.json +205 -0
- package/templates/minimal/static/api-specs/test-api.json +256 -0
- package/templates/minimal/static/api-specs/users-api.json +264 -0
- package/templates/minimal/static/favicon.svg +4 -0
- package/templates/minimal/svelte.config.js +13 -0
- package/templates/minimal/tsconfig.json +12 -0
- package/templates/minimal/vite.config.ts +6 -0
package/LICENSE.MD
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
MIT License with Branding Requirement
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 dalmasonto, arthur-kamau
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
1. The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
2. BRANDING / WATERMARK REQUIREMENT: All documentation sites generated using
|
|
16
|
+
this Software or the associated Specra SDK MUST display the "Powered by
|
|
17
|
+
Specra" watermark in a visible location (footer or equivalent) on every
|
|
18
|
+
public-facing page.
|
|
19
|
+
|
|
20
|
+
The watermark MUST NOT be removed, hidden, obscured, or made invisible
|
|
21
|
+
unless the user holds an active paid subscription (Starter tier or above)
|
|
22
|
+
on the Specra platform (https://specra-docs.com).
|
|
23
|
+
|
|
24
|
+
Removal, hiding, or circumvention of the watermark without a valid paid
|
|
25
|
+
subscription constitutes a COPYRIGHT VIOLATION and a breach of this license.
|
|
26
|
+
|
|
27
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
28
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
29
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
30
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
31
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
32
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
33
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# create-specra
|
|
2
|
+
|
|
3
|
+
The fastest way to create a new Specra documentation site. Scaffold a complete documentation project with a single command.
|
|
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
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
### With npx (recommended)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx create-specra my-docs
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### With npm
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm create specra my-docs
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### With yarn
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
yarn create specra my-docs
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### With pnpm
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pnpm create specra my-docs
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Options
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx create-specra [project-directory] [options]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Arguments
|
|
49
|
+
|
|
50
|
+
- `[project-directory]` - The directory to create the project in (optional, will prompt if not provided)
|
|
51
|
+
|
|
52
|
+
### Options
|
|
53
|
+
|
|
54
|
+
- `--template <template>` - Template to use: `minimal`, `book-docs`, `jbrains-docs` (will prompt if not provided)
|
|
55
|
+
- `--use-npm` - Use npm as the package manager
|
|
56
|
+
- `--use-pnpm` - Use pnpm as the package manager
|
|
57
|
+
- `--use-yarn` - Use yarn as the package manager
|
|
58
|
+
- `--skip-install` - Skip package installation
|
|
59
|
+
|
|
60
|
+
## Templates
|
|
61
|
+
|
|
62
|
+
### Minimal (Default)
|
|
63
|
+
|
|
64
|
+
Minimal setup to get started quickly:
|
|
65
|
+
- Basic documentation structure
|
|
66
|
+
- Essential configuration
|
|
67
|
+
- Clean starting point
|
|
68
|
+
- Ready to customize
|
|
69
|
+
|
|
70
|
+
### Book Docs
|
|
71
|
+
|
|
72
|
+
Knowledge base style inspired by popular docs platforms:
|
|
73
|
+
- Dark theme by default
|
|
74
|
+
- Categorized sidebar with section headers (Content, Customization)
|
|
75
|
+
- Site-wide banner
|
|
76
|
+
- Flush sidebar layout (attached to screen edge)
|
|
77
|
+
- Version badge in sidebar
|
|
78
|
+
|
|
79
|
+
### JBrains Docs
|
|
80
|
+
|
|
81
|
+
Reference documentation style with tabbed navigation:
|
|
82
|
+
- Light theme by default
|
|
83
|
+
- Tab groups for organizing content (Language, Multiplatform)
|
|
84
|
+
- Collapsible tree-style sidebar
|
|
85
|
+
- No table of contents (right panel)
|
|
86
|
+
- Flush sidebar layout
|
|
87
|
+
- Version badge in sidebar
|
|
88
|
+
|
|
89
|
+
## Examples
|
|
90
|
+
|
|
91
|
+
Create a new project with interactive prompts:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npx create-specra
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Create a project with the minimal template using npm:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npx create-specra my-docs --template minimal --use-npm
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Create a project with the book-docs template:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npx create-specra my-docs --template book-docs
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Create a project and skip installation:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npx create-specra my-docs --skip-install
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## What's Created
|
|
116
|
+
|
|
117
|
+
The CLI creates a new SvelteKit project with Specra pre-configured:
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
my-docs/
|
|
121
|
+
├── src/
|
|
122
|
+
│ ├── routes/
|
|
123
|
+
│ │ ├── +layout.svelte
|
|
124
|
+
│ │ ├── +page.svelte
|
|
125
|
+
│ │ └── docs/
|
|
126
|
+
│ │ └── [version]/[...slug]/
|
|
127
|
+
│ │ ├── +page.svelte
|
|
128
|
+
│ │ └── +page.ts
|
|
129
|
+
│ └── app.html
|
|
130
|
+
├── docs/
|
|
131
|
+
│ └── v1.0.0/
|
|
132
|
+
│ └── index.mdx
|
|
133
|
+
├── static/
|
|
134
|
+
├── specra.config.json
|
|
135
|
+
├── svelte.config.js
|
|
136
|
+
├── vite.config.ts
|
|
137
|
+
└── package.json
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## After Creation
|
|
141
|
+
|
|
142
|
+
Once your project is created, you can:
|
|
143
|
+
|
|
144
|
+
1. Start the development server:
|
|
145
|
+
```bash
|
|
146
|
+
cd my-docs
|
|
147
|
+
npm run dev
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
2. Open [http://localhost:5173](http://localhost:5173) in your browser
|
|
151
|
+
|
|
152
|
+
3. Edit your documentation in the `docs/` directory
|
|
153
|
+
|
|
154
|
+
4. Customize your site in `specra.config.json`
|
|
155
|
+
|
|
156
|
+
## Deployment
|
|
157
|
+
|
|
158
|
+
Specra projects are standard SvelteKit apps, so you can deploy anywhere SvelteKit runs.
|
|
159
|
+
|
|
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.).
|
|
231
|
+
|
|
232
|
+
## Learn More
|
|
233
|
+
|
|
234
|
+
- [Specra on npm](https://www.npmjs.com/package/specra)
|
|
235
|
+
- [SvelteKit Documentation](https://svelte.dev/docs/kit)
|
|
236
|
+
- [MDX Documentation](https://mdxjs.com)
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
MIT with Branding Requirement — see [LICENSE.MD](LICENSE.MD).
|
|
241
|
+
|
|
242
|
+
All documentation sites generated with create-specra display a "Powered by Specra" watermark by default. Removing the watermark requires an active paid subscription (Starter tier or above) at [specra-docs.com](https://specra-docs.com). Unauthorized removal is a copyright violation.
|
|
243
|
+
|
|
244
|
+
## Authors
|
|
245
|
+
|
|
246
|
+
dalmasonto, arthur-kamau
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ApiError,
|
|
4
|
+
apiRequest,
|
|
5
|
+
apiUpload,
|
|
6
|
+
formatError
|
|
7
|
+
} from "./chunk-72RDEJR2.js";
|
|
8
|
+
import "./chunk-5765WX4D.js";
|
|
9
|
+
export {
|
|
10
|
+
ApiError,
|
|
11
|
+
apiRequest,
|
|
12
|
+
apiUpload,
|
|
13
|
+
formatError
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=api-client-VHQARPDT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -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":[]}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getConfig,
|
|
4
|
+
getToken
|
|
5
|
+
} from "./chunk-5765WX4D.js";
|
|
6
|
+
|
|
7
|
+
// src/api-client.ts
|
|
8
|
+
var ApiError = class extends Error {
|
|
9
|
+
constructor(status, message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.name = "ApiError";
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var STATUS_HINTS = {
|
|
16
|
+
401: "Try running `specra login` to re-authenticate.",
|
|
17
|
+
403: "You may not have permission for this action. Check your plan or project access.",
|
|
18
|
+
502: "The server is temporarily unavailable. Try again in a moment.",
|
|
19
|
+
503: "The server is temporarily unavailable. Try again in a moment."
|
|
20
|
+
};
|
|
21
|
+
function formatError(context, err) {
|
|
22
|
+
const prefix = context ? `${context}: ` : "";
|
|
23
|
+
if (err instanceof ApiError) {
|
|
24
|
+
const hint = STATUS_HINTS[err.status] || "";
|
|
25
|
+
return `${prefix}${err.message} (${err.status})${hint ? `
|
|
26
|
+
${hint}` : ""}`;
|
|
27
|
+
}
|
|
28
|
+
if (err instanceof Error) {
|
|
29
|
+
return `${prefix}${err.message}`;
|
|
30
|
+
}
|
|
31
|
+
return `${prefix}${String(err)}`;
|
|
32
|
+
}
|
|
33
|
+
async function apiRequest(path, options = {}) {
|
|
34
|
+
const config = getConfig();
|
|
35
|
+
const token = getToken();
|
|
36
|
+
if (!token) {
|
|
37
|
+
throw new Error("Not authenticated. Run `specra login` first.");
|
|
38
|
+
}
|
|
39
|
+
const url = `${config.apiUrl}${path}`;
|
|
40
|
+
const res = await fetch(url, {
|
|
41
|
+
...options,
|
|
42
|
+
headers: {
|
|
43
|
+
Authorization: `Bearer ${token}`,
|
|
44
|
+
...options.headers
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
if (!res.ok) {
|
|
48
|
+
let message;
|
|
49
|
+
try {
|
|
50
|
+
const data = await res.json();
|
|
51
|
+
message = data.error || res.statusText;
|
|
52
|
+
} catch {
|
|
53
|
+
message = res.statusText;
|
|
54
|
+
}
|
|
55
|
+
throw new ApiError(res.status, message);
|
|
56
|
+
}
|
|
57
|
+
return res.json();
|
|
58
|
+
}
|
|
59
|
+
async function apiUpload(path, body, headers = {}) {
|
|
60
|
+
const config = getConfig();
|
|
61
|
+
const token = getToken();
|
|
62
|
+
if (!token) {
|
|
63
|
+
throw new Error("Not authenticated. Run `specra login` first.");
|
|
64
|
+
}
|
|
65
|
+
const url = `${config.apiUrl}${path}`;
|
|
66
|
+
const res = await fetch(url, {
|
|
67
|
+
method: "POST",
|
|
68
|
+
headers: {
|
|
69
|
+
Authorization: `Bearer ${token}`,
|
|
70
|
+
"Content-Type": "application/octet-stream",
|
|
71
|
+
...headers
|
|
72
|
+
},
|
|
73
|
+
body
|
|
74
|
+
});
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
let message;
|
|
77
|
+
try {
|
|
78
|
+
const data = await res.json();
|
|
79
|
+
message = data.error || res.statusText;
|
|
80
|
+
} catch {
|
|
81
|
+
message = res.statusText;
|
|
82
|
+
}
|
|
83
|
+
throw new ApiError(res.status, message);
|
|
84
|
+
}
|
|
85
|
+
return res.json();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export {
|
|
89
|
+
ApiError,
|
|
90
|
+
formatError,
|
|
91
|
+
apiRequest,
|
|
92
|
+
apiUpload
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=chunk-72RDEJR2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/api-client.ts"],"sourcesContent":["import { getConfig, getToken } from './config.js'\n\nexport class ApiError extends Error {\n constructor(public status: number, message: string) {\n super(message)\n this.name = 'ApiError'\n }\n}\n\nconst STATUS_HINTS: Record<number, string> = {\n 401: 'Try running `specra login` to re-authenticate.',\n 403: 'You may not have permission for this action. Check your plan or project access.',\n 502: 'The server is temporarily unavailable. Try again in a moment.',\n 503: 'The server is temporarily unavailable. Try again in a moment.',\n}\n\n/** Format an error for CLI display (no stack traces). */\nexport function formatError(context: string, err: unknown): string {\n const prefix = context ? `${context}: ` : ''\n if (err instanceof ApiError) {\n const hint = STATUS_HINTS[err.status] || ''\n return `${prefix}${err.message} (${err.status})${hint ? `\\n ${hint}` : ''}`\n }\n if (err instanceof Error) {\n return `${prefix}${err.message}`\n }\n return `${prefix}${String(err)}`\n}\n\nexport async function apiRequest<T = unknown>(\n path: string,\n options: RequestInit = {}\n): Promise<T> {\n const config = getConfig()\n const token = getToken()\n\n if (!token) {\n throw new Error('Not authenticated. Run `specra login` first.')\n }\n\n const url = `${config.apiUrl}${path}`\n const res = await fetch(url, {\n ...options,\n headers: {\n Authorization: `Bearer ${token}`,\n ...options.headers,\n },\n })\n\n if (!res.ok) {\n let message: string\n try {\n const data = (await res.json()) as Record<string, string>\n message = data.error || res.statusText\n } catch {\n message = res.statusText\n }\n throw new ApiError(res.status, message)\n }\n\n return res.json() as Promise<T>\n}\n\nexport async function apiUpload(\n path: string,\n body: Buffer | ReadableStream,\n headers: Record<string, string> = {}\n): Promise<unknown> {\n const config = getConfig()\n const token = getToken()\n\n if (!token) {\n throw new Error('Not authenticated. Run `specra login` first.')\n }\n\n const url = `${config.apiUrl}${path}`\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/octet-stream',\n ...headers,\n },\n body,\n })\n\n if (!res.ok) {\n let message: string\n try {\n const data = (await res.json()) as Record<string, string>\n message = data.error || res.statusText\n } catch {\n message = res.statusText\n }\n throw new ApiError(res.status, message)\n }\n\n return res.json()\n}\n"],"mappings":";;;;;;;AAEO,IAAM,WAAN,cAAuB,MAAM;AAAA,EAClC,YAAmB,QAAgB,SAAiB;AAClD,UAAM,OAAO;AADI;AAEjB,SAAK,OAAO;AAAA,EACd;AACF;AAEA,IAAM,eAAuC;AAAA,EAC3C,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AAGO,SAAS,YAAY,SAAiB,KAAsB;AACjE,QAAM,SAAS,UAAU,GAAG,OAAO,OAAO;AAC1C,MAAI,eAAe,UAAU;AAC3B,UAAM,OAAO,aAAa,IAAI,MAAM,KAAK;AACzC,WAAO,GAAG,MAAM,GAAG,IAAI,OAAO,KAAK,IAAI,MAAM,IAAI,OAAO;AAAA,IAAO,IAAI,KAAK,EAAE;AAAA,EAC5E;AACA,MAAI,eAAe,OAAO;AACxB,WAAO,GAAG,MAAM,GAAG,IAAI,OAAO;AAAA,EAChC;AACA,SAAO,GAAG,MAAM,GAAG,OAAO,GAAG,CAAC;AAChC;AAEA,eAAsB,WACpB,MACA,UAAuB,CAAC,GACZ;AACZ,QAAM,SAAS,UAAU;AACzB,QAAM,QAAQ,SAAS;AAEvB,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AAEA,QAAM,MAAM,GAAG,OAAO,MAAM,GAAG,IAAI;AACnC,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,GAAG;AAAA,IACH,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,GAAG,QAAQ;AAAA,IACb;AAAA,EACF,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,QAAI;AACJ,QAAI;AACF,YAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,gBAAU,KAAK,SAAS,IAAI;AAAA,IAC9B,QAAQ;AACN,gBAAU,IAAI;AAAA,IAChB;AACA,UAAM,IAAI,SAAS,IAAI,QAAQ,OAAO;AAAA,EACxC;AAEA,SAAO,IAAI,KAAK;AAClB;AAEA,eAAsB,UACpB,MACA,MACA,UAAkC,CAAC,GACjB;AAClB,QAAM,SAAS,UAAU;AACzB,QAAM,QAAQ,SAAS;AAEvB,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AAEA,QAAM,MAAM,GAAG,OAAO,MAAM,GAAG,IAAI;AACnC,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,UAAU,KAAK;AAAA,MAC9B,gBAAgB;AAAA,MAChB,GAAG;AAAA,IACL;AAAA,IACA;AAAA,EACF,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,QAAI;AACJ,QAAI;AACF,YAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,gBAAU,KAAK,SAAS,IAAI;AAAA,IAC9B,QAAQ;AACN,gBAAU,IAAI;AAAA,IAChB;AACA,UAAM,IAAI,SAAS,IAAI,QAAQ,OAAO;AAAA,EACxC;AAEA,SAAO,IAAI,KAAK;AAClB;","names":[]}
|