pelagora 0.1.5

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 (122) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/LICENSE +663 -0
  3. package/README.md +139 -0
  4. package/dist/ai/product-lookup.d.ts +26 -0
  5. package/dist/ai/product-lookup.d.ts.map +1 -0
  6. package/dist/ai/product-lookup.js +153 -0
  7. package/dist/ai/product-lookup.js.map +1 -0
  8. package/dist/api/collections.d.ts +3 -0
  9. package/dist/api/collections.d.ts.map +1 -0
  10. package/dist/api/collections.js +69 -0
  11. package/dist/api/collections.js.map +1 -0
  12. package/dist/api/favorites.d.ts +3 -0
  13. package/dist/api/favorites.d.ts.map +1 -0
  14. package/dist/api/favorites.js +43 -0
  15. package/dist/api/favorites.js.map +1 -0
  16. package/dist/api/health.d.ts +12 -0
  17. package/dist/api/health.d.ts.map +1 -0
  18. package/dist/api/health.js +54 -0
  19. package/dist/api/health.js.map +1 -0
  20. package/dist/api/index.d.ts +3 -0
  21. package/dist/api/index.d.ts.map +1 -0
  22. package/dist/api/index.js +56 -0
  23. package/dist/api/index.js.map +1 -0
  24. package/dist/api/items.d.ts +3 -0
  25. package/dist/api/items.d.ts.map +1 -0
  26. package/dist/api/items.js +170 -0
  27. package/dist/api/items.js.map +1 -0
  28. package/dist/api/media.d.ts +3 -0
  29. package/dist/api/media.d.ts.map +1 -0
  30. package/dist/api/media.js +241 -0
  31. package/dist/api/media.js.map +1 -0
  32. package/dist/api/negotiations.d.ts +3 -0
  33. package/dist/api/negotiations.d.ts.map +1 -0
  34. package/dist/api/negotiations.js +244 -0
  35. package/dist/api/negotiations.js.map +1 -0
  36. package/dist/api/offers.d.ts +3 -0
  37. package/dist/api/offers.d.ts.map +1 -0
  38. package/dist/api/offers.js +57 -0
  39. package/dist/api/offers.js.map +1 -0
  40. package/dist/api/refs.d.ts +3 -0
  41. package/dist/api/refs.d.ts.map +1 -0
  42. package/dist/api/refs.js +390 -0
  43. package/dist/api/refs.js.map +1 -0
  44. package/dist/api/scans.d.ts +3 -0
  45. package/dist/api/scans.d.ts.map +1 -0
  46. package/dist/api/scans.js +384 -0
  47. package/dist/api/scans.js.map +1 -0
  48. package/dist/api/settings.d.ts +3 -0
  49. package/dist/api/settings.d.ts.map +1 -0
  50. package/dist/api/settings.js +442 -0
  51. package/dist/api/settings.js.map +1 -0
  52. package/dist/db/index.d.ts +4 -0
  53. package/dist/db/index.d.ts.map +1 -0
  54. package/dist/db/index.js +18 -0
  55. package/dist/db/index.js.map +1 -0
  56. package/dist/db/queries.d.ts +237 -0
  57. package/dist/db/queries.d.ts.map +1 -0
  58. package/dist/db/queries.js +891 -0
  59. package/dist/db/queries.js.map +1 -0
  60. package/dist/db/schema.d.ts +6 -0
  61. package/dist/db/schema.d.ts.map +1 -0
  62. package/dist/db/schema.js +531 -0
  63. package/dist/db/schema.js.map +1 -0
  64. package/dist/dht/discovery.d.ts +33 -0
  65. package/dist/dht/discovery.d.ts.map +1 -0
  66. package/dist/dht/discovery.js +281 -0
  67. package/dist/dht/discovery.js.map +1 -0
  68. package/dist/dht/index.d.ts +2 -0
  69. package/dist/dht/index.d.ts.map +1 -0
  70. package/dist/dht/index.js +6 -0
  71. package/dist/dht/index.js.map +1 -0
  72. package/dist/index.d.ts +2 -0
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.js +215 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/ref-schemas.d.ts +59 -0
  77. package/dist/ref-schemas.d.ts.map +1 -0
  78. package/dist/ref-schemas.js +1038 -0
  79. package/dist/ref-schemas.js.map +1 -0
  80. package/dist/skills/export.d.ts +12 -0
  81. package/dist/skills/export.d.ts.map +1 -0
  82. package/dist/skills/export.js +54 -0
  83. package/dist/skills/export.js.map +1 -0
  84. package/dist/skills/index.d.ts +4 -0
  85. package/dist/skills/index.d.ts.map +1 -0
  86. package/dist/skills/index.js +11 -0
  87. package/dist/skills/index.js.map +1 -0
  88. package/dist/skills/loader.d.ts +37 -0
  89. package/dist/skills/loader.d.ts.map +1 -0
  90. package/dist/skills/loader.js +183 -0
  91. package/dist/skills/loader.js.map +1 -0
  92. package/dist/skills/registry.d.ts +37 -0
  93. package/dist/skills/registry.d.ts.map +1 -0
  94. package/dist/skills/registry.js +136 -0
  95. package/dist/skills/registry.js.map +1 -0
  96. package/dist/sync/index.d.ts +58 -0
  97. package/dist/sync/index.d.ts.map +1 -0
  98. package/dist/sync/index.js +331 -0
  99. package/dist/sync/index.js.map +1 -0
  100. package/dist/sync/reffo-client.d.ts +144 -0
  101. package/dist/sync/reffo-client.d.ts.map +1 -0
  102. package/dist/sync/reffo-client.js +279 -0
  103. package/dist/sync/reffo-client.js.map +1 -0
  104. package/dist/taxonomy.d.ts +4 -0
  105. package/dist/taxonomy.d.ts.map +1 -0
  106. package/dist/taxonomy.js +141 -0
  107. package/dist/taxonomy.js.map +1 -0
  108. package/dist/types/index.d.ts +198 -0
  109. package/dist/types/index.d.ts.map +1 -0
  110. package/dist/types/index.js +25 -0
  111. package/dist/types/index.js.map +1 -0
  112. package/dist/ui.d.ts +2 -0
  113. package/dist/ui.d.ts.map +1 -0
  114. package/dist/ui.js +6786 -0
  115. package/dist/ui.js.map +1 -0
  116. package/dist/version.d.ts +2 -0
  117. package/dist/version.d.ts.map +1 -0
  118. package/dist/version.js +14 -0
  119. package/dist/version.js.map +1 -0
  120. package/footer-brand.png +0 -0
  121. package/header-brand.png +0 -0
  122. package/package.json +61 -0
@@ -0,0 +1,891 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ScanItemQueries = exports.ScanQueries = exports.CollectionQueries = exports.SettingsQueries = exports.FavoriteQueries = exports.NegotiationQueries = exports.MediaQueries = exports.OfferQueries = exports.RefQueries = void 0;
4
+ const uuid_1 = require("uuid");
5
+ const schema_1 = require("./schema");
6
+ function rowToRef(row) {
7
+ return {
8
+ id: row.id,
9
+ name: row.name,
10
+ description: row.description,
11
+ category: row.category,
12
+ subcategory: row.subcategory,
13
+ image: row.image,
14
+ sku: row.sku,
15
+ listingStatus: row.listing_status,
16
+ quantity: row.quantity || 1,
17
+ reffoSynced: !!row.reffo_synced,
18
+ reffoRefId: row.reffo_ref_id,
19
+ locationLat: row.location_lat,
20
+ locationLng: row.location_lng,
21
+ locationAddress: row.location_address,
22
+ locationCity: row.location_city,
23
+ locationState: row.location_state,
24
+ locationZip: row.location_zip,
25
+ locationCountry: row.location_country,
26
+ sellingScope: row.selling_scope || undefined,
27
+ sellingRadiusMiles: row.selling_radius_miles,
28
+ beaconId: row.beacon_id,
29
+ createdAt: row.created_at,
30
+ updatedAt: row.updated_at,
31
+ attributes: row.attributes ? JSON.parse(row.attributes) : undefined,
32
+ condition: row.condition,
33
+ rentalTerms: row.rental_terms,
34
+ rentalDeposit: row.rental_deposit,
35
+ rentalDuration: row.rental_duration,
36
+ rentalDurationUnit: row.rental_duration_unit,
37
+ purchaseDate: row.purchase_date,
38
+ purchasePrice: row.purchase_price,
39
+ collectionId: row.collection_id,
40
+ };
41
+ }
42
+ function rowToOffer(row) {
43
+ return {
44
+ id: row.id,
45
+ refId: row.ref_id,
46
+ price: row.price,
47
+ priceCurrency: row.price_currency,
48
+ status: row.status,
49
+ sellerId: row.seller_id,
50
+ location: row.location,
51
+ createdAt: row.created_at,
52
+ updatedAt: row.updated_at,
53
+ };
54
+ }
55
+ class RefQueries {
56
+ db;
57
+ constructor(db) {
58
+ this.db = db || (0, schema_1.getDb)();
59
+ }
60
+ list(category, subcategory) {
61
+ let sql = 'SELECT * FROM refs';
62
+ const conditions = ["listing_status NOT IN ('archived_sold', 'archived_deleted')"];
63
+ const params = [];
64
+ if (category) {
65
+ conditions.push('category = ?');
66
+ params.push(category);
67
+ }
68
+ if (subcategory) {
69
+ conditions.push('subcategory = ?');
70
+ params.push(subcategory);
71
+ }
72
+ sql += ' WHERE ' + conditions.join(' AND ');
73
+ sql += ' ORDER BY created_at DESC';
74
+ const rows = this.db.prepare(sql).all(...params);
75
+ return rows.map(r => rowToRef(r));
76
+ }
77
+ get(id) {
78
+ const row = this.db.prepare('SELECT * FROM refs WHERE id = ?').get(id);
79
+ return row ? rowToRef(row) : undefined;
80
+ }
81
+ create(data, beaconId) {
82
+ const id = (0, uuid_1.v4)();
83
+ const now = new Date().toISOString();
84
+ // Apply default location from settings if not provided
85
+ let locLat = data.locationLat ?? null;
86
+ let locLng = data.locationLng ?? null;
87
+ let locAddress = data.locationAddress ?? null;
88
+ let locCity = data.locationCity ?? null;
89
+ let locState = data.locationState ?? null;
90
+ let locZip = data.locationZip ?? null;
91
+ let locCountry = data.locationCountry ?? null;
92
+ let scope = data.sellingScope ?? null;
93
+ let radiusMiles = data.sellingRadiusMiles ?? null;
94
+ if (locLat == null && locLng == null) {
95
+ const settings = new SettingsQueries(this.db).get();
96
+ if (settings) {
97
+ locLat = settings.locationLat ?? null;
98
+ locLng = settings.locationLng ?? null;
99
+ locAddress = settings.locationAddress ?? null;
100
+ locCity = locCity ?? settings.locationCity ?? null;
101
+ locState = locState ?? settings.locationState ?? null;
102
+ locZip = locZip ?? settings.locationZip ?? null;
103
+ locCountry = locCountry ?? settings.locationCountry ?? null;
104
+ scope = scope ?? settings.defaultSellingScope;
105
+ radiusMiles = radiusMiles ?? settings.defaultSellingRadiusMiles;
106
+ }
107
+ }
108
+ this.db.prepare(`
109
+ INSERT INTO refs (id, name, description, category, subcategory, image, sku, listing_status, quantity,
110
+ location_lat, location_lng, location_address, location_city, location_state, location_zip, location_country,
111
+ selling_scope, selling_radius_miles, attributes, condition,
112
+ rental_terms, rental_deposit, rental_duration, rental_duration_unit,
113
+ purchase_date, purchase_price,
114
+ collection_id, beacon_id, created_at, updated_at)
115
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
116
+ `).run(id, data.name, data.description || '', data.category || '', data.subcategory || '', data.image || null, data.sku || null, data.listingStatus || 'private', data.quantity || 1, locLat, locLng, locAddress, locCity, locState, locZip, locCountry, scope || 'global', radiusMiles, JSON.stringify(data.attributes) || null, data.condition || null, data.rentalTerms || null, data.rentalDeposit ?? null, data.rentalDuration ?? null, data.rentalDurationUnit || null, data.purchaseDate || null, data.purchasePrice ?? null, data.collectionId || null, beaconId, now, now);
117
+ return this.get(id);
118
+ }
119
+ /** Create a ref with a specific ID (used when pulling from webapp to preserve IDs) */
120
+ createWithId(id, data, beaconId) {
121
+ const now = new Date().toISOString();
122
+ this.db.prepare(`
123
+ INSERT OR IGNORE INTO refs (id, name, description, category, subcategory, image, sku, listing_status, quantity,
124
+ location_lat, location_lng, location_address, location_city, location_state, location_zip, location_country,
125
+ selling_scope, selling_radius_miles, attributes, condition,
126
+ rental_terms, rental_deposit, rental_duration, rental_duration_unit,
127
+ purchase_date, purchase_price,
128
+ collection_id, beacon_id, created_at, updated_at)
129
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
130
+ `).run(id, data.name, data.description || '', data.category || '', data.subcategory || '', data.image || null, data.sku || null, data.listingStatus || 'private', data.quantity || 1, data.locationLat ?? null, data.locationLng ?? null, data.locationAddress ?? null, data.locationCity ?? null, data.locationState ?? null, data.locationZip ?? null, data.locationCountry ?? null, data.sellingScope || 'global', data.sellingRadiusMiles ?? null, JSON.stringify(data.attributes) || null, data.condition || null, data.rentalTerms || null, data.rentalDeposit ?? null, data.rentalDuration ?? null, data.rentalDurationUnit || null, data.purchaseDate || null, data.purchasePrice ?? null, data.collectionId || null, beaconId, now, now);
131
+ return this.get(id);
132
+ }
133
+ update(id, data) {
134
+ const existing = this.get(id);
135
+ if (!existing)
136
+ return undefined;
137
+ const fields = [];
138
+ const values = [];
139
+ if (data.name !== undefined) {
140
+ fields.push('name = ?');
141
+ values.push(data.name);
142
+ }
143
+ if (data.description !== undefined) {
144
+ fields.push('description = ?');
145
+ values.push(data.description);
146
+ }
147
+ if (data.category !== undefined) {
148
+ fields.push('category = ?');
149
+ values.push(data.category);
150
+ }
151
+ if (data.subcategory !== undefined) {
152
+ fields.push('subcategory = ?');
153
+ values.push(data.subcategory);
154
+ }
155
+ if (data.image !== undefined) {
156
+ fields.push('image = ?');
157
+ values.push(data.image);
158
+ }
159
+ if (data.sku !== undefined) {
160
+ fields.push('sku = ?');
161
+ values.push(data.sku);
162
+ }
163
+ if (data.listingStatus !== undefined) {
164
+ fields.push('listing_status = ?');
165
+ values.push(data.listingStatus);
166
+ }
167
+ if (data.quantity !== undefined) {
168
+ fields.push('quantity = ?');
169
+ values.push(data.quantity);
170
+ }
171
+ if (data.locationLat !== undefined) {
172
+ fields.push('location_lat = ?');
173
+ values.push(data.locationLat);
174
+ }
175
+ if (data.locationLng !== undefined) {
176
+ fields.push('location_lng = ?');
177
+ values.push(data.locationLng);
178
+ }
179
+ if (data.locationAddress !== undefined) {
180
+ fields.push('location_address = ?');
181
+ values.push(data.locationAddress);
182
+ }
183
+ if (data.locationCity !== undefined) {
184
+ fields.push('location_city = ?');
185
+ values.push(data.locationCity);
186
+ }
187
+ if (data.locationState !== undefined) {
188
+ fields.push('location_state = ?');
189
+ values.push(data.locationState);
190
+ }
191
+ if (data.locationZip !== undefined) {
192
+ fields.push('location_zip = ?');
193
+ values.push(data.locationZip);
194
+ }
195
+ if (data.locationCountry !== undefined) {
196
+ fields.push('location_country = ?');
197
+ values.push(data.locationCountry);
198
+ }
199
+ if (data.sellingScope !== undefined) {
200
+ fields.push('selling_scope = ?');
201
+ values.push(data.sellingScope);
202
+ }
203
+ if (data.sellingRadiusMiles !== undefined) {
204
+ fields.push('selling_radius_miles = ?');
205
+ values.push(data.sellingRadiusMiles);
206
+ }
207
+ if (data.attributes !== undefined) {
208
+ fields.push('attributes = ?');
209
+ values.push(JSON.stringify(data.attributes));
210
+ }
211
+ if (data.condition !== undefined) {
212
+ fields.push('condition = ?');
213
+ values.push(data.condition);
214
+ }
215
+ if (data.rentalTerms !== undefined) {
216
+ fields.push('rental_terms = ?');
217
+ values.push(data.rentalTerms);
218
+ }
219
+ if (data.rentalDeposit !== undefined) {
220
+ fields.push('rental_deposit = ?');
221
+ values.push(data.rentalDeposit);
222
+ }
223
+ if (data.rentalDuration !== undefined) {
224
+ fields.push('rental_duration = ?');
225
+ values.push(data.rentalDuration);
226
+ }
227
+ if (data.rentalDurationUnit !== undefined) {
228
+ fields.push('rental_duration_unit = ?');
229
+ values.push(data.rentalDurationUnit);
230
+ }
231
+ if (data.purchaseDate !== undefined) {
232
+ fields.push('purchase_date = ?');
233
+ values.push(data.purchaseDate);
234
+ }
235
+ if (data.purchasePrice !== undefined) {
236
+ fields.push('purchase_price = ?');
237
+ values.push(data.purchasePrice);
238
+ }
239
+ if (data.collectionId !== undefined) {
240
+ fields.push('collection_id = ?');
241
+ values.push(data.collectionId);
242
+ }
243
+ if (fields.length === 0)
244
+ return existing;
245
+ fields.push("updated_at = datetime('now')");
246
+ values.push(id);
247
+ this.db.prepare(`UPDATE refs SET ${fields.join(', ')} WHERE id = ?`).run(...values);
248
+ return this.get(id);
249
+ }
250
+ delete(id) {
251
+ const result = this.db.prepare('DELETE FROM refs WHERE id = ?').run(id);
252
+ return result.changes > 0;
253
+ }
254
+ search(term) {
255
+ const rows = this.db.prepare("SELECT * FROM refs WHERE listing_status NOT IN ('archived_sold', 'archived_deleted') AND (name LIKE ? OR description LIKE ?) ORDER BY created_at DESC").all(`%${term}%`, `%${term}%`);
256
+ return rows.map(r => rowToRef(r));
257
+ }
258
+ listDiscoverable(category, subcategory) {
259
+ let sql = "SELECT * FROM refs WHERE listing_status IN ('for_sale', 'willing_to_sell', 'for_rent')";
260
+ const params = [];
261
+ if (category) {
262
+ sql += ' AND category = ?';
263
+ params.push(category);
264
+ }
265
+ if (subcategory) {
266
+ sql += ' AND subcategory = ?';
267
+ params.push(subcategory);
268
+ }
269
+ sql += ' ORDER BY created_at DESC';
270
+ const rows = this.db.prepare(sql).all(...params);
271
+ return rows.map(r => rowToRef(r));
272
+ }
273
+ searchDiscoverable(term) {
274
+ const rows = this.db.prepare("SELECT * FROM refs WHERE listing_status IN ('for_sale', 'willing_to_sell', 'for_rent') AND (name LIKE ? OR description LIKE ?) ORDER BY created_at DESC").all(`%${term}%`, `%${term}%`);
275
+ return rows.map(r => rowToRef(r));
276
+ }
277
+ count() {
278
+ const row = this.db.prepare("SELECT COUNT(*) as cnt FROM refs WHERE listing_status NOT IN ('archived_sold', 'archived_deleted')").get();
279
+ return row.cnt;
280
+ }
281
+ setSynced(id, synced, refId) {
282
+ if (synced && refId) {
283
+ this.db.prepare("UPDATE refs SET reffo_synced = 1, reffo_ref_id = ?, updated_at = datetime('now') WHERE id = ?").run(refId, id);
284
+ }
285
+ else if (synced) {
286
+ this.db.prepare("UPDATE refs SET reffo_synced = 1, updated_at = datetime('now') WHERE id = ?").run(id);
287
+ }
288
+ else {
289
+ this.db.prepare("UPDATE refs SET reffo_synced = 0, reffo_ref_id = NULL, updated_at = datetime('now') WHERE id = ?").run(id);
290
+ }
291
+ }
292
+ listSynced() {
293
+ const rows = this.db.prepare('SELECT * FROM refs WHERE reffo_synced = 1 ORDER BY created_at DESC').all();
294
+ return rows.map(r => rowToRef(r));
295
+ }
296
+ listArchived() {
297
+ const rows = this.db.prepare("SELECT * FROM refs WHERE listing_status IN ('archived_sold', 'archived_deleted') ORDER BY updated_at DESC").all();
298
+ return rows.map(r => rowToRef(r));
299
+ }
300
+ archive(id, reason) {
301
+ const status = reason === 'sold' ? 'archived_sold' : 'archived_deleted';
302
+ const result = this.db.prepare("UPDATE refs SET listing_status = ?, reffo_synced = 0, reffo_ref_id = NULL, updated_at = datetime('now') WHERE id = ?").run(status, id);
303
+ return result.changes > 0;
304
+ }
305
+ restore(id) {
306
+ const item = this.get(id);
307
+ if (!item)
308
+ return undefined;
309
+ if (item.listingStatus !== 'archived_sold' && item.listingStatus !== 'archived_deleted')
310
+ return undefined;
311
+ const newQuantity = item.listingStatus === 'archived_sold' ? 1 : item.quantity;
312
+ this.db.prepare("UPDATE refs SET listing_status = 'private', quantity = ?, updated_at = datetime('now') WHERE id = ?").run(newQuantity, id);
313
+ return this.get(id);
314
+ }
315
+ decrementQuantity(id) {
316
+ this.db.prepare("UPDATE refs SET quantity = MAX(0, quantity - 1), updated_at = datetime('now') WHERE id = ?").run(id);
317
+ const item = this.get(id);
318
+ return item ? item.quantity : 0;
319
+ }
320
+ }
321
+ exports.RefQueries = RefQueries;
322
+ class OfferQueries {
323
+ db;
324
+ constructor(db) {
325
+ this.db = db || (0, schema_1.getDb)();
326
+ }
327
+ list(refId) {
328
+ const query = refId
329
+ ? this.db.prepare('SELECT * FROM offers WHERE ref_id = ? ORDER BY created_at DESC')
330
+ : this.db.prepare('SELECT * FROM offers ORDER BY created_at DESC');
331
+ const rows = refId ? query.all(refId) : query.all();
332
+ return rows.map(r => rowToOffer(r));
333
+ }
334
+ get(id) {
335
+ const row = this.db.prepare('SELECT * FROM offers WHERE id = ?').get(id);
336
+ return row ? rowToOffer(row) : undefined;
337
+ }
338
+ create(data, sellerId) {
339
+ const id = (0, uuid_1.v4)();
340
+ const now = new Date().toISOString();
341
+ this.db.prepare(`
342
+ INSERT INTO offers (id, ref_id, price, price_currency, status, seller_id, location, created_at, updated_at)
343
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
344
+ `).run(id, data.refId, data.price, data.priceCurrency || 'USD', data.status || 'active', sellerId, data.location || null, now, now);
345
+ return this.get(id);
346
+ }
347
+ update(id, data) {
348
+ const existing = this.get(id);
349
+ if (!existing)
350
+ return undefined;
351
+ const fields = [];
352
+ const values = [];
353
+ if (data.price !== undefined) {
354
+ fields.push('price = ?');
355
+ values.push(data.price);
356
+ }
357
+ if (data.priceCurrency !== undefined) {
358
+ fields.push('price_currency = ?');
359
+ values.push(data.priceCurrency);
360
+ }
361
+ if (data.status !== undefined) {
362
+ fields.push('status = ?');
363
+ values.push(data.status);
364
+ }
365
+ if (data.location !== undefined) {
366
+ fields.push('location = ?');
367
+ values.push(data.location);
368
+ }
369
+ if (fields.length === 0)
370
+ return existing;
371
+ fields.push("updated_at = datetime('now')");
372
+ values.push(id);
373
+ this.db.prepare(`UPDATE offers SET ${fields.join(', ')} WHERE id = ?`).run(...values);
374
+ return this.get(id);
375
+ }
376
+ delete(id) {
377
+ const result = this.db.prepare('DELETE FROM offers WHERE id = ?').run(id);
378
+ return result.changes > 0;
379
+ }
380
+ countActive() {
381
+ const row = this.db.prepare("SELECT COUNT(*) as cnt FROM offers WHERE status = 'active'").get();
382
+ return row.cnt;
383
+ }
384
+ }
385
+ exports.OfferQueries = OfferQueries;
386
+ function rowToMedia(row) {
387
+ return {
388
+ id: row.id,
389
+ refId: row.ref_id,
390
+ mediaType: row.media_type,
391
+ filePath: row.file_path,
392
+ mimeType: row.mime_type,
393
+ fileSize: row.file_size,
394
+ sortOrder: row.sort_order,
395
+ createdAt: row.created_at,
396
+ };
397
+ }
398
+ class MediaQueries {
399
+ db;
400
+ constructor(db) {
401
+ this.db = db || (0, schema_1.getDb)();
402
+ }
403
+ listForRef(refId) {
404
+ const rows = this.db.prepare('SELECT * FROM ref_media WHERE ref_id = ? ORDER BY sort_order ASC, created_at ASC').all(refId);
405
+ return rows.map(r => rowToMedia(r));
406
+ }
407
+ countPhotos(refId) {
408
+ const row = this.db.prepare("SELECT COUNT(*) as cnt FROM ref_media WHERE ref_id = ? AND media_type = 'photo'").get(refId);
409
+ return row.cnt;
410
+ }
411
+ hasVideo(refId) {
412
+ const row = this.db.prepare("SELECT COUNT(*) as cnt FROM ref_media WHERE ref_id = ? AND media_type = 'video'").get(refId);
413
+ return row.cnt > 0;
414
+ }
415
+ create(data) {
416
+ const now = new Date().toISOString();
417
+ this.db.prepare(`
418
+ INSERT INTO ref_media (id, ref_id, media_type, file_path, mime_type, file_size, sort_order, created_at)
419
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
420
+ `).run(data.id, data.refId, data.mediaType, data.filePath, data.mimeType, data.fileSize, data.sortOrder || 0, now);
421
+ const row = this.db.prepare('SELECT * FROM ref_media WHERE id = ?').get(data.id);
422
+ return rowToMedia(row);
423
+ }
424
+ delete(id) {
425
+ const row = this.db.prepare('SELECT * FROM ref_media WHERE id = ?').get(id);
426
+ if (!row)
427
+ return undefined;
428
+ const media = rowToMedia(row);
429
+ this.db.prepare('DELETE FROM ref_media WHERE id = ?').run(id);
430
+ return media;
431
+ }
432
+ deleteAllForRef(refId) {
433
+ const rows = this.db.prepare('SELECT file_path FROM ref_media WHERE ref_id = ?').all(refId);
434
+ const paths = rows.map(r => r.file_path);
435
+ this.db.prepare('DELETE FROM ref_media WHERE ref_id = ?').run(refId);
436
+ return paths;
437
+ }
438
+ }
439
+ exports.MediaQueries = MediaQueries;
440
+ function rowToNegotiation(row) {
441
+ return {
442
+ id: row.id,
443
+ refId: row.ref_id,
444
+ refName: row.ref_name,
445
+ buyerBeaconId: row.buyer_beacon_id,
446
+ sellerBeaconId: row.seller_beacon_id,
447
+ price: row.price,
448
+ priceCurrency: row.price_currency,
449
+ message: row.message,
450
+ status: row.status,
451
+ role: row.role,
452
+ counterPrice: row.counter_price,
453
+ responseMessage: row.response_message,
454
+ createdAt: row.created_at,
455
+ updatedAt: row.updated_at,
456
+ archivedAt: row.archived_at,
457
+ };
458
+ }
459
+ class NegotiationQueries {
460
+ db;
461
+ constructor(db) {
462
+ this.db = db || (0, schema_1.getDb)();
463
+ }
464
+ get(id) {
465
+ const row = this.db.prepare('SELECT * FROM negotiations WHERE id = ?').get(id);
466
+ return row ? rowToNegotiation(row) : undefined;
467
+ }
468
+ listIncoming() {
469
+ const rows = this.db.prepare("SELECT * FROM negotiations WHERE role = 'seller' AND archived_at IS NULL AND status IN ('pending', 'countered') ORDER BY created_at DESC").all();
470
+ return rows.map(r => rowToNegotiation(r));
471
+ }
472
+ listOutgoing() {
473
+ const rows = this.db.prepare("SELECT * FROM negotiations WHERE role = 'buyer' AND archived_at IS NULL AND status IN ('pending', 'countered') ORDER BY created_at DESC").all();
474
+ return rows.map(r => rowToNegotiation(r));
475
+ }
476
+ listResolved() {
477
+ const rows = this.db.prepare("SELECT * FROM negotiations WHERE archived_at IS NULL AND status IN ('accepted', 'rejected', 'withdrawn', 'sold') ORDER BY updated_at DESC").all();
478
+ return rows.map(r => rowToNegotiation(r));
479
+ }
480
+ listArchived() {
481
+ const rows = this.db.prepare("SELECT * FROM negotiations WHERE archived_at IS NOT NULL ORDER BY archived_at DESC").all();
482
+ return rows.map(r => rowToNegotiation(r));
483
+ }
484
+ archive(id) {
485
+ this.db.prepare("UPDATE negotiations SET archived_at = datetime('now') WHERE id = ?").run(id);
486
+ return this.get(id);
487
+ }
488
+ unarchive(id) {
489
+ this.db.prepare("UPDATE negotiations SET archived_at = NULL WHERE id = ?").run(id);
490
+ return this.get(id);
491
+ }
492
+ delete(id) {
493
+ const result = this.db.prepare("DELETE FROM negotiations WHERE id = ?").run(id);
494
+ return result.changes > 0;
495
+ }
496
+ listForRef(refId) {
497
+ const rows = this.db.prepare('SELECT * FROM negotiations WHERE ref_id = ? ORDER BY created_at DESC').all(refId);
498
+ return rows.map(r => rowToNegotiation(r));
499
+ }
500
+ create(data) {
501
+ const now = new Date().toISOString();
502
+ this.db.prepare(`
503
+ INSERT INTO negotiations (id, ref_id, ref_name, buyer_beacon_id, seller_beacon_id, price, price_currency, message, status, role, created_at, updated_at)
504
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
505
+ `).run(data.id, data.refId, data.refName || '', data.buyerBeaconId, data.sellerBeaconId, data.price, data.priceCurrency || 'USD', data.message || '', data.status || 'pending', data.role, now, now);
506
+ return this.get(data.id);
507
+ }
508
+ updateStatus(id, status, counterPrice, responseMessage) {
509
+ const existing = this.get(id);
510
+ if (!existing)
511
+ return undefined;
512
+ if (counterPrice !== undefined) {
513
+ this.db.prepare("UPDATE negotiations SET status = ?, counter_price = ?, response_message = ?, updated_at = datetime('now') WHERE id = ?")
514
+ .run(status, counterPrice, responseMessage || null, id);
515
+ }
516
+ else {
517
+ this.db.prepare("UPDATE negotiations SET status = ?, response_message = ?, updated_at = datetime('now') WHERE id = ?")
518
+ .run(status, responseMessage || null, id);
519
+ }
520
+ return this.get(id);
521
+ }
522
+ listPendingForRef(refId, excludeId) {
523
+ const rows = this.db.prepare("SELECT * FROM negotiations WHERE ref_id = ? AND id != ? AND status IN ('pending', 'countered')").all(refId, excludeId);
524
+ return rows.map(r => rowToNegotiation(r));
525
+ }
526
+ countPending() {
527
+ const row = this.db.prepare("SELECT COUNT(*) as cnt FROM negotiations WHERE status = 'pending' AND role = 'seller' AND archived_at IS NULL").get();
528
+ return row.cnt;
529
+ }
530
+ }
531
+ exports.NegotiationQueries = NegotiationQueries;
532
+ function rowToFavorite(row) {
533
+ return {
534
+ id: row.id,
535
+ refId: row.ref_id,
536
+ refName: row.ref_name,
537
+ beaconId: row.beacon_id,
538
+ offerPrice: row.offer_price,
539
+ offerCurrency: row.offer_currency || 'USD',
540
+ listingStatus: row.listing_status,
541
+ category: row.category || '',
542
+ subcategory: row.subcategory || '',
543
+ locationCity: row.location_city,
544
+ locationState: row.location_state,
545
+ locationZip: row.location_zip,
546
+ imageUrl: row.image_url,
547
+ createdAt: row.created_at,
548
+ };
549
+ }
550
+ class FavoriteQueries {
551
+ db;
552
+ constructor(db) {
553
+ this.db = db || (0, schema_1.getDb)();
554
+ }
555
+ list() {
556
+ const rows = this.db.prepare('SELECT * FROM favorites ORDER BY created_at DESC').all();
557
+ return rows.map(r => rowToFavorite(r));
558
+ }
559
+ isFavorited(refId, beaconId) {
560
+ const row = this.db.prepare('SELECT id FROM favorites WHERE ref_id = ? AND beacon_id = ?').get(refId, beaconId);
561
+ return !!row;
562
+ }
563
+ add(data) {
564
+ const id = (0, uuid_1.v4)();
565
+ this.db.prepare(`
566
+ INSERT INTO favorites (id, ref_id, ref_name, beacon_id, offer_price, offer_currency, listing_status, category, subcategory, location_city, location_state, location_zip, image_url)
567
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
568
+ `).run(id, data.refId, data.refName || '', data.beaconId, data.offerPrice ?? null, data.offerCurrency || 'USD', data.listingStatus || null, data.category || '', data.subcategory || '', data.locationCity || null, data.locationState || null, data.locationZip || null, data.imageUrl || null);
569
+ const row = this.db.prepare('SELECT * FROM favorites WHERE id = ?').get(id);
570
+ return rowToFavorite(row);
571
+ }
572
+ remove(refId, beaconId) {
573
+ const result = this.db.prepare('DELETE FROM favorites WHERE ref_id = ? AND beacon_id = ?').run(refId, beaconId);
574
+ return result.changes > 0;
575
+ }
576
+ toggle(data) {
577
+ if (this.isFavorited(data.refId, data.beaconId)) {
578
+ this.remove(data.refId, data.beaconId);
579
+ return { favorited: false };
580
+ }
581
+ else {
582
+ this.add(data);
583
+ return { favorited: true };
584
+ }
585
+ }
586
+ listKeys() {
587
+ const rows = this.db.prepare('SELECT ref_id, beacon_id FROM favorites').all();
588
+ return rows.map(r => r.ref_id + ':' + r.beacon_id);
589
+ }
590
+ count() {
591
+ const row = this.db.prepare('SELECT COUNT(*) as cnt FROM favorites').get();
592
+ return row.cnt;
593
+ }
594
+ }
595
+ exports.FavoriteQueries = FavoriteQueries;
596
+ function rowToSettings(row) {
597
+ return {
598
+ id: row.id,
599
+ locationLat: row.location_lat,
600
+ locationLng: row.location_lng,
601
+ locationAddress: row.location_address,
602
+ locationCity: row.location_city,
603
+ locationState: row.location_state,
604
+ locationZip: row.location_zip,
605
+ locationCountry: row.location_country,
606
+ defaultSellingScope: row.default_selling_scope || 'global',
607
+ defaultSellingRadiusMiles: row.default_selling_radius_miles || 250,
608
+ profilePicturePath: row.profile_picture_path,
609
+ };
610
+ }
611
+ class SettingsQueries {
612
+ db;
613
+ constructor(db) {
614
+ this.db = db || (0, schema_1.getDb)();
615
+ }
616
+ get() {
617
+ const row = this.db.prepare("SELECT * FROM beacon_settings WHERE id = 'default'").get();
618
+ return row ? rowToSettings(row) : undefined;
619
+ }
620
+ upsert(data) {
621
+ const existing = this.get();
622
+ if (existing) {
623
+ const fields = [];
624
+ const values = [];
625
+ if (data.locationLat !== undefined) {
626
+ fields.push('location_lat = ?');
627
+ values.push(data.locationLat);
628
+ }
629
+ if (data.locationLng !== undefined) {
630
+ fields.push('location_lng = ?');
631
+ values.push(data.locationLng);
632
+ }
633
+ if (data.locationAddress !== undefined) {
634
+ fields.push('location_address = ?');
635
+ values.push(data.locationAddress);
636
+ }
637
+ if (data.locationCity !== undefined) {
638
+ fields.push('location_city = ?');
639
+ values.push(data.locationCity);
640
+ }
641
+ if (data.locationState !== undefined) {
642
+ fields.push('location_state = ?');
643
+ values.push(data.locationState);
644
+ }
645
+ if (data.locationZip !== undefined) {
646
+ fields.push('location_zip = ?');
647
+ values.push(data.locationZip);
648
+ }
649
+ if (data.locationCountry !== undefined) {
650
+ fields.push('location_country = ?');
651
+ values.push(data.locationCountry);
652
+ }
653
+ if (data.defaultSellingScope !== undefined) {
654
+ fields.push('default_selling_scope = ?');
655
+ values.push(data.defaultSellingScope);
656
+ }
657
+ if (data.defaultSellingRadiusMiles !== undefined) {
658
+ fields.push('default_selling_radius_miles = ?');
659
+ values.push(data.defaultSellingRadiusMiles);
660
+ }
661
+ if (data.profilePicturePath !== undefined) {
662
+ fields.push('profile_picture_path = ?');
663
+ values.push(data.profilePicturePath);
664
+ }
665
+ if (fields.length > 0) {
666
+ fields.push("updated_at = datetime('now')");
667
+ values.push('default');
668
+ this.db.prepare(`UPDATE beacon_settings SET ${fields.join(', ')} WHERE id = ?`).run(...values);
669
+ }
670
+ }
671
+ else {
672
+ this.db.prepare(`
673
+ INSERT INTO beacon_settings (id, location_lat, location_lng, location_address, location_city, location_state, location_zip, location_country, default_selling_scope, default_selling_radius_miles, profile_picture_path)
674
+ VALUES ('default', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
675
+ `).run(data.locationLat ?? null, data.locationLng ?? null, data.locationAddress ?? null, data.locationCity ?? null, data.locationState ?? null, data.locationZip ?? null, data.locationCountry ?? 'US', data.defaultSellingScope ?? 'global', data.defaultSellingRadiusMiles ?? 250, data.profilePicturePath ?? null);
676
+ }
677
+ return this.get();
678
+ }
679
+ }
680
+ exports.SettingsQueries = SettingsQueries;
681
+ function rowToCollection(row) {
682
+ return {
683
+ id: row.id,
684
+ name: row.name,
685
+ description: row.description,
686
+ createdAt: row.created_at,
687
+ updatedAt: row.updated_at,
688
+ };
689
+ }
690
+ class CollectionQueries {
691
+ db;
692
+ constructor(db) {
693
+ this.db = db || (0, schema_1.getDb)();
694
+ }
695
+ list() {
696
+ const rows = this.db.prepare('SELECT * FROM collections ORDER BY name ASC').all();
697
+ return rows.map(r => rowToCollection(r));
698
+ }
699
+ get(id) {
700
+ const row = this.db.prepare('SELECT * FROM collections WHERE id = ?').get(id);
701
+ return row ? rowToCollection(row) : undefined;
702
+ }
703
+ create(data) {
704
+ const id = (0, uuid_1.v4)();
705
+ const now = new Date().toISOString();
706
+ this.db.prepare(`
707
+ INSERT INTO collections (id, name, description, created_at, updated_at)
708
+ VALUES (?, ?, ?, ?, ?)
709
+ `).run(id, data.name, data.description || null, now, now);
710
+ return this.get(id);
711
+ }
712
+ update(id, data) {
713
+ const existing = this.get(id);
714
+ if (!existing)
715
+ return undefined;
716
+ const fields = [];
717
+ const values = [];
718
+ if (data.name !== undefined) {
719
+ fields.push('name = ?');
720
+ values.push(data.name);
721
+ }
722
+ if (data.description !== undefined) {
723
+ fields.push('description = ?');
724
+ values.push(data.description);
725
+ }
726
+ if (fields.length === 0)
727
+ return existing;
728
+ fields.push("updated_at = datetime('now')");
729
+ values.push(id);
730
+ this.db.prepare(`UPDATE collections SET ${fields.join(', ')} WHERE id = ?`).run(...values);
731
+ return this.get(id);
732
+ }
733
+ delete(id) {
734
+ const result = this.db.prepare('DELETE FROM collections WHERE id = ?').run(id);
735
+ return result.changes > 0;
736
+ }
737
+ listRefs(collectionId) {
738
+ const rows = this.db.prepare("SELECT * FROM refs WHERE collection_id = ? AND listing_status NOT IN ('archived_sold', 'archived_deleted') ORDER BY created_at DESC").all(collectionId);
739
+ return rows.map(r => rowToRef(r));
740
+ }
741
+ countRefs(collectionId) {
742
+ const row = this.db.prepare("SELECT COUNT(*) as cnt FROM refs WHERE collection_id = ? AND listing_status NOT IN ('archived_sold', 'archived_deleted')").get(collectionId);
743
+ return row.cnt;
744
+ }
745
+ }
746
+ exports.CollectionQueries = CollectionQueries;
747
+ function rowToScan(row) {
748
+ return {
749
+ id: row.id,
750
+ imagePath: row.image_path,
751
+ collectionId: row.collection_id,
752
+ status: row.status,
753
+ itemCount: row.item_count || 0,
754
+ aiModel: row.ai_model,
755
+ createdAt: row.created_at,
756
+ };
757
+ }
758
+ function rowToScanItem(row) {
759
+ return {
760
+ id: row.id,
761
+ scanId: row.scan_id,
762
+ name: row.name,
763
+ category: row.category,
764
+ confidence: row.confidence,
765
+ description: row.description,
766
+ condition: row.condition,
767
+ priceLow: row.price_low,
768
+ priceHigh: row.price_high,
769
+ priceTypical: row.price_typical,
770
+ attributes: row.attributes ? JSON.parse(row.attributes) : {},
771
+ enriched: !!row.enriched,
772
+ refId: row.ref_id,
773
+ createdAt: row.created_at,
774
+ };
775
+ }
776
+ class ScanQueries {
777
+ db;
778
+ constructor(db) {
779
+ this.db = db || (0, schema_1.getDb)();
780
+ }
781
+ list() {
782
+ const rows = this.db.prepare('SELECT * FROM scans ORDER BY created_at DESC').all();
783
+ return rows.map(r => rowToScan(r));
784
+ }
785
+ get(id) {
786
+ const row = this.db.prepare('SELECT * FROM scans WHERE id = ?').get(id);
787
+ return row ? rowToScan(row) : undefined;
788
+ }
789
+ create(data) {
790
+ const now = new Date().toISOString();
791
+ this.db.prepare(`
792
+ INSERT INTO scans (id, image_path, collection_id, status, ai_model, created_at)
793
+ VALUES (?, ?, ?, ?, ?, ?)
794
+ `).run(data.id, data.imagePath || null, data.collectionId || null, data.status || 'processing', data.aiModel || null, now);
795
+ return this.get(data.id);
796
+ }
797
+ updateStatus(id, status, itemCount) {
798
+ if (itemCount !== undefined) {
799
+ this.db.prepare('UPDATE scans SET status = ?, item_count = ? WHERE id = ?').run(status, itemCount, id);
800
+ }
801
+ else {
802
+ this.db.prepare('UPDATE scans SET status = ? WHERE id = ?').run(status, id);
803
+ }
804
+ }
805
+ delete(id) {
806
+ const result = this.db.prepare('DELETE FROM scans WHERE id = ?').run(id);
807
+ return result.changes > 0;
808
+ }
809
+ }
810
+ exports.ScanQueries = ScanQueries;
811
+ class ScanItemQueries {
812
+ db;
813
+ constructor(db) {
814
+ this.db = db || (0, schema_1.getDb)();
815
+ }
816
+ listForScan(scanId) {
817
+ const rows = this.db.prepare('SELECT * FROM scan_items WHERE scan_id = ? ORDER BY created_at ASC').all(scanId);
818
+ return rows.map(r => rowToScanItem(r));
819
+ }
820
+ get(id) {
821
+ const row = this.db.prepare('SELECT * FROM scan_items WHERE id = ?').get(id);
822
+ return row ? rowToScanItem(row) : undefined;
823
+ }
824
+ create(data) {
825
+ const now = new Date().toISOString();
826
+ this.db.prepare(`
827
+ INSERT INTO scan_items (id, scan_id, name, category, confidence, description, condition, price_low, price_high, price_typical, attributes, created_at)
828
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
829
+ `).run(data.id, data.scanId, data.name, data.category ?? null, data.confidence ?? null, data.description ?? null, data.condition ?? null, data.priceLow ?? null, data.priceHigh ?? null, data.priceTypical ?? null, JSON.stringify(data.attributes || {}), now);
830
+ return this.get(data.id);
831
+ }
832
+ createBatch(items) {
833
+ const now = new Date().toISOString();
834
+ const stmt = this.db.prepare(`
835
+ INSERT INTO scan_items (id, scan_id, name, category, confidence, description, condition, price_low, price_high, price_typical, attributes, created_at)
836
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
837
+ `);
838
+ const insertMany = this.db.transaction((rows) => {
839
+ for (const data of rows) {
840
+ stmt.run(data.id, data.scanId, data.name, data.category ?? null, data.confidence ?? null, data.description ?? null, data.condition ?? null, data.priceLow ?? null, data.priceHigh ?? null, data.priceTypical ?? null, JSON.stringify(data.attributes || {}), now);
841
+ }
842
+ });
843
+ insertMany(items);
844
+ return items.length > 0 ? this.listForScan(items[0].scanId) : [];
845
+ }
846
+ update(id, data) {
847
+ const existing = this.get(id);
848
+ if (!existing)
849
+ return undefined;
850
+ const fields = [];
851
+ const values = [];
852
+ if (data.name !== undefined) {
853
+ fields.push('name = ?');
854
+ values.push(data.name);
855
+ }
856
+ if (data.category !== undefined) {
857
+ fields.push('category = ?');
858
+ values.push(data.category);
859
+ }
860
+ if (data.condition !== undefined) {
861
+ fields.push('condition = ?');
862
+ values.push(data.condition);
863
+ }
864
+ if (data.description !== undefined) {
865
+ fields.push('description = ?');
866
+ values.push(data.description);
867
+ }
868
+ if (data.priceLow !== undefined) {
869
+ fields.push('price_low = ?');
870
+ values.push(data.priceLow);
871
+ }
872
+ if (data.priceHigh !== undefined) {
873
+ fields.push('price_high = ?');
874
+ values.push(data.priceHigh);
875
+ }
876
+ if (data.priceTypical !== undefined) {
877
+ fields.push('price_typical = ?');
878
+ values.push(data.priceTypical);
879
+ }
880
+ if (fields.length === 0)
881
+ return existing;
882
+ values.push(id);
883
+ this.db.prepare(`UPDATE scan_items SET ${fields.join(', ')} WHERE id = ?`).run(...values);
884
+ return this.get(id);
885
+ }
886
+ linkToRef(id, refId) {
887
+ this.db.prepare('UPDATE scan_items SET ref_id = ? WHERE id = ?').run(refId, id);
888
+ }
889
+ }
890
+ exports.ScanItemQueries = ScanItemQueries;
891
+ //# sourceMappingURL=queries.js.map