@kyro-cms/core 0.1.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.
Files changed (88) hide show
  1. package/README.md +241 -0
  2. package/dist/base-CQkFzqQl.d.ts +62 -0
  3. package/dist/base-DlhVlwnN.d.cts +62 -0
  4. package/dist/chunk-3Q3FS5J4.cjs +273 -0
  5. package/dist/chunk-3Q3FS5J4.cjs.map +1 -0
  6. package/dist/chunk-3TPQ2BU6.js +423 -0
  7. package/dist/chunk-3TPQ2BU6.js.map +1 -0
  8. package/dist/chunk-3VZCX4DF.cjs +384 -0
  9. package/dist/chunk-3VZCX4DF.cjs.map +1 -0
  10. package/dist/chunk-BXMWDUED.js +115 -0
  11. package/dist/chunk-BXMWDUED.js.map +1 -0
  12. package/dist/chunk-DIC236EW.js +290 -0
  13. package/dist/chunk-DIC236EW.js.map +1 -0
  14. package/dist/chunk-DKSMFC3L.js +268 -0
  15. package/dist/chunk-DKSMFC3L.js.map +1 -0
  16. package/dist/chunk-DVD5P72E.cjs +428 -0
  17. package/dist/chunk-DVD5P72E.cjs.map +1 -0
  18. package/dist/chunk-HT6VE4NW.cjs +293 -0
  19. package/dist/chunk-HT6VE4NW.cjs.map +1 -0
  20. package/dist/chunk-K7QF2QCM.cjs +311 -0
  21. package/dist/chunk-K7QF2QCM.cjs.map +1 -0
  22. package/dist/chunk-OG3KX56O.js +308 -0
  23. package/dist/chunk-OG3KX56O.js.map +1 -0
  24. package/dist/chunk-R3XIBBAW.cjs +34 -0
  25. package/dist/chunk-R3XIBBAW.cjs.map +1 -0
  26. package/dist/chunk-RLTG4YZM.cjs +117 -0
  27. package/dist/chunk-RLTG4YZM.cjs.map +1 -0
  28. package/dist/chunk-SDMNUYVU.js +30 -0
  29. package/dist/chunk-SDMNUYVU.js.map +1 -0
  30. package/dist/chunk-UEG7KMKC.cjs +228 -0
  31. package/dist/chunk-UEG7KMKC.cjs.map +1 -0
  32. package/dist/chunk-UEYC46RL.js +374 -0
  33. package/dist/chunk-UEYC46RL.js.map +1 -0
  34. package/dist/chunk-YPAFJ7EV.js +225 -0
  35. package/dist/chunk-YPAFJ7EV.js.map +1 -0
  36. package/dist/cli/index.cjs +306 -0
  37. package/dist/cli/index.cjs.map +1 -0
  38. package/dist/cli/index.d.cts +1 -0
  39. package/dist/cli/index.d.ts +1 -0
  40. package/dist/cli/index.js +303 -0
  41. package/dist/cli/index.js.map +1 -0
  42. package/dist/drizzle/index.cjs +25 -0
  43. package/dist/drizzle/index.cjs.map +1 -0
  44. package/dist/drizzle/index.d.cts +49 -0
  45. package/dist/drizzle/index.d.ts +49 -0
  46. package/dist/drizzle/index.js +4 -0
  47. package/dist/drizzle/index.js.map +1 -0
  48. package/dist/graphql/index.cjs +16 -0
  49. package/dist/graphql/index.cjs.map +1 -0
  50. package/dist/graphql/index.d.cts +20 -0
  51. package/dist/graphql/index.d.ts +20 -0
  52. package/dist/graphql/index.js +3 -0
  53. package/dist/graphql/index.js.map +1 -0
  54. package/dist/index-4fJKLFK2.d.ts +63 -0
  55. package/dist/index-DI0DRPNv.d.cts +63 -0
  56. package/dist/index.cjs +2506 -0
  57. package/dist/index.cjs.map +1 -0
  58. package/dist/index.d.cts +525 -0
  59. package/dist/index.d.ts +525 -0
  60. package/dist/index.js +2334 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/mongodb/index.cjs +17 -0
  63. package/dist/mongodb/index.cjs.map +1 -0
  64. package/dist/mongodb/index.d.cts +49 -0
  65. package/dist/mongodb/index.d.ts +49 -0
  66. package/dist/mongodb/index.js +4 -0
  67. package/dist/mongodb/index.js.map +1 -0
  68. package/dist/rest/index.cjs +17 -0
  69. package/dist/rest/index.cjs.map +1 -0
  70. package/dist/rest/index.d.cts +28 -0
  71. package/dist/rest/index.d.ts +28 -0
  72. package/dist/rest/index.js +4 -0
  73. package/dist/rest/index.js.map +1 -0
  74. package/dist/trpc/index.cjs +45 -0
  75. package/dist/trpc/index.cjs.map +1 -0
  76. package/dist/trpc/index.d.cts +130 -0
  77. package/dist/trpc/index.d.ts +130 -0
  78. package/dist/trpc/index.js +4 -0
  79. package/dist/trpc/index.js.map +1 -0
  80. package/dist/types-BGM5MV_K.d.cts +589 -0
  81. package/dist/types-BGM5MV_K.d.ts +589 -0
  82. package/dist/ws/index.cjs +24 -0
  83. package/dist/ws/index.cjs.map +1 -0
  84. package/dist/ws/index.d.cts +88 -0
  85. package/dist/ws/index.d.ts +88 -0
  86. package/dist/ws/index.js +3 -0
  87. package/dist/ws/index.js.map +1 -0
  88. package/package.json +120 -0
package/README.md ADDED
@@ -0,0 +1,241 @@
1
+ # Kyro CMS
2
+
3
+ **Astro-Native Headless CMS with Multi-Database Adapters, Multi-Protocol APIs, and Multi-Vendor Support**
4
+
5
+ Kyro is an open-source, TypeScript-native headless CMS inspired by Payload CMS but architected specifically for Astro JS. It provides zero-inference tRPC, SQL-sovereign Drizzle schemas, and built-in multi-tenancy.
6
+
7
+ ---
8
+
9
+ ## Features
10
+
11
+ ### Local-First with SQLite
12
+ ```typescript
13
+ import { createKyro, LocalAdapter } from '@kyro-cms/core';
14
+
15
+ const kyro = createKyro({
16
+ adapter: new LocalAdapter({ path: './data.db' }),
17
+ collections: [productsCollection],
18
+ });
19
+ ```
20
+ Works out of the box - no external database required.
21
+
22
+ ### Deploy Anywhere with Adapters
23
+ - **Local/SQLite**: Zero-config local development
24
+ - **PostgreSQL/MySQL/SQLite**: Via Drizzle ORM
25
+ - **MongoDB**: NoSQL flexibility
26
+
27
+ ### E-Commerce Ready
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
34
+
35
+ ### Multi-Protocol API
36
+ - **REST**: Hono-based with query params
37
+ - **GraphQL**: Dynamic schema
38
+ - **tRPC**: Type-safe RPC (zero inference)
39
+ - **WebSocket**: Real-time pub/sub
40
+
41
+ ### Multi-Vendor Ready
42
+ Row-level access control with tenant scoping built-in.
43
+
44
+ ### Plugin System
45
+ Extend with:
46
+ - SEO (sitemaps, structured data)
47
+ - Analytics
48
+ - Reviews & Comments
49
+ - Wishlists
50
+
51
+ ### Any Styling System
52
+ - Plain CSS
53
+ - Tailwind CSS
54
+ - CSS-in-JS
55
+ - Styled Components
56
+ - Vanilla Extract
57
+
58
+ ---
59
+
60
+ ## Quick Start
61
+
62
+ ```bash
63
+ npm install @kyro-cms/core
64
+ ```
65
+
66
+ ### Basic Setup
67
+
68
+ ```typescript
69
+ import { createKyro, LocalAdapter } from '@kyro-cms/core';
70
+
71
+ const kyro = createKyro({
72
+ adapter: new LocalAdapter(),
73
+ collections: [{
74
+ slug: 'posts',
75
+ fields: [
76
+ { name: 'title', type: 'text', required: true },
77
+ { name: 'content', type: 'richtext' },
78
+ ],
79
+ }],
80
+ });
81
+
82
+ await kyro.init();
83
+ ```
84
+
85
+ ### REST API
86
+
87
+ ```bash
88
+ curl http://localhost:3000/api/posts
89
+ curl -X POST http://localhost:3000/api/posts \
90
+ -H "Content-Type: application/json" \
91
+ -d '{"title":"Hello World"}'
92
+ ```
93
+
94
+ ### GraphQL
95
+
96
+ ```graphql
97
+ query { postsFind { docs { id title } totalDocs } }
98
+ mutation { postsCreate(data: { title: "New Post" }) { doc { id } } }
99
+ ```
100
+
101
+ ---
102
+
103
+ ## E-Commerce Example
104
+
105
+ ```typescript
106
+ import { createKyro, LocalAdapter } from '@kyro-cms/core';
107
+ import {
108
+ productsCollection,
109
+ ordersCollection,
110
+ customersCollection,
111
+ ecommerceCollections
112
+ } from '@kyro-cms/core/examples/ecommerce';
113
+
114
+ const kyro = createKyro({
115
+ adapter: new LocalAdapter({ path: './store.db' }),
116
+ collections: ecommerceCollections,
117
+ tenantScoped: true, // Multi-vendor
118
+ });
119
+
120
+ await kyro.init();
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Plugin System
126
+
127
+ ```typescript
128
+ import { createKyro, SEOPLugin, ReviewsPlugin } from '@kyro-cms/core';
129
+
130
+ const kyro = createKyro({
131
+ adapter: new LocalAdapter(),
132
+ collections: [...],
133
+ plugins: [
134
+ new SEOPLugin(),
135
+ new ReviewsPlugin(),
136
+ ],
137
+ });
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Styling
143
+
144
+ ```typescript
145
+ import { ecommerce2026Theme, generateCSSVariables } from '@kyro-cms/core';
146
+
147
+ // Generate CSS variables
148
+ const css = generateCSSVariables(ecommerce2026Theme);
149
+ ```
150
+
151
+ ---
152
+
153
+ ## Architecture
154
+
155
+ ```
156
+ ┌──────────────────────────────────────────────────────────────┐
157
+ │ Your Config │
158
+ │ (CollectionConfig[]) │
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
+ └──────────────────────────────────────────────────────────────┘
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Project Structure
186
+
187
+ ```
188
+ kyro-cms/
189
+ ├── src/
190
+ │ ├── index.ts # Main exports
191
+ │ ├── registry/ # Configuration engine
192
+ │ ├── fields/ # 21 field types
193
+ │ ├── database/ # Adapters (Local, Drizzle, MongoDB)
194
+ │ ├── api/ # REST, GraphQL, tRPC, WebSocket
195
+ │ ├── plugins/ # Plugin system
196
+ │ ├── styling/ # Theming & CSS generation
197
+ │ └── cli/ # CLI tools
198
+ ├── admin/ # Admin dashboard
199
+ ├── examples/
200
+ │ ├── basic.config.ts # Blog example
201
+ │ └── ecommerce.config.ts # E-commerce example
202
+ └── docs/ # Documentation
203
+ ```
204
+
205
+ ---
206
+
207
+ ## CLI Commands
208
+
209
+ ```bash
210
+ kyro generate # Generate TypeScript types
211
+ kyro migrate # Run migrations
212
+ kyro health # Check system health
213
+ ```
214
+
215
+ ---
216
+
217
+ ## Documentation
218
+
219
+ - [Getting Started](docs/getting-started.md)
220
+ - [API Reference](docs/api.md)
221
+ - [E-Commerce Guide](docs/ecommerce.md)
222
+ - [Plugin Development](docs/plugins.md)
223
+ - [Styling Guide](docs/styling.md)
224
+
225
+ ---
226
+
227
+ ## License
228
+
229
+ MIT
230
+
231
+ ---
232
+
233
+ ## Roadmap
234
+
235
+ - [x] Local-first SQLite adapter
236
+ - [x] E-commerce collections
237
+ - [x] Plugin system
238
+ - [x] Styling abstraction
239
+ - [ ] Full admin dashboard
240
+ - [ ] Authentication
241
+ - [ ] Version history
@@ -0,0 +1,62 @@
1
+ import { B as BaseAdapter, C as CollectionConfig, G as GlobalConfig, a as FindArgs, b as FindResult, c as FindByIDArgs, d as CreateArgs, U as UpdateArgs, D as DeleteArgs, F as Field, R as RelationshipField, e as UploadField } from './types-BGM5MV_K.js';
2
+
3
+ declare abstract class AbstractBaseAdapter implements BaseAdapter {
4
+ protected collections: Map<string, CollectionConfig>;
5
+ protected globals: Map<string, GlobalConfig>;
6
+ protected connected: boolean;
7
+ abstract connect(): Promise<void>;
8
+ abstract disconnect(): Promise<void>;
9
+ init(collections: CollectionConfig[], globals?: GlobalConfig[]): Promise<void>;
10
+ abstract find<T>(args: FindArgs): Promise<FindResult<T>>;
11
+ abstract findByID<T>(args: FindByIDArgs): Promise<T | null>;
12
+ abstract create<T>(args: CreateArgs): Promise<T>;
13
+ abstract update<T>(args: UpdateArgs): Promise<T>;
14
+ abstract delete<T>(args: DeleteArgs): Promise<T>;
15
+ abstract count(args: {
16
+ collection: string;
17
+ where?: Record<string, any>;
18
+ tenantID?: string;
19
+ }): Promise<number>;
20
+ abstract findOne(args: {
21
+ collection: string;
22
+ where: Record<string, any>;
23
+ tenantID?: string;
24
+ }): Promise<any>;
25
+ abstract findVersions(args: FindArgs): Promise<FindResult<any>>;
26
+ abstract findVersionByID(args: FindByIDArgs): Promise<any>;
27
+ abstract createVersion(args: CreateArgs): Promise<any>;
28
+ abstract deleteVersions(args: {
29
+ collection: string;
30
+ where: Record<string, any>;
31
+ }): Promise<void>;
32
+ migrate?(): Promise<void>;
33
+ rollback?(): Promise<void>;
34
+ transaction?<T>(fn: (tx: any) => Promise<T>): Promise<T>;
35
+ protected getCollection(slug: string): CollectionConfig;
36
+ protected applyTenantFilter(where?: Record<string, any>, tenantID?: string): Record<string, any>;
37
+ protected getTableName(slug: string): string;
38
+ protected prepareData(data: Record<string, any>, collection: CollectionConfig): Record<string, any>;
39
+ protected processRelationships(data: Record<string, any>, fields: Field[], depth: number): Record<string, any>;
40
+ protected parseSort(sort?: string): {
41
+ field: string;
42
+ direction: 'asc' | 'desc';
43
+ };
44
+ protected calculatePagination(page: number, limit: number, totalDocs: number): {
45
+ totalDocs: number;
46
+ limit: number;
47
+ totalPages: number;
48
+ page: number;
49
+ pagingCounter: number;
50
+ hasPrevPage: boolean;
51
+ hasNextPage: boolean;
52
+ prevPage: number | null;
53
+ nextPage: number | null;
54
+ };
55
+ protected selectFields(data: Record<string, any>, select?: string[]): Record<string, any>;
56
+ protected isRelationshipField(field: Field): field is RelationshipField;
57
+ protected isUploadField(field: Field): field is UploadField;
58
+ protected getRelationshipFields(fields: Field[]): RelationshipField[];
59
+ protected getUploadFields(fields: Field[]): UploadField[];
60
+ }
61
+
62
+ export { AbstractBaseAdapter as A };
@@ -0,0 +1,62 @@
1
+ import { B as BaseAdapter, C as CollectionConfig, G as GlobalConfig, a as FindArgs, b as FindResult, c as FindByIDArgs, d as CreateArgs, U as UpdateArgs, D as DeleteArgs, F as Field, R as RelationshipField, e as UploadField } from './types-BGM5MV_K.cjs';
2
+
3
+ declare abstract class AbstractBaseAdapter implements BaseAdapter {
4
+ protected collections: Map<string, CollectionConfig>;
5
+ protected globals: Map<string, GlobalConfig>;
6
+ protected connected: boolean;
7
+ abstract connect(): Promise<void>;
8
+ abstract disconnect(): Promise<void>;
9
+ init(collections: CollectionConfig[], globals?: GlobalConfig[]): Promise<void>;
10
+ abstract find<T>(args: FindArgs): Promise<FindResult<T>>;
11
+ abstract findByID<T>(args: FindByIDArgs): Promise<T | null>;
12
+ abstract create<T>(args: CreateArgs): Promise<T>;
13
+ abstract update<T>(args: UpdateArgs): Promise<T>;
14
+ abstract delete<T>(args: DeleteArgs): Promise<T>;
15
+ abstract count(args: {
16
+ collection: string;
17
+ where?: Record<string, any>;
18
+ tenantID?: string;
19
+ }): Promise<number>;
20
+ abstract findOne(args: {
21
+ collection: string;
22
+ where: Record<string, any>;
23
+ tenantID?: string;
24
+ }): Promise<any>;
25
+ abstract findVersions(args: FindArgs): Promise<FindResult<any>>;
26
+ abstract findVersionByID(args: FindByIDArgs): Promise<any>;
27
+ abstract createVersion(args: CreateArgs): Promise<any>;
28
+ abstract deleteVersions(args: {
29
+ collection: string;
30
+ where: Record<string, any>;
31
+ }): Promise<void>;
32
+ migrate?(): Promise<void>;
33
+ rollback?(): Promise<void>;
34
+ transaction?<T>(fn: (tx: any) => Promise<T>): Promise<T>;
35
+ protected getCollection(slug: string): CollectionConfig;
36
+ protected applyTenantFilter(where?: Record<string, any>, tenantID?: string): Record<string, any>;
37
+ protected getTableName(slug: string): string;
38
+ protected prepareData(data: Record<string, any>, collection: CollectionConfig): Record<string, any>;
39
+ protected processRelationships(data: Record<string, any>, fields: Field[], depth: number): Record<string, any>;
40
+ protected parseSort(sort?: string): {
41
+ field: string;
42
+ direction: 'asc' | 'desc';
43
+ };
44
+ protected calculatePagination(page: number, limit: number, totalDocs: number): {
45
+ totalDocs: number;
46
+ limit: number;
47
+ totalPages: number;
48
+ page: number;
49
+ pagingCounter: number;
50
+ hasPrevPage: boolean;
51
+ hasNextPage: boolean;
52
+ prevPage: number | null;
53
+ nextPage: number | null;
54
+ };
55
+ protected selectFields(data: Record<string, any>, select?: string[]): Record<string, any>;
56
+ protected isRelationshipField(field: Field): field is RelationshipField;
57
+ protected isUploadField(field: Field): field is UploadField;
58
+ protected getRelationshipFields(fields: Field[]): RelationshipField[];
59
+ protected getUploadFields(fields: Field[]): UploadField[];
60
+ }
61
+
62
+ export { AbstractBaseAdapter as A };
@@ -0,0 +1,273 @@
1
+ 'use strict';
2
+
3
+ var chunkRLTG4YZM_cjs = require('./chunk-RLTG4YZM.cjs');
4
+
5
+ // src/database/drizzle/adapter.ts
6
+ function fieldToDrizzleType(field, dialect = "postgres") {
7
+ switch (field.type) {
8
+ case "text":
9
+ case "email":
10
+ case "password":
11
+ case "textarea":
12
+ case "color":
13
+ case "code":
14
+ case "markdown":
15
+ return dialect === "sqlite" ? "text" : "varchar";
16
+ case "number":
17
+ return field.integer ? "integer" : "decimal";
18
+ case "checkbox":
19
+ return "boolean";
20
+ case "date":
21
+ return "timestamp";
22
+ case "select":
23
+ case "radio":
24
+ return dialect === "sqlite" ? "text" : "varchar";
25
+ case "richtext":
26
+ case "json":
27
+ case "array":
28
+ case "group":
29
+ case "blocks":
30
+ case "row":
31
+ case "collapsible":
32
+ case "tabs":
33
+ return "jsonb";
34
+ case "relationship":
35
+ return dialect === "sqlite" ? "text" : "varchar";
36
+ case "upload":
37
+ return dialect === "sqlite" ? "text" : "varchar";
38
+ default:
39
+ return "jsonb";
40
+ }
41
+ }
42
+ function collectionToDrizzleSchema(collection, dialect = "postgres") {
43
+ const tableName = collection.slug.replace(/-/g, "_");
44
+ const lines = [];
45
+ lines.push(`export const ${tableName} = ${dialect === "mysql" ? "mysqlTable" : "pgTable"}('${tableName}', {`);
46
+ lines.push(` id: ${dialect === "mysql" ? "varchar" : "uuid"}('${dialect === "mysql" ? "id" : "id"}').${dialect === "mysql" ? "primaryKey().default(sql`UUID()`)" : "primaryKey().defaultRandom()"},`);
47
+ for (const field of collection.fields) {
48
+ if (field.name === "id") continue;
49
+ const dbType = fieldToDrizzleType(field, dialect);
50
+ const isRequired = field.required;
51
+ let fieldDef = ` ${field.name}: ${dialect === "mysql" ? "mysql" : "pg"}.${dbType}('${field.name}')`;
52
+ if (field.unique) fieldDef += ".unique()";
53
+ if (!isRequired) fieldDef += ".nullable()";
54
+ if (field.defaultValue !== void 0) {
55
+ if (typeof field.defaultValue === "string") {
56
+ fieldDef += `.default('${field.defaultValue}')`;
57
+ } else if (typeof field.defaultValue === "boolean") {
58
+ fieldDef += `.default(${field.defaultValue})`;
59
+ } else {
60
+ fieldDef += `.default(sql\`${JSON.stringify(field.defaultValue)}\`)`;
61
+ }
62
+ }
63
+ fieldDef += ",";
64
+ lines.push(fieldDef);
65
+ }
66
+ if (collection.timestamps) {
67
+ lines.push(` createdAt: ${dialect === "mysql" ? "mysql" : "pg"}.timestamp('created_at').defaultNow(),`);
68
+ lines.push(` updatedAt: ${dialect === "mysql" ? "mysql" : "pg"}.timestamp('updated_at').defaultNow(),`);
69
+ }
70
+ if (collection.tenantScoped) {
71
+ lines.push(` tenantId: ${dialect === "mysql" ? "mysql" : "pg"}.varchar('tenant_id'),`);
72
+ }
73
+ lines.push("});");
74
+ return lines.join("\n");
75
+ }
76
+ var DrizzleAdapter = class extends chunkRLTG4YZM_cjs.AbstractBaseAdapter {
77
+ client;
78
+ schema;
79
+ dialect;
80
+ constructor(options) {
81
+ super();
82
+ this.client = options.client;
83
+ this.schema = options.schema || {};
84
+ this.dialect = options.type;
85
+ }
86
+ async connect() {
87
+ this.connected = true;
88
+ console.log(`[DrizzleAdapter] Connected to ${this.dialect}`);
89
+ }
90
+ async disconnect() {
91
+ this.connected = false;
92
+ console.log(`[DrizzleAdapter] Disconnected from ${this.dialect}`);
93
+ }
94
+ async find(args) {
95
+ const { collection: slug, where = {}, sort, limit = 10, page = 1, tenantID, select } = args;
96
+ const config = this.getCollection(slug);
97
+ const table = this.getTable(slug);
98
+ const filters = this.buildWhereClause(where, config, tenantID);
99
+ const sortOption = this.parseSort(sort);
100
+ const totalDocs = await this.count({ collection: slug, where, tenantID });
101
+ const offset = (page - 1) * limit;
102
+ let docs = [];
103
+ try {
104
+ const results = await this.client.select().from(table).where(filters).orderBy(sortOption.direction === "asc" ? table[sortOption.field] : void 0).limit(limit).offset(offset);
105
+ docs = results.map((doc) => this.processResult(doc, config));
106
+ } catch (error) {
107
+ console.error(`[DrizzleAdapter] Query error:`, error);
108
+ docs = [];
109
+ }
110
+ return {
111
+ docs,
112
+ ...this.calculatePagination(page, limit, totalDocs)
113
+ };
114
+ }
115
+ async findByID(args) {
116
+ const { collection: slug, id, tenantID } = args;
117
+ const config = this.getCollection(slug);
118
+ const table = this.getTable(slug);
119
+ let query = this.client.select().from(table).where(table.id.equals(id));
120
+ if (tenantID) {
121
+ query = query.where(table.tenantId.equals(tenantID));
122
+ }
123
+ const results = await query.limit(1);
124
+ if (results.length === 0) return null;
125
+ return this.processResult(results[0], config);
126
+ }
127
+ async create(args) {
128
+ const { collection: slug, data, tenantID } = args;
129
+ const config = this.getCollection(slug);
130
+ const table = this.getTable(slug);
131
+ const insertData = this.prepareData(data, config);
132
+ if (tenantID) {
133
+ insertData.tenantId = tenantID;
134
+ }
135
+ const result = await this.client.insert(table).values(insertData).returning();
136
+ return this.processResult(result[0], config);
137
+ }
138
+ async update(args) {
139
+ const { collection: slug, id, data, tenantID } = args;
140
+ const config = this.getCollection(slug);
141
+ const table = this.getTable(slug);
142
+ const updateData = this.prepareData(data, config);
143
+ if (tenantID) {
144
+ updateData.tenantId = tenantID;
145
+ }
146
+ const result = await this.client.update(table).set(updateData).where(table.id.equals(id)).returning();
147
+ return this.processResult(result[0], config);
148
+ }
149
+ async delete(args) {
150
+ const { collection: slug, id, tenantID } = args;
151
+ const config = this.getCollection(slug);
152
+ const table = this.getTable(slug);
153
+ let query = this.client.delete(table).where(table.id.equals(id)).returning();
154
+ if (tenantID) {
155
+ query = query.where(table.tenantId.equals(tenantID));
156
+ }
157
+ const result = await query;
158
+ if (result.length === 0) {
159
+ throw new Error(`Document not found: ${slug}/${id}`);
160
+ }
161
+ return this.processResult(result[0], config);
162
+ }
163
+ async count(args) {
164
+ const { collection: slug, where = {}, tenantID } = args;
165
+ const config = this.getCollection(slug);
166
+ const table = this.getTable(slug);
167
+ const filters = this.buildWhereClause(where, config, tenantID);
168
+ try {
169
+ const result = await this.client.select({ count: `count(*)` }).from(table).where(filters);
170
+ return parseInt(result[0]?.count || "0");
171
+ } catch {
172
+ return 0;
173
+ }
174
+ }
175
+ async findOne(args) {
176
+ const { collection: slug, where = {}, tenantID } = args;
177
+ const config = this.getCollection(slug);
178
+ const table = this.getTable(slug);
179
+ const filters = this.buildWhereClause(where, config, tenantID);
180
+ const results = await this.client.select().from(table).where(filters).limit(1);
181
+ if (results.length === 0) return null;
182
+ return this.processResult(results[0], config);
183
+ }
184
+ async findVersions(args) {
185
+ const { collection: slug, where = {}, sort, limit = 10, page = 1 } = args;
186
+ return {
187
+ docs: [],
188
+ ...this.calculatePagination(page, limit, 0)
189
+ };
190
+ }
191
+ async findVersionByID(args) {
192
+ return null;
193
+ }
194
+ async createVersion(args) {
195
+ return args.data;
196
+ }
197
+ async deleteVersions(args) {
198
+ }
199
+ // ========================================================================
200
+ // Helper Methods
201
+ // ========================================================================
202
+ getTable(slug) {
203
+ const tableName = this.getTableName(slug);
204
+ const table = this.schema[tableName];
205
+ if (!table) {
206
+ throw new Error(`Table "${tableName}" not found in schema`);
207
+ }
208
+ return table;
209
+ }
210
+ buildWhereClause(where, config, tenantID) {
211
+ const conditions = [];
212
+ if (tenantID && config.tenantScoped) {
213
+ conditions.push({ tenantId: tenantID });
214
+ }
215
+ for (const [key, value] of Object.entries(where)) {
216
+ if (key === "AND" && Array.isArray(value)) {
217
+ for (const subCondition of value) {
218
+ conditions.push(...Object.entries(subCondition).map(([k, v]) => ({ [k]: v })));
219
+ }
220
+ } else if (key === "OR" && Array.isArray(value)) {
221
+ conditions.push(...value.flatMap(
222
+ (v) => Object.entries(v).map(([k, val]) => ({ [k]: val }))
223
+ ));
224
+ } else if (typeof value === "object" && value !== null) {
225
+ if (value.equals !== void 0) conditions.push({ [key]: value.equals });
226
+ if (value.not_equals !== void 0) conditions.push({ [key]: { not: value.not_equals } });
227
+ if (value.in) conditions.push({ [key]: { in: value.in } });
228
+ if (value.like) conditions.push({ [key]: { like: value.like } });
229
+ if (value.greater_than !== void 0) conditions.push({ [key]: { gt: value.greater_than } });
230
+ if (value.greater_than_equal !== void 0) conditions.push({ [key]: { gte: value.greater_than_equal } });
231
+ if (value.less_than !== void 0) conditions.push({ [key]: { lt: value.less_than } });
232
+ if (value.less_than_equal !== void 0) conditions.push({ [key]: { lte: value.less_than_equal } });
233
+ } else {
234
+ conditions.push({ [key]: value });
235
+ }
236
+ }
237
+ return conditions.length > 0 ? conditions : void 0;
238
+ }
239
+ processResult(data, config) {
240
+ if (!data) return null;
241
+ const result = { ...data };
242
+ if (data.id) {
243
+ result.id = String(data.id);
244
+ }
245
+ for (const field of config.fields) {
246
+ if (field.type === "json" || field.type === "richtext" || field.type === "array" || field.type === "group" || field.type === "blocks") {
247
+ if (result[field.name] && typeof result[field.name] === "string") {
248
+ try {
249
+ result[field.name] = JSON.parse(result[field.name]);
250
+ } catch {
251
+ }
252
+ }
253
+ }
254
+ }
255
+ if (result.createdAt) {
256
+ result.createdAt = new Date(result.createdAt).toISOString();
257
+ }
258
+ if (result.updatedAt) {
259
+ result.updatedAt = new Date(result.updatedAt).toISOString();
260
+ }
261
+ return result;
262
+ }
263
+ };
264
+ function createDrizzleAdapter(options) {
265
+ return new DrizzleAdapter(options);
266
+ }
267
+
268
+ exports.DrizzleAdapter = DrizzleAdapter;
269
+ exports.collectionToDrizzleSchema = collectionToDrizzleSchema;
270
+ exports.createDrizzleAdapter = createDrizzleAdapter;
271
+ exports.fieldToDrizzleType = fieldToDrizzleType;
272
+ //# sourceMappingURL=chunk-3Q3FS5J4.cjs.map
273
+ //# sourceMappingURL=chunk-3Q3FS5J4.cjs.map