mycontext-cli 2.0.28 → 2.0.30
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 +106 -14
- package/dist/cli.js +89 -99
- package/dist/cli.js.map +1 -1
- package/dist/commands/generate-components.d.ts +10 -0
- package/dist/commands/generate-components.d.ts.map +1 -1
- package/dist/commands/generate-components.js +300 -3
- package/dist/commands/generate-components.js.map +1 -1
- package/dist/commands/generate-context-files.d.ts +9 -0
- package/dist/commands/generate-context-files.d.ts.map +1 -1
- package/dist/commands/generate-context-files.js +57 -0
- package/dist/commands/generate-context-files.js.map +1 -1
- package/dist/commands/generate.d.ts +5 -0
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +75 -1
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +223 -68
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/preview-components.d.ts +12 -0
- package/dist/commands/preview-components.d.ts.map +1 -0
- package/dist/commands/preview-components.js +122 -0
- package/dist/commands/preview-components.js.map +1 -0
- package/dist/commands/refine-component.d.ts +43 -0
- package/dist/commands/refine-component.d.ts.map +1 -0
- package/dist/commands/refine-component.js +313 -0
- package/dist/commands/refine-component.js.map +1 -0
- package/dist/commands/review-context.d.ts +47 -0
- package/dist/commands/review-context.d.ts.map +1 -0
- package/dist/commands/review-context.js +335 -0
- package/dist/commands/review-context.js.map +1 -0
- package/dist/package.json +11 -2
- package/dist/services/ContextValidator.d.ts +99 -0
- package/dist/services/ContextValidator.d.ts.map +1 -0
- package/dist/services/ContextValidator.js +433 -0
- package/dist/services/ContextValidator.js.map +1 -0
- package/dist/services/MutationLogger.d.ts +54 -0
- package/dist/services/MutationLogger.d.ts.map +1 -0
- package/dist/services/MutationLogger.js +164 -0
- package/dist/services/MutationLogger.js.map +1 -0
- package/dist/services/RegressionRunner.d.ts +49 -0
- package/dist/services/RegressionRunner.d.ts.map +1 -0
- package/dist/services/RegressionRunner.js +285 -0
- package/dist/services/RegressionRunner.js.map +1 -0
- package/dist/services/TriggerLogger.d.ts +101 -0
- package/dist/services/TriggerLogger.d.ts.map +1 -0
- package/dist/services/TriggerLogger.js +263 -0
- package/dist/services/TriggerLogger.js.map +1 -0
- package/dist/templates/instantdb/db.template.ts +14 -0
- package/dist/templates/instantdb/home-client.template.tsx +127 -0
- package/dist/templates/instantdb/page.template.tsx +5 -0
- package/dist/templates/instantdb/perms.template.ts +9 -0
- package/dist/templates/instantdb/schema.template.ts +28 -0
- package/dist/templates/playbooks/instantdb-integration.md +851 -0
- package/dist/templates/playbooks/mpesa-integration.md +652 -0
- package/dist/templates/pm-integration-config.json +20 -0
- package/dist/templates/ui-spec-examples.md +318 -0
- package/dist/templates/ui-spec-templates.json +244 -0
- package/dist/utils/envExampleGenerator.d.ts.map +1 -1
- package/dist/utils/envExampleGenerator.js +9 -3
- package/dist/utils/envExampleGenerator.js.map +1 -1
- package/dist/utils/hybridAIClient.d.ts.map +1 -1
- package/dist/utils/hybridAIClient.js +21 -0
- package/dist/utils/hybridAIClient.js.map +1 -1
- package/dist/utils/openRouterClient.d.ts +10 -0
- package/dist/utils/openRouterClient.d.ts.map +1 -0
- package/dist/utils/openRouterClient.js +61 -0
- package/dist/utils/openRouterClient.js.map +1 -0
- package/package.json +11 -2
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TriggerLogger = void 0;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
class TriggerLogger {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.logPath = ".mycontext/trigger-log.json";
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Log a trigger event
|
|
14
|
+
*/
|
|
15
|
+
async logTrigger(type, description, affectedComponents, userAction, metadata) {
|
|
16
|
+
const event = {
|
|
17
|
+
id: this.generateEventId(),
|
|
18
|
+
type,
|
|
19
|
+
timestamp: new Date().toISOString(),
|
|
20
|
+
description,
|
|
21
|
+
affectedComponents,
|
|
22
|
+
userAction,
|
|
23
|
+
metadata,
|
|
24
|
+
};
|
|
25
|
+
const log = await this.loadLog();
|
|
26
|
+
log.events.push(event);
|
|
27
|
+
log.lastUpdated = new Date().toISOString();
|
|
28
|
+
await this.saveLog(log);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Log context file changes
|
|
32
|
+
*/
|
|
33
|
+
async logContextChange(changedFiles, userAction = "Context files updated") {
|
|
34
|
+
const affectedComponents = await this.getAffectedComponentsFromContext(changedFiles);
|
|
35
|
+
await this.logTrigger("context-change", `Context files changed: ${changedFiles.join(", ")}`, affectedComponents, userAction, { changedFiles });
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Log schema changes
|
|
39
|
+
*/
|
|
40
|
+
async logSchemaChange(userAction = "Schema updated") {
|
|
41
|
+
const affectedComponents = await this.getAffectedComponentsFromSchema();
|
|
42
|
+
await this.logTrigger("schema-change", "InstantDB schema modified", affectedComponents, userAction, { schemaChanged: true });
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Log component refinement
|
|
46
|
+
*/
|
|
47
|
+
async logComponentRefinement(componentName, refinementType, userAction = "Component refined") {
|
|
48
|
+
await this.logTrigger("component-refinement", `Component ${componentName} refined via ${refinementType}`, [componentName], userAction, { refinementType, componentName });
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Log approval changes
|
|
52
|
+
*/
|
|
53
|
+
async logApprovalChange(featureId, oldApproval, newApproval, userAction = "Feature approval changed") {
|
|
54
|
+
const affectedComponents = await this.getAffectedComponentsFromFeature(featureId);
|
|
55
|
+
await this.logTrigger("approval-change", `Feature ${featureId} approval changed from ${oldApproval} to ${newApproval}`, affectedComponents, userAction, { featureId, oldApproval, newApproval });
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get recent trigger events
|
|
59
|
+
*/
|
|
60
|
+
async getRecentEvents(limit = 10) {
|
|
61
|
+
const log = await this.loadLog();
|
|
62
|
+
return log.events
|
|
63
|
+
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())
|
|
64
|
+
.slice(0, limit);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get events by type
|
|
68
|
+
*/
|
|
69
|
+
async getEventsByType(type) {
|
|
70
|
+
const log = await this.loadLog();
|
|
71
|
+
return log.events.filter((event) => event.type === type);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get events affecting a specific component
|
|
75
|
+
*/
|
|
76
|
+
async getEventsForComponent(componentName) {
|
|
77
|
+
const log = await this.loadLog();
|
|
78
|
+
return log.events.filter((event) => event.affectedComponents.includes(componentName));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Check if component needs regeneration based on triggers
|
|
82
|
+
*/
|
|
83
|
+
async needsRegeneration(componentName) {
|
|
84
|
+
const events = await this.getEventsForComponent(componentName);
|
|
85
|
+
// Check if there are any recent trigger events
|
|
86
|
+
const recentEvents = events.filter((event) => {
|
|
87
|
+
const eventTime = new Date(event.timestamp).getTime();
|
|
88
|
+
const oneHourAgo = Date.now() - 60 * 60 * 1000;
|
|
89
|
+
return eventTime > oneHourAgo;
|
|
90
|
+
});
|
|
91
|
+
return recentEvents.length > 0;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get regeneration recommendations
|
|
95
|
+
*/
|
|
96
|
+
async getRegenerationRecommendations() {
|
|
97
|
+
const recentEvents = await this.getRecentEvents(5);
|
|
98
|
+
const shouldRegenerate = [];
|
|
99
|
+
let reason = "";
|
|
100
|
+
for (const event of recentEvents) {
|
|
101
|
+
if (event.type === "context-change" || event.type === "schema-change") {
|
|
102
|
+
shouldRegenerate.push(...event.affectedComponents);
|
|
103
|
+
reason = `Recent ${event.type} detected`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
shouldRegenerate: [...new Set(shouldRegenerate)], // Remove duplicates
|
|
108
|
+
reason,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Clear old events (keep last 50)
|
|
113
|
+
*/
|
|
114
|
+
async cleanupOldEvents() {
|
|
115
|
+
const log = await this.loadLog();
|
|
116
|
+
log.events = log.events
|
|
117
|
+
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())
|
|
118
|
+
.slice(0, 50);
|
|
119
|
+
await this.saveLog(log);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Load trigger log from file
|
|
123
|
+
*/
|
|
124
|
+
async loadLog() {
|
|
125
|
+
try {
|
|
126
|
+
const fs = require("fs-extra");
|
|
127
|
+
if (await fs.pathExists(this.logPath)) {
|
|
128
|
+
const content = await fs.readFile(this.logPath, "utf8");
|
|
129
|
+
return JSON.parse(content);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
// If file doesn't exist or is corrupted, return empty log
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
events: [],
|
|
137
|
+
lastUpdated: new Date().toISOString(),
|
|
138
|
+
version: "1.0",
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Save trigger log to file
|
|
143
|
+
*/
|
|
144
|
+
async saveLog(log) {
|
|
145
|
+
const fs = require("fs-extra");
|
|
146
|
+
await fs.ensureDir(".mycontext");
|
|
147
|
+
await fs.writeFile(this.logPath, JSON.stringify(log, null, 2));
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Generate unique event ID
|
|
151
|
+
*/
|
|
152
|
+
generateEventId() {
|
|
153
|
+
return `event_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get affected components from context file changes
|
|
157
|
+
*/
|
|
158
|
+
async getAffectedComponentsFromContext(changedFiles) {
|
|
159
|
+
// This would analyze which components are affected by context changes
|
|
160
|
+
// For now, return all components if PRD or features files changed
|
|
161
|
+
const criticalFiles = [
|
|
162
|
+
"01a-features.md",
|
|
163
|
+
"01b-user-flows.md",
|
|
164
|
+
"01c-edge-cases.md",
|
|
165
|
+
];
|
|
166
|
+
const hasCriticalChange = changedFiles.some((file) => criticalFiles.some((critical) => file.includes(critical)));
|
|
167
|
+
if (hasCriticalChange) {
|
|
168
|
+
// Return all components - this is a conservative approach
|
|
169
|
+
return await this.getAllComponentNames();
|
|
170
|
+
}
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get affected components from schema changes
|
|
175
|
+
*/
|
|
176
|
+
async getAffectedComponentsFromSchema() {
|
|
177
|
+
// Schema changes typically affect all components that use data
|
|
178
|
+
return await this.getAllComponentNames();
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get affected components from feature approval changes
|
|
182
|
+
*/
|
|
183
|
+
async getAffectedComponentsFromFeature(featureId) {
|
|
184
|
+
// Map feature ID to component name
|
|
185
|
+
return [
|
|
186
|
+
featureId.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
187
|
+
];
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get all component names from component list
|
|
191
|
+
*/
|
|
192
|
+
async getAllComponentNames() {
|
|
193
|
+
try {
|
|
194
|
+
const fs = require("fs-extra");
|
|
195
|
+
const componentListPath = ".mycontext/component-list.json";
|
|
196
|
+
if (await fs.pathExists(componentListPath)) {
|
|
197
|
+
const content = await fs.readFile(componentListPath, "utf8");
|
|
198
|
+
const componentList = JSON.parse(content);
|
|
199
|
+
// Extract component names from hierarchical structure
|
|
200
|
+
const names = [];
|
|
201
|
+
const extractNames = (item) => {
|
|
202
|
+
if (item.components) {
|
|
203
|
+
item.components.forEach((comp) => names.push(comp.name));
|
|
204
|
+
}
|
|
205
|
+
if (item.children) {
|
|
206
|
+
item.children.forEach(extractNames);
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
extractNames(componentList);
|
|
210
|
+
return names;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
// Return empty array if component list not found
|
|
215
|
+
}
|
|
216
|
+
return [];
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Display trigger log summary
|
|
220
|
+
*/
|
|
221
|
+
async displaySummary() {
|
|
222
|
+
const recentEvents = await this.getRecentEvents(5);
|
|
223
|
+
const recommendations = await this.getRegenerationRecommendations();
|
|
224
|
+
console.log(chalk_1.default.blue("\n📋 Trigger Log Summary"));
|
|
225
|
+
console.log(chalk_1.default.gray("Recent events affecting your components:"));
|
|
226
|
+
if (recentEvents.length === 0) {
|
|
227
|
+
console.log(chalk_1.default.green(" ✅ No recent trigger events"));
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
recentEvents.forEach((event, index) => {
|
|
231
|
+
const timeAgo = this.getTimeAgo(event.timestamp);
|
|
232
|
+
console.log(chalk_1.default.yellow(` ${index + 1}. ${event.description}`));
|
|
233
|
+
console.log(chalk_1.default.gray(` ${timeAgo} - ${event.userAction}`));
|
|
234
|
+
if (event.affectedComponents.length > 0) {
|
|
235
|
+
console.log(chalk_1.default.gray(` Affects: ${event.affectedComponents.join(", ")}`));
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
if (recommendations.shouldRegenerate.length > 0) {
|
|
239
|
+
console.log(chalk_1.default.yellow(`\n⚠️ ${recommendations.reason}`));
|
|
240
|
+
console.log(chalk_1.default.blue(` Consider regenerating: ${recommendations.shouldRegenerate.join(", ")}`));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Get human-readable time ago
|
|
245
|
+
*/
|
|
246
|
+
getTimeAgo(timestamp) {
|
|
247
|
+
const now = new Date().getTime();
|
|
248
|
+
const eventTime = new Date(timestamp).getTime();
|
|
249
|
+
const diffMs = now - eventTime;
|
|
250
|
+
const diffMins = Math.floor(diffMs / (1000 * 60));
|
|
251
|
+
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
|
|
252
|
+
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
|
253
|
+
if (diffMins < 1)
|
|
254
|
+
return "just now";
|
|
255
|
+
if (diffMins < 60)
|
|
256
|
+
return `${diffMins}m ago`;
|
|
257
|
+
if (diffHours < 24)
|
|
258
|
+
return `${diffHours}h ago`;
|
|
259
|
+
return `${diffDays}d ago`;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
exports.TriggerLogger = TriggerLogger;
|
|
263
|
+
//# sourceMappingURL=TriggerLogger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TriggerLogger.js","sourceRoot":"","sources":["../../src/services/TriggerLogger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { init } from '@instantdb/react';
|
|
2
|
+
import schema from '../instant.schema';
|
|
3
|
+
|
|
4
|
+
const APP_ID = process.env.NEXT_PUBLIC_INSTANT_APP_ID!;
|
|
5
|
+
|
|
6
|
+
if (!APP_ID) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
'NEXT_PUBLIC_INSTANT_APP_ID is not set. Run: mycontext init . --framework instantdb'
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const db = init({ appId: APP_ID, schema });
|
|
13
|
+
|
|
14
|
+
export default db;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { id } from "@instantdb/react";
|
|
4
|
+
import db from "@/lib/db";
|
|
5
|
+
import { Button } from "@/components/ui/button";
|
|
6
|
+
import { Input } from "@/components/ui/input";
|
|
7
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
8
|
+
import { Checkbox } from "@/components/ui/checkbox";
|
|
9
|
+
import { useState } from "react";
|
|
10
|
+
|
|
11
|
+
export default function HomeClient() {
|
|
12
|
+
const [newTodo, setNewTodo] = useState("");
|
|
13
|
+
const { isLoading, error, data } = db.useQuery({ todos: {} });
|
|
14
|
+
|
|
15
|
+
const addTodo = () => {
|
|
16
|
+
if (!newTodo.trim()) return;
|
|
17
|
+
|
|
18
|
+
db.transact(
|
|
19
|
+
db.tx.todos[id()].update({
|
|
20
|
+
text: newTodo,
|
|
21
|
+
done: false,
|
|
22
|
+
createdAt: Date.now(),
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
setNewTodo("");
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const toggleTodo = (todo: any) => {
|
|
29
|
+
db.transact(db.tx.todos[todo.id].update({ done: !todo.done }));
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const deleteTodo = (todo: any) => {
|
|
33
|
+
db.transact(db.tx.todos[todo.id].delete());
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
if (isLoading) {
|
|
37
|
+
return (
|
|
38
|
+
<div className="max-w-2xl mx-auto p-8">
|
|
39
|
+
<div className="text-center">Loading...</div>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (error) {
|
|
45
|
+
return (
|
|
46
|
+
<div className="max-w-2xl mx-auto p-8">
|
|
47
|
+
<Card className="border-red-500">
|
|
48
|
+
<CardHeader>
|
|
49
|
+
<CardTitle className="text-red-500">Error</CardTitle>
|
|
50
|
+
</CardHeader>
|
|
51
|
+
<CardContent>
|
|
52
|
+
<p className="text-sm text-muted-foreground">{error.message}</p>
|
|
53
|
+
<p className="text-xs text-muted-foreground mt-4">
|
|
54
|
+
Make sure NEXT_PUBLIC_INSTANT_APP_ID is set in your .env file
|
|
55
|
+
</p>
|
|
56
|
+
</CardContent>
|
|
57
|
+
</Card>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const { todos } = data;
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div className="max-w-2xl mx-auto p-8">
|
|
66
|
+
<Card>
|
|
67
|
+
<CardHeader>
|
|
68
|
+
<CardTitle className="text-4xl font-bold">My Todos</CardTitle>
|
|
69
|
+
<p className="text-sm text-muted-foreground">
|
|
70
|
+
Real-time todos powered by InstantDB
|
|
71
|
+
</p>
|
|
72
|
+
</CardHeader>
|
|
73
|
+
<CardContent className="space-y-4">
|
|
74
|
+
<div className="flex gap-2">
|
|
75
|
+
<Input
|
|
76
|
+
value={newTodo}
|
|
77
|
+
onChange={(e) => setNewTodo(e.target.value)}
|
|
78
|
+
placeholder="What needs to be done?"
|
|
79
|
+
onKeyPress={(e) => e.key === "Enter" && addTodo()}
|
|
80
|
+
className="flex-1"
|
|
81
|
+
/>
|
|
82
|
+
<Button onClick={addTodo}>Add</Button>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<div className="space-y-2">
|
|
86
|
+
{todos.length === 0 ? (
|
|
87
|
+
<div className="text-center py-8 text-muted-foreground">
|
|
88
|
+
No todos yet. Add one above!
|
|
89
|
+
</div>
|
|
90
|
+
) : (
|
|
91
|
+
todos.map((todo: any) => (
|
|
92
|
+
<Card key={todo.id} className="p-4">
|
|
93
|
+
<div className="flex items-center gap-4">
|
|
94
|
+
<Checkbox
|
|
95
|
+
checked={todo.done}
|
|
96
|
+
onCheckedChange={() => toggleTodo(todo)}
|
|
97
|
+
/>
|
|
98
|
+
<span
|
|
99
|
+
className={`flex-1 ${
|
|
100
|
+
todo.done ? "line-through text-muted-foreground" : ""
|
|
101
|
+
}`}
|
|
102
|
+
>
|
|
103
|
+
{todo.text}
|
|
104
|
+
</span>
|
|
105
|
+
<Button
|
|
106
|
+
variant="destructive"
|
|
107
|
+
size="sm"
|
|
108
|
+
onClick={() => deleteTodo(todo)}
|
|
109
|
+
>
|
|
110
|
+
Delete
|
|
111
|
+
</Button>
|
|
112
|
+
</div>
|
|
113
|
+
</Card>
|
|
114
|
+
))
|
|
115
|
+
)}
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div className="text-xs text-muted-foreground pt-4 border-t">
|
|
119
|
+
<p>
|
|
120
|
+
✨ Try opening this in multiple tabs - changes sync in real-time!
|
|
121
|
+
</p>
|
|
122
|
+
</div>
|
|
123
|
+
</CardContent>
|
|
124
|
+
</Card>
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { i } from "@instantdb/react";
|
|
2
|
+
|
|
3
|
+
const _schema = i.schema({
|
|
4
|
+
entities: {
|
|
5
|
+
$files: i.entity({
|
|
6
|
+
path: i.string().unique().indexed(),
|
|
7
|
+
url: i.string(),
|
|
8
|
+
}),
|
|
9
|
+
$users: i.entity({
|
|
10
|
+
email: i.string().unique().indexed().optional(),
|
|
11
|
+
type: i.string().optional(),
|
|
12
|
+
}),
|
|
13
|
+
todos: i.entity({
|
|
14
|
+
text: i.string(),
|
|
15
|
+
done: i.boolean(),
|
|
16
|
+
createdAt: i.number(),
|
|
17
|
+
}),
|
|
18
|
+
},
|
|
19
|
+
links: {},
|
|
20
|
+
rooms: {},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
type _AppSchema = typeof _schema;
|
|
24
|
+
interface AppSchema extends _AppSchema {}
|
|
25
|
+
const schema: AppSchema = _schema;
|
|
26
|
+
|
|
27
|
+
export type { AppSchema };
|
|
28
|
+
export default schema;
|