@kyro-cms/core 0.1.0 → 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 +556 -130
- 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 +101 -0
- package/dist/templates/index.cjs.map +1 -0
- package/dist/templates/index.d.cts +55 -0
- package/dist/templates/index.d.ts +55 -0
- package/dist/templates/index.js +4 -0
- package/dist/templates/index.js.map +1 -0
- 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 +40 -6
package/README.md
CHANGED
|
@@ -1,205 +1,610 @@
|
|
|
1
1
|
# Kyro CMS
|
|
2
2
|
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
3
5
|
**Astro-Native Headless CMS with Multi-Database Adapters, Multi-Protocol APIs, and Multi-Vendor Support**
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
[](https://www.npmjs.com/package/@kyro-cms/core)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[](https://www.typescriptlang.org/)
|
|
10
|
+
|
|
11
|
+
</div>
|
|
6
12
|
|
|
7
13
|
---
|
|
8
14
|
|
|
9
|
-
##
|
|
15
|
+
## Why Kyro?
|
|
10
16
|
|
|
11
|
-
|
|
12
|
-
```typescript
|
|
13
|
-
import { createKyro, LocalAdapter } from '@kyro-cms/core';
|
|
17
|
+
Kyro is built for **Astro** from the ground up. Unlike other CMS solutions that bolt on Astro support, Kyro is architected to leverage Astro's islands architecture, server output modes, and performance-first approach.
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
adapter: new LocalAdapter({ path: './data.db' }),
|
|
17
|
-
collections: [productsCollection],
|
|
18
|
-
});
|
|
19
|
-
```
|
|
20
|
-
Works out of the box - no external database required.
|
|
19
|
+
### Key Features
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
21
|
+
- **Local-First** - SQLite for zero-config development, no external database needed
|
|
22
|
+
- **Multi-Database** - SQLite, PostgreSQL, MySQL, MongoDB via unified adapter interface
|
|
23
|
+
- **Multi-Protocol API** - REST, GraphQL, tRPC, and WebSocket from a single config
|
|
24
|
+
- **Multi-Vendor** - Built-in tenant scoping and row-level access control
|
|
25
|
+
- **E-Commerce Ready** - Products, orders, customers, inventory, coupons out of the box
|
|
26
|
+
- **Plugin System** - Extend with SEO, analytics, reviews, and more
|
|
27
|
+
- **Any Styling** - Tailwind, CSS Modules, Styled Components, or plain CSS
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
Pre-built collections for:
|
|
29
|
-
- Products with variants, pricing, inventory
|
|
30
|
-
- Customers with addresses, orders
|
|
31
|
-
- Orders with items, shipping, payments
|
|
32
|
-
- Coupons and promotions
|
|
33
|
-
- Inventory tracking
|
|
29
|
+
---
|
|
34
30
|
|
|
35
|
-
|
|
36
|
-
- **REST**: Hono-based with query params
|
|
37
|
-
- **GraphQL**: Dynamic schema
|
|
38
|
-
- **tRPC**: Type-safe RPC (zero inference)
|
|
39
|
-
- **WebSocket**: Real-time pub/sub
|
|
31
|
+
## Quick Start
|
|
40
32
|
|
|
41
|
-
###
|
|
42
|
-
Row-level access control with tenant scoping built-in.
|
|
33
|
+
### Option 1: Create New Project (Recommended)
|
|
43
34
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- Analytics
|
|
48
|
-
- Reviews & Comments
|
|
49
|
-
- Wishlists
|
|
35
|
+
```bash
|
|
36
|
+
npm create kyro@latest
|
|
37
|
+
```
|
|
50
38
|
|
|
51
|
-
|
|
52
|
-
- Plain CSS
|
|
53
|
-
- Tailwind CSS
|
|
54
|
-
- CSS-in-JS
|
|
55
|
-
- Styled Components
|
|
56
|
-
- Vanilla Extract
|
|
39
|
+
This launches an interactive wizard that asks:
|
|
57
40
|
|
|
58
|
-
|
|
41
|
+
- Project name
|
|
42
|
+
- Database (SQLite, PostgreSQL, MySQL, MongoDB)
|
|
43
|
+
- API protocols (REST, GraphQL, tRPC, WebSocket)
|
|
44
|
+
- Styling (Tailwind, CSS Modules, Styled Components, None)
|
|
45
|
+
- Authentication (JWT)
|
|
46
|
+
- Versioning/Drafts
|
|
47
|
+
- Admin dashboard
|
|
48
|
+
- Starting template (Minimal, Blog, E-commerce)
|
|
59
49
|
|
|
60
|
-
|
|
50
|
+
### Option 2: Add to Existing Project
|
|
61
51
|
|
|
62
52
|
```bash
|
|
63
53
|
npm install @kyro-cms/core
|
|
64
54
|
```
|
|
65
55
|
|
|
66
|
-
|
|
56
|
+
```typescript
|
|
57
|
+
// kyro.config.ts
|
|
58
|
+
import { defineConfig, localAdapter } from "@kyro-cms/core";
|
|
59
|
+
|
|
60
|
+
export default defineConfig({
|
|
61
|
+
name: "my-app",
|
|
62
|
+
adapter: localAdapter({ path: "./data.db" }),
|
|
63
|
+
collections: {
|
|
64
|
+
posts: {
|
|
65
|
+
slug: "posts",
|
|
66
|
+
label: "Posts",
|
|
67
|
+
fields: [
|
|
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 },
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
api: {
|
|
76
|
+
rest: true,
|
|
77
|
+
graphql: true,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Database Adapters
|
|
85
|
+
|
|
86
|
+
### SQLite (Local-First)
|
|
67
87
|
|
|
68
88
|
```typescript
|
|
69
|
-
import {
|
|
89
|
+
import { localAdapter } from "@kyro-cms/core";
|
|
70
90
|
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
91
|
+
const adapter = localAdapter({
|
|
92
|
+
path: "./data.db", // or ':memory:' for in-memory
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Perfect for development and small projects. Zero configuration required.
|
|
97
|
+
|
|
98
|
+
### PostgreSQL/MySQL (Production)
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { drizzleAdapter } from "@kyro-cms/core";
|
|
102
|
+
|
|
103
|
+
const adapter = drizzleAdapter({
|
|
104
|
+
connectionString: process.env.DATABASE_URL,
|
|
80
105
|
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### MongoDB (Flexible Schemas)
|
|
81
109
|
|
|
82
|
-
|
|
110
|
+
```typescript
|
|
111
|
+
import { mongoAdapter } from "@kyro-cms/core";
|
|
112
|
+
|
|
113
|
+
const adapter = mongoAdapter({
|
|
114
|
+
connectionString: process.env.MONGODB_URI,
|
|
115
|
+
});
|
|
83
116
|
```
|
|
84
117
|
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## API Protocols
|
|
121
|
+
|
|
122
|
+
Kyro exposes your data through multiple protocols simultaneously.
|
|
123
|
+
|
|
85
124
|
### REST API
|
|
86
125
|
|
|
87
126
|
```bash
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
127
|
+
# List documents
|
|
128
|
+
GET /api/posts
|
|
129
|
+
|
|
130
|
+
# Get single document
|
|
131
|
+
GET /api/posts/:id
|
|
132
|
+
|
|
133
|
+
# Create document
|
|
134
|
+
POST /api/posts
|
|
135
|
+
{ "title": "Hello World" }
|
|
136
|
+
|
|
137
|
+
# Update document
|
|
138
|
+
PATCH /api/posts/:id
|
|
139
|
+
{ "title": "Updated Title" }
|
|
140
|
+
|
|
141
|
+
# Delete document
|
|
142
|
+
DELETE /api/posts/:id
|
|
92
143
|
```
|
|
93
144
|
|
|
94
145
|
### GraphQL
|
|
95
146
|
|
|
96
147
|
```graphql
|
|
97
|
-
query {
|
|
98
|
-
|
|
148
|
+
query {
|
|
149
|
+
postsFind(where: {}, page: 1, limit: 10) {
|
|
150
|
+
docs {
|
|
151
|
+
id
|
|
152
|
+
title
|
|
153
|
+
slug
|
|
154
|
+
}
|
|
155
|
+
totalDocs
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
mutation {
|
|
160
|
+
postsCreate(data: { title: "New Post", slug: "new-post" }) {
|
|
161
|
+
doc {
|
|
162
|
+
id
|
|
163
|
+
title
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### tRPC
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
const client = createTRPCClient({
|
|
173
|
+
router: kyro.router,
|
|
174
|
+
transformer: superjson,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Type-safe queries
|
|
178
|
+
const posts = await client.posts.find.query({ page: 1 });
|
|
179
|
+
const newPost = await client.posts.create.mutate({
|
|
180
|
+
title: "Hello",
|
|
181
|
+
slug: "hello",
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### WebSocket (Real-time)
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
const ws = new WebSocket("ws://localhost:4321/api/ws");
|
|
189
|
+
|
|
190
|
+
ws.send(
|
|
191
|
+
JSON.stringify({
|
|
192
|
+
type: "subscribe",
|
|
193
|
+
collection: "posts",
|
|
194
|
+
event: "create",
|
|
195
|
+
}),
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
ws.onmessage = (event) => {
|
|
199
|
+
const data = JSON.parse(event.data);
|
|
200
|
+
// Handle real-time updates
|
|
201
|
+
};
|
|
99
202
|
```
|
|
100
203
|
|
|
101
204
|
---
|
|
102
205
|
|
|
103
|
-
##
|
|
206
|
+
## Field Types
|
|
207
|
+
|
|
208
|
+
Kyro supports 21 field types:
|
|
209
|
+
|
|
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 |
|
|
234
|
+
|
|
235
|
+
### Example: Complex Fields
|
|
104
236
|
|
|
105
237
|
```typescript
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
238
|
+
fields: [
|
|
239
|
+
{ name: "title", type: "text", required: true },
|
|
240
|
+
|
|
241
|
+
{
|
|
242
|
+
name: "author",
|
|
243
|
+
type: "relationship",
|
|
244
|
+
relationTo: "users",
|
|
245
|
+
required: true,
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
{
|
|
249
|
+
name: "tags",
|
|
250
|
+
type: "array",
|
|
251
|
+
fields: [
|
|
252
|
+
{ name: "name", type: "text" },
|
|
253
|
+
{ name: "slug", type: "text" },
|
|
254
|
+
],
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
{
|
|
258
|
+
name: "metadata",
|
|
259
|
+
type: "group",
|
|
260
|
+
fields: [
|
|
261
|
+
{ name: "views", type: "number", defaultValue: 0 },
|
|
262
|
+
{ name: "featured", type: "checkbox" },
|
|
263
|
+
],
|
|
264
|
+
},
|
|
265
|
+
];
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## E-Commerce Collections
|
|
271
|
+
|
|
272
|
+
Pre-built collections for building online stores:
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import { ecommerceCollections } from "@kyro-cms/core";
|
|
113
276
|
|
|
114
277
|
const kyro = createKyro({
|
|
115
|
-
adapter:
|
|
278
|
+
adapter: localAdapter({ path: "./store.db" }),
|
|
116
279
|
collections: ecommerceCollections,
|
|
117
|
-
tenantScoped: true, // Multi-vendor
|
|
118
280
|
});
|
|
119
281
|
|
|
120
|
-
|
|
282
|
+
// Includes:
|
|
283
|
+
// - products (with variants, pricing, inventory)
|
|
284
|
+
// - categories (hierarchical)
|
|
285
|
+
// - customers (with addresses)
|
|
286
|
+
// - orders (with items, status tracking)
|
|
287
|
+
// - coupons (percentage, fixed, free shipping)
|
|
288
|
+
// - store settings (globals)
|
|
121
289
|
```
|
|
122
290
|
|
|
123
291
|
---
|
|
124
292
|
|
|
293
|
+
## Authentication
|
|
294
|
+
|
|
295
|
+
Built-in JWT authentication with Redis sessions and PostgreSQL support:
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import { RedisAuthAdapter } from "@kyro-cms/core";
|
|
299
|
+
import { createAuthConfig } from "@kyro-cms/core";
|
|
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",
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// Or use PostgreSQL for production
|
|
308
|
+
import { PostgresAuthAdapter, createDatabase } from "@kyro-cms/core";
|
|
309
|
+
|
|
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
|
|
348
|
+
|
|
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!
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
## Version History & Drafts
|
|
375
|
+
|
|
376
|
+
Track document changes with built-in versioning:
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
import { createVersionManager } from "@kyro-cms/core";
|
|
380
|
+
|
|
381
|
+
const versions = createVersionManager(adapter, {
|
|
382
|
+
versioningEnabled: true,
|
|
383
|
+
maxVersionsPerDocument: 50,
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// Create a new version
|
|
387
|
+
const version = await versions.createVersion({
|
|
388
|
+
collection: "posts",
|
|
389
|
+
documentId: "abc123",
|
|
390
|
+
data: { title: "Updated Post" },
|
|
391
|
+
status: "draft",
|
|
392
|
+
createdBy: "user123",
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// Publish
|
|
396
|
+
await versions.publishVersion({
|
|
397
|
+
collection: "posts",
|
|
398
|
+
documentId: "abc123",
|
|
399
|
+
versionId: version.id,
|
|
400
|
+
publishedBy: "user123",
|
|
401
|
+
});
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## Admin Dashboard
|
|
407
|
+
|
|
408
|
+
Kyro includes a full admin dashboard:
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
npm install @kyro-cms/admin
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
```astro
|
|
415
|
+
---
|
|
416
|
+
// admin/index.astro
|
|
417
|
+
import { Admin } from '@kyro-cms/admin';
|
|
418
|
+
import config from '../kyro.config';
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
<Admin client:load config={config} />
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
Features:
|
|
425
|
+
|
|
426
|
+
- Collection browser with filtering and sorting
|
|
427
|
+
- Document editor with all field types
|
|
428
|
+
- Media library
|
|
429
|
+
- Global settings editor
|
|
430
|
+
- Dark mode support
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
125
434
|
## Plugin System
|
|
126
435
|
|
|
436
|
+
Extend Kyro with plugins:
|
|
437
|
+
|
|
127
438
|
```typescript
|
|
128
|
-
import {
|
|
439
|
+
import {
|
|
440
|
+
KyroPlugin,
|
|
441
|
+
SEOPLugin,
|
|
442
|
+
AnalyticsPlugin,
|
|
443
|
+
CommentsPlugin,
|
|
444
|
+
ReviewsPlugin,
|
|
445
|
+
WishlistPlugin
|
|
446
|
+
} from '@kyro-cms/core';
|
|
129
447
|
|
|
130
448
|
const kyro = createKyro({
|
|
131
|
-
adapter:
|
|
449
|
+
adapter: localAdapter(),
|
|
132
450
|
collections: [...],
|
|
133
451
|
plugins: [
|
|
134
|
-
new SEOPLugin(
|
|
452
|
+
new SEOPLugin({
|
|
453
|
+
sitemap: true,
|
|
454
|
+
robotsTxt: true,
|
|
455
|
+
}),
|
|
456
|
+
new AnalyticsPlugin({
|
|
457
|
+
providers: ['google', 'plausible'],
|
|
458
|
+
}),
|
|
459
|
+
new CommentsPlugin(),
|
|
135
460
|
new ReviewsPlugin(),
|
|
136
461
|
],
|
|
137
462
|
});
|
|
138
463
|
```
|
|
139
464
|
|
|
465
|
+
### Creating Plugins
|
|
466
|
+
|
|
467
|
+
```typescript
|
|
468
|
+
import { KyroPlugin } from "@kyro-cms/core";
|
|
469
|
+
|
|
470
|
+
class MyPlugin extends KyroPlugin {
|
|
471
|
+
name = "my-plugin";
|
|
472
|
+
|
|
473
|
+
hooks = {
|
|
474
|
+
"collection.beforeCreate": async (args) => {
|
|
475
|
+
// Transform data before creation
|
|
476
|
+
return { ...args, data: { ...args.data, source: "my-plugin" } };
|
|
477
|
+
},
|
|
478
|
+
|
|
479
|
+
"document.afterSave": async (args) => {
|
|
480
|
+
// Send webhook, log analytics, etc.
|
|
481
|
+
await sendWebhook(args);
|
|
482
|
+
},
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
140
487
|
---
|
|
141
488
|
|
|
142
|
-
## Styling
|
|
489
|
+
## Styling System
|
|
490
|
+
|
|
491
|
+
Kyro ships with a complete styling system:
|
|
143
492
|
|
|
144
493
|
```typescript
|
|
145
|
-
import {
|
|
494
|
+
import {
|
|
495
|
+
ecommerce2026Theme,
|
|
496
|
+
generateCSSVariables,
|
|
497
|
+
generateTailwindConfig,
|
|
498
|
+
} from "@kyro-cms/core";
|
|
146
499
|
|
|
147
500
|
// Generate CSS variables
|
|
148
|
-
const
|
|
501
|
+
const cssVars = generateCSSVariables(ecommerce2026Theme);
|
|
502
|
+
|
|
503
|
+
// Generate Tailwind config
|
|
504
|
+
const tailwindConfig = generateTailwindConfig(ecommerce2026Theme);
|
|
505
|
+
|
|
506
|
+
// Custom themes
|
|
507
|
+
import { createAdminStyling } from "@kyro-cms/core";
|
|
508
|
+
|
|
509
|
+
const myTheme = createAdminStyling({
|
|
510
|
+
primaryColor: "#6366f1",
|
|
511
|
+
borderRadius: "medium",
|
|
512
|
+
fontFamily: "Inter",
|
|
513
|
+
});
|
|
149
514
|
```
|
|
150
515
|
|
|
151
516
|
---
|
|
152
517
|
|
|
153
|
-
##
|
|
518
|
+
## Deployment
|
|
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
|
+
|
|
551
|
+
### Vercel
|
|
552
|
+
|
|
553
|
+
```bash
|
|
554
|
+
vercel --prod
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
Environment variables:
|
|
558
|
+
|
|
559
|
+
- `DATABASE_URL` - PostgreSQL connection string
|
|
560
|
+
- `JWT_SECRET` - JWT signing secret
|
|
561
|
+
|
|
562
|
+
### Railway
|
|
154
563
|
|
|
564
|
+
```bash
|
|
565
|
+
railway up
|
|
155
566
|
```
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
┌──────────────────────────────────────────────────────────────┐
|
|
163
|
-
│ Registry │
|
|
164
|
-
│ • Stores configs │
|
|
165
|
-
│ • Generates Zod schemas │
|
|
166
|
-
│ • Validates config │
|
|
167
|
-
└───────────────────────────┬──────────────────────────────────┘
|
|
168
|
-
│
|
|
169
|
-
┌────────────────┼────────────────┐
|
|
170
|
-
▼ ▼ ▼
|
|
171
|
-
┌─────────────────┐ ┌─────────────┐ ┌─────────────────┐
|
|
172
|
-
│ Local/SQLite │ │ Drizzle │ │ MongoDB │
|
|
173
|
-
│ (Local-first) │ │ (SQL) │ │ (NoSQL) │
|
|
174
|
-
└─────────────────┘ └─────────────┘ └─────────────────┘
|
|
175
|
-
│
|
|
176
|
-
▼
|
|
177
|
-
┌──────────────────────────────────────────────────────────────┐
|
|
178
|
-
│ Multi-Protocol API Gateway │
|
|
179
|
-
│ • REST (Hono) • GraphQL • tRPC • WebSocket │
|
|
180
|
-
└──────────────────────────────────────────────────────────────┘
|
|
567
|
+
|
|
568
|
+
### Docker
|
|
569
|
+
|
|
570
|
+
```bash
|
|
571
|
+
cd deployments/docker
|
|
572
|
+
docker-compose up -d
|
|
181
573
|
```
|
|
182
574
|
|
|
575
|
+
See `deployments/` for complete configuration.
|
|
576
|
+
|
|
183
577
|
---
|
|
184
578
|
|
|
185
579
|
## Project Structure
|
|
186
580
|
|
|
187
581
|
```
|
|
188
582
|
kyro-cms/
|
|
583
|
+
├── packages/
|
|
584
|
+
│ └── create-kyro/ # Project scaffolding CLI
|
|
189
585
|
├── src/
|
|
190
|
-
│ ├── index.ts
|
|
191
|
-
│ ├──
|
|
192
|
-
│ ├──
|
|
193
|
-
│ ├──
|
|
194
|
-
│ ├──
|
|
195
|
-
│ ├──
|
|
196
|
-
│ ├──
|
|
197
|
-
│ └──
|
|
198
|
-
├──
|
|
199
|
-
├──
|
|
200
|
-
│ ├──
|
|
201
|
-
│
|
|
202
|
-
└──
|
|
586
|
+
│ ├── index.ts # Main exports
|
|
587
|
+
│ ├── createKyro.ts # Factory function
|
|
588
|
+
│ ├── registry/ # Config registry & validation
|
|
589
|
+
│ ├── fields/ # 21 field type definitions
|
|
590
|
+
│ ├── database/ # Adapter implementations
|
|
591
|
+
│ │ ├── local/ # SQLite adapter
|
|
592
|
+
│ │ ├── drizzle/ # SQL adapters
|
|
593
|
+
│ │ └── mongodb/ # MongoDB adapter
|
|
594
|
+
│ ├── api/ # Multi-protocol gateway
|
|
595
|
+
│ │ ├── rest/ # Hono REST
|
|
596
|
+
│ │ ├── graphql/ # GraphQL schema
|
|
597
|
+
│ │ ├── trpc/ # tRPC router
|
|
598
|
+
│ │ └── ws/ # WebSocket server
|
|
599
|
+
│ ├── auth/ # JWT authentication
|
|
600
|
+
│ ├── versions/ # Version history
|
|
601
|
+
│ ├── plugins/ # Plugin system
|
|
602
|
+
│ ├── styling/ # Theming
|
|
603
|
+
│ └── cli/ # CLI tools
|
|
604
|
+
├── admin/ # Admin dashboard (Astro)
|
|
605
|
+
├── examples/ # Example configurations
|
|
606
|
+
├── docs/ # Documentation
|
|
607
|
+
└── deployments/ # Deployment configs
|
|
203
608
|
```
|
|
204
609
|
|
|
205
610
|
---
|
|
@@ -207,9 +612,20 @@ kyro-cms/
|
|
|
207
612
|
## CLI Commands
|
|
208
613
|
|
|
209
614
|
```bash
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
615
|
+
# Initialize a new project
|
|
616
|
+
npm create kyro@latest
|
|
617
|
+
|
|
618
|
+
# Generate TypeScript types
|
|
619
|
+
kyro generate
|
|
620
|
+
|
|
621
|
+
# Push schema to database
|
|
622
|
+
kyro push
|
|
623
|
+
|
|
624
|
+
# Open database studio
|
|
625
|
+
kyro studio
|
|
626
|
+
|
|
627
|
+
# Check system health
|
|
628
|
+
kyro health
|
|
213
629
|
```
|
|
214
630
|
|
|
215
631
|
---
|
|
@@ -220,22 +636,32 @@ kyro health # Check system health
|
|
|
220
636
|
- [API Reference](docs/api.md)
|
|
221
637
|
- [E-Commerce Guide](docs/ecommerce.md)
|
|
222
638
|
- [Plugin Development](docs/plugins.md)
|
|
223
|
-
- [
|
|
639
|
+
- [Deployment Guide](docs/deployment.md)
|
|
640
|
+
|
|
641
|
+
---
|
|
642
|
+
|
|
643
|
+
## Contributing
|
|
644
|
+
|
|
645
|
+
Contributions are welcome! Please read our contributing guide before submitting PRs.
|
|
646
|
+
|
|
647
|
+
1. Fork the repository
|
|
648
|
+
2. Create your feature branch (`git checkout -b feature/amazing`)
|
|
649
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
650
|
+
4. Push to the branch (`git push origin feature/amazing`)
|
|
651
|
+
5. Open a Pull Request
|
|
224
652
|
|
|
225
653
|
---
|
|
226
654
|
|
|
227
655
|
## License
|
|
228
656
|
|
|
229
|
-
MIT
|
|
657
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
230
658
|
|
|
231
659
|
---
|
|
232
660
|
|
|
233
|
-
##
|
|
661
|
+
## Acknowledgments
|
|
662
|
+
|
|
663
|
+
Built with inspiration from:
|
|
234
664
|
|
|
235
|
-
- [
|
|
236
|
-
- [
|
|
237
|
-
- [
|
|
238
|
-
- [x] Styling abstraction
|
|
239
|
-
- [ ] Full admin dashboard
|
|
240
|
-
- [ ] Authentication
|
|
241
|
-
- [ ] Version history
|
|
665
|
+
- [Payload CMS](https://payloadcms.com/) - The headless CMS that pushed the industry forward
|
|
666
|
+
- [Strapi](https://strapi.io/) - Open source headless CMS
|
|
667
|
+
- [Sanity](https://www.sanity.io/) - Real-time content infrastructure
|