Yogesh commited on
Commit
f1c8e7a
Β·
1 Parent(s): b0baf04

Configure Space: migrate catalog and autopilot database adapter to Supabase

Browse files
Files changed (3) hide show
  1. package-lock.json +100 -0
  2. package.json +1 -0
  3. server.js +79 -71
package-lock.json CHANGED
@@ -9,6 +9,7 @@
9
  "version": "1.0.0",
10
  "dependencies": {
11
  "@huggingface/inference": "^2.8.1",
 
12
  "cors": "^2.8.5",
13
  "dotenv": "^16.4.5",
14
  "express": "^4.19.2",
@@ -45,6 +46,90 @@
45
  "sparse-bitfield": "^3.0.3"
46
  }
47
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  "node_modules/@types/webidl-conversions": {
49
  "version": "7.0.3",
50
  "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
@@ -640,6 +725,15 @@
640
  "url": "https://opencollective.com/express"
641
  }
642
  },
 
 
 
 
 
 
 
 
 
643
  "node_modules/iconv-lite": {
644
  "version": "0.4.24",
645
  "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -1401,6 +1495,12 @@
1401
  "node": ">=18"
1402
  }
1403
  },
 
 
 
 
 
 
1404
  "node_modules/type-is": {
1405
  "version": "1.6.18",
1406
  "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
 
9
  "version": "1.0.0",
10
  "dependencies": {
11
  "@huggingface/inference": "^2.8.1",
12
+ "@supabase/supabase-js": "^2.106.2",
13
  "cors": "^2.8.5",
14
  "dotenv": "^16.4.5",
15
  "express": "^4.19.2",
 
46
  "sparse-bitfield": "^3.0.3"
47
  }
48
  },
49
+ "node_modules/@supabase/auth-js": {
50
+ "version": "2.106.2",
51
+ "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.106.2.tgz",
52
+ "integrity": "sha512-VcAjUErkHkhC5Jaf+g/G1qbkQrFh8edaCdHa7pxJmHUjkWKjT7UnYCtPA89XV0N0GIYRkEqJZw5V62CtOxTmBQ==",
53
+ "license": "MIT",
54
+ "dependencies": {
55
+ "tslib": "2.8.1"
56
+ },
57
+ "engines": {
58
+ "node": ">=20.0.0"
59
+ }
60
+ },
61
+ "node_modules/@supabase/functions-js": {
62
+ "version": "2.106.2",
63
+ "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.106.2.tgz",
64
+ "integrity": "sha512-oRnr0QrL8H+zTO1YyQ1QjiHZU/957jvubbxSJTUm2XLAgzoGGV9Tahfyd+uvLsBLRVmXLtpU3oyCjdQIvkGMOA==",
65
+ "license": "MIT",
66
+ "dependencies": {
67
+ "tslib": "2.8.1"
68
+ },
69
+ "engines": {
70
+ "node": ">=20.0.0"
71
+ }
72
+ },
73
+ "node_modules/@supabase/phoenix": {
74
+ "version": "0.4.2",
75
+ "resolved": "https://registry.npmjs.org/@supabase/phoenix/-/phoenix-0.4.2.tgz",
76
+ "integrity": "sha512-YSAGnmDAfuleFCVt3CeurQZAhxRfXWeZIIkwp7NhYzQ1UwW6ePSnzsFAiUm/mbCkfoCf70QQHKW/K6RKh52a4A==",
77
+ "license": "MIT"
78
+ },
79
+ "node_modules/@supabase/postgrest-js": {
80
+ "version": "2.106.2",
81
+ "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.106.2.tgz",
82
+ "integrity": "sha512-tDOzyPgp9pIRMR2x6C9+uDSJrnXSzxLtt3d7nC+Lrsy3jnJDHYfdQC/xcRyhJE/TOBJ0heSqRKR3UmejDjZxsw==",
83
+ "license": "MIT",
84
+ "dependencies": {
85
+ "tslib": "2.8.1"
86
+ },
87
+ "engines": {
88
+ "node": ">=20.0.0"
89
+ }
90
+ },
91
+ "node_modules/@supabase/realtime-js": {
92
+ "version": "2.106.2",
93
+ "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.106.2.tgz",
94
+ "integrity": "sha512-LdRGT7DNhyZkPjubUv5bSdAZ0jSEX8wTHvx7htj7+K59TOZRvz4TuQK7tL2RWxyIZVeFMRluL04SzWS61rKnUA==",
95
+ "license": "MIT",
96
+ "dependencies": {
97
+ "@supabase/phoenix": "^0.4.2",
98
+ "tslib": "2.8.1"
99
+ },
100
+ "engines": {
101
+ "node": ">=20.0.0"
102
+ }
103
+ },
104
+ "node_modules/@supabase/storage-js": {
105
+ "version": "2.106.2",
106
+ "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.106.2.tgz",
107
+ "integrity": "sha512-xgKCSYuev1YarV+iVqr+zlfgSyremnJtn8T0NCT8L4XmMv1CLtESc0Q6kNp8+mKWdX/8ND0nzm7OMKx08kwNAw==",
108
+ "license": "MIT",
109
+ "dependencies": {
110
+ "iceberg-js": "^0.8.1",
111
+ "tslib": "2.8.1"
112
+ },
113
+ "engines": {
114
+ "node": ">=20.0.0"
115
+ }
116
+ },
117
+ "node_modules/@supabase/supabase-js": {
118
+ "version": "2.106.2",
119
+ "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.106.2.tgz",
120
+ "integrity": "sha512-2/RZ/1fmJx/MRSEDG2Xk8+J4JVk5clM9V0uSI6kUTrcS32KA89DtqI5RUOC9r6mzY3WBC9qexLjssIHjbLyVJA==",
121
+ "license": "MIT",
122
+ "dependencies": {
123
+ "@supabase/auth-js": "2.106.2",
124
+ "@supabase/functions-js": "2.106.2",
125
+ "@supabase/postgrest-js": "2.106.2",
126
+ "@supabase/realtime-js": "2.106.2",
127
+ "@supabase/storage-js": "2.106.2"
128
+ },
129
+ "engines": {
130
+ "node": ">=20.0.0"
131
+ }
132
+ },
133
  "node_modules/@types/webidl-conversions": {
134
  "version": "7.0.3",
135
  "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
 
725
  "url": "https://opencollective.com/express"
726
  }
727
  },
728
+ "node_modules/iceberg-js": {
729
+ "version": "0.8.1",
730
+ "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz",
731
+ "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==",
732
+ "license": "MIT",
733
+ "engines": {
734
+ "node": ">=20.0.0"
735
+ }
736
+ },
737
  "node_modules/iconv-lite": {
738
  "version": "0.4.24",
739
  "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
 
1495
  "node": ">=18"
1496
  }
1497
  },
1498
+ "node_modules/tslib": {
1499
+ "version": "2.8.1",
1500
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
1501
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
1502
+ "license": "0BSD"
1503
+ },
1504
  "node_modules/type-is": {
1505
  "version": "1.6.18",
1506
  "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
package.json CHANGED
@@ -10,6 +10,7 @@
10
  },
11
  "dependencies": {
12
  "@huggingface/inference": "^2.8.1",
 
13
  "cors": "^2.8.5",
14
  "dotenv": "^16.4.5",
15
  "express": "^4.19.2",
 
10
  },
11
  "dependencies": {
12
  "@huggingface/inference": "^2.8.1",
13
+ "@supabase/supabase-js": "^2.106.2",
14
  "cors": "^2.8.5",
15
  "dotenv": "^16.4.5",
16
  "express": "^4.19.2",
server.js CHANGED
@@ -4,7 +4,7 @@ import dotenv from 'dotenv';
4
  import { HfInference } from '@huggingface/inference';
5
  import fs from 'fs';
6
  import path from 'path';
7
- import mongoose from 'mongoose';
8
 
9
  // Load environment variables
10
  dotenv.config();
@@ -17,36 +17,25 @@ app.use(cors());
17
  app.use(express.json());
18
 
19
  // ----------------------------------------------------
20
- // DATABASE CONFIGURATION: MONGODB ATLAS WITH JSON FALLBACK
21
  // ----------------------------------------------------
22
 
23
- let isMongoConnected = false;
 
24
 
25
- // Define MongoDB Schema & Model
26
- const BookSchema = new mongoose.Schema({
27
- title: { type: String, required: true },
28
- subtitle: { type: String, default: '' },
29
- type: { type: String, default: 'other' },
30
- price: { type: Number, default: 9.99 },
31
- date: { type: String, default: () => new Date().toLocaleDateString() }
32
- });
33
-
34
- const BookModel = mongoose.models.Book || mongoose.model('Book', BookSchema);
35
-
36
- // Attempt MongoDB Connection if MONGODB_URI is provided
37
- if (process.env.MONGODB_URI && !process.env.MONGODB_URI.includes('cluster0.xxxx')) {
38
- console.log('πŸ”Œ Connecting to MongoDB Atlas Cloud...');
39
- mongoose.connect(process.env.MONGODB_URI)
40
- .then(() => {
41
- isMongoConnected = true;
42
- console.log('βœ… Connected to MongoDB Atlas Cloud Database!');
43
- })
44
- .catch((err) => {
45
- console.error('❌ MongoDB Atlas Connection Error:', err.message);
46
- console.log('⚠️ Falling back to Local JSON Database.');
47
- });
48
  } else {
49
- console.log('ℹ️ MONGODB_URI not set or using template. Using Local JSON Database.');
50
  }
51
 
52
  // JSON File Database Fallback Configuration
@@ -94,7 +83,7 @@ app.get('/api/health', (req, res) => {
94
  res.json({
95
  status: 'ok',
96
  hfConfigured: !!process.env.HF_API_KEY,
97
- dbType: isMongoConnected ? 'mongodb_atlas' : 'local_json',
98
  dbConnected: true
99
  });
100
  });
@@ -104,21 +93,17 @@ app.get('/api/health', (req, res) => {
104
  // ----------------------------------------------------
105
 
106
  app.get('/api/catalog', async (req, res) => {
107
- if (isMongoConnected) {
108
  try {
109
- const catalog = await BookModel.find().sort({ _id: -1 });
110
- // Map _id to id for frontend compatibility
111
- const mappedCatalog = catalog.map(book => ({
112
- id: book._id.toString(),
113
- title: book.title,
114
- subtitle: book.subtitle,
115
- type: book.type,
116
- price: book.price,
117
- date: book.date
118
- }));
119
- return res.json(mappedCatalog);
120
  } catch (err) {
121
- console.error('Error fetching from MongoDB:', err);
122
  // Fallback
123
  }
124
  }
@@ -134,24 +119,24 @@ app.post('/api/catalog', async (req, res) => {
134
  return res.status(400).json({ error: 'Book title is required' });
135
  }
136
 
137
- if (isMongoConnected) {
138
  try {
139
- const newBook = await BookModel.create({
140
- title,
141
- subtitle: subtitle || '',
142
- type: type || 'other',
143
- price: price || 9.99
144
- });
145
- return res.status(201).json({
146
- id: newBook._id.toString(),
147
- title: newBook.title,
148
- subtitle: newBook.subtitle,
149
- type: newBook.type,
150
- price: newBook.price,
151
- date: newBook.date
152
- });
153
  } catch (err) {
154
- console.error('Error saving to MongoDB:', err);
155
  // Fallback
156
  }
157
  }
@@ -175,15 +160,17 @@ app.post('/api/catalog', async (req, res) => {
175
  app.delete('/api/catalog/:id', async (req, res) => {
176
  const { id } = req.params;
177
 
178
- if (isMongoConnected) {
179
  try {
180
- const deletedBook = await BookModel.findByIdAndDelete(id);
181
- if (!deletedBook) {
182
- return res.status(404).json({ error: 'Book not found' });
183
- }
 
 
184
  return res.json({ success: true });
185
  } catch (err) {
186
- console.error('Error deleting from MongoDB:', err);
187
  // Fallback
188
  }
189
  }
@@ -330,14 +317,35 @@ Start writing now:`;
330
 
331
  autopilotThoughts.unshift(`[${timestamp}] πŸ’° Printing Cost Calculations: pages=120. Maximizing net margin for price $${recommendedPrice}...`);
332
 
333
- if (isMongoConnected) {
334
- await BookModel.create({
335
- title: parsedTitle,
336
- subtitle: parsedSubtitle,
337
- type: bookType,
338
- price: recommendedPrice
339
- });
340
- autopilotThoughts.unshift(`[${timestamp}] πŸ“¦ Cloud Save: Stored "${parsedTitle.slice(0, 30)}..." to MongoDB Atlas!`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  } else {
342
  const catalog = readDb();
343
  catalog.unshift({
 
4
  import { HfInference } from '@huggingface/inference';
5
  import fs from 'fs';
6
  import path from 'path';
7
+ import { createClient } from '@supabase/supabase-js';
8
 
9
  // Load environment variables
10
  dotenv.config();
 
17
  app.use(express.json());
18
 
19
  // ----------------------------------------------------
20
+ // DATABASE CONFIGURATION: SUPABASE WITH JSON FALLBACK
21
  // ----------------------------------------------------
22
 
23
+ let isSupabaseConnected = false;
24
+ let supabase = null;
25
 
26
+ // Attempt Supabase Connection if credentials are provided
27
+ if (process.env.SUPABASE_URL && process.env.SUPABASE_KEY && !process.env.SUPABASE_URL.includes('your-project-id')) {
28
+ console.log('πŸ”Œ Connecting to Supabase Cloud Database...');
29
+ try {
30
+ supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY);
31
+ isSupabaseConnected = true;
32
+ console.log('βœ… Connected to Supabase Cloud Database!');
33
+ } catch (err) {
34
+ console.error('❌ Supabase Connection Error:', err.message);
35
+ console.log('⚠️ Falling back to Local JSON Database.');
36
+ }
 
 
 
 
 
 
 
 
 
 
 
 
37
  } else {
38
+ console.log('ℹ️ Supabase credentials not set or using template. Using Local JSON Database.');
39
  }
40
 
41
  // JSON File Database Fallback Configuration
 
83
  res.json({
84
  status: 'ok',
85
  hfConfigured: !!process.env.HF_API_KEY,
86
+ dbType: isSupabaseConnected ? 'supabase' : 'local_json',
87
  dbConnected: true
88
  });
89
  });
 
93
  // ----------------------------------------------------
94
 
95
  app.get('/api/catalog', async (req, res) => {
96
+ if (isSupabaseConnected) {
97
  try {
98
+ const { data, error } = await supabase
99
+ .from('catalog')
100
+ .select('*')
101
+ .order('id', { ascending: false });
102
+
103
+ if (error) throw error;
104
+ return res.json(data || []);
 
 
 
 
105
  } catch (err) {
106
+ console.error('Error fetching from Supabase:', err.message);
107
  // Fallback
108
  }
109
  }
 
119
  return res.status(400).json({ error: 'Book title is required' });
120
  }
121
 
122
+ if (isSupabaseConnected) {
123
  try {
124
+ const { data, error } = await supabase
125
+ .from('catalog')
126
+ .insert([{
127
+ title,
128
+ subtitle: subtitle || '',
129
+ type: type || 'other',
130
+ price: price || 9.99
131
+ }])
132
+ .select();
133
+
134
+ if (error) throw error;
135
+ if (data && data.length > 0) {
136
+ return res.status(201).json(data[0]);
137
+ }
138
  } catch (err) {
139
+ console.error('Error saving to Supabase:', err.message);
140
  // Fallback
141
  }
142
  }
 
160
  app.delete('/api/catalog/:id', async (req, res) => {
161
  const { id } = req.params;
162
 
163
+ if (isSupabaseConnected) {
164
  try {
165
+ const { error } = await supabase
166
+ .from('catalog')
167
+ .delete()
168
+ .eq('id', id);
169
+
170
+ if (error) throw error;
171
  return res.json({ success: true });
172
  } catch (err) {
173
+ console.error('Error deleting from Supabase:', err.message);
174
  // Fallback
175
  }
176
  }
 
317
 
318
  autopilotThoughts.unshift(`[${timestamp}] πŸ’° Printing Cost Calculations: pages=120. Maximizing net margin for price $${recommendedPrice}...`);
319
 
320
+ if (isSupabaseConnected) {
321
+ try {
322
+ const { error } = await supabase
323
+ .from('catalog')
324
+ .insert([{
325
+ title: parsedTitle,
326
+ subtitle: parsedSubtitle,
327
+ type: bookType,
328
+ price: recommendedPrice
329
+ }]);
330
+
331
+ if (error) throw error;
332
+ autopilotThoughts.unshift(`[${timestamp}] πŸ“¦ Cloud Save: Stored "${parsedTitle.slice(0, 30)}..." to Supabase!`);
333
+ } catch (err) {
334
+ console.error('Error saving to Supabase in Autopilot:', err.message);
335
+ autopilotThoughts.unshift(`[${timestamp}] ⚠️ Cloud Save Failed. Storing to local fallback...`);
336
+ // Fallback
337
+ const catalog = readDb();
338
+ catalog.unshift({
339
+ id: Date.now().toString(),
340
+ title: parsedTitle,
341
+ subtitle: parsedSubtitle,
342
+ type: bookType,
343
+ price: recommendedPrice,
344
+ date: new Date().toLocaleDateString()
345
+ });
346
+ writeDb(catalog);
347
+ autopilotThoughts.unshift(`[${timestamp}] πŸ“¦ Database Save: Stored "${parsedTitle.slice(0, 30)}..." to Local JSON Fallback!`);
348
+ }
349
  } else {
350
  const catalog = readDb();
351
  catalog.unshift({