@livestore/cli 0.0.0-snapshot-2ac5fd340c97c9e07fe4c5dc6d31d5132aa6557c.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/.claude/settings.local.json +12 -0
- package/LICENSE +201 -0
- package/dist/cli +0 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +22 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/mcp-coach.d.ts +15 -0
- package/dist/commands/mcp-coach.d.ts.map +1 -0
- package/dist/commands/mcp-coach.js +87 -0
- package/dist/commands/mcp-coach.js.map +1 -0
- package/dist/commands/mcp-tools.d.ts +41 -0
- package/dist/commands/mcp-tools.d.ts.map +1 -0
- package/dist/commands/mcp-tools.js +148 -0
- package/dist/commands/mcp-tools.js.map +1 -0
- package/dist/commands/mcp.d.ts +5 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +67 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/new-project.d.ts +34 -0
- package/dist/commands/new-project.d.ts.map +1 -0
- package/dist/commands/new-project.js +163 -0
- package/dist/commands/new-project.js.map +1 -0
- package/dist/mcp-content/architecture.d.ts +2 -0
- package/dist/mcp-content/architecture.d.ts.map +1 -0
- package/dist/mcp-content/architecture.js +171 -0
- package/dist/mcp-content/architecture.js.map +1 -0
- package/dist/mcp-content/features.d.ts +2 -0
- package/dist/mcp-content/features.d.ts.map +1 -0
- package/dist/mcp-content/features.js +177 -0
- package/dist/mcp-content/features.js.map +1 -0
- package/dist/mcp-content/getting-started.d.ts +2 -0
- package/dist/mcp-content/getting-started.d.ts.map +1 -0
- package/dist/mcp-content/getting-started.js +405 -0
- package/dist/mcp-content/getting-started.js.map +1 -0
- package/dist/mcp-content/overview.d.ts +2 -0
- package/dist/mcp-content/overview.d.ts.map +1 -0
- package/dist/mcp-content/overview.js +120 -0
- package/dist/mcp-content/overview.js.map +1 -0
- package/dist/mcp-content/schemas/blog.d.ts +2 -0
- package/dist/mcp-content/schemas/blog.d.ts.map +1 -0
- package/dist/mcp-content/schemas/blog.js +223 -0
- package/dist/mcp-content/schemas/blog.js.map +1 -0
- package/dist/mcp-content/schemas/ecommerce.d.ts +2 -0
- package/dist/mcp-content/schemas/ecommerce.d.ts.map +1 -0
- package/dist/mcp-content/schemas/ecommerce.js +436 -0
- package/dist/mcp-content/schemas/ecommerce.js.map +1 -0
- package/dist/mcp-content/schemas/social.d.ts +2 -0
- package/dist/mcp-content/schemas/social.d.ts.map +1 -0
- package/dist/mcp-content/schemas/social.js +339 -0
- package/dist/mcp-content/schemas/social.js.map +1 -0
- package/dist/mcp-content/schemas/todo.d.ts +2 -0
- package/dist/mcp-content/schemas/todo.d.ts.map +1 -0
- package/dist/mcp-content/schemas/todo.js +172 -0
- package/dist/mcp-content/schemas/todo.js.map +1 -0
- package/dist/mod.d.ts +2 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +2 -0
- package/dist/mod.js.map +1 -0
- package/dist/test-tool.d.ts +2 -0
- package/dist/test-tool.d.ts.map +1 -0
- package/dist/test-tool.js +57 -0
- package/dist/test-tool.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +27 -0
- package/src/cli.ts +35 -0
- package/src/commands/mcp-coach.ts +121 -0
- package/src/commands/mcp-tools.ts +169 -0
- package/src/commands/mcp.ts +97 -0
- package/src/commands/new-project.ts +263 -0
- package/src/mcp-content/architecture.ts +170 -0
- package/src/mcp-content/features.ts +176 -0
- package/src/mcp-content/getting-started.ts +404 -0
- package/src/mcp-content/overview.ts +119 -0
- package/src/mcp-content/schemas/blog.ts +222 -0
- package/src/mcp-content/schemas/ecommerce.ts +435 -0
- package/src/mcp-content/schemas/social.ts +338 -0
- package/src/mcp-content/schemas/todo.ts +171 -0
- package/src/mod.ts +1 -0
- package/tsconfig.json +9 -0
@@ -0,0 +1,120 @@
|
|
1
|
+
export const overviewContent = `# LiveStore: Local-First Data Platform
|
2
|
+
|
3
|
+
LiveStore is a production-ready local-first data platform that combines the immediate responsiveness of local SQLite databases with the collaborative power of real-time synchronization. Built on distributed systems principles from Martin Kleppmann's research, LiveStore enables applications that work seamlessly offline and sync reliably when online.
|
4
|
+
|
5
|
+
## Core Philosophy
|
6
|
+
|
7
|
+
**Local-First Principles**: Your data lives primarily on your device, not in the cloud. Applications respond immediately to user actions without network round-trips, providing the smooth experience users expect from native applications.
|
8
|
+
|
9
|
+
**Collaborative by Design**: Real-time collaboration isn't an afterthought – it's built into the foundation. Multiple users can work together seamlessly with automatic conflict resolution and eventual consistency guarantees.
|
10
|
+
|
11
|
+
**Reliability Through Event Sourcing**: All changes are captured as immutable events, providing a complete audit trail and enabling powerful features like undo/redo, time travel debugging, and deterministic testing.
|
12
|
+
|
13
|
+
## What Makes LiveStore Different
|
14
|
+
|
15
|
+
### 💾 Local SQLite Performance
|
16
|
+
- **Sub-millisecond queries** from local SQLite database
|
17
|
+
- **Complex joins and aggregations** with full SQL expressiveness
|
18
|
+
- **Reactive queries** that automatically update your UI
|
19
|
+
- **ACID transactions** for data integrity
|
20
|
+
|
21
|
+
### 🌐 Distributed Systems Reliability
|
22
|
+
- **Conflict-free synchronization** using CRDT-inspired merge strategies
|
23
|
+
- **Causal consistency** with vector clocks and event ordering
|
24
|
+
- **Network partition tolerance** – works offline, syncs when online
|
25
|
+
- **Eventually consistent** convergence across all replicas
|
26
|
+
|
27
|
+
### 🔐 End-to-End Type Safety
|
28
|
+
- **Schema-first development** with Effect-based validation
|
29
|
+
- **Compile-time query validation** prevents runtime errors
|
30
|
+
- **Automatic TypeScript generation** from schema definitions
|
31
|
+
- **Runtime safety** with comprehensive input validation
|
32
|
+
|
33
|
+
### 🏗️ Framework Agnostic
|
34
|
+
- **React, Vue, Solid, Svelte** – use with any frontend framework
|
35
|
+
- **Web, Node.js, React Native** – deploy anywhere JavaScript runs
|
36
|
+
- **Consistent API** across all platforms and frameworks
|
37
|
+
|
38
|
+
## Real-World Use Cases
|
39
|
+
|
40
|
+
### 📝 Collaborative Applications
|
41
|
+
- **Document editors** with real-time collaboration (Google Docs-style)
|
42
|
+
- **Project management** tools with team coordination
|
43
|
+
- **Design tools** with multiplayer editing capabilities
|
44
|
+
- **Chat applications** with offline message queuing
|
45
|
+
|
46
|
+
### 📱 Mobile-First Applications
|
47
|
+
- **Field service apps** that work in areas with poor connectivity
|
48
|
+
- **Healthcare applications** with sensitive data that must stay local
|
49
|
+
- **Educational apps** for students in low-connectivity environments
|
50
|
+
- **Financial apps** requiring immediate transaction feedback
|
51
|
+
|
52
|
+
### 🏮 Enterprise Applications
|
53
|
+
- **CRM systems** with offline sales capability
|
54
|
+
- **Inventory management** with real-time stock updates
|
55
|
+
- **Customer service** tools with offline case management
|
56
|
+
- **Analytics dashboards** with local data caching
|
57
|
+
|
58
|
+
## Architecture at a Glance
|
59
|
+
|
60
|
+
\`\`\`mermaid
|
61
|
+
graph TB
|
62
|
+
UI[UI Framework] --> Queries[Reactive Queries]
|
63
|
+
UI --> Events[Event Dispatch]
|
64
|
+
|
65
|
+
Events --> EventLog[Event Log]
|
66
|
+
EventLog --> Materializers[Materializers]
|
67
|
+
Materializers --> SQLite[SQLite Database]
|
68
|
+
Queries --> SQLite
|
69
|
+
|
70
|
+
EventLog --> Sync[Sync Engine]
|
71
|
+
Sync --> Network[Network Layer]
|
72
|
+
Network --> Server[Sync Server]
|
73
|
+
|
74
|
+
Server --> OtherClients[Other Clients]
|
75
|
+
OtherClients --> Server
|
76
|
+
Server --> Network
|
77
|
+
\`\`\`
|
78
|
+
|
79
|
+
1. **UI Layer**: Framework-specific bindings (React, Vue, etc.)
|
80
|
+
2. **Query Layer**: Reactive SQL queries with automatic UI updates
|
81
|
+
3. **Event Layer**: Immutable event log with schema validation
|
82
|
+
4. **Materialization**: Events applied to SQLite tables via materializers
|
83
|
+
5. **Synchronization**: Conflict-free replication across devices/users
|
84
|
+
6. **Storage**: Local SQLite database for immediate data access
|
85
|
+
|
86
|
+
## Key Technical Innovations
|
87
|
+
|
88
|
+
### Event-Driven State Management
|
89
|
+
Unlike traditional ORMs that hide change tracking, LiveStore makes all state changes explicit through events. This provides:
|
90
|
+
- **Deterministic state updates** that can be tested and debugged
|
91
|
+
- **Conflict resolution** through event reordering and semantic merging
|
92
|
+
- **Time travel** capabilities for debugging and feature development
|
93
|
+
- **Audit trails** for compliance and data governance
|
94
|
+
|
95
|
+
### Sophisticated Conflict Resolution
|
96
|
+
LiveStore handles conflicts intelligently using multiple strategies:
|
97
|
+
- **Last-Write-Wins**: Simple timestamp-based resolution
|
98
|
+
- **Semantic Merging**: Application-specific conflict resolution logic
|
99
|
+
- **Operational Transforms**: For real-time collaborative text editing
|
100
|
+
- **CRDT Integration**: Conflict-free data types for specific use cases
|
101
|
+
|
102
|
+
### Performance Optimization
|
103
|
+
- **Query compilation caching** for repeated queries
|
104
|
+
- **Reactive dependency tracking** to minimize unnecessary updates
|
105
|
+
- **Incremental synchronization** to reduce network overhead
|
106
|
+
- **Background processing** to keep the UI thread responsive
|
107
|
+
|
108
|
+
## Production Ready
|
109
|
+
|
110
|
+
LiveStore is designed for production applications with enterprise-grade requirements:
|
111
|
+
|
112
|
+
- **Security**: End-to-end encryption, event signatures, access control
|
113
|
+
- **Observability**: Distributed tracing, performance monitoring, health checks
|
114
|
+
- **Scalability**: Horizontal scaling, connection pooling, data partitioning
|
115
|
+
- **Reliability**: Automatic retries, circuit breakers, graceful degradation
|
116
|
+
|
117
|
+
Whether you're building a simple todo app or a complex collaborative platform, LiveStore provides the foundation for applications that users love – fast, reliable, and always available.
|
118
|
+
|
119
|
+
**Ready to get started?** Check out our [Getting Started Guide](./getting-started) or explore our [Example Applications](https://github.com/livestorejs/examples).`;
|
120
|
+
//# sourceMappingURL=overview.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"overview.js","sourceRoot":"","sources":["../../src/mcp-content/overview.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mKAsHoI,CAAA"}
|
@@ -0,0 +1,2 @@
|
|
1
|
+
export declare const blogSchemaContent = "import { Events, makeSchema, Schema, SessionIdSymbol, State } from '@livestore/livestore'\n\n// Content management with collaborative editing capabilities\nexport const tables = {\n posts: State.SQLite.table({\n name: 'posts',\n columns: {\n id: State.SQLite.text({ primaryKey: true }),\n title: State.SQLite.text(),\n content: State.SQLite.text(), // Consider using JSON for rich text operations\n slug: State.SQLite.text(),\n published: State.SQLite.boolean({ default: false }),\n authorId: State.SQLite.text(),\n createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),\n publishedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),\n deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),\n version: State.SQLite.integer({ default: 1 }), // For optimistic concurrency\n },\n }),\n \n comments: State.SQLite.table({\n name: 'comments',\n columns: {\n id: State.SQLite.text({ primaryKey: true }),\n postId: State.SQLite.text(),\n authorId: State.SQLite.text(),\n content: State.SQLite.text(),\n parentId: State.SQLite.text({ nullable: true }), // For threaded comments\n createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),\n editedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),\n deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),\n },\n }),\n \n authors: State.SQLite.table({\n name: 'authors',\n columns: {\n id: State.SQLite.text({ primaryKey: true }),\n name: State.SQLite.text(),\n email: State.SQLite.text(),\n bio: State.SQLite.text({ nullable: true }),\n avatarUrl: State.SQLite.text({ nullable: true }),\n createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),\n },\n }),\n \n // Track collaborative editing sessions\n editingSessions: State.SQLite.clientDocument({\n name: 'editingSessions',\n schema: Schema.Struct({\n postId: Schema.String,\n authorId: Schema.String,\n lastActivity: Schema.Date,\n cursorPosition: Schema.Number,\n }),\n default: { \n id: SessionIdSymbol, \n value: { postId: '', authorId: '', lastActivity: new Date(), cursorPosition: 0 }\n },\n }),\n}\n\nexport const events = {\n // Post lifecycle events\n postCreated: Events.synced({\n name: 'v1.PostCreated',\n schema: Schema.Struct({\n id: Schema.String,\n title: Schema.String,\n slug: Schema.String,\n authorId: Schema.String,\n createdAt: Schema.Date,\n }),\n }),\n \n postTitleChanged: Events.synced({\n name: 'v1.PostTitleChanged',\n schema: Schema.Struct({\n id: Schema.String,\n title: Schema.String,\n version: Schema.Number, // Optimistic concurrency control\n }),\n }),\n \n postContentChanged: Events.synced({\n name: 'v1.PostContentChanged',\n schema: Schema.Struct({\n id: Schema.String,\n content: Schema.String,\n version: Schema.Number,\n authorId: Schema.String,\n }),\n }),\n \n postPublished: Events.synced({\n name: 'v1.PostPublished',\n schema: Schema.Struct({\n id: Schema.String,\n publishedAt: Schema.Date,\n }),\n }),\n \n postUnpublished: Events.synced({\n name: 'v1.PostUnpublished',\n schema: Schema.Struct({ id: Schema.String }),\n }),\n \n postDeleted: Events.synced({\n name: 'v1.PostDeleted',\n schema: Schema.Struct({\n id: Schema.String,\n deletedAt: Schema.Date,\n }),\n }),\n \n // Comment events\n commentCreated: Events.synced({\n name: 'v1.CommentCreated',\n schema: Schema.Struct({\n id: Schema.String,\n postId: Schema.String,\n authorId: Schema.String,\n content: Schema.String,\n parentId: Schema.NullOr(Schema.String),\n createdAt: Schema.Date,\n }),\n }),\n \n commentEdited: Events.synced({\n name: 'v1.CommentEdited',\n schema: Schema.Struct({\n id: Schema.String,\n content: Schema.String,\n editedAt: Schema.Date,\n }),\n }),\n \n commentDeleted: Events.synced({\n name: 'v1.CommentDeleted',\n schema: Schema.Struct({\n id: Schema.String,\n deletedAt: Schema.Date,\n }),\n }),\n \n // Author events\n authorCreated: Events.synced({\n name: 'v1.AuthorCreated',\n schema: Schema.Struct({\n id: Schema.String,\n name: Schema.String,\n email: Schema.String,\n createdAt: Schema.Date,\n }),\n }),\n \n // Local editing session tracking\n editingSessionUpdated: tables.editingSessions.set,\n}\n\n// Materializers with conflict resolution strategies\nconst materializers = State.SQLite.materializers(events, {\n // Post materializers\n 'v1.PostCreated': ({ id, title, slug, authorId, createdAt }) =>\n tables.posts.insert({ id, title, content: '', slug, authorId, createdAt, version: 1 }),\n \n 'v1.PostTitleChanged': ({ id, title, version }) =>\n // Last-write-wins with version check for optimistic concurrency\n tables.posts.update({ title, version }).where({ id }),\n \n 'v1.PostContentChanged': ({ id, content, version, authorId }) =>\n tables.posts.update({ content, version }).where({ id }),\n \n 'v1.PostPublished': ({ id, publishedAt }) =>\n tables.posts.update({ published: true, publishedAt }).where({ id }),\n \n 'v1.PostUnpublished': ({ id }) =>\n tables.posts.update({ published: false, publishedAt: null }).where({ id }),\n \n 'v1.PostDeleted': ({ id, deletedAt }) =>\n tables.posts.update({ deletedAt }).where({ id }),\n \n // Comment materializers\n 'v1.CommentCreated': ({ id, postId, authorId, content, parentId, createdAt }) =>\n tables.comments.insert({ id, postId, authorId, content, parentId, createdAt }),\n \n 'v1.CommentEdited': ({ id, content, editedAt }) =>\n tables.comments.update({ content, editedAt }).where({ id }),\n \n 'v1.CommentDeleted': ({ id, deletedAt }) =>\n tables.comments.update({ deletedAt }).where({ id }),\n \n // Author materializers\n 'v1.AuthorCreated': ({ id, name, email, createdAt }) =>\n tables.authors.insert({ id, name, email, createdAt }),\n})\n\nconst state = State.SQLite.makeState({ tables, materializers })\n\nexport const schema = makeSchema({ events, state })\n\n// Example queries:\n//\n// // Published posts with author info\n// const publishedPosts$ = queryDb(\n// tables.posts\n// .select()\n// .join(tables.authors, 'authorId', 'id')\n// .where({ published: true, deletedAt: null })\n// .orderBy('publishedAt', 'desc'),\n// { label: 'publishedPosts' }\n// )\n//\n// // Comments for a post (threaded)\n// const postComments$ = (postId: string) => queryDb(\n// tables.comments\n// .select()\n// .join(tables.authors, 'authorId', 'id') \n// .where({ postId, deletedAt: null })\n// .orderBy('createdAt'),\n// { label: `postComments-${postId}` }\n// )";
|
2
|
+
//# sourceMappingURL=blog.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"blog.d.ts","sourceRoot":"","sources":["../../../src/mcp-content/schemas/blog.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,w1NA6NzB,CAAA"}
|
@@ -0,0 +1,223 @@
|
|
1
|
+
export const blogSchemaContent = `import { Events, makeSchema, Schema, SessionIdSymbol, State } from '@livestore/livestore'
|
2
|
+
|
3
|
+
// Content management with collaborative editing capabilities
|
4
|
+
export const tables = {
|
5
|
+
posts: State.SQLite.table({
|
6
|
+
name: 'posts',
|
7
|
+
columns: {
|
8
|
+
id: State.SQLite.text({ primaryKey: true }),
|
9
|
+
title: State.SQLite.text(),
|
10
|
+
content: State.SQLite.text(), // Consider using JSON for rich text operations
|
11
|
+
slug: State.SQLite.text(),
|
12
|
+
published: State.SQLite.boolean({ default: false }),
|
13
|
+
authorId: State.SQLite.text(),
|
14
|
+
createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),
|
15
|
+
publishedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
|
16
|
+
deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
|
17
|
+
version: State.SQLite.integer({ default: 1 }), // For optimistic concurrency
|
18
|
+
},
|
19
|
+
}),
|
20
|
+
|
21
|
+
comments: State.SQLite.table({
|
22
|
+
name: 'comments',
|
23
|
+
columns: {
|
24
|
+
id: State.SQLite.text({ primaryKey: true }),
|
25
|
+
postId: State.SQLite.text(),
|
26
|
+
authorId: State.SQLite.text(),
|
27
|
+
content: State.SQLite.text(),
|
28
|
+
parentId: State.SQLite.text({ nullable: true }), // For threaded comments
|
29
|
+
createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),
|
30
|
+
editedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
|
31
|
+
deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
|
32
|
+
},
|
33
|
+
}),
|
34
|
+
|
35
|
+
authors: State.SQLite.table({
|
36
|
+
name: 'authors',
|
37
|
+
columns: {
|
38
|
+
id: State.SQLite.text({ primaryKey: true }),
|
39
|
+
name: State.SQLite.text(),
|
40
|
+
email: State.SQLite.text(),
|
41
|
+
bio: State.SQLite.text({ nullable: true }),
|
42
|
+
avatarUrl: State.SQLite.text({ nullable: true }),
|
43
|
+
createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),
|
44
|
+
},
|
45
|
+
}),
|
46
|
+
|
47
|
+
// Track collaborative editing sessions
|
48
|
+
editingSessions: State.SQLite.clientDocument({
|
49
|
+
name: 'editingSessions',
|
50
|
+
schema: Schema.Struct({
|
51
|
+
postId: Schema.String,
|
52
|
+
authorId: Schema.String,
|
53
|
+
lastActivity: Schema.Date,
|
54
|
+
cursorPosition: Schema.Number,
|
55
|
+
}),
|
56
|
+
default: {
|
57
|
+
id: SessionIdSymbol,
|
58
|
+
value: { postId: '', authorId: '', lastActivity: new Date(), cursorPosition: 0 }
|
59
|
+
},
|
60
|
+
}),
|
61
|
+
}
|
62
|
+
|
63
|
+
export const events = {
|
64
|
+
// Post lifecycle events
|
65
|
+
postCreated: Events.synced({
|
66
|
+
name: 'v1.PostCreated',
|
67
|
+
schema: Schema.Struct({
|
68
|
+
id: Schema.String,
|
69
|
+
title: Schema.String,
|
70
|
+
slug: Schema.String,
|
71
|
+
authorId: Schema.String,
|
72
|
+
createdAt: Schema.Date,
|
73
|
+
}),
|
74
|
+
}),
|
75
|
+
|
76
|
+
postTitleChanged: Events.synced({
|
77
|
+
name: 'v1.PostTitleChanged',
|
78
|
+
schema: Schema.Struct({
|
79
|
+
id: Schema.String,
|
80
|
+
title: Schema.String,
|
81
|
+
version: Schema.Number, // Optimistic concurrency control
|
82
|
+
}),
|
83
|
+
}),
|
84
|
+
|
85
|
+
postContentChanged: Events.synced({
|
86
|
+
name: 'v1.PostContentChanged',
|
87
|
+
schema: Schema.Struct({
|
88
|
+
id: Schema.String,
|
89
|
+
content: Schema.String,
|
90
|
+
version: Schema.Number,
|
91
|
+
authorId: Schema.String,
|
92
|
+
}),
|
93
|
+
}),
|
94
|
+
|
95
|
+
postPublished: Events.synced({
|
96
|
+
name: 'v1.PostPublished',
|
97
|
+
schema: Schema.Struct({
|
98
|
+
id: Schema.String,
|
99
|
+
publishedAt: Schema.Date,
|
100
|
+
}),
|
101
|
+
}),
|
102
|
+
|
103
|
+
postUnpublished: Events.synced({
|
104
|
+
name: 'v1.PostUnpublished',
|
105
|
+
schema: Schema.Struct({ id: Schema.String }),
|
106
|
+
}),
|
107
|
+
|
108
|
+
postDeleted: Events.synced({
|
109
|
+
name: 'v1.PostDeleted',
|
110
|
+
schema: Schema.Struct({
|
111
|
+
id: Schema.String,
|
112
|
+
deletedAt: Schema.Date,
|
113
|
+
}),
|
114
|
+
}),
|
115
|
+
|
116
|
+
// Comment events
|
117
|
+
commentCreated: Events.synced({
|
118
|
+
name: 'v1.CommentCreated',
|
119
|
+
schema: Schema.Struct({
|
120
|
+
id: Schema.String,
|
121
|
+
postId: Schema.String,
|
122
|
+
authorId: Schema.String,
|
123
|
+
content: Schema.String,
|
124
|
+
parentId: Schema.NullOr(Schema.String),
|
125
|
+
createdAt: Schema.Date,
|
126
|
+
}),
|
127
|
+
}),
|
128
|
+
|
129
|
+
commentEdited: Events.synced({
|
130
|
+
name: 'v1.CommentEdited',
|
131
|
+
schema: Schema.Struct({
|
132
|
+
id: Schema.String,
|
133
|
+
content: Schema.String,
|
134
|
+
editedAt: Schema.Date,
|
135
|
+
}),
|
136
|
+
}),
|
137
|
+
|
138
|
+
commentDeleted: Events.synced({
|
139
|
+
name: 'v1.CommentDeleted',
|
140
|
+
schema: Schema.Struct({
|
141
|
+
id: Schema.String,
|
142
|
+
deletedAt: Schema.Date,
|
143
|
+
}),
|
144
|
+
}),
|
145
|
+
|
146
|
+
// Author events
|
147
|
+
authorCreated: Events.synced({
|
148
|
+
name: 'v1.AuthorCreated',
|
149
|
+
schema: Schema.Struct({
|
150
|
+
id: Schema.String,
|
151
|
+
name: Schema.String,
|
152
|
+
email: Schema.String,
|
153
|
+
createdAt: Schema.Date,
|
154
|
+
}),
|
155
|
+
}),
|
156
|
+
|
157
|
+
// Local editing session tracking
|
158
|
+
editingSessionUpdated: tables.editingSessions.set,
|
159
|
+
}
|
160
|
+
|
161
|
+
// Materializers with conflict resolution strategies
|
162
|
+
const materializers = State.SQLite.materializers(events, {
|
163
|
+
// Post materializers
|
164
|
+
'v1.PostCreated': ({ id, title, slug, authorId, createdAt }) =>
|
165
|
+
tables.posts.insert({ id, title, content: '', slug, authorId, createdAt, version: 1 }),
|
166
|
+
|
167
|
+
'v1.PostTitleChanged': ({ id, title, version }) =>
|
168
|
+
// Last-write-wins with version check for optimistic concurrency
|
169
|
+
tables.posts.update({ title, version }).where({ id }),
|
170
|
+
|
171
|
+
'v1.PostContentChanged': ({ id, content, version, authorId }) =>
|
172
|
+
tables.posts.update({ content, version }).where({ id }),
|
173
|
+
|
174
|
+
'v1.PostPublished': ({ id, publishedAt }) =>
|
175
|
+
tables.posts.update({ published: true, publishedAt }).where({ id }),
|
176
|
+
|
177
|
+
'v1.PostUnpublished': ({ id }) =>
|
178
|
+
tables.posts.update({ published: false, publishedAt: null }).where({ id }),
|
179
|
+
|
180
|
+
'v1.PostDeleted': ({ id, deletedAt }) =>
|
181
|
+
tables.posts.update({ deletedAt }).where({ id }),
|
182
|
+
|
183
|
+
// Comment materializers
|
184
|
+
'v1.CommentCreated': ({ id, postId, authorId, content, parentId, createdAt }) =>
|
185
|
+
tables.comments.insert({ id, postId, authorId, content, parentId, createdAt }),
|
186
|
+
|
187
|
+
'v1.CommentEdited': ({ id, content, editedAt }) =>
|
188
|
+
tables.comments.update({ content, editedAt }).where({ id }),
|
189
|
+
|
190
|
+
'v1.CommentDeleted': ({ id, deletedAt }) =>
|
191
|
+
tables.comments.update({ deletedAt }).where({ id }),
|
192
|
+
|
193
|
+
// Author materializers
|
194
|
+
'v1.AuthorCreated': ({ id, name, email, createdAt }) =>
|
195
|
+
tables.authors.insert({ id, name, email, createdAt }),
|
196
|
+
})
|
197
|
+
|
198
|
+
const state = State.SQLite.makeState({ tables, materializers })
|
199
|
+
|
200
|
+
export const schema = makeSchema({ events, state })
|
201
|
+
|
202
|
+
// Example queries:
|
203
|
+
//
|
204
|
+
// // Published posts with author info
|
205
|
+
// const publishedPosts$ = queryDb(
|
206
|
+
// tables.posts
|
207
|
+
// .select()
|
208
|
+
// .join(tables.authors, 'authorId', 'id')
|
209
|
+
// .where({ published: true, deletedAt: null })
|
210
|
+
// .orderBy('publishedAt', 'desc'),
|
211
|
+
// { label: 'publishedPosts' }
|
212
|
+
// )
|
213
|
+
//
|
214
|
+
// // Comments for a post (threaded)
|
215
|
+
// const postComments$ = (postId: string) => queryDb(
|
216
|
+
// tables.comments
|
217
|
+
// .select()
|
218
|
+
// .join(tables.authors, 'authorId', 'id')
|
219
|
+
// .where({ postId, deletedAt: null })
|
220
|
+
// .orderBy('createdAt'),
|
221
|
+
// { label: \`postComments-\${postId}\` }
|
222
|
+
// )`;
|
223
|
+
//# sourceMappingURL=blog.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"blog.js","sourceRoot":"","sources":["../../../src/mcp-content/schemas/blog.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA6N5B,CAAA"}
|
@@ -0,0 +1,2 @@
|
|
1
|
+
export declare const ecommerceSchemaContent = "import { Events, makeSchema, Schema, SessionIdSymbol, State } from '@livestore/livestore'\n\n// E-commerce with inventory management and order processing\nexport const tables = {\n products: State.SQLite.table({\n name: 'products',\n columns: {\n id: State.SQLite.text({ primaryKey: true }),\n sku: State.SQLite.text(),\n name: State.SQLite.text(),\n description: State.SQLite.text(),\n price: State.SQLite.integer(), // Store as cents to avoid floating point issues\n currency: State.SQLite.text({ default: 'USD' }),\n stock: State.SQLite.integer({ default: 0 }),\n reservedStock: State.SQLite.integer({ default: 0 }), // For pending orders\n isActive: State.SQLite.boolean({ default: true }),\n weight: State.SQLite.real({ nullable: true }), // For shipping calculations\n dimensions: State.SQLite.text({ nullable: true }), // JSON: {width, height, depth}\n imageUrls: State.SQLite.text({ nullable: true }), // JSON array\n createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),\n updatedAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),\n deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),\n },\n }),\n \n categories: State.SQLite.table({\n name: 'categories',\n columns: {\n id: State.SQLite.text({ primaryKey: true }),\n name: State.SQLite.text(),\n slug: State.SQLite.text(),\n parentId: State.SQLite.text({ nullable: true }), // For hierarchical categories\n description: State.SQLite.text({ nullable: true }),\n imageUrl: State.SQLite.text({ nullable: true }),\n sortOrder: State.SQLite.integer({ default: 0 }),\n isActive: State.SQLite.boolean({ default: true }),\n createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),\n },\n }),\n \n productCategories: State.SQLite.table({\n name: 'product_categories',\n columns: {\n productId: State.SQLite.text(),\n categoryId: State.SQLite.text(),\n createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),\n },\n }),\n \n customers: State.SQLite.table({\n name: 'customers',\n columns: {\n id: State.SQLite.text({ primaryKey: true }),\n email: State.SQLite.text(),\n firstName: State.SQLite.text({ nullable: true }),\n lastName: State.SQLite.text({ nullable: true }),\n phone: State.SQLite.text({ nullable: true }),\n createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),\n lastOrderAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),\n },\n }),\n \n addresses: State.SQLite.table({\n name: 'addresses',\n columns: {\n id: State.SQLite.text({ primaryKey: true }),\n customerId: State.SQLite.text(),\n type: State.SQLite.text({ default: 'shipping' }), // shipping, billing\n firstName: State.SQLite.text(),\n lastName: State.SQLite.text(),\n company: State.SQLite.text({ nullable: true }),\n address1: State.SQLite.text(),\n address2: State.SQLite.text({ nullable: true }),\n city: State.SQLite.text(),\n state: State.SQLite.text(),\n country: State.SQLite.text(),\n postalCode: State.SQLite.text(),\n isDefault: State.SQLite.boolean({ default: false }),\n },\n }),\n \n orders: State.SQLite.table({\n name: 'orders',\n columns: {\n id: State.SQLite.text({ primaryKey: true }),\n orderNumber: State.SQLite.text(), // Human-readable order number\n customerId: State.SQLite.text(),\n status: State.SQLite.text({ default: 'draft' }), // draft, pending, paid, processing, shipped, delivered, cancelled\n paymentStatus: State.SQLite.text({ default: 'pending' }), // pending, paid, failed, refunded\n fulfillmentStatus: State.SQLite.text({ default: 'unfulfilled' }), // unfulfilled, partial, fulfilled\n \n subtotal: State.SQLite.integer(), // In cents\n taxAmount: State.SQLite.integer({ default: 0 }),\n shippingAmount: State.SQLite.integer({ default: 0 }),\n discountAmount: State.SQLite.integer({ default: 0 }),\n total: State.SQLite.integer(),\n currency: State.SQLite.text({ default: 'USD' }),\n \n shippingAddress: State.SQLite.text(), // JSON\n billingAddress: State.SQLite.text(), // JSON\n \n notes: State.SQLite.text({ nullable: true }),\n \n createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),\n updatedAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),\n cancelledAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),\n shippedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),\n deliveredAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),\n },\n }),\n \n orderItems: State.SQLite.table({\n name: 'order_items',\n columns: {\n id: State.SQLite.text({ primaryKey: true }),\n orderId: State.SQLite.text(),\n productId: State.SQLite.text(),\n variantId: State.SQLite.text({ nullable: true }),\n sku: State.SQLite.text(), // Snapshot at time of order\n name: State.SQLite.text(), // Product name at time of order\n quantity: State.SQLite.integer(),\n unitPrice: State.SQLite.integer(), // Price per unit in cents\n totalPrice: State.SQLite.integer(), // quantity * unitPrice\n fulfillmentStatus: State.SQLite.text({ default: 'unfulfilled' }),\n },\n }),\n \n // Inventory tracking with event sourcing\n inventoryEvents: State.SQLite.table({\n name: 'inventory_events',\n columns: {\n id: State.SQLite.text({ primaryKey: true }),\n productId: State.SQLite.text(),\n type: State.SQLite.text(), // 'adjustment', 'sale', 'return', 'damage', 'restock'\n quantity: State.SQLite.integer(), // Can be positive or negative\n reason: State.SQLite.text({ nullable: true }),\n referenceId: State.SQLite.text({ nullable: true }), // Order ID, adjustment ID, etc.\n createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),\n },\n }),\n \n // Shopping cart (client-side state)\n cart: State.SQLite.clientDocument({\n name: 'cart',\n schema: Schema.Struct({\n items: Schema.Array(Schema.Struct({\n productId: Schema.String,\n quantity: Schema.Number,\n addedAt: Schema.Date,\n })),\n discountCode: Schema.NullOr(Schema.String),\n notes: Schema.String,\n }),\n default: { \n id: SessionIdSymbol, \n value: { items: [], discountCode: null, notes: '' }\n },\n }),\n}\n\nexport const events = {\n // Product management\n productCreated: Events.synced({\n name: 'v1.ProductCreated',\n schema: Schema.Struct({\n id: Schema.String,\n sku: Schema.String,\n name: Schema.String,\n description: Schema.String,\n price: Schema.Number, // In cents\n currency: Schema.String,\n createdAt: Schema.Date,\n }),\n }),\n \n productUpdated: Events.synced({\n name: 'v1.ProductUpdated',\n schema: Schema.Struct({\n id: Schema.String,\n name: Schema.NullOr(Schema.String),\n description: Schema.NullOr(Schema.String),\n price: Schema.NullOr(Schema.Number),\n updatedAt: Schema.Date,\n }),\n }),\n \n productStockAdjusted: Events.synced({\n name: 'v1.ProductStockAdjusted',\n schema: Schema.Struct({\n productId: Schema.String,\n adjustment: Schema.Number, // Can be positive or negative\n reason: Schema.String,\n referenceId: Schema.NullOr(Schema.String),\n createdAt: Schema.Date,\n }),\n }),\n \n productDeactivated: Events.synced({\n name: 'v1.ProductDeactivated',\n schema: Schema.Struct({ id: Schema.String }),\n }),\n \n // Customer management\n customerCreated: Events.synced({\n name: 'v1.CustomerCreated',\n schema: Schema.Struct({\n id: Schema.String,\n email: Schema.String,\n firstName: Schema.NullOr(Schema.String),\n lastName: Schema.NullOr(Schema.String),\n createdAt: Schema.Date,\n }),\n }),\n \n // Order lifecycle with state machine\n orderCreated: Events.synced({\n name: 'v1.OrderCreated',\n schema: Schema.Struct({\n id: Schema.String,\n orderNumber: Schema.String,\n customerId: Schema.String,\n items: Schema.Array(Schema.Struct({\n productId: Schema.String,\n sku: Schema.String,\n name: Schema.String,\n quantity: Schema.Number,\n unitPrice: Schema.Number,\n })),\n subtotal: Schema.Number,\n total: Schema.Number,\n shippingAddress: Schema.Object,\n billingAddress: Schema.Object,\n createdAt: Schema.Date,\n }),\n }),\n \n orderPaymentReceived: Events.synced({\n name: 'v1.OrderPaymentReceived',\n schema: Schema.Struct({\n orderId: Schema.String,\n amount: Schema.Number,\n paymentMethod: Schema.String,\n transactionId: Schema.String,\n paidAt: Schema.Date,\n }),\n }),\n \n orderShipped: Events.synced({\n name: 'v1.OrderShipped',\n schema: Schema.Struct({\n orderId: Schema.String,\n trackingNumber: Schema.NullOr(Schema.String),\n carrier: Schema.NullOr(Schema.String),\n shippedAt: Schema.Date,\n }),\n }),\n \n orderDelivered: Events.synced({\n name: 'v1.OrderDelivered',\n schema: Schema.Struct({\n orderId: Schema.String,\n deliveredAt: Schema.Date,\n }),\n }),\n \n orderCancelled: Events.synced({\n name: 'v1.OrderCancelled',\n schema: Schema.Struct({\n orderId: Schema.String,\n reason: Schema.String,\n cancelledAt: Schema.Date,\n }),\n }),\n \n // Cart management (local)\n cartUpdated: tables.cart.set,\n}\n\n// Materializers with business logic and constraints\nconst materializers = State.SQLite.materializers(events, {\n // Product materializers\n 'v1.ProductCreated': ({ id, sku, name, description, price, currency, createdAt }) =>\n tables.products.insert({ id, sku, name, description, price, currency, createdAt, updatedAt: createdAt }),\n \n 'v1.ProductUpdated': ({ id, name, description, price, updatedAt }) =>\n tables.products.update({ \n name: name ?? undefined,\n description: description ?? undefined, \n price: price ?? undefined,\n updatedAt \n }).where({ id }),\n \n 'v1.ProductStockAdjusted': ({ productId, adjustment, reason, referenceId, createdAt }) => [\n // Record the inventory event\n tables.inventoryEvents.insert({ \n id: crypto.randomUUID(),\n productId, \n type: 'adjustment',\n quantity: adjustment, \n reason, \n referenceId, \n createdAt \n }),\n // Update product stock (eventually consistent)\n tables.products.update({ \n stock: Math.max(0, tables.products.select('stock').where({ id: productId }).scalar() + adjustment),\n updatedAt: createdAt\n }).where({ id: productId }),\n ],\n \n 'v1.ProductDeactivated': ({ id }) =>\n tables.products.update({ isActive: false }).where({ id }),\n \n // Customer materializers\n 'v1.CustomerCreated': ({ id, email, firstName, lastName, createdAt }) =>\n tables.customers.insert({ id, email, firstName, lastName, createdAt }),\n \n // Order materializers with inventory reservation\n 'v1.OrderCreated': ({ id, orderNumber, customerId, items, subtotal, total, shippingAddress, billingAddress, createdAt }) => [\n // Create the order\n tables.orders.insert({ \n id, \n orderNumber, \n customerId, \n status: 'pending',\n subtotal, \n total, \n shippingAddress: JSON.stringify(shippingAddress),\n billingAddress: JSON.stringify(billingAddress),\n createdAt, \n updatedAt: createdAt \n }),\n // Create order items and reserve inventory\n ...items.flatMap(item => [\n tables.orderItems.insert({ \n id: crypto.randomUUID(),\n orderId: id,\n productId: item.productId,\n sku: item.sku,\n name: item.name,\n quantity: item.quantity,\n unitPrice: item.unitPrice,\n totalPrice: item.quantity * item.unitPrice,\n }),\n // Reserve stock\n tables.products.update({ \n reservedStock: tables.products.select('reservedStock').where({ id: item.productId }).scalar() + item.quantity\n }).where({ id: item.productId }),\n ]),\n ],\n \n 'v1.OrderPaymentReceived': ({ orderId, amount, paymentMethod, transactionId, paidAt }) =>\n tables.orders.update({ \n status: 'paid', \n paymentStatus: 'paid',\n updatedAt: paidAt \n }).where({ id: orderId }),\n \n 'v1.OrderShipped': ({ orderId, trackingNumber, carrier, shippedAt }) => [\n tables.orders.update({ \n status: 'shipped',\n fulfillmentStatus: 'fulfilled',\n shippedAt,\n updatedAt: shippedAt \n }).where({ id: orderId }),\n // Convert reserved stock to actual stock reduction\n ...tables.orderItems.select().where({ orderId }).map(item => \n tables.products.update({ \n stock: tables.products.select('stock').where({ id: item.productId }).scalar() - item.quantity,\n reservedStock: tables.products.select('reservedStock').where({ id: item.productId }).scalar() - item.quantity\n }).where({ id: item.productId })\n ),\n ],\n \n 'v1.OrderDelivered': ({ orderId, deliveredAt }) =>\n tables.orders.update({ \n status: 'delivered',\n deliveredAt,\n updatedAt: deliveredAt \n }).where({ id: orderId }),\n \n 'v1.OrderCancelled': ({ orderId, reason, cancelledAt }) => [\n tables.orders.update({ \n status: 'cancelled',\n cancelledAt,\n notes: reason,\n updatedAt: cancelledAt \n }).where({ id: orderId }),\n // Release reserved inventory\n ...tables.orderItems.select().where({ orderId }).map(item => \n tables.products.update({ \n reservedStock: Math.max(0, tables.products.select('reservedStock').where({ id: item.productId }).scalar() - item.quantity)\n }).where({ id: item.productId })\n ),\n ],\n})\n\nconst state = State.SQLite.makeState({ tables, materializers })\n\nexport const schema = makeSchema({ events, state })\n\n// Example queries for business intelligence:\n//\n// // Available products with real-time stock\n// const availableProducts$ = queryDb(\n// tables.products\n// .select()\n// .where({ isActive: true, deletedAt: null })\n// .having(tables.products.column('stock').minus(tables.products.column('reservedStock')).gt(0))\n// .orderBy('name'),\n// { label: 'availableProducts' }\n// )\n//\n// // Orders requiring fulfillment\n// const pendingOrders$ = queryDb(\n// tables.orders\n// .select()\n// .join(tables.customers, 'customerId', 'id')\n// .where({ \n// 'orders.status': 'paid',\n// 'orders.fulfillmentStatus': 'unfulfilled'\n// })\n// .orderBy('orders.createdAt'),\n// { label: 'pendingOrders' }\n// )\n//\n// // Low stock alerts\n// const lowStockProducts$ = queryDb(\n// tables.products\n// .select()\n// .where({ isActive: true })\n// .having(tables.products.column('stock').minus(tables.products.column('reservedStock')).lt(10))\n// .orderBy('stock'),\n// { label: 'lowStockProducts' }\n// )";
|
2
|
+
//# sourceMappingURL=ecommerce.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"ecommerce.d.ts","sourceRoot":"","sources":["../../../src/mcp-content/schemas/ecommerce.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,y+dAkb9B,CAAA"}
|