@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.
Files changed (80) hide show
  1. package/.claude/settings.local.json +12 -0
  2. package/LICENSE +201 -0
  3. package/dist/cli +0 -0
  4. package/dist/cli.d.ts +15 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +22 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/mcp-coach.d.ts +15 -0
  9. package/dist/commands/mcp-coach.d.ts.map +1 -0
  10. package/dist/commands/mcp-coach.js +87 -0
  11. package/dist/commands/mcp-coach.js.map +1 -0
  12. package/dist/commands/mcp-tools.d.ts +41 -0
  13. package/dist/commands/mcp-tools.d.ts.map +1 -0
  14. package/dist/commands/mcp-tools.js +148 -0
  15. package/dist/commands/mcp-tools.js.map +1 -0
  16. package/dist/commands/mcp.d.ts +5 -0
  17. package/dist/commands/mcp.d.ts.map +1 -0
  18. package/dist/commands/mcp.js +67 -0
  19. package/dist/commands/mcp.js.map +1 -0
  20. package/dist/commands/new-project.d.ts +34 -0
  21. package/dist/commands/new-project.d.ts.map +1 -0
  22. package/dist/commands/new-project.js +163 -0
  23. package/dist/commands/new-project.js.map +1 -0
  24. package/dist/mcp-content/architecture.d.ts +2 -0
  25. package/dist/mcp-content/architecture.d.ts.map +1 -0
  26. package/dist/mcp-content/architecture.js +171 -0
  27. package/dist/mcp-content/architecture.js.map +1 -0
  28. package/dist/mcp-content/features.d.ts +2 -0
  29. package/dist/mcp-content/features.d.ts.map +1 -0
  30. package/dist/mcp-content/features.js +177 -0
  31. package/dist/mcp-content/features.js.map +1 -0
  32. package/dist/mcp-content/getting-started.d.ts +2 -0
  33. package/dist/mcp-content/getting-started.d.ts.map +1 -0
  34. package/dist/mcp-content/getting-started.js +405 -0
  35. package/dist/mcp-content/getting-started.js.map +1 -0
  36. package/dist/mcp-content/overview.d.ts +2 -0
  37. package/dist/mcp-content/overview.d.ts.map +1 -0
  38. package/dist/mcp-content/overview.js +120 -0
  39. package/dist/mcp-content/overview.js.map +1 -0
  40. package/dist/mcp-content/schemas/blog.d.ts +2 -0
  41. package/dist/mcp-content/schemas/blog.d.ts.map +1 -0
  42. package/dist/mcp-content/schemas/blog.js +223 -0
  43. package/dist/mcp-content/schemas/blog.js.map +1 -0
  44. package/dist/mcp-content/schemas/ecommerce.d.ts +2 -0
  45. package/dist/mcp-content/schemas/ecommerce.d.ts.map +1 -0
  46. package/dist/mcp-content/schemas/ecommerce.js +436 -0
  47. package/dist/mcp-content/schemas/ecommerce.js.map +1 -0
  48. package/dist/mcp-content/schemas/social.d.ts +2 -0
  49. package/dist/mcp-content/schemas/social.d.ts.map +1 -0
  50. package/dist/mcp-content/schemas/social.js +339 -0
  51. package/dist/mcp-content/schemas/social.js.map +1 -0
  52. package/dist/mcp-content/schemas/todo.d.ts +2 -0
  53. package/dist/mcp-content/schemas/todo.d.ts.map +1 -0
  54. package/dist/mcp-content/schemas/todo.js +172 -0
  55. package/dist/mcp-content/schemas/todo.js.map +1 -0
  56. package/dist/mod.d.ts +2 -0
  57. package/dist/mod.d.ts.map +1 -0
  58. package/dist/mod.js +2 -0
  59. package/dist/mod.js.map +1 -0
  60. package/dist/test-tool.d.ts +2 -0
  61. package/dist/test-tool.d.ts.map +1 -0
  62. package/dist/test-tool.js +57 -0
  63. package/dist/test-tool.js.map +1 -0
  64. package/dist/tsconfig.tsbuildinfo +1 -0
  65. package/package.json +27 -0
  66. package/src/cli.ts +35 -0
  67. package/src/commands/mcp-coach.ts +121 -0
  68. package/src/commands/mcp-tools.ts +169 -0
  69. package/src/commands/mcp.ts +97 -0
  70. package/src/commands/new-project.ts +263 -0
  71. package/src/mcp-content/architecture.ts +170 -0
  72. package/src/mcp-content/features.ts +176 -0
  73. package/src/mcp-content/getting-started.ts +404 -0
  74. package/src/mcp-content/overview.ts +119 -0
  75. package/src/mcp-content/schemas/blog.ts +222 -0
  76. package/src/mcp-content/schemas/ecommerce.ts +435 -0
  77. package/src/mcp-content/schemas/social.ts +338 -0
  78. package/src/mcp-content/schemas/todo.ts +171 -0
  79. package/src/mod.ts +1 -0
  80. package/tsconfig.json +9 -0
@@ -0,0 +1,338 @@
1
+ export const socialSchemaContent = `import { Events, makeSchema, Schema, SessionIdSymbol, State } from '@livestore/livestore'
2
+
3
+ // Social network with activity feeds and real-time interactions
4
+ export const tables = {
5
+ users: State.SQLite.table({
6
+ name: 'users',
7
+ columns: {
8
+ id: State.SQLite.text({ primaryKey: true }),
9
+ username: State.SQLite.text(),
10
+ email: State.SQLite.text(),
11
+ displayName: State.SQLite.text(),
12
+ bio: State.SQLite.text({ nullable: true }),
13
+ avatarUrl: State.SQLite.text({ nullable: true }),
14
+ isVerified: State.SQLite.boolean({ default: false }),
15
+ createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),
16
+ lastActiveAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
17
+ // Privacy settings
18
+ isPrivate: State.SQLite.boolean({ default: false }),
19
+ allowsFollowers: State.SQLite.boolean({ default: true }),
20
+ },
21
+ }),
22
+
23
+ posts: State.SQLite.table({
24
+ name: 'posts',
25
+ columns: {
26
+ id: State.SQLite.text({ primaryKey: true }),
27
+ authorId: State.SQLite.text(),
28
+ content: State.SQLite.text(),
29
+ mediaUrls: State.SQLite.text({ nullable: true }), // JSON array of media URLs
30
+ replyToId: State.SQLite.text({ nullable: true }), // For threading
31
+ visibility: State.SQLite.text({ default: 'public' }), // public, followers, private
32
+ createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),
33
+ editedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
34
+ deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
35
+ },
36
+ }),
37
+
38
+ follows: State.SQLite.table({
39
+ name: 'follows',
40
+ columns: {
41
+ followerId: State.SQLite.text(),
42
+ followingId: State.SQLite.text(),
43
+ status: State.SQLite.text({ default: 'active' }), // active, pending, blocked
44
+ createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),
45
+ approvedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
46
+ },
47
+ }),
48
+
49
+ likes: State.SQLite.table({
50
+ name: 'likes',
51
+ columns: {
52
+ userId: State.SQLite.text(),
53
+ postId: State.SQLite.text(),
54
+ createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),
55
+ },
56
+ }),
57
+
58
+ // Aggregate tables for performance (eventually consistent)
59
+ postStats: State.SQLite.table({
60
+ name: 'post_stats',
61
+ columns: {
62
+ postId: State.SQLite.text({ primaryKey: true }),
63
+ likeCount: State.SQLite.integer({ default: 0 }),
64
+ replyCount: State.SQLite.integer({ default: 0 }),
65
+ shareCount: State.SQLite.integer({ default: 0 }),
66
+ lastUpdated: State.SQLite.integer({ schema: Schema.DateFromNumber }),
67
+ },
68
+ }),
69
+
70
+ userStats: State.SQLite.table({
71
+ name: 'user_stats',
72
+ columns: {
73
+ userId: State.SQLite.text({ primaryKey: true }),
74
+ followerCount: State.SQLite.integer({ default: 0 }),
75
+ followingCount: State.SQLite.integer({ default: 0 }),
76
+ postCount: State.SQLite.integer({ default: 0 }),
77
+ lastUpdated: State.SQLite.integer({ schema: Schema.DateFromNumber }),
78
+ },
79
+ }),
80
+
81
+ // Client-side state for UI
82
+ feedState: State.SQLite.clientDocument({
83
+ name: 'feedState',
84
+ schema: Schema.Struct({
85
+ currentFeed: Schema.Literal('home', 'discover', 'following'),
86
+ lastRefresh: Schema.Date,
87
+ scrollPosition: Schema.Number,
88
+ }),
89
+ default: {
90
+ id: SessionIdSymbol,
91
+ value: { currentFeed: 'home', lastRefresh: new Date(), scrollPosition: 0 }
92
+ },
93
+ }),
94
+ }
95
+
96
+ export const events = {
97
+ // User events
98
+ userCreated: Events.synced({
99
+ name: 'v1.UserCreated',
100
+ schema: Schema.Struct({
101
+ id: Schema.String,
102
+ username: Schema.String,
103
+ email: Schema.String,
104
+ displayName: Schema.String,
105
+ createdAt: Schema.Date,
106
+ }),
107
+ }),
108
+
109
+ userProfileUpdated: Events.synced({
110
+ name: 'v1.UserProfileUpdated',
111
+ schema: Schema.Struct({
112
+ id: Schema.String,
113
+ displayName: Schema.NullOr(Schema.String),
114
+ bio: Schema.NullOr(Schema.String),
115
+ avatarUrl: Schema.NullOr(Schema.String),
116
+ }),
117
+ }),
118
+
119
+ userPrivacySettingsChanged: Events.synced({
120
+ name: 'v1.UserPrivacySettingsChanged',
121
+ schema: Schema.Struct({
122
+ id: Schema.String,
123
+ isPrivate: Schema.Boolean,
124
+ allowsFollowers: Schema.Boolean,
125
+ }),
126
+ }),
127
+
128
+ userLastActiveUpdated: Events.synced({
129
+ name: 'v1.UserLastActiveUpdated',
130
+ schema: Schema.Struct({
131
+ id: Schema.String,
132
+ lastActiveAt: Schema.Date,
133
+ }),
134
+ }),
135
+
136
+ // Post events
137
+ postCreated: Events.synced({
138
+ name: 'v1.PostCreated',
139
+ schema: Schema.Struct({
140
+ id: Schema.String,
141
+ authorId: Schema.String,
142
+ content: Schema.String,
143
+ mediaUrls: Schema.NullOr(Schema.Array(Schema.String)),
144
+ replyToId: Schema.NullOr(Schema.String),
145
+ visibility: Schema.Literal('public', 'followers', 'private'),
146
+ createdAt: Schema.Date,
147
+ }),
148
+ }),
149
+
150
+ postEdited: Events.synced({
151
+ name: 'v1.PostEdited',
152
+ schema: Schema.Struct({
153
+ id: Schema.String,
154
+ content: Schema.String,
155
+ editedAt: Schema.Date,
156
+ }),
157
+ }),
158
+
159
+ postDeleted: Events.synced({
160
+ name: 'v1.PostDeleted',
161
+ schema: Schema.Struct({
162
+ id: Schema.String,
163
+ deletedAt: Schema.Date,
164
+ }),
165
+ }),
166
+
167
+ // Social interaction events
168
+ followRequested: Events.synced({
169
+ name: 'v1.FollowRequested',
170
+ schema: Schema.Struct({
171
+ followerId: Schema.String,
172
+ followingId: Schema.String,
173
+ createdAt: Schema.Date,
174
+ }),
175
+ }),
176
+
177
+ followApproved: Events.synced({
178
+ name: 'v1.FollowApproved',
179
+ schema: Schema.Struct({
180
+ followerId: Schema.String,
181
+ followingId: Schema.String,
182
+ approvedAt: Schema.Date,
183
+ }),
184
+ }),
185
+
186
+ unfollowed: Events.synced({
187
+ name: 'v1.Unfollowed',
188
+ schema: Schema.Struct({
189
+ followerId: Schema.String,
190
+ followingId: Schema.String,
191
+ }),
192
+ }),
193
+
194
+ postLiked: Events.synced({
195
+ name: 'v1.PostLiked',
196
+ schema: Schema.Struct({
197
+ userId: Schema.String,
198
+ postId: Schema.String,
199
+ createdAt: Schema.Date,
200
+ }),
201
+ }),
202
+
203
+ postUnliked: Events.synced({
204
+ name: 'v1.PostUnliked',
205
+ schema: Schema.Struct({
206
+ userId: Schema.String,
207
+ postId: Schema.String,
208
+ }),
209
+ }),
210
+
211
+ // Local UI state
212
+ feedStateUpdated: tables.feedState.set,
213
+ }
214
+
215
+ // Materializers with eventual consistency for aggregates
216
+ const materializers = State.SQLite.materializers(events, {
217
+ // User materializers
218
+ 'v1.UserCreated': ({ id, username, email, displayName, createdAt }) => [
219
+ tables.users.insert({ id, username, email, displayName, createdAt }),
220
+ tables.userStats.insert({ userId: id, lastUpdated: createdAt }),
221
+ ],
222
+
223
+ 'v1.UserProfileUpdated': ({ id, displayName, bio, avatarUrl }) =>
224
+ tables.users.update({ displayName, bio, avatarUrl }).where({ id }),
225
+
226
+ 'v1.UserPrivacySettingsChanged': ({ id, isPrivate, allowsFollowers }) =>
227
+ tables.users.update({ isPrivate, allowsFollowers }).where({ id }),
228
+
229
+ 'v1.UserLastActiveUpdated': ({ id, lastActiveAt }) =>
230
+ tables.users.update({ lastActiveAt }).where({ id }),
231
+
232
+ // Post materializers
233
+ 'v1.PostCreated': ({ id, authorId, content, mediaUrls, replyToId, visibility, createdAt }) => [
234
+ tables.posts.insert({
235
+ id,
236
+ authorId,
237
+ content,
238
+ mediaUrls: mediaUrls ? JSON.stringify(mediaUrls) : null,
239
+ replyToId,
240
+ visibility,
241
+ createdAt
242
+ }),
243
+ tables.postStats.insert({ postId: id, lastUpdated: createdAt }),
244
+ // Update user post count
245
+ tables.userStats.update({
246
+ postCount: tables.userStats.select('postCount').where({ userId: authorId }).scalar() + 1,
247
+ lastUpdated: createdAt
248
+ }).where({ userId: authorId }),
249
+ ],
250
+
251
+ 'v1.PostEdited': ({ id, content, editedAt }) =>
252
+ tables.posts.update({ content, editedAt }).where({ id }),
253
+
254
+ 'v1.PostDeleted': ({ id, deletedAt }) =>
255
+ tables.posts.update({ deletedAt }).where({ id }),
256
+
257
+ // Follow materializers
258
+ 'v1.FollowRequested': ({ followerId, followingId, createdAt }) =>
259
+ tables.follows.insert({ followerId, followingId, status: 'pending', createdAt }),
260
+
261
+ 'v1.FollowApproved': ({ followerId, followingId, approvedAt }) => [
262
+ tables.follows.update({ status: 'active', approvedAt }).where({ followerId, followingId }),
263
+ // Update follower counts
264
+ tables.userStats.update({
265
+ followerCount: tables.userStats.select('followerCount').where({ userId: followingId }).scalar() + 1,
266
+ lastUpdated: approvedAt
267
+ }).where({ userId: followingId }),
268
+ tables.userStats.update({
269
+ followingCount: tables.userStats.select('followingCount').where({ userId: followerId }).scalar() + 1,
270
+ lastUpdated: approvedAt
271
+ }).where({ userId: followerId }),
272
+ ],
273
+
274
+ 'v1.Unfollowed': ({ followerId, followingId }) => [
275
+ tables.follows.delete().where({ followerId, followingId }),
276
+ // Update follower counts (eventual consistency)
277
+ tables.userStats.update({
278
+ followerCount: Math.max(0, tables.userStats.select('followerCount').where({ userId: followingId }).scalar() - 1),
279
+ lastUpdated: new Date()
280
+ }).where({ userId: followingId }),
281
+ tables.userStats.update({
282
+ followingCount: Math.max(0, tables.userStats.select('followingCount').where({ userId: followerId }).scalar() - 1),
283
+ lastUpdated: new Date()
284
+ }).where({ userId: followerId }),
285
+ ],
286
+
287
+ // Like materializers (idempotent)
288
+ 'v1.PostLiked': ({ userId, postId, createdAt }) => [
289
+ tables.likes.insert({ userId, postId, createdAt }),
290
+ // Update like count
291
+ tables.postStats.update({
292
+ likeCount: tables.postStats.select('likeCount').where({ postId }).scalar() + 1,
293
+ lastUpdated: createdAt
294
+ }).where({ postId }),
295
+ ],
296
+
297
+ 'v1.PostUnliked': ({ userId, postId }) => [
298
+ tables.likes.delete().where({ userId, postId }),
299
+ // Update like count
300
+ tables.postStats.update({
301
+ likeCount: Math.max(0, tables.postStats.select('likeCount').where({ postId }).scalar() - 1),
302
+ lastUpdated: new Date()
303
+ }).where({ postId }),
304
+ ],
305
+ })
306
+
307
+ const state = State.SQLite.makeState({ tables, materializers })
308
+
309
+ export const schema = makeSchema({ events, state })
310
+
311
+ // Example queries for activity feeds:
312
+ //
313
+ // // Home feed - posts from followed users
314
+ // const homeFeed$ = (userId: string) => queryDb(
315
+ // tables.posts
316
+ // .select()
317
+ // .join(tables.follows, 'authorId', 'followingId')
318
+ // .join(tables.users, 'authorId', 'id')
319
+ // .leftJoin(tables.postStats, 'id', 'postId')
320
+ // .where({
321
+ // followerId: userId,
322
+ // 'follows.status': 'active',
323
+ // 'posts.deletedAt': null,
324
+ // 'posts.visibility': ['public', 'followers']
325
+ // })
326
+ // .orderBy('createdAt', 'desc')
327
+ // .limit(50),
328
+ // { label: \`homeFeed-\${userId}\` }
329
+ // )
330
+ //
331
+ // // User profile with stats
332
+ // const userProfile$ = (username: string) => queryDb(
333
+ // tables.users
334
+ // .select()
335
+ // .leftJoin(tables.userStats, 'id', 'userId')
336
+ // .where({ username }),
337
+ // { label: \`userProfile-\${username}\` }
338
+ // )`
@@ -0,0 +1,171 @@
1
+ export const todoSchemaContent = `import { Events, makeSchema, Schema, SessionIdSymbol, State } from '@livestore/livestore'
2
+
3
+ // State tables - Define your application state as SQLite tables
4
+ export const tables = {
5
+ todos: State.SQLite.table({
6
+ name: 'todos',
7
+ columns: {
8
+ id: State.SQLite.text({ primaryKey: true }),
9
+ title: State.SQLite.text({ default: '' }),
10
+ completed: State.SQLite.boolean({ default: false }),
11
+ deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
12
+ createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),
13
+ position: State.SQLite.real(), // For ordering - enables conflict-free reordering
14
+ },
15
+ }),
16
+ tags: State.SQLite.table({
17
+ name: 'tags',
18
+ columns: {
19
+ id: State.SQLite.text({ primaryKey: true }),
20
+ name: State.SQLite.text(),
21
+ color: State.SQLite.text({ nullable: true }),
22
+ createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),
23
+ deletedAt: State.SQLite.integer({ nullable: true, schema: Schema.DateFromNumber }),
24
+ },
25
+ }),
26
+ todoTags: State.SQLite.table({
27
+ name: 'todo_tags',
28
+ columns: {
29
+ todoId: State.SQLite.text(),
30
+ tagId: State.SQLite.text(),
31
+ createdAt: State.SQLite.integer({ schema: Schema.DateFromNumber }),
32
+ },
33
+ }),
34
+ // Client-only state for UI (not synced)
35
+ uiState: State.SQLite.clientDocument({
36
+ name: 'uiState',
37
+ schema: Schema.Struct({
38
+ newTodoText: Schema.String,
39
+ filter: Schema.Literal('all', 'active', 'completed'),
40
+ selectedTags: Schema.Array(Schema.String)
41
+ }),
42
+ default: { id: SessionIdSymbol, value: { newTodoText: '', filter: 'all', selectedTags: [] } },
43
+ }),
44
+ }
45
+
46
+ // Events - Define state changes as events for reliable sync and replay
47
+ export const events = {
48
+ // Todo events
49
+ todoCreated: Events.synced({
50
+ name: 'v1.TodoCreated',
51
+ schema: Schema.Struct({
52
+ id: Schema.String,
53
+ title: Schema.String,
54
+ createdAt: Schema.Date,
55
+ position: Schema.Number
56
+ }),
57
+ }),
58
+ todoCompleted: Events.synced({
59
+ name: 'v1.TodoCompleted',
60
+ schema: Schema.Struct({ id: Schema.String }),
61
+ }),
62
+ todoUncompleted: Events.synced({
63
+ name: 'v1.TodoUncompleted',
64
+ schema: Schema.Struct({ id: Schema.String }),
65
+ }),
66
+ todoTitleChanged: Events.synced({
67
+ name: 'v1.TodoTitleChanged',
68
+ schema: Schema.Struct({ id: Schema.String, title: Schema.String }),
69
+ }),
70
+ todoReordered: Events.synced({
71
+ name: 'v1.TodoReordered',
72
+ schema: Schema.Struct({ id: Schema.String, position: Schema.Number }),
73
+ }),
74
+ todoDeleted: Events.synced({
75
+ name: 'v1.TodoDeleted',
76
+ schema: Schema.Struct({ id: Schema.String, deletedAt: Schema.Date }),
77
+ }),
78
+ todosCleared: Events.synced({
79
+ name: 'v1.TodosCleared',
80
+ schema: Schema.Struct({ deletedAt: Schema.Date }),
81
+ }),
82
+
83
+ // Tag events
84
+ tagCreated: Events.synced({
85
+ name: 'v1.TagCreated',
86
+ schema: Schema.Struct({
87
+ id: Schema.String,
88
+ name: Schema.String,
89
+ color: Schema.NullOr(Schema.String),
90
+ createdAt: Schema.Date
91
+ }),
92
+ }),
93
+ tagDeleted: Events.synced({
94
+ name: 'v1.TagDeleted',
95
+ schema: Schema.Struct({ id: Schema.String, deletedAt: Schema.Date }),
96
+ }),
97
+
98
+ // Todo-Tag relationship events
99
+ todoTagged: Events.synced({
100
+ name: 'v1.TodoTagged',
101
+ schema: Schema.Struct({ todoId: Schema.String, tagId: Schema.String, createdAt: Schema.Date }),
102
+ }),
103
+ todoUntagged: Events.synced({
104
+ name: 'v1.TodoUntagged',
105
+ schema: Schema.Struct({ todoId: Schema.String, tagId: Schema.String }),
106
+ }),
107
+
108
+ // UI state events (local only)
109
+ uiStateSet: tables.uiState.set,
110
+ }
111
+
112
+ // Materializers - Map events to state changes with conflict-free semantics
113
+ const materializers = State.SQLite.materializers(events, {
114
+ // Todo materializers
115
+ 'v1.TodoCreated': ({ id, title, createdAt, position }) =>
116
+ tables.todos.insert({ id, title, completed: false, createdAt, position }),
117
+
118
+ 'v1.TodoCompleted': ({ id }) =>
119
+ tables.todos.update({ completed: true }).where({ id }),
120
+
121
+ 'v1.TodoUncompleted': ({ id }) =>
122
+ tables.todos.update({ completed: false }).where({ id }),
123
+
124
+ 'v1.TodoTitleChanged': ({ id, title }) =>
125
+ tables.todos.update({ title }).where({ id }),
126
+
127
+ 'v1.TodoReordered': ({ id, position }) =>
128
+ tables.todos.update({ position }).where({ id }),
129
+
130
+ 'v1.TodoDeleted': ({ id, deletedAt }) =>
131
+ tables.todos.update({ deletedAt }).where({ id }),
132
+
133
+ 'v1.TodosCleared': ({ deletedAt }) =>
134
+ tables.todos.update({ deletedAt }).where({ completed: true, deletedAt: null }),
135
+
136
+ // Tag materializers
137
+ 'v1.TagCreated': ({ id, name, color, createdAt }) =>
138
+ tables.tags.insert({ id, name, color, createdAt }),
139
+
140
+ 'v1.TagDeleted': ({ id, deletedAt }) =>
141
+ tables.tags.update({ deletedAt }).where({ id }),
142
+
143
+ // Todo-Tag relationship materializers
144
+ 'v1.TodoTagged': ({ todoId, tagId, createdAt }) =>
145
+ tables.todoTags.insert({ todoId, tagId, createdAt }),
146
+
147
+ 'v1.TodoUntagged': ({ todoId, tagId }) =>
148
+ tables.todoTags.delete().where({ todoId, tagId }),
149
+ })
150
+
151
+ const state = State.SQLite.makeState({ tables, materializers })
152
+
153
+ export const schema = makeSchema({ events, state })
154
+
155
+ // Example usage:
156
+ //
157
+ // import { queryDb, dispatchEvent } from '@livestore/livestore'
158
+ // import { schema, events, tables } from './schema.js'
159
+ //
160
+ // // Query active todos
161
+ // const activeTodos$ = queryDb(
162
+ // tables.todos.select().where({ deletedAt: null, completed: false }).orderBy('position'),
163
+ // { label: 'activeTodos' }
164
+ // )
165
+ //
166
+ // // Create a new todo
167
+ // const createTodo = (title: string) => {
168
+ // const id = crypto.randomUUID()
169
+ // const position = Date.now() // Simple position strategy
170
+ // dispatchEvent(events.todoCreated({ id, title, createdAt: new Date(), position }))
171
+ // }`
package/src/mod.ts ADDED
@@ -0,0 +1 @@
1
+ export { command as LivestoreCliCommand } from './cli.ts'
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo",
6
+ "rootDir": "src"
7
+ },
8
+ "include": ["src/**/*"]
9
+ }