mycontext-cli 3.0.2 → 3.0.3
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 +67 -5
- package/dist/cli.js +28 -15
- package/dist/cli.js.map +1 -1
- package/dist/commands/help.d.ts.map +1 -1
- package/dist/commands/help.js +94 -25
- package/dist/commands/help.js.map +1 -1
- package/dist/commands/init.d.ts +12 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +135 -32
- package/dist/commands/init.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/templates/instantdb/auth.ts +89 -0
- package/dist/templates/instantdb/instant-admin.ts +9 -0
- package/dist/templates/instantdb/instant-client.ts +36 -0
- package/dist/templates/instantdb/instantdb-storage.ts +236 -0
- package/dist/utils/fileSystem.d.ts +9 -0
- package/dist/utils/fileSystem.d.ts.map +1 -1
- package/dist/utils/fileSystem.js +36 -0
- package/dist/utils/fileSystem.js.map +1 -1
- package/package.json +1 -1
- package/dist/templates/instantdb/db.template.ts +0 -14
- package/dist/templates/instantdb/home-client.template.tsx +0 -127
- package/dist/templates/instantdb/page.template.tsx +0 -5
- package/dist/templates/instantdb/perms.template.ts +0 -9
- package/dist/templates/instantdb/schema.template.ts +0 -28
package/dist/commands/init.js
CHANGED
|
@@ -78,62 +78,165 @@ class InitCommand {
|
|
|
78
78
|
? workingDir
|
|
79
79
|
: path.resolve(workingDir, finalProjectName);
|
|
80
80
|
spinner.start();
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
81
|
+
// Determine framework (default to instantdb for backward compatibility)
|
|
82
|
+
const framework = options.framework || "instantdb";
|
|
83
|
+
if (framework === "instantdb") {
|
|
84
|
+
// InstantDB workflow
|
|
85
|
+
await this.initInstantDBProject(spinner, workingDir, projectPath, finalProjectName, options, useCurrentDir);
|
|
86
|
+
}
|
|
87
|
+
else if (framework === "nextjs" || framework === "next") {
|
|
88
|
+
// Next.js workflow (shadcn + MyContext only)
|
|
89
|
+
await this.initNextJSProject(spinner, workingDir, projectPath, finalProjectName, options, useCurrentDir);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// Default: MyContext only
|
|
93
|
+
await this.initBasicProject(spinner, projectPath, finalProjectName, options, useCurrentDir);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
spinner.error({ text: "Failed to initialize project" });
|
|
98
|
+
console.error(chalk_1.default.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Initialize an InstantDB project with full setup
|
|
104
|
+
*/
|
|
105
|
+
async initInstantDBProject(spinner, workingDir, projectPath, projectName, options, useCurrentDir) {
|
|
106
|
+
// 1. Run shadcn init
|
|
107
|
+
spinner.updateText("Running shadcn init...");
|
|
108
|
+
(0, child_process_1.execSync)("pnpm dlx shadcn@latest init", {
|
|
109
|
+
cwd: workingDir,
|
|
110
|
+
stdio: "inherit",
|
|
111
|
+
});
|
|
112
|
+
// 2. Prompt user for instant-cli init
|
|
113
|
+
spinner.stop();
|
|
114
|
+
const { runInstantInit } = await (0, prompts_1.default)({
|
|
115
|
+
type: "confirm",
|
|
116
|
+
name: "runInstantInit",
|
|
117
|
+
message: "Run 'npx instant-cli init' to initialize InstantDB?",
|
|
118
|
+
initial: true,
|
|
119
|
+
});
|
|
120
|
+
if (runInstantInit) {
|
|
121
|
+
spinner.start();
|
|
88
122
|
spinner.updateText("Running instant-cli init...");
|
|
89
123
|
(0, child_process_1.execSync)("npx instant-cli init", {
|
|
90
124
|
cwd: projectPath,
|
|
91
125
|
stdio: "inherit",
|
|
92
126
|
});
|
|
93
|
-
//
|
|
94
|
-
spinner.
|
|
95
|
-
(0,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
spinner.updateText("Initializing MyContext project files...");
|
|
101
|
-
const config = await this.fs.initializeProject(finalProjectName, options.description || `${finalProjectName} - AI-powered app`, workingDir, useCurrentDir);
|
|
102
|
-
spinner.success({
|
|
103
|
-
text: `Project "${finalProjectName}" initialized successfully!`,
|
|
127
|
+
// Prompt user to push schemas
|
|
128
|
+
spinner.stop();
|
|
129
|
+
const { pushSchemas } = await (0, prompts_1.default)({
|
|
130
|
+
type: "confirm",
|
|
131
|
+
name: "pushSchemas",
|
|
132
|
+
message: "Push schemas to InstantDB dashboard? (Make sure you've configured your app)",
|
|
133
|
+
initial: false,
|
|
104
134
|
});
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
135
|
+
if (pushSchemas) {
|
|
136
|
+
spinner.start();
|
|
137
|
+
spinner.updateText("Pushing schemas to InstantDB...");
|
|
138
|
+
(0, child_process_1.execSync)("npx instant-cli push", {
|
|
139
|
+
cwd: projectPath,
|
|
140
|
+
stdio: "inherit",
|
|
141
|
+
});
|
|
142
|
+
}
|
|
111
143
|
}
|
|
144
|
+
// 3. Install @instantdb/react and @instantdb/admin
|
|
145
|
+
spinner.start();
|
|
146
|
+
spinner.updateText("Installing InstantDB packages...");
|
|
147
|
+
(0, child_process_1.execSync)("pnpm add @instantdb/react @instantdb/admin", {
|
|
148
|
+
cwd: projectPath,
|
|
149
|
+
stdio: "inherit",
|
|
150
|
+
});
|
|
151
|
+
// Install bcrypt for auth utilities
|
|
152
|
+
spinner.updateText("Installing auth dependencies...");
|
|
153
|
+
(0, child_process_1.execSync)("pnpm add bcryptjs nanoid && pnpm add -D @types/bcryptjs", {
|
|
154
|
+
cwd: projectPath,
|
|
155
|
+
stdio: "inherit",
|
|
156
|
+
});
|
|
157
|
+
// 4. Copy InstantDB templates to lib folder
|
|
158
|
+
spinner.updateText("Copying InstantDB template files...");
|
|
159
|
+
await this.fs.copyInstantDBTemplates(projectPath);
|
|
160
|
+
// 5. Initialize MyContext directory structure and context
|
|
161
|
+
spinner.updateText("Initializing MyContext project files...");
|
|
162
|
+
const config = await this.fs.initializeProject(projectName, options.description || `${projectName} - AI-powered app`, workingDir, useCurrentDir);
|
|
163
|
+
spinner.success({
|
|
164
|
+
text: `Project "${projectName}" initialized successfully with InstantDB!`,
|
|
165
|
+
});
|
|
166
|
+
// Show next steps
|
|
167
|
+
this.showNextSteps(config, "instantdb", useCurrentDir);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Initialize a Next.js project (shadcn + MyContext only)
|
|
171
|
+
*/
|
|
172
|
+
async initNextJSProject(spinner, workingDir, projectPath, projectName, options, useCurrentDir) {
|
|
173
|
+
// 1. Run shadcn init
|
|
174
|
+
spinner.updateText("Running shadcn init...");
|
|
175
|
+
(0, child_process_1.execSync)("pnpm dlx shadcn@latest init", {
|
|
176
|
+
cwd: workingDir,
|
|
177
|
+
stdio: "inherit",
|
|
178
|
+
});
|
|
179
|
+
// 2. Initialize MyContext directory structure and context
|
|
180
|
+
spinner.updateText("Initializing MyContext project files...");
|
|
181
|
+
const config = await this.fs.initializeProject(projectName, options.description || `${projectName} - Next.js app`, workingDir, useCurrentDir);
|
|
182
|
+
spinner.success({
|
|
183
|
+
text: `Project "${projectName}" initialized successfully with Next.js!`,
|
|
184
|
+
});
|
|
185
|
+
// Show next steps
|
|
186
|
+
this.showNextSteps(config, "nextjs", useCurrentDir);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Initialize a basic MyContext project (no framework)
|
|
190
|
+
*/
|
|
191
|
+
async initBasicProject(spinner, projectPath, projectName, options, useCurrentDir) {
|
|
192
|
+
spinner.updateText("Initializing MyContext project files...");
|
|
193
|
+
const config = await this.fs.initializeProject(projectName, options.description || `${projectName} - AI-powered app`, process.cwd(), useCurrentDir);
|
|
194
|
+
spinner.success({
|
|
195
|
+
text: `Project "${projectName}" initialized successfully!`,
|
|
196
|
+
});
|
|
197
|
+
// Show next steps
|
|
198
|
+
this.showNextSteps(config, undefined, useCurrentDir);
|
|
112
199
|
}
|
|
113
200
|
isValidProjectName(name) {
|
|
114
201
|
// Allow alphanumeric, hyphens, and underscores
|
|
115
202
|
return /^[a-zA-Z0-9._-]+$/.test(name);
|
|
116
203
|
}
|
|
117
204
|
showNextSteps(config, framework, useCurrentDir) {
|
|
118
|
-
const projectPath = useCurrentDir ?
|
|
205
|
+
const projectPath = useCurrentDir ? "." : config.name;
|
|
119
206
|
console.log(chalk_1.default.blue("\n🎯 Quick Start:\n"));
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
207
|
+
if (!useCurrentDir) {
|
|
208
|
+
console.log(chalk_1.default.yellow("1. Navigate to your project:"));
|
|
209
|
+
console.log(chalk_1.default.gray(` cd ${projectPath}\n`));
|
|
210
|
+
}
|
|
211
|
+
if (framework === "instantdb") {
|
|
212
|
+
console.log(chalk_1.default.yellow("2. Configure InstantDB:"));
|
|
213
|
+
console.log(chalk_1.default.gray(" • Add your InstantDB App ID to .env.local:"));
|
|
214
|
+
console.log(chalk_1.default.cyan(" NEXT_PUBLIC_INSTANT_APP_ID=your-app-id"));
|
|
215
|
+
console.log(chalk_1.default.gray(" • Template files copied to lib/ (or src/lib/):"));
|
|
216
|
+
console.log(chalk_1.default.gray(" - instant-client.ts (Client SDK)"));
|
|
217
|
+
console.log(chalk_1.default.gray(" - instant-admin.ts (Admin SDK)"));
|
|
218
|
+
console.log(chalk_1.default.gray(" - auth.ts (Auth helpers)"));
|
|
219
|
+
console.log(chalk_1.default.gray(" - instantdb-storage.ts (File storage)\n"));
|
|
220
|
+
}
|
|
221
|
+
console.log(chalk_1.default.yellow("3. ️ Analyze a screenshot (Gemini 2.0 Flash):"));
|
|
123
222
|
console.log(chalk_1.default.cyan(" mycontext analyze /path/to/screenshot.png"));
|
|
124
223
|
console.log(chalk_1.default.gray(" # Reverse-engineer any UI into a comprehensive spec!\n"));
|
|
125
|
-
console.log(chalk_1.default.yellow("
|
|
126
|
-
console.log(chalk_1.default.gray("
|
|
224
|
+
console.log(chalk_1.default.yellow("4. Configure AI provider:"));
|
|
225
|
+
console.log(chalk_1.default.gray(" 🔥 Gemini (Free - Recommended for screenshots):"));
|
|
127
226
|
console.log(chalk_1.default.gray(" Get API key: https://aistudio.google.com/apikey"));
|
|
128
227
|
console.log(chalk_1.default.cyan(" echo 'GEMINI_API_KEY=your-key' >> .mycontext/.env\n"));
|
|
129
228
|
console.log(chalk_1.default.gray(" 📌 Claude (Best for text generation):"));
|
|
130
229
|
console.log(chalk_1.default.gray(" https://console.anthropic.com/\n"));
|
|
131
|
-
console.log(chalk_1.default.yellow("
|
|
230
|
+
console.log(chalk_1.default.yellow("5. Generate full context:"));
|
|
132
231
|
console.log(chalk_1.default.gray(" mycontext generate context --full\n"));
|
|
133
|
-
console.log(chalk_1.default.yellow("
|
|
232
|
+
console.log(chalk_1.default.yellow("6. Start development:"));
|
|
134
233
|
console.log(chalk_1.default.gray(" pnpm dev\n"));
|
|
135
234
|
console.log(chalk_1.default.green("✨ Tips:"));
|
|
136
235
|
console.log(chalk_1.default.gray("• Check .mycontext/ for all generated files"));
|
|
236
|
+
if (framework === "instantdb") {
|
|
237
|
+
console.log(chalk_1.default.gray("• InstantDB templates are ready to use in your lib/ folder"));
|
|
238
|
+
console.log(chalk_1.default.gray("• Update instant.schema.ts with your data model"));
|
|
239
|
+
}
|
|
137
240
|
console.log(chalk_1.default.gray("• Use --yes flag to skip prompts"));
|
|
138
241
|
console.log(chalk_1.default.gray("• Run 'mycontext status' to check project progress\n"));
|
|
139
242
|
// Exit the process gracefully after displaying all information
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAA0B;AAC1B,sDAA8B;AAC9B,oDAA4B;AAC5B,sEAAuC;AACvC,8CAAmD;AACnD,oDAAwD;AAExD,iDAAyC;AAEzC,2CAA6B;AAgB7B,MAAa,WAAW;IAAxB;QACU,OAAE,GAAG,IAAI,8BAAiB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
package/dist/package.json
CHANGED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import bcrypt from "bcryptjs";
|
|
2
|
+
import { nanoid } from "nanoid";
|
|
3
|
+
|
|
4
|
+
export interface CreateUserInput {
|
|
5
|
+
email?: string;
|
|
6
|
+
phone?: string;
|
|
7
|
+
name: string;
|
|
8
|
+
password?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface MagicCodeData {
|
|
12
|
+
code: string;
|
|
13
|
+
identifier: string; // email or phone
|
|
14
|
+
type: "email" | "phone";
|
|
15
|
+
expiresAt: number;
|
|
16
|
+
userId?: string; // For existing users
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Hash a password using bcrypt
|
|
21
|
+
*/
|
|
22
|
+
export async function hashPassword(password: string): Promise<string> {
|
|
23
|
+
const salt = await bcrypt.genSalt(10);
|
|
24
|
+
return bcrypt.hash(password, salt);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Verify a password against a hash
|
|
29
|
+
*/
|
|
30
|
+
export async function verifyPassword(
|
|
31
|
+
password: string,
|
|
32
|
+
hash: string
|
|
33
|
+
): Promise<boolean> {
|
|
34
|
+
return bcrypt.compare(password, hash);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Generate a 6-digit magic code
|
|
39
|
+
*/
|
|
40
|
+
export function generateMagicCode(): string {
|
|
41
|
+
return Math.floor(100000 + Math.random() * 900000).toString();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Generate a unique subdomain from business name
|
|
46
|
+
*/
|
|
47
|
+
export function generateSubdomain(businessName: string): string {
|
|
48
|
+
const base = businessName
|
|
49
|
+
.toLowerCase()
|
|
50
|
+
.replace(/[^a-z0-9]/g, "-")
|
|
51
|
+
.replace(/-+/g, "-")
|
|
52
|
+
.replace(/^-|-$/g, "");
|
|
53
|
+
|
|
54
|
+
// Add random suffix to ensure uniqueness
|
|
55
|
+
const suffix = nanoid(6).toLowerCase();
|
|
56
|
+
return `${base}-${suffix}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Validate subdomain format
|
|
61
|
+
*/
|
|
62
|
+
export function isValidSubdomain(subdomain: string): boolean {
|
|
63
|
+
const regex = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;
|
|
64
|
+
return regex.test(subdomain);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Create a magic code with expiry (10 minutes)
|
|
69
|
+
*/
|
|
70
|
+
export function createMagicCodeData(
|
|
71
|
+
identifier: string,
|
|
72
|
+
type: "email" | "phone",
|
|
73
|
+
userId?: string
|
|
74
|
+
): MagicCodeData {
|
|
75
|
+
return {
|
|
76
|
+
code: generateMagicCode(),
|
|
77
|
+
identifier,
|
|
78
|
+
type,
|
|
79
|
+
expiresAt: Date.now() + 10 * 60 * 1000, // 10 minutes
|
|
80
|
+
userId,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Verify if magic code is still valid
|
|
86
|
+
*/
|
|
87
|
+
export function isMagicCodeValid(magicCodeData: MagicCodeData): boolean {
|
|
88
|
+
return Date.now() < magicCodeData.expiresAt;
|
|
89
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { init, id } from "@instantdb/admin";
|
|
2
|
+
import schema, { AppSchema } from "@/instant.schema";
|
|
3
|
+
|
|
4
|
+
export const adminDb = init({
|
|
5
|
+
appId: process.env.NEXT_PUBLIC_INSTANT_APP_ID!,
|
|
6
|
+
adminToken: process.env.INSTANT_APP_ADMIN_TOKEN!,
|
|
7
|
+
schema,
|
|
8
|
+
});
|
|
9
|
+
export { id };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { init, id } from "@instantdb/react";
|
|
2
|
+
import schema from "@/instant.schema";
|
|
3
|
+
|
|
4
|
+
// ID for app: jibu-delivery
|
|
5
|
+
const APP_ID = process.env.NEXT_PUBLIC_INSTANT_APP_ID!;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* InstantDB client initialization
|
|
9
|
+
*
|
|
10
|
+
* Note: InstantDB uses localStorage and IndexedDB for caching query results.
|
|
11
|
+
* If you encounter JSON parse errors, use the storage utilities from @/lib/storage-utils
|
|
12
|
+
* to clear corrupted storage.
|
|
13
|
+
*
|
|
14
|
+
* The useStorageInit hook in app layout handles automatic error recovery.
|
|
15
|
+
*/
|
|
16
|
+
// Mock for E2E testing
|
|
17
|
+
const isE2E = process.env.NEXT_PUBLIC_IS_E2E === "true";
|
|
18
|
+
|
|
19
|
+
const db = isE2E
|
|
20
|
+
? {
|
|
21
|
+
useAuth: () => ({
|
|
22
|
+
isLoading: false,
|
|
23
|
+
user: { id: "mock-user-id", email: "[EMAIL_ADDRESS]", isGuest: false },
|
|
24
|
+
error: null,
|
|
25
|
+
}),
|
|
26
|
+
useQuery: () => ({ isLoading: false, error: null, data: {} }),
|
|
27
|
+
auth: {
|
|
28
|
+
signOut: async () => {},
|
|
29
|
+
signInAsGuest: async () => {},
|
|
30
|
+
sendMagicCode: async () => {},
|
|
31
|
+
signInWithMagicCode: async () => {},
|
|
32
|
+
},
|
|
33
|
+
} as any
|
|
34
|
+
: init({ appId: APP_ID, schema });
|
|
35
|
+
|
|
36
|
+
export { db, id };
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InstantDB Storage Helper
|
|
3
|
+
*
|
|
4
|
+
* Utilities for uploading and managing files using InstantDB's storage feature.
|
|
5
|
+
* https://www.instantdb.com/docs/storage
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { db } from "./instant-client";
|
|
9
|
+
|
|
10
|
+
export interface UploadResult {
|
|
11
|
+
success: boolean;
|
|
12
|
+
url?: string;
|
|
13
|
+
path?: string;
|
|
14
|
+
id?: string;
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface UploadOptions {
|
|
19
|
+
contentType?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Upload a file to InstantDB storage
|
|
24
|
+
*
|
|
25
|
+
* @param file - The file to upload
|
|
26
|
+
* @param path - Optional custom path (defaults to auto-generated)
|
|
27
|
+
* @param options - Optional upload options (contentType)
|
|
28
|
+
* @returns Upload result with URL
|
|
29
|
+
*/
|
|
30
|
+
export async function uploadFile(
|
|
31
|
+
file: File,
|
|
32
|
+
path?: string,
|
|
33
|
+
options?: UploadOptions
|
|
34
|
+
): Promise<UploadResult> {
|
|
35
|
+
try {
|
|
36
|
+
// Generate path if not provided
|
|
37
|
+
const fileName = path || `uploads/${Date.now()}-${file.name}`;
|
|
38
|
+
|
|
39
|
+
console.log("📤 Uploading file:", fileName);
|
|
40
|
+
|
|
41
|
+
// Upload to InstantDB storage with correct API
|
|
42
|
+
const opts = {
|
|
43
|
+
contentType: options?.contentType || file.type,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const { data } = await db.storage.uploadFile(fileName, file, opts);
|
|
47
|
+
|
|
48
|
+
console.log("✅ File uploaded successfully, ID:", data.id);
|
|
49
|
+
|
|
50
|
+
// Return the path data
|
|
51
|
+
// Note: To get a displayable URL, the client must query $files or use a Signed URL
|
|
52
|
+
return {
|
|
53
|
+
success: true,
|
|
54
|
+
path: fileName,
|
|
55
|
+
id: data.id,
|
|
56
|
+
url: fileName, // Returning path as 'url' for compatibility, consumer should resolve it
|
|
57
|
+
};
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error("❌ Error uploading file:", error);
|
|
60
|
+
return {
|
|
61
|
+
success: false,
|
|
62
|
+
error: error instanceof Error ? error.message : "Upload failed",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Upload an image for inventory item
|
|
69
|
+
*
|
|
70
|
+
* @param file - The image file to upload
|
|
71
|
+
* @param itemId - The inventory item ID
|
|
72
|
+
* @returns Upload result with URL
|
|
73
|
+
*/
|
|
74
|
+
export async function uploadInventoryImage(
|
|
75
|
+
file: File,
|
|
76
|
+
itemId: string
|
|
77
|
+
): Promise<UploadResult> {
|
|
78
|
+
try {
|
|
79
|
+
// Validate file is an image
|
|
80
|
+
if (!file.type.startsWith("image/")) {
|
|
81
|
+
return {
|
|
82
|
+
success: false,
|
|
83
|
+
error: "File must be an image",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Validate file size (max 5MB)
|
|
88
|
+
const maxSize = 5 * 1024 * 1024; // 5MB
|
|
89
|
+
if (file.size > maxSize) {
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
error: "Image must be less than 5MB",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Generate unique path
|
|
97
|
+
const ext = file.name.split(".").pop() || "jpg";
|
|
98
|
+
const fileName = `inventory/${itemId}-${Date.now()}.${ext}`;
|
|
99
|
+
|
|
100
|
+
return await uploadFile(file, fileName, {
|
|
101
|
+
contentType: file.type,
|
|
102
|
+
});
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error("❌ Error uploading inventory image:", error);
|
|
105
|
+
return {
|
|
106
|
+
success: false,
|
|
107
|
+
error: error instanceof Error ? error.message : "Upload failed",
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Delete a file from InstantDB storage
|
|
114
|
+
*
|
|
115
|
+
* @param url - The file URL to delete
|
|
116
|
+
* @returns Success status
|
|
117
|
+
*/
|
|
118
|
+
export async function deleteFile(url: string): Promise<boolean> {
|
|
119
|
+
try {
|
|
120
|
+
console.log("🗑️ Deleting file:", url);
|
|
121
|
+
|
|
122
|
+
await db.storage.delete(url);
|
|
123
|
+
|
|
124
|
+
console.log("✅ File deleted successfully");
|
|
125
|
+
return true;
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error("❌ Error deleting file:", error);
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Get a file URL from InstantDB storage
|
|
134
|
+
*
|
|
135
|
+
* @param path - The file path
|
|
136
|
+
* @returns The file URL
|
|
137
|
+
*/
|
|
138
|
+
export function getFileUrl(path: string): string {
|
|
139
|
+
return db.storage.getDownloadUrl(path) as any;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Validate image file
|
|
144
|
+
*
|
|
145
|
+
* @param file - The file to validate
|
|
146
|
+
* @returns Validation result
|
|
147
|
+
*/
|
|
148
|
+
export function validateImageFile(file: File): {
|
|
149
|
+
valid: boolean;
|
|
150
|
+
error?: string;
|
|
151
|
+
} {
|
|
152
|
+
// Check file type
|
|
153
|
+
if (!file.type.startsWith("image/")) {
|
|
154
|
+
return {
|
|
155
|
+
valid: false,
|
|
156
|
+
error: "File must be an image (PNG, JPG, GIF, WEBP)",
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Check file size (max 5MB)
|
|
161
|
+
const maxSize = 5 * 1024 * 1024; // 5MB
|
|
162
|
+
if (file.size > maxSize) {
|
|
163
|
+
return {
|
|
164
|
+
valid: false,
|
|
165
|
+
error: "Image must be less than 5MB",
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Check image dimensions (optional)
|
|
170
|
+
const validTypes = [
|
|
171
|
+
"image/png",
|
|
172
|
+
"image/jpeg",
|
|
173
|
+
"image/jpg",
|
|
174
|
+
"image/gif",
|
|
175
|
+
"image/webp",
|
|
176
|
+
];
|
|
177
|
+
if (!validTypes.includes(file.type)) {
|
|
178
|
+
return {
|
|
179
|
+
valid: false,
|
|
180
|
+
error: "Supported formats: PNG, JPG, GIF, WEBP",
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return { valid: true };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Validate any file based on accept string
|
|
189
|
+
*
|
|
190
|
+
* @param file - The file to validate
|
|
191
|
+
* @param accept - The accept string (e.g. "image/*,application/pdf")
|
|
192
|
+
* @returns Validation result
|
|
193
|
+
*/
|
|
194
|
+
export function validateFile(file: File, accept?: string): {
|
|
195
|
+
valid: boolean;
|
|
196
|
+
error?: string;
|
|
197
|
+
} {
|
|
198
|
+
// If no accept string, allow everything
|
|
199
|
+
if (!accept || accept === "*") {
|
|
200
|
+
return { valid: true };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const acceptedTypes = accept.split(",").map(t => t.trim());
|
|
204
|
+
const fileType = file.type;
|
|
205
|
+
|
|
206
|
+
// Check if file type matches any accepted type
|
|
207
|
+
const isTypeValid = acceptedTypes.some(type => {
|
|
208
|
+
// Handle wildcards like image/*
|
|
209
|
+
if (type.endsWith("/*")) {
|
|
210
|
+
const mainType = type.split("/")[0];
|
|
211
|
+
return fileType.startsWith(`${mainType}/`);
|
|
212
|
+
}
|
|
213
|
+
// Handle explicit extensions like .pdf (mapped to MIME types usually, but here we check MIME)
|
|
214
|
+
// Note: This is a simple check. For robust file input behavior, usually relying on the input itself is best,
|
|
215
|
+
// but here we validate post-select.
|
|
216
|
+
return type === fileType;
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
if (!isTypeValid) {
|
|
220
|
+
return {
|
|
221
|
+
valid: false,
|
|
222
|
+
error: `File type ${fileType} is not supported. Allowed: ${accept}`,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Generic size limit (10MB for documents, 5MB for images usually, but let's stick to 10MB global for now or parameterize)
|
|
227
|
+
const maxSize = 10 * 1024 * 1024; // 10MB
|
|
228
|
+
if (file.size > maxSize) {
|
|
229
|
+
return {
|
|
230
|
+
valid: false,
|
|
231
|
+
error: "File must be less than 10MB",
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return { valid: true };
|
|
236
|
+
}
|
|
@@ -54,5 +54,14 @@ export declare class FileSystemManager {
|
|
|
54
54
|
* Restore a file from backup
|
|
55
55
|
*/
|
|
56
56
|
restoreFile(backupPath: string, targetPath: string): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Detect the lib directory in the project
|
|
59
|
+
* Returns src/lib/ if src directory exists, otherwise lib/
|
|
60
|
+
*/
|
|
61
|
+
detectLibDirectory(projectPath: string): Promise<string>;
|
|
62
|
+
/**
|
|
63
|
+
* Copy InstantDB template files to the project's lib directory
|
|
64
|
+
*/
|
|
65
|
+
copyInstantDBTemplates(projectPath: string): Promise<void>;
|
|
57
66
|
}
|
|
58
67
|
//# sourceMappingURL=fileSystem.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileSystem.d.ts","sourceRoot":"","sources":["../../src/utils/fileSystem.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAgB,MAAM,UAAU,CAAC;AAEvD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAE3C;;OAEG;IACG,iBAAiB,CACrB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,OAAO,GACtB,OAAO,CAAC,aAAa,CAAC;IAsCzB;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIjD;;OAEG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjE;;OAEG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIhD;;OAEG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C;;OAEG;IACG,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUvD;;OAEG;IACG,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAa1E;;OAEG;IACG,mBAAmB,CACvB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC;IAiBhB;;OAEG;IACG,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAa9D;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAgCzB;;OAEG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBnE;;OAEG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMnD;;OAEG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"fileSystem.d.ts","sourceRoot":"","sources":["../../src/utils/fileSystem.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAgB,MAAM,UAAU,CAAC;AAEvD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAE3C;;OAEG;IACG,iBAAiB,CACrB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,OAAO,GACtB,OAAO,CAAC,aAAa,CAAC;IAsCzB;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIjD;;OAEG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjE;;OAEG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIhD;;OAEG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C;;OAEG;IACG,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUvD;;OAEG;IACG,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAa1E;;OAEG;IACG,mBAAmB,CACvB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC;IAiBhB;;OAEG;IACG,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAa9D;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAgCzB;;OAEG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBnE;;OAEG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMnD;;OAEG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxE;;;OAGG;IACG,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAW9D;;OAEG;IACG,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAyBjE"}
|