@inneropen/marvin-sdk 1.0.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/QUICKSTART.md ADDED
@@ -0,0 +1,408 @@
1
+ # Marvin SDK Quick Start
2
+
3
+ Get up and running with the Marvin TypeScript SDK in 5 minutes.
4
+
5
+ The Marvin SDK is framework-agnostic and works with Astro, Next.js, Express, CLI tools, automation workflows, and any trusted runtime.
6
+
7
+ ---
8
+
9
+ ## Step 1: Copy the SDK
10
+
11
+ Copy the SDK into your project:
12
+
13
+ ```bash
14
+ # Navigate to your project
15
+ cd /path/to/your-project
16
+
17
+ # Create lib directory
18
+ mkdir -p src/lib
19
+
20
+ # Copy the SDK
21
+ cp -r /path/to/marvin/packages/marvin-sdk src/lib/marvin
22
+ ```
23
+
24
+ ## Step 2: Configure Environment Variables
25
+
26
+ Create a `.env` file in your project root:
27
+
28
+ ```env
29
+ MARVIN_API_URL=https://marvin.example.com
30
+ MARVIN_SITE_CLIENT_TOKEN=your-token-here
31
+ MARVIN_WORKSPACE_SLUG=your-workspace
32
+ ```
33
+
34
+ **Get your Site Client Token:**
35
+
36
+ 1. Log into Marvin
37
+ 2. Go to **Settings → Publishing → Site Clients**
38
+ 3. Create a new client for your application
39
+ 4. Copy the token
40
+
41
+ **🔒 Security Note:** Site client tokens must only be used in **server-side, build-time, or trusted backend code**. Never expose them in browser-side bundles.
42
+
43
+ ## Step 3: Create SDK Instance
44
+
45
+ Create a file to initialize the SDK:
46
+
47
+ ```ts
48
+ // src/lib/marvin.ts
49
+ import { createMarvinClient } from './marvin';
50
+
51
+ export const marvin = createMarvinClient();
52
+ ```
53
+
54
+ ### Optional: Preload Workspace Data
55
+
56
+ If you want to preload site configuration at startup:
57
+
58
+ ```ts
59
+ // src/lib/marvin.ts
60
+ import { createMarvinClient } from './marvin';
61
+
62
+ export const marvin = createMarvinClient({
63
+ autoInitialize: true, // Preload site config on creation
64
+ });
65
+ ```
66
+
67
+ Or initialize manually when needed:
68
+
69
+ ```ts
70
+ import { marvin } from '@/lib/marvin';
71
+
72
+ // Initialize when needed
73
+ await marvin.initialize();
74
+
75
+ // Now site config is cached
76
+ console.log(marvin.site?.title);
77
+ ```
78
+
79
+ ## Step 4: Fetch Content
80
+
81
+ ### Workspace-First API (Recommended)
82
+
83
+ ```ts
84
+ import { marvin } from '@/lib/marvin';
85
+
86
+ // Get workspace
87
+ const workspace = await marvin.getWorkspace();
88
+ console.log(workspace.site?.title);
89
+
90
+ // Get entries
91
+ const entries = await workspace.entries.list();
92
+
93
+ // Get a collection
94
+ const collection = await workspace.collections.get('projects');
95
+ const projectEntries = await collection.entries();
96
+
97
+ // Get resources
98
+ const resources = await workspace.resources.list();
99
+ const fabric = await workspace.resources.get('kuroki-s022');
100
+ const entriesUsingFabric = await fabric.entries();
101
+ ```
102
+
103
+ ### Convenience API
104
+
105
+ ```ts
106
+ import { marvin } from '@/lib/marvin';
107
+
108
+ // Quick access to entries
109
+ const entry = await marvin.entry('about-us');
110
+ const projects = await marvin.projects();
111
+
112
+ // Get entries by type
113
+ const articles = await marvin.getEntries({ entryType: 'article' });
114
+
115
+ // Get a collection
116
+ const featured = await marvin.collection('featured');
117
+
118
+ // Get resources
119
+ const fabric = await marvin.resource('kuroki-s022');
120
+ ```
121
+
122
+ ### Backwards-Compatible API
123
+
124
+ ```ts
125
+ import { marvin } from '@/lib/marvin';
126
+
127
+ // Still works! (Deprecated but supported)
128
+ const site = await marvin.getSite();
129
+ const entries = await marvin.getEntries();
130
+ const entry = await marvin.getEntry('about');
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Framework Examples
136
+
137
+ ### Astro (Static Site)
138
+
139
+ ```astro
140
+ ---
141
+ // src/pages/[slug].astro
142
+ import { marked } from 'marked';
143
+ import { marvin } from '@/lib/marvin';
144
+
145
+ export async function getStaticPaths() {
146
+ const entries = await marvin.getEntries({ entryType: 'page' });
147
+
148
+ return entries.map((entry) => ({
149
+ params: { slug: entry.slug },
150
+ props: { entry },
151
+ }));
152
+ }
153
+
154
+ const { entry } = Astro.props;
155
+
156
+ // Parse Markdown to HTML
157
+ const contentHtml = marked.parse(entry.contentMarkdown ?? '');
158
+ ---
159
+
160
+ <html>
161
+ <head>
162
+ <title>{entry.title}</title>
163
+ </head>
164
+ <body>
165
+ <h1>{entry.title}</h1>
166
+ <div class="content" set:html={contentHtml} />
167
+ </body>
168
+ </html>
169
+ ```
170
+
171
+ ### Next.js (App Router)
172
+
173
+ ```tsx
174
+ // app/projects/page.tsx
175
+ import { marvin } from '@/lib/marvin';
176
+
177
+ export default async function ProjectsPage() {
178
+ const projects = await marvin.projects();
179
+
180
+ return (
181
+ <div>
182
+ <h1>Projects</h1>
183
+ {projects.map((project) => (
184
+ <article key={project.id}>
185
+ <h2>{project.title}</h2>
186
+ <p>{project.summary}</p>
187
+ <a href={`/projects/${project.slug}`}>View project →</a>
188
+ </article>
189
+ ))}
190
+ </div>
191
+ );
192
+ }
193
+ ```
194
+
195
+ ### Express (Server)
196
+
197
+ ```ts
198
+ import express from 'express';
199
+ import { marvin } from './lib/marvin';
200
+
201
+ const app = express();
202
+
203
+ app.get('/api/entries', async (req, res) => {
204
+ const entries = await marvin.getEntries({
205
+ entryType: req.query.type as string,
206
+ });
207
+ res.json(entries);
208
+ });
209
+
210
+ app.get('/api/entries/:slug', async (req, res) => {
211
+ const entry = await marvin.entry(req.params.slug);
212
+ res.json(entry.toJSON());
213
+ });
214
+
215
+ app.listen(3000, () => {
216
+ console.log('Server running on http://localhost:3000');
217
+ });
218
+ ```
219
+
220
+ ### CLI Tool
221
+
222
+ ```ts
223
+ #!/usr/bin/env node
224
+ import { marvin } from './lib/marvin';
225
+
226
+ async function main() {
227
+ // Initialize SDK
228
+ await marvin.initialize();
229
+
230
+ console.log('Site:', marvin.site?.title);
231
+
232
+ // List all entries
233
+ const entries = await marvin.getEntries();
234
+ console.log(`\nFound ${entries.length} entries:`);
235
+
236
+ for (const entry of entries) {
237
+ console.log(`- ${entry.title} (${entry.status})`);
238
+ }
239
+
240
+ // List collections
241
+ const collections = await marvin.getCollections();
242
+ console.log(`\nFound ${collections.length} collections:`);
243
+
244
+ for (const collection of collections) {
245
+ console.log(`- ${collection.name}`);
246
+ }
247
+ }
248
+
249
+ main().catch(console.error);
250
+ ```
251
+
252
+ ---
253
+
254
+ ## Rendering Markdown Content
255
+
256
+ **Important:** `entry.contentMarkdown` is raw Markdown, not HTML. You must parse it before rendering.
257
+
258
+ ### Install Markdown Parser
259
+
260
+ ```bash
261
+ npm install marked
262
+ ```
263
+
264
+ ### Parse Before Rendering
265
+
266
+ ```ts
267
+ import { marked } from 'marked';
268
+
269
+ const entry = await marvin.entry('about');
270
+
271
+ // Parse Markdown to HTML
272
+ const contentHtml = marked.parse(entry.contentMarkdown ?? '');
273
+
274
+ // Then render in your template
275
+ // Astro: <div set:html={contentHtml} />
276
+ // React: <div dangerouslySetInnerHTML={{ __html: contentHtml }} />
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Build Your Application
282
+
283
+ ```bash
284
+ npm run build
285
+ ```
286
+
287
+ Your application will fetch all content from Marvin at build time!
288
+
289
+ ---
290
+
291
+ ## API Styles
292
+
293
+ The SDK supports three API styles:
294
+
295
+ ### 1. Workspace API (Recommended)
296
+
297
+ Work with workspace as a first-class object:
298
+
299
+ ```ts
300
+ const workspace = await marvin.getWorkspace();
301
+ const entries = await workspace.entries.list();
302
+ const collection = await workspace.collections.get('featured');
303
+ ```
304
+
305
+ ### 2. Convenience API
306
+
307
+ Quick access to common patterns:
308
+
309
+ ```ts
310
+ const entry = await marvin.entry('about');
311
+ const projects = await marvin.projects();
312
+ const featured = await marvin.collection('featured');
313
+ ```
314
+
315
+ ### 3. Backwards-Compatible API
316
+
317
+ Original publishing client methods still work:
318
+
319
+ ```ts
320
+ const site = await marvin.getSite();
321
+ const entries = await marvin.getEntries();
322
+ const entry = await marvin.getEntry('about');
323
+ ```
324
+
325
+ ---
326
+
327
+ ## Security Best Practices
328
+
329
+ ### ✅ DO
330
+
331
+ - Use site client tokens in **server-side** code only
332
+ - Use tokens at **build time** in static site generators
333
+ - Use tokens in **trusted backend** services
334
+ - Store tokens in `.env` files (never commit to git)
335
+ - Add `.env` to `.gitignore`
336
+
337
+ ### ❌ DON'T
338
+
339
+ - Expose tokens in browser-side JavaScript
340
+ - Commit tokens to version control
341
+ - Use tokens in client-side bundles
342
+ - Share tokens publicly
343
+ - Use user tokens instead of site client tokens
344
+
345
+ ---
346
+
347
+ ## Next Steps
348
+
349
+ - 📖 Read the [full README](./README.md) for all API methods
350
+ - 💡 Check out [examples](./examples.md) for real-world usage patterns
351
+ - 🎯 Explore object-oriented APIs (Entry, Collection objects)
352
+ - 🚀 Build with your framework of choice
353
+ - 🔧 Use convenience methods for common content types
354
+
355
+ ---
356
+
357
+ ## Troubleshooting
358
+
359
+ ### Cannot find module '@/lib/marvin'
360
+
361
+ Add path alias to your `tsconfig.json`:
362
+
363
+ ```json
364
+ {
365
+ "compilerOptions": {
366
+ "baseUrl": ".",
367
+ "paths": {
368
+ "@/*": ["src/*"]
369
+ }
370
+ }
371
+ }
372
+ ```
373
+
374
+ ### "MARVIN_API_URL is required"
375
+
376
+ Make sure:
377
+ 1. `.env` file exists in project root
378
+ 2. All three variables are set
379
+ 3. Restart your dev server after adding `.env`
380
+
381
+ ### 401 Unauthorized
382
+
383
+ - Verify your site client token is correct
384
+ - Check that the token hasn't expired
385
+ - Make sure you're using a **site client token**, not a user token
386
+ - Ensure the token is only used server-side
387
+
388
+ ### TypeScript Errors
389
+
390
+ Make sure your `tsconfig.json` includes:
391
+
392
+ ```json
393
+ {
394
+ "compilerOptions": {
395
+ "moduleResolution": "bundler",
396
+ "types": ["node"]
397
+ }
398
+ }
399
+ ```
400
+
401
+ ---
402
+
403
+ ## Need Help?
404
+
405
+ - 📖 Read the [full documentation](./README.md)
406
+ - 💡 Check the [examples](./examples.md)
407
+ - 🐛 Report issues on GitHub
408
+ - 🚀 Check TODO comments for upcoming features