@kyro-cms/core 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +196 -109
- package/dist/bootstrap-2WJK6PG7.cjs +29 -0
- package/dist/bootstrap-2WJK6PG7.cjs.map +1 -0
- package/dist/bootstrap-Q2TWUQF3.js +4 -0
- package/dist/bootstrap-Q2TWUQF3.js.map +1 -0
- package/dist/chunk-3QX6KG2S.js +2125 -0
- package/dist/chunk-3QX6KG2S.js.map +1 -0
- package/dist/chunk-5AOILNGY.cjs +212 -0
- package/dist/chunk-5AOILNGY.cjs.map +1 -0
- package/dist/{chunk-DKSMFC3L.js → chunk-EINVJPFM.js} +2 -2
- package/dist/{chunk-DKSMFC3L.js.map → chunk-EINVJPFM.js.map} +1 -1
- package/dist/chunk-F5B64H5S.cjs +2149 -0
- package/dist/chunk-F5B64H5S.cjs.map +1 -0
- package/dist/chunk-I4BORBXT.cjs +914 -0
- package/dist/chunk-I4BORBXT.cjs.map +1 -0
- package/dist/chunk-KA3UOIFC.js +206 -0
- package/dist/chunk-KA3UOIFC.js.map +1 -0
- package/dist/chunk-KWTKEBHM.cjs +176 -0
- package/dist/chunk-KWTKEBHM.cjs.map +1 -0
- package/dist/chunk-M4JFHQ5J.js +170 -0
- package/dist/chunk-M4JFHQ5J.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +9 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-Q7SFCCGT.cjs +11 -0
- package/dist/chunk-Q7SFCCGT.cjs.map +1 -0
- package/dist/chunk-U4CHJTWX.cjs +94 -0
- package/dist/chunk-U4CHJTWX.cjs.map +1 -0
- package/dist/{chunk-3Q3FS5J4.cjs → chunk-V3B25QOK.cjs} +2 -2
- package/dist/{chunk-3Q3FS5J4.cjs.map → chunk-V3B25QOK.cjs.map} +1 -1
- package/dist/chunk-V67YXRBT.js +899 -0
- package/dist/chunk-V67YXRBT.js.map +1 -0
- package/dist/chunk-XLMVCGXA.js +86 -0
- package/dist/chunk-XLMVCGXA.js.map +1 -0
- package/dist/cli/index.cjs +106 -14
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +106 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/database-37KXWUER.js +5 -0
- package/dist/database-37KXWUER.js.map +1 -0
- package/dist/database-LJKD3HE4.cjs +22 -0
- package/dist/database-LJKD3HE4.cjs.map +1 -0
- package/dist/drizzle/index.cjs +25 -5
- package/dist/drizzle/index.d.cts +5 -49
- package/dist/drizzle/index.d.ts +5 -49
- package/dist/drizzle/index.js +5 -1
- package/dist/graphql/index.cjs +1 -0
- package/dist/graphql/index.js +1 -0
- package/dist/index-BVFlb7uU.d.ts +192 -0
- package/dist/index-CzkEHKqu.d.cts +192 -0
- package/dist/index.cjs +1203 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +382 -68
- package/dist/index.d.ts +382 -68
- package/dist/index.js +1110 -20
- package/dist/index.js.map +1 -1
- package/dist/mongodb/index.cjs +1 -0
- package/dist/mongodb/index.js +1 -0
- package/dist/postgres-auth-adapter-CYZAVPPP.cjs +14 -0
- package/dist/postgres-auth-adapter-CYZAVPPP.cjs.map +1 -0
- package/dist/postgres-auth-adapter-LTDUGBMB.js +5 -0
- package/dist/postgres-auth-adapter-LTDUGBMB.js.map +1 -0
- package/dist/rest/index.cjs +1 -0
- package/dist/rest/index.js +1 -0
- package/dist/templates/index.cjs +94 -536
- package/dist/templates/index.cjs.map +1 -1
- package/dist/templates/index.d.cts +45 -1
- package/dist/templates/index.d.ts +45 -1
- package/dist/templates/index.js +2 -535
- package/dist/templates/index.js.map +1 -1
- package/dist/trpc/index.cjs +1 -0
- package/dist/trpc/index.js +1 -0
- package/dist/ws/index.cjs +1 -0
- package/dist/ws/index.js +1 -0
- package/package.json +23 -8
package/README.md
CHANGED
|
@@ -37,6 +37,7 @@ npm create kyro@latest
|
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
This launches an interactive wizard that asks:
|
|
40
|
+
|
|
40
41
|
- Project name
|
|
41
42
|
- Database (SQLite, PostgreSQL, MySQL, MongoDB)
|
|
42
43
|
- API protocols (REST, GraphQL, tRPC, WebSocket)
|
|
@@ -54,20 +55,20 @@ npm install @kyro-cms/core
|
|
|
54
55
|
|
|
55
56
|
```typescript
|
|
56
57
|
// kyro.config.ts
|
|
57
|
-
import { defineConfig, localAdapter } from
|
|
58
|
+
import { defineConfig, localAdapter } from "@kyro-cms/core";
|
|
58
59
|
|
|
59
60
|
export default defineConfig({
|
|
60
|
-
name:
|
|
61
|
-
adapter: localAdapter({ path:
|
|
61
|
+
name: "my-app",
|
|
62
|
+
adapter: localAdapter({ path: "./data.db" }),
|
|
62
63
|
collections: {
|
|
63
64
|
posts: {
|
|
64
|
-
slug:
|
|
65
|
-
label:
|
|
65
|
+
slug: "posts",
|
|
66
|
+
label: "Posts",
|
|
66
67
|
fields: [
|
|
67
|
-
{ name:
|
|
68
|
-
{ name:
|
|
69
|
-
{ name:
|
|
70
|
-
{ name:
|
|
68
|
+
{ name: "title", type: "text", required: true },
|
|
69
|
+
{ name: "slug", type: "text", required: true },
|
|
70
|
+
{ name: "content", type: "richtext" },
|
|
71
|
+
{ name: "published", type: "checkbox", defaultValue: false },
|
|
71
72
|
],
|
|
72
73
|
},
|
|
73
74
|
},
|
|
@@ -85,10 +86,10 @@ export default defineConfig({
|
|
|
85
86
|
### SQLite (Local-First)
|
|
86
87
|
|
|
87
88
|
```typescript
|
|
88
|
-
import { localAdapter } from
|
|
89
|
+
import { localAdapter } from "@kyro-cms/core";
|
|
89
90
|
|
|
90
91
|
const adapter = localAdapter({
|
|
91
|
-
path:
|
|
92
|
+
path: "./data.db", // or ':memory:' for in-memory
|
|
92
93
|
});
|
|
93
94
|
```
|
|
94
95
|
|
|
@@ -97,7 +98,7 @@ Perfect for development and small projects. Zero configuration required.
|
|
|
97
98
|
### PostgreSQL/MySQL (Production)
|
|
98
99
|
|
|
99
100
|
```typescript
|
|
100
|
-
import { drizzleAdapter } from
|
|
101
|
+
import { drizzleAdapter } from "@kyro-cms/core";
|
|
101
102
|
|
|
102
103
|
const adapter = drizzleAdapter({
|
|
103
104
|
connectionString: process.env.DATABASE_URL,
|
|
@@ -107,7 +108,7 @@ const adapter = drizzleAdapter({
|
|
|
107
108
|
### MongoDB (Flexible Schemas)
|
|
108
109
|
|
|
109
110
|
```typescript
|
|
110
|
-
import { mongoAdapter } from
|
|
111
|
+
import { mongoAdapter } from "@kyro-cms/core";
|
|
111
112
|
|
|
112
113
|
const adapter = mongoAdapter({
|
|
113
114
|
connectionString: process.env.MONGODB_URI,
|
|
@@ -177,20 +178,22 @@ const client = createTRPCClient({
|
|
|
177
178
|
const posts = await client.posts.find.query({ page: 1 });
|
|
178
179
|
const newPost = await client.posts.create.mutate({
|
|
179
180
|
title: "Hello",
|
|
180
|
-
slug: "hello"
|
|
181
|
+
slug: "hello",
|
|
181
182
|
});
|
|
182
183
|
```
|
|
183
184
|
|
|
184
185
|
### WebSocket (Real-time)
|
|
185
186
|
|
|
186
187
|
```typescript
|
|
187
|
-
const ws = new WebSocket(
|
|
188
|
+
const ws = new WebSocket("ws://localhost:4321/api/ws");
|
|
188
189
|
|
|
189
|
-
ws.send(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
190
|
+
ws.send(
|
|
191
|
+
JSON.stringify({
|
|
192
|
+
type: "subscribe",
|
|
193
|
+
collection: "posts",
|
|
194
|
+
event: "create",
|
|
195
|
+
}),
|
|
196
|
+
);
|
|
194
197
|
|
|
195
198
|
ws.onmessage = (event) => {
|
|
196
199
|
const data = JSON.parse(event.data);
|
|
@@ -204,62 +207,62 @@ ws.onmessage = (event) => {
|
|
|
204
207
|
|
|
205
208
|
Kyro supports 21 field types:
|
|
206
209
|
|
|
207
|
-
| Type
|
|
208
|
-
|
|
209
|
-
| `text`
|
|
210
|
-
| `textarea`
|
|
211
|
-
| `richtext`
|
|
212
|
-
| `markdown`
|
|
213
|
-
| `number`
|
|
214
|
-
| `email`
|
|
215
|
-
| `password`
|
|
216
|
-
| `checkbox`
|
|
217
|
-
| `date`
|
|
218
|
-
| `select`
|
|
219
|
-
| `radio`
|
|
220
|
-
| `color`
|
|
221
|
-
| `json`
|
|
222
|
-
| `code`
|
|
223
|
-
| `array`
|
|
224
|
-
| `group`
|
|
225
|
-
| `relationship` | Link to other documents
|
|
226
|
-
| `upload`
|
|
227
|
-
| `blocks`
|
|
228
|
-
| `row`
|
|
229
|
-
| `collapsible`
|
|
230
|
-
| `tabs`
|
|
210
|
+
| Type | Description |
|
|
211
|
+
| -------------- | -------------------------- |
|
|
212
|
+
| `text` | Single-line text input |
|
|
213
|
+
| `textarea` | Multi-line text |
|
|
214
|
+
| `richtext` | Rich text editor content |
|
|
215
|
+
| `markdown` | Markdown content |
|
|
216
|
+
| `number` | Numeric values |
|
|
217
|
+
| `email` | Email with validation |
|
|
218
|
+
| `password` | Hashed password storage |
|
|
219
|
+
| `checkbox` | Boolean toggle |
|
|
220
|
+
| `date` | Date/time picker |
|
|
221
|
+
| `select` | Dropdown selection |
|
|
222
|
+
| `radio` | Radio button group |
|
|
223
|
+
| `color` | Color picker |
|
|
224
|
+
| `json` | JSON data |
|
|
225
|
+
| `code` | Code editor content |
|
|
226
|
+
| `array` | Repeatable field groups |
|
|
227
|
+
| `group` | Nested field groups |
|
|
228
|
+
| `relationship` | Link to other documents |
|
|
229
|
+
| `upload` | File/media uploads |
|
|
230
|
+
| `blocks` | Structured content blocks |
|
|
231
|
+
| `row` | Horizontal field layout |
|
|
232
|
+
| `collapsible` | Collapsible field sections |
|
|
233
|
+
| `tabs` | Tabbed interface |
|
|
231
234
|
|
|
232
235
|
### Example: Complex Fields
|
|
233
236
|
|
|
234
237
|
```typescript
|
|
235
238
|
fields: [
|
|
236
|
-
{ name:
|
|
237
|
-
|
|
239
|
+
{ name: "title", type: "text", required: true },
|
|
240
|
+
|
|
238
241
|
{
|
|
239
|
-
name:
|
|
240
|
-
type:
|
|
241
|
-
relationTo:
|
|
242
|
-
required: true
|
|
242
|
+
name: "author",
|
|
243
|
+
type: "relationship",
|
|
244
|
+
relationTo: "users",
|
|
245
|
+
required: true,
|
|
243
246
|
},
|
|
244
|
-
|
|
247
|
+
|
|
245
248
|
{
|
|
246
|
-
name:
|
|
247
|
-
type:
|
|
249
|
+
name: "tags",
|
|
250
|
+
type: "array",
|
|
248
251
|
fields: [
|
|
249
|
-
{ name:
|
|
250
|
-
{ name:
|
|
251
|
-
]
|
|
252
|
+
{ name: "name", type: "text" },
|
|
253
|
+
{ name: "slug", type: "text" },
|
|
254
|
+
],
|
|
252
255
|
},
|
|
253
|
-
|
|
256
|
+
|
|
254
257
|
{
|
|
255
|
-
name:
|
|
256
|
-
type:
|
|
258
|
+
name: "metadata",
|
|
259
|
+
type: "group",
|
|
257
260
|
fields: [
|
|
258
|
-
{ name:
|
|
259
|
-
{ name:
|
|
260
|
-
]
|
|
261
|
-
}
|
|
262
|
-
]
|
|
261
|
+
{ name: "views", type: "number", defaultValue: 0 },
|
|
262
|
+
{ name: "featured", type: "checkbox" },
|
|
263
|
+
],
|
|
264
|
+
},
|
|
265
|
+
];
|
|
263
266
|
```
|
|
264
267
|
|
|
265
268
|
---
|
|
@@ -269,10 +272,10 @@ fields: [
|
|
|
269
272
|
Pre-built collections for building online stores:
|
|
270
273
|
|
|
271
274
|
```typescript
|
|
272
|
-
import { ecommerceCollections } from
|
|
275
|
+
import { ecommerceCollections } from "@kyro-cms/core";
|
|
273
276
|
|
|
274
277
|
const kyro = createKyro({
|
|
275
|
-
adapter: localAdapter({ path:
|
|
278
|
+
adapter: localAdapter({ path: "./store.db" }),
|
|
276
279
|
collections: ecommerceCollections,
|
|
277
280
|
});
|
|
278
281
|
|
|
@@ -289,31 +292,81 @@ const kyro = createKyro({
|
|
|
289
292
|
|
|
290
293
|
## Authentication
|
|
291
294
|
|
|
292
|
-
Built-in JWT authentication:
|
|
295
|
+
Built-in JWT authentication with Redis sessions and PostgreSQL support:
|
|
293
296
|
|
|
294
297
|
```typescript
|
|
295
|
-
import {
|
|
298
|
+
import { RedisAuthAdapter } from "@kyro-cms/core";
|
|
299
|
+
import { createAuthConfig } from "@kyro-cms/core";
|
|
296
300
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
+
// Use Redis for sessions (recommended)
|
|
302
|
+
const adapter = new RedisAuthAdapter({
|
|
303
|
+
url: process.env.REDIS_URL,
|
|
304
|
+
tls: process.env.REDIS_TLS === "true",
|
|
301
305
|
});
|
|
302
306
|
|
|
303
|
-
//
|
|
304
|
-
|
|
305
|
-
email: 'user@example.com',
|
|
306
|
-
password: 'secure123',
|
|
307
|
-
role: 'customer',
|
|
308
|
-
});
|
|
307
|
+
// Or use PostgreSQL for production
|
|
308
|
+
import { PostgresAuthAdapter, createDatabase } from "@kyro-cms/core";
|
|
309
309
|
|
|
310
|
-
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
310
|
+
const { db } = await createDatabase();
|
|
311
|
+
const pgAdapter = new PostgresAuthAdapter({ db });
|
|
312
|
+
|
|
313
|
+
// Or use env-based config with all features
|
|
314
|
+
const authConfig = await createAuthConfig();
|
|
315
|
+
const { redis, routes, passwordPolicy, lockout } = authConfig;
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Authentication Features
|
|
319
|
+
|
|
320
|
+
- **JWT Tokens** - 24h expiry with refresh token support
|
|
321
|
+
- **Redis Sessions** - Fast session storage with Redis Cloud support
|
|
322
|
+
- **PostgreSQL Storage** - Production-ready with Drizzle ORM
|
|
323
|
+
- **Password Policy** - 12+ chars, complexity requirements, history check
|
|
324
|
+
- **Account Lockout** - 5 failed attempts → 15 minute lockout
|
|
325
|
+
- **Rate Limiting** - Per-IP and per-user limits
|
|
326
|
+
- **Audit Logging** - 30-day retention with action tracking
|
|
327
|
+
|
|
328
|
+
### CLI Commands
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
# Create admin user (first-run bootstrap)
|
|
332
|
+
kyro auth bootstrap -e admin@example.com -p "SecurePass123!" -r admin
|
|
333
|
+
|
|
334
|
+
# Database setup
|
|
335
|
+
kyro db migrate # Run migrations
|
|
336
|
+
kyro db push # Push schema to database
|
|
337
|
+
kyro db seed # Seed default roles
|
|
338
|
+
kyro db studio # Open Drizzle Studio
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### RBAC Roles (Hierarchy)
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
super_admin (100) > admin (90) > editor (70) > author (50) > customer (30) > guest (10)
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Environment Variables
|
|
315
348
|
|
|
316
|
-
|
|
349
|
+
```bash
|
|
350
|
+
# Database
|
|
351
|
+
DATABASE_URL=postgresql://user:pass@host:5432/kyro_cms
|
|
352
|
+
DATABASE_SSL=false
|
|
353
|
+
|
|
354
|
+
# Redis (sessions/cache)
|
|
355
|
+
REDIS_URL=redis://localhost:6379
|
|
356
|
+
REDIS_TLS=false
|
|
357
|
+
|
|
358
|
+
# JWT
|
|
359
|
+
JWT_SECRET=your-32-char-secret
|
|
360
|
+
JWT_EXPIRES_IN=24h
|
|
361
|
+
|
|
362
|
+
# Auth Settings
|
|
363
|
+
LOCKOUT_MAX_ATTEMPTS=5
|
|
364
|
+
LOCKOUT_DURATION_MINUTES=15
|
|
365
|
+
PASSWORD_MIN_LENGTH=12
|
|
366
|
+
|
|
367
|
+
# Bootstrap (first-run admin)
|
|
368
|
+
KYRO_ADMIN_EMAIL=admin@example.com
|
|
369
|
+
KYRO_ADMIN_PASSWORD=SecurePass123!
|
|
317
370
|
```
|
|
318
371
|
|
|
319
372
|
---
|
|
@@ -323,7 +376,7 @@ console.log(result.token); // JWT token
|
|
|
323
376
|
Track document changes with built-in versioning:
|
|
324
377
|
|
|
325
378
|
```typescript
|
|
326
|
-
import { createVersionManager } from
|
|
379
|
+
import { createVersionManager } from "@kyro-cms/core";
|
|
327
380
|
|
|
328
381
|
const versions = createVersionManager(adapter, {
|
|
329
382
|
versioningEnabled: true,
|
|
@@ -332,19 +385,19 @@ const versions = createVersionManager(adapter, {
|
|
|
332
385
|
|
|
333
386
|
// Create a new version
|
|
334
387
|
const version = await versions.createVersion({
|
|
335
|
-
collection:
|
|
336
|
-
documentId:
|
|
337
|
-
data: { title:
|
|
338
|
-
status:
|
|
339
|
-
createdBy:
|
|
388
|
+
collection: "posts",
|
|
389
|
+
documentId: "abc123",
|
|
390
|
+
data: { title: "Updated Post" },
|
|
391
|
+
status: "draft",
|
|
392
|
+
createdBy: "user123",
|
|
340
393
|
});
|
|
341
394
|
|
|
342
395
|
// Publish
|
|
343
396
|
await versions.publishVersion({
|
|
344
|
-
collection:
|
|
345
|
-
documentId:
|
|
397
|
+
collection: "posts",
|
|
398
|
+
documentId: "abc123",
|
|
346
399
|
versionId: version.id,
|
|
347
|
-
publishedBy:
|
|
400
|
+
publishedBy: "user123",
|
|
348
401
|
});
|
|
349
402
|
```
|
|
350
403
|
|
|
@@ -369,6 +422,7 @@ import config from '../kyro.config';
|
|
|
369
422
|
```
|
|
370
423
|
|
|
371
424
|
Features:
|
|
425
|
+
|
|
372
426
|
- Collection browser with filtering and sorting
|
|
373
427
|
- Document editor with all field types
|
|
374
428
|
- Media library
|
|
@@ -382,13 +436,13 @@ Features:
|
|
|
382
436
|
Extend Kyro with plugins:
|
|
383
437
|
|
|
384
438
|
```typescript
|
|
385
|
-
import {
|
|
439
|
+
import {
|
|
386
440
|
KyroPlugin,
|
|
387
441
|
SEOPLugin,
|
|
388
442
|
AnalyticsPlugin,
|
|
389
443
|
CommentsPlugin,
|
|
390
444
|
ReviewsPlugin,
|
|
391
|
-
WishlistPlugin
|
|
445
|
+
WishlistPlugin
|
|
392
446
|
} from '@kyro-cms/core';
|
|
393
447
|
|
|
394
448
|
const kyro = createKyro({
|
|
@@ -411,18 +465,18 @@ const kyro = createKyro({
|
|
|
411
465
|
### Creating Plugins
|
|
412
466
|
|
|
413
467
|
```typescript
|
|
414
|
-
import { KyroPlugin } from
|
|
468
|
+
import { KyroPlugin } from "@kyro-cms/core";
|
|
415
469
|
|
|
416
470
|
class MyPlugin extends KyroPlugin {
|
|
417
|
-
name =
|
|
418
|
-
|
|
471
|
+
name = "my-plugin";
|
|
472
|
+
|
|
419
473
|
hooks = {
|
|
420
|
-
|
|
474
|
+
"collection.beforeCreate": async (args) => {
|
|
421
475
|
// Transform data before creation
|
|
422
|
-
return { ...args, data: { ...args.data, source:
|
|
476
|
+
return { ...args, data: { ...args.data, source: "my-plugin" } };
|
|
423
477
|
},
|
|
424
|
-
|
|
425
|
-
|
|
478
|
+
|
|
479
|
+
"document.afterSave": async (args) => {
|
|
426
480
|
// Send webhook, log analytics, etc.
|
|
427
481
|
await sendWebhook(args);
|
|
428
482
|
},
|
|
@@ -437,11 +491,11 @@ class MyPlugin extends KyroPlugin {
|
|
|
437
491
|
Kyro ships with a complete styling system:
|
|
438
492
|
|
|
439
493
|
```typescript
|
|
440
|
-
import {
|
|
494
|
+
import {
|
|
441
495
|
ecommerce2026Theme,
|
|
442
496
|
generateCSSVariables,
|
|
443
|
-
generateTailwindConfig
|
|
444
|
-
} from
|
|
497
|
+
generateTailwindConfig,
|
|
498
|
+
} from "@kyro-cms/core";
|
|
445
499
|
|
|
446
500
|
// Generate CSS variables
|
|
447
501
|
const cssVars = generateCSSVariables(ecommerce2026Theme);
|
|
@@ -450,12 +504,12 @@ const cssVars = generateCSSVariables(ecommerce2026Theme);
|
|
|
450
504
|
const tailwindConfig = generateTailwindConfig(ecommerce2026Theme);
|
|
451
505
|
|
|
452
506
|
// Custom themes
|
|
453
|
-
import { createAdminStyling } from
|
|
507
|
+
import { createAdminStyling } from "@kyro-cms/core";
|
|
454
508
|
|
|
455
509
|
const myTheme = createAdminStyling({
|
|
456
|
-
primaryColor:
|
|
457
|
-
borderRadius:
|
|
458
|
-
fontFamily:
|
|
510
|
+
primaryColor: "#6366f1",
|
|
511
|
+
borderRadius: "medium",
|
|
512
|
+
fontFamily: "Inter",
|
|
459
513
|
});
|
|
460
514
|
```
|
|
461
515
|
|
|
@@ -463,6 +517,37 @@ const myTheme = createAdminStyling({
|
|
|
463
517
|
|
|
464
518
|
## Deployment
|
|
465
519
|
|
|
520
|
+
### Quick Start with Docker
|
|
521
|
+
|
|
522
|
+
```bash
|
|
523
|
+
# Start PostgreSQL + Redis
|
|
524
|
+
docker compose up -d
|
|
525
|
+
|
|
526
|
+
# Push schema to database
|
|
527
|
+
npm run db:push
|
|
528
|
+
|
|
529
|
+
# Create admin user
|
|
530
|
+
kyro auth bootstrap -e admin@example.com -p "SecurePass123!"
|
|
531
|
+
|
|
532
|
+
# Start development
|
|
533
|
+
npm run dev
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Environment Variables Required
|
|
537
|
+
|
|
538
|
+
```bash
|
|
539
|
+
# Database (PostgreSQL)
|
|
540
|
+
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/kyro_cms
|
|
541
|
+
DATABASE_SSL=false
|
|
542
|
+
|
|
543
|
+
# Redis (sessions/cache) - supports Redis Cloud
|
|
544
|
+
REDIS_URL=redis://localhost:6379
|
|
545
|
+
REDIS_TLS=false
|
|
546
|
+
|
|
547
|
+
# JWT (required)
|
|
548
|
+
JWT_SECRET=change-me-in-production-min-32-chars
|
|
549
|
+
```
|
|
550
|
+
|
|
466
551
|
### Vercel
|
|
467
552
|
|
|
468
553
|
```bash
|
|
@@ -470,6 +555,7 @@ vercel --prod
|
|
|
470
555
|
```
|
|
471
556
|
|
|
472
557
|
Environment variables:
|
|
558
|
+
|
|
473
559
|
- `DATABASE_URL` - PostgreSQL connection string
|
|
474
560
|
- `JWT_SECRET` - JWT signing secret
|
|
475
561
|
|
|
@@ -575,6 +661,7 @@ MIT License - see [LICENSE](LICENSE) for details.
|
|
|
575
661
|
## Acknowledgments
|
|
576
662
|
|
|
577
663
|
Built with inspiration from:
|
|
664
|
+
|
|
578
665
|
- [Payload CMS](https://payloadcms.com/) - The headless CMS that pushed the industry forward
|
|
579
666
|
- [Strapi](https://strapi.io/) - Open source headless CMS
|
|
580
667
|
- [Sanity](https://www.sanity.io/) - Real-time content infrastructure
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkI4BORBXT_cjs = require('./chunk-I4BORBXT.cjs');
|
|
4
|
+
require('./chunk-Q7SFCCGT.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Object.defineProperty(exports, "autoBootstrap", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
get: function () { return chunkI4BORBXT_cjs.autoBootstrap; }
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "bootstrapAdmin", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () { return chunkI4BORBXT_cjs.bootstrapAdmin; }
|
|
15
|
+
});
|
|
16
|
+
Object.defineProperty(exports, "bootstrapWithRetry", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return chunkI4BORBXT_cjs.bootstrapWithRetry; }
|
|
19
|
+
});
|
|
20
|
+
Object.defineProperty(exports, "checkBootstrapRequired", {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: function () { return chunkI4BORBXT_cjs.checkBootstrapRequired; }
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "getBootstrapFromEnv", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () { return chunkI4BORBXT_cjs.getBootstrapFromEnv; }
|
|
27
|
+
});
|
|
28
|
+
//# sourceMappingURL=bootstrap-2WJK6PG7.cjs.map
|
|
29
|
+
//# sourceMappingURL=bootstrap-2WJK6PG7.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"bootstrap-2WJK6PG7.cjs"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"bootstrap-Q2TWUQF3.js"}
|