@purveyors/cli 0.25.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -45
- package/dist/commands/auth.d.ts +6 -2
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +119 -71
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/catalog.d.ts.map +1 -1
- package/dist/commands/catalog.js +11 -47
- package/dist/commands/catalog.js.map +1 -1
- package/dist/commands/inventory.d.ts.map +1 -1
- package/dist/commands/inventory.js +18 -45
- package/dist/commands/inventory.js.map +1 -1
- package/dist/commands/market.d.ts.map +1 -1
- package/dist/commands/market.js +4 -2
- package/dist/commands/market.js.map +1 -1
- package/dist/commands/roast.d.ts +5 -2
- package/dist/commands/roast.d.ts.map +1 -1
- package/dist/commands/roast.js +29 -28
- package/dist/commands/roast.js.map +1 -1
- package/dist/commands/sales.d.ts +17 -1
- package/dist/commands/sales.d.ts.map +1 -1
- package/dist/commands/sales.js +33 -26
- package/dist/commands/sales.js.map +1 -1
- package/dist/commands/tasting.d.ts.map +1 -1
- package/dist/commands/tasting.js +20 -9
- package/dist/commands/tasting.js.map +1 -1
- package/dist/lib/ai.d.ts +2 -2
- package/dist/lib/ai.d.ts.map +1 -1
- package/dist/lib/ai.js.map +1 -1
- package/dist/lib/auth-client.d.ts +33 -0
- package/dist/lib/auth-client.d.ts.map +1 -0
- package/dist/lib/auth-client.js +63 -0
- package/dist/lib/auth-client.js.map +1 -0
- package/dist/lib/auth-guard.d.ts +3 -3
- package/dist/lib/auth-guard.d.ts.map +1 -1
- package/dist/lib/auth-guard.js +16 -8
- package/dist/lib/auth-guard.js.map +1 -1
- package/dist/lib/catalog.d.ts +12 -14
- package/dist/lib/catalog.d.ts.map +1 -1
- package/dist/lib/catalog.js +177 -520
- package/dist/lib/catalog.js.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +23 -2
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/interactive/forms.d.ts +4 -5
- package/dist/lib/interactive/forms.d.ts.map +1 -1
- package/dist/lib/interactive/forms.js +18 -46
- package/dist/lib/interactive/forms.js.map +1 -1
- package/dist/lib/interactive/watch.d.ts +5 -2
- package/dist/lib/interactive/watch.d.ts.map +1 -1
- package/dist/lib/interactive/watch.js +35 -15
- package/dist/lib/interactive/watch.js.map +1 -1
- package/dist/lib/inventory.d.ts +8 -16
- package/dist/lib/inventory.d.ts.map +1 -1
- package/dist/lib/inventory.js +44 -227
- package/dist/lib/inventory.js.map +1 -1
- package/dist/lib/manifest.d.ts.map +1 -1
- package/dist/lib/manifest.js +20 -27
- package/dist/lib/manifest.js.map +1 -1
- package/dist/lib/market.d.ts +1 -1
- package/dist/lib/market.d.ts.map +1 -1
- package/dist/lib/parchment-base.d.ts +3 -0
- package/dist/lib/parchment-base.d.ts.map +1 -0
- package/dist/lib/parchment-base.js +9 -0
- package/dist/lib/parchment-base.js.map +1 -0
- package/dist/lib/parchment.d.ts +5 -5
- package/dist/lib/parchment.d.ts.map +1 -1
- package/dist/lib/parchment.js +9 -11
- package/dist/lib/parchment.js.map +1 -1
- package/dist/lib/roast.d.ts +16 -24
- package/dist/lib/roast.d.ts.map +1 -1
- package/dist/lib/roast.js +33 -224
- package/dist/lib/roast.js.map +1 -1
- package/dist/lib/sales.d.ts +18 -23
- package/dist/lib/sales.d.ts.map +1 -1
- package/dist/lib/sales.js +100 -156
- package/dist/lib/sales.js.map +1 -1
- package/dist/lib/tasting.d.ts +4 -5
- package/dist/lib/tasting.d.ts.map +1 -1
- package/dist/lib/tasting.js +14 -94
- package/dist/lib/tasting.js.map +1 -1
- package/dist/program.js +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -5
- package/dist/lib/supabase.d.ts +0 -22
- package/dist/lib/supabase.d.ts.map +0 -1
- package/dist/lib/supabase.js +0 -103
- package/dist/lib/supabase.js.map +0 -1
- package/dist/types/database.types.d.ts +0 -13
- package/dist/types/database.types.d.ts.map +0 -1
- package/dist/types/database.types.js +0 -8
- package/dist/types/database.types.js.map +0 -1
package/dist/lib/sales.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
1
2
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
// ─── Shared select columns ────────────────────────────────────────────────────
|
|
3
|
+
import { PrvrsError } from './errors.js';
|
|
4
|
+
import { createParchmentClient, unwrapParchment } from './parchment.js';
|
|
5
5
|
export const SALE_SELECT = 'id, roast_id, oz_sold, sale_price, buyer, sell_date, user, last_updated';
|
|
6
|
-
// ─── Zod schemas ──────────────────────────────────────────────────────────────
|
|
7
6
|
export const listSalesSchema = z.object({
|
|
8
7
|
limit: z.number().int().min(1).default(20),
|
|
9
8
|
offset: z.number().int().min(0).optional(),
|
|
10
|
-
|
|
9
|
+
greenCoffeeInvId: z.number().int().positive().optional(),
|
|
11
10
|
dateStart: z.string().optional(),
|
|
12
11
|
dateEnd: z.string().optional(),
|
|
13
12
|
buyer: z.string().optional(),
|
|
@@ -64,175 +63,120 @@ export const updateSaleSchema = z
|
|
|
64
63
|
buyer: z.string().optional(),
|
|
65
64
|
sellDate: z.string().optional(),
|
|
66
65
|
})
|
|
67
|
-
.refine((v) => Object.
|
|
66
|
+
.refine((v) => Object.values(v).some((value) => value !== undefined), {
|
|
68
67
|
message: 'No update fields provided. Pass at least one of: oz, price, buyer, sellDate.',
|
|
69
68
|
});
|
|
70
|
-
export const deleteSaleSchema = z.object({
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
export const deleteSaleSchema = z.object({ id: z.number().int().positive() });
|
|
70
|
+
async function listExactSaleRoastMatches(client, coffeeId, batchName) {
|
|
71
|
+
const exactMatches = [];
|
|
72
|
+
const pageSize = 100;
|
|
73
|
+
let offset = 0;
|
|
74
|
+
const seenRoastIds = new Set();
|
|
75
|
+
do {
|
|
76
|
+
const envelope = unwrapParchment(await client.roasts.list({
|
|
77
|
+
coffee_id: coffeeId,
|
|
78
|
+
batch_name: batchName,
|
|
79
|
+
limit: pageSize,
|
|
80
|
+
offset,
|
|
81
|
+
}), 'Sale roast selector');
|
|
82
|
+
const rows = envelope.data;
|
|
83
|
+
if (rows.length === 0)
|
|
84
|
+
break;
|
|
85
|
+
const unseenRows = rows.filter((row) => !seenRoastIds.has(row.roast_id));
|
|
86
|
+
if (unseenRows.length === 0) {
|
|
87
|
+
throw new PrvrsError('GENERAL_ERROR', 'Sale roast selector pagination did not advance. Retry the request.');
|
|
88
|
+
}
|
|
89
|
+
for (const row of unseenRows)
|
|
90
|
+
seenRoastIds.add(row.roast_id);
|
|
91
|
+
exactMatches.push(...unseenRows.filter((row) => row.coffee_id === coffeeId && (row.batch_name ?? undefined) === batchName));
|
|
92
|
+
if (exactMatches.length > 1)
|
|
93
|
+
break;
|
|
94
|
+
offset += unseenRows.length;
|
|
95
|
+
} while (true);
|
|
96
|
+
return exactMatches;
|
|
97
|
+
}
|
|
98
|
+
export async function listSales(opts = {}, tokenOverride) {
|
|
78
99
|
const parsed = listSalesSchema.parse(opts);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
.
|
|
82
|
-
.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (parsed.dateEnd !== undefined) {
|
|
90
|
-
query = query.lte('sell_date', parsed.dateEnd);
|
|
91
|
-
}
|
|
92
|
-
if (parsed.buyer !== undefined) {
|
|
93
|
-
const safe = sanitizeFilterValue(parsed.buyer);
|
|
94
|
-
query = query.ilike('buyer', `%${safe}%`);
|
|
95
|
-
}
|
|
96
|
-
const offset = parsed.offset ?? 0;
|
|
97
|
-
const { data, error } = await query
|
|
98
|
-
.order('sell_date', { ascending: false })
|
|
99
|
-
.range(offset, offset + parsed.limit - 1);
|
|
100
|
-
if (error)
|
|
101
|
-
throw error;
|
|
102
|
-
return (data ?? []);
|
|
100
|
+
const client = await createParchmentClient('member', tokenOverride);
|
|
101
|
+
const envelope = unwrapParchment(await client.sales.list({
|
|
102
|
+
green_coffee_inv_id: parsed.greenCoffeeInvId,
|
|
103
|
+
date_start: parsed.dateStart,
|
|
104
|
+
date_end: parsed.dateEnd,
|
|
105
|
+
buyer: parsed.buyer,
|
|
106
|
+
limit: parsed.limit,
|
|
107
|
+
offset: parsed.offset,
|
|
108
|
+
}), 'Sales list');
|
|
109
|
+
return envelope.data;
|
|
103
110
|
}
|
|
104
|
-
export async function resolveSaleRoast(
|
|
111
|
+
export async function resolveSaleRoast(input, tokenOverride) {
|
|
105
112
|
const parsed = saleTargetSelectorSchema.parse(input);
|
|
113
|
+
const client = await createParchmentClient('member', tokenOverride);
|
|
106
114
|
if (parsed.roastId !== undefined) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
const getRoast = Promise.resolve(client.roasts.get(String(parsed.roastId))).then((result) => unwrapParchment(result, 'Sale roast selector'));
|
|
116
|
+
const envelope = await getRoast;
|
|
117
|
+
const roast = envelope.data;
|
|
118
|
+
if (roast.coffee_id == null) {
|
|
119
|
+
throw new PrvrsError('INVALID_ARGUMENT', `Roast profile ${parsed.roastId} is not linked to a green coffee inventory item.`);
|
|
120
|
+
}
|
|
121
|
+
const batchName = roast.batch_name ?? undefined;
|
|
122
|
+
const exactMatches = await listExactSaleRoastMatches(client, roast.coffee_id, batchName);
|
|
123
|
+
if (exactMatches.length > 1) {
|
|
124
|
+
throw new PrvrsError('INVALID_ARGUMENT', `Roast profile ${parsed.roastId} shares inventory item ${roast.coffee_id} and batch name "${batchName ?? ''}" with roast IDs ${exactMatches.map((row) => row.roast_id).join(', ')}. The canonical sales record cannot retain a roast ID; give each roast a unique batch name before recording this sale.`);
|
|
115
125
|
}
|
|
116
|
-
return {
|
|
126
|
+
return {
|
|
127
|
+
greenCoffeeInvId: roast.coffee_id,
|
|
128
|
+
batchName,
|
|
129
|
+
roastId: roast.roast_id,
|
|
130
|
+
mode: 'exact',
|
|
131
|
+
};
|
|
117
132
|
}
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
.select('roast_id, batch_name')
|
|
121
|
-
.eq('user', userId)
|
|
122
|
-
.eq('coffee_id', parsed.coffeeId)
|
|
123
|
-
.eq('batch_name', parsed.batchName)
|
|
124
|
-
.limit(2);
|
|
125
|
-
if (lookupError)
|
|
126
|
-
throw lookupError;
|
|
127
|
-
const resolvedMatches = (matches ?? []);
|
|
128
|
-
if (resolvedMatches.length === 0) {
|
|
133
|
+
const exactMatches = await listExactSaleRoastMatches(client, parsed.coffeeId, parsed.batchName);
|
|
134
|
+
if (exactMatches.length === 0) {
|
|
129
135
|
throw new PrvrsError('NOT_FOUND', `No roast profile found for --coffee-id ${parsed.coffeeId} with batch name "${parsed.batchName}". Use 'purvey roast list --coffee-id ${parsed.coffeeId}' to inspect candidates, or pass --roast-id directly.`);
|
|
130
136
|
}
|
|
131
|
-
if (
|
|
132
|
-
|
|
133
|
-
throw new PrvrsError('INVALID_ARGUMENT', `Multiple roast profiles match --coffee-id ${parsed.coffeeId} and batch name "${parsed.batchName}". Matching roast IDs: ${matchIds}. Re-run with --roast-id.`);
|
|
137
|
+
if (exactMatches.length > 1) {
|
|
138
|
+
throw new PrvrsError('INVALID_ARGUMENT', `Multiple roast profiles match --coffee-id ${parsed.coffeeId} and batch name "${parsed.batchName}". Matching roast IDs: ${exactMatches.map((row) => row.roast_id).join(', ')}. The canonical sales record cannot retain a roast ID; give each roast a unique batch name before recording this sale.`);
|
|
134
139
|
}
|
|
135
|
-
return {
|
|
140
|
+
return {
|
|
141
|
+
greenCoffeeInvId: parsed.coffeeId,
|
|
142
|
+
batchName: parsed.batchName,
|
|
143
|
+
roastId: exactMatches[0].roast_id,
|
|
144
|
+
mode: 'resolved',
|
|
145
|
+
};
|
|
136
146
|
}
|
|
137
|
-
|
|
138
|
-
* Record a new sale (target roast must belong to userId).
|
|
139
|
-
*/
|
|
140
|
-
export async function recordSale(supabase, userId, input) {
|
|
147
|
+
export async function recordSale(input, tokenOverride) {
|
|
141
148
|
const parsed = recordSaleSchema.parse(input);
|
|
142
|
-
const target = await resolveSaleRoast(
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
149
|
+
const target = await resolveSaleRoast(parsed, tokenOverride);
|
|
150
|
+
const client = await createParchmentClient('member', tokenOverride);
|
|
151
|
+
const body = {
|
|
152
|
+
greenCoffeeInvId: target.greenCoffeeInvId,
|
|
153
|
+
ozSold: parsed.oz,
|
|
154
|
+
price: parsed.price,
|
|
155
|
+
...(parsed.buyer !== undefined ? { buyer: parsed.buyer } : {}),
|
|
156
|
+
...(target.batchName !== undefined ? { batchName: target.batchName } : {}),
|
|
157
|
+
...(parsed.sellDate !== undefined ? { sellDate: parsed.sellDate } : {}),
|
|
150
158
|
};
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const { data: inserted, error: insertError } = await supabase
|
|
154
|
-
.from('sales')
|
|
155
|
-
.insert(insertPayload)
|
|
156
|
-
.select('id')
|
|
157
|
-
.single();
|
|
158
|
-
if (insertError)
|
|
159
|
-
throw insertError;
|
|
160
|
-
// Re-fetch the full row with roast join
|
|
161
|
-
const { data, error } = await supabase
|
|
162
|
-
.from('sales')
|
|
163
|
-
.select(`${SALE_SELECT}, roast_profiles!roast_id (batch_name, coffee_name)`)
|
|
164
|
-
.eq('id', inserted.id)
|
|
165
|
-
.single();
|
|
166
|
-
if (error)
|
|
167
|
-
throw error;
|
|
168
|
-
return data;
|
|
159
|
+
const envelope = unwrapParchment(await client.sales.create(body, { idempotencyKey: randomUUID() }), 'Sale create');
|
|
160
|
+
return envelope.data;
|
|
169
161
|
}
|
|
170
|
-
|
|
171
|
-
* Update an existing sale (must belong to userId).
|
|
172
|
-
*/
|
|
173
|
-
export async function updateSale(supabase, userId, id, input) {
|
|
162
|
+
export async function updateSale(id, input, tokenOverride) {
|
|
174
163
|
deleteSaleSchema.parse({ id });
|
|
175
164
|
const parsed = updateSaleSchema.parse(input);
|
|
176
|
-
|
|
177
|
-
const
|
|
178
|
-
.
|
|
179
|
-
.
|
|
180
|
-
.
|
|
181
|
-
.
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const updates = {};
|
|
187
|
-
if (parsed.oz !== undefined)
|
|
188
|
-
updates.oz_sold = parsed.oz;
|
|
189
|
-
if (parsed.price !== undefined)
|
|
190
|
-
updates.sale_price = parsed.price;
|
|
191
|
-
if (parsed.buyer !== undefined)
|
|
192
|
-
updates.buyer = parsed.buyer;
|
|
193
|
-
if (parsed.sellDate !== undefined)
|
|
194
|
-
updates.sell_date = parsed.sellDate;
|
|
195
|
-
if (Object.keys(updates).length === 0) {
|
|
196
|
-
throw new PrvrsError('INVALID_ARGUMENT', 'No update fields provided. Pass at least one of: oz, price, buyer, sellDate.');
|
|
197
|
-
}
|
|
198
|
-
const { error: updateError } = await supabase
|
|
199
|
-
.from('sales')
|
|
200
|
-
.update(updates)
|
|
201
|
-
.eq('id', id)
|
|
202
|
-
.eq('user', userId);
|
|
203
|
-
if (updateError)
|
|
204
|
-
throw updateError;
|
|
205
|
-
// Re-fetch the updated row
|
|
206
|
-
const { data, error } = await supabase
|
|
207
|
-
.from('sales')
|
|
208
|
-
.select(`${SALE_SELECT}, roast_profiles!roast_id (batch_name, coffee_name)`)
|
|
209
|
-
.eq('id', id)
|
|
210
|
-
.single();
|
|
211
|
-
if (error)
|
|
212
|
-
throw error;
|
|
213
|
-
return data;
|
|
165
|
+
const client = await createParchmentClient('member', tokenOverride);
|
|
166
|
+
const body = {
|
|
167
|
+
...(parsed.oz !== undefined ? { ozSold: parsed.oz } : {}),
|
|
168
|
+
...(parsed.price !== undefined ? { price: parsed.price } : {}),
|
|
169
|
+
...(parsed.buyer !== undefined ? { buyer: parsed.buyer } : {}),
|
|
170
|
+
...(parsed.sellDate !== undefined ? { sellDate: parsed.sellDate } : {}),
|
|
171
|
+
};
|
|
172
|
+
const update = Promise.resolve(client.sales.update(id, body)).then((result) => unwrapParchment(result, 'Sale update'));
|
|
173
|
+
const envelope = await update;
|
|
174
|
+
return envelope.data;
|
|
214
175
|
}
|
|
215
|
-
|
|
216
|
-
* Delete a sale (must belong to userId).
|
|
217
|
-
*/
|
|
218
|
-
export async function deleteSale(supabase, userId, id) {
|
|
176
|
+
export async function deleteSale(id, tokenOverride) {
|
|
219
177
|
deleteSaleSchema.parse({ id });
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
.select('id')
|
|
224
|
-
.eq('id', id)
|
|
225
|
-
.eq('user', userId)
|
|
226
|
-
.single();
|
|
227
|
-
if (fetchError || !existing) {
|
|
228
|
-
throw new AuthError(`Sale ${id} not found or does not belong to you.`);
|
|
229
|
-
}
|
|
230
|
-
const { error: deleteError } = await supabase
|
|
231
|
-
.from('sales')
|
|
232
|
-
.delete()
|
|
233
|
-
.eq('id', id)
|
|
234
|
-
.eq('user', userId);
|
|
235
|
-
if (deleteError)
|
|
236
|
-
throw deleteError;
|
|
178
|
+
const client = await createParchmentClient('member', tokenOverride);
|
|
179
|
+
const remove = Promise.resolve(client.sales.delete(id)).then((result) => unwrapParchment(result, 'Sale delete'));
|
|
180
|
+
await remove;
|
|
237
181
|
}
|
|
238
182
|
//# sourceMappingURL=sales.js.map
|
package/dist/lib/sales.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sales.js","sourceRoot":"","sources":["../../src/lib/sales.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"sales.js","sourceRoot":"","sources":["../../src/lib/sales.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/tasting.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import type
|
|
3
|
-
import type { InventoryItem } from './inventory.js';
|
|
2
|
+
import { type InventoryItem } from './inventory.js';
|
|
4
3
|
export type TastingFilter = 'user' | 'supplier' | 'both';
|
|
5
4
|
export interface SupplierTastingNotes {
|
|
6
5
|
source: 'supplier';
|
|
@@ -68,9 +67,9 @@ export declare function parseCuppingScore(raw: string, flag: string): number;
|
|
|
68
67
|
* Get tasting notes for a bean by coffee_catalog ID.
|
|
69
68
|
* Combines supplier notes from coffee_catalog with user notes from green_coffee_inv.
|
|
70
69
|
*/
|
|
71
|
-
export declare function getTastingNotes(
|
|
70
|
+
export declare function getTastingNotes(id: number, filter?: TastingFilter): Promise<TastingData>;
|
|
72
71
|
/**
|
|
73
|
-
* Rate
|
|
72
|
+
* Rate an owned inventory lot through the canonical Parchment API.
|
|
74
73
|
*/
|
|
75
|
-
export declare function rateCoffee(
|
|
74
|
+
export declare function rateCoffee(id: number, input: RateCoffeeInput, tokenOverride?: string): Promise<InventoryItem>;
|
|
76
75
|
//# sourceMappingURL=tasting.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasting.d.ts","sourceRoot":"","sources":["../../src/lib/tasting.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"tasting.d.ts","sourceRoot":"","sources":["../../src/lib/tasting.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAKlE,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;AAEzD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAID,eAAO,MAAM,mBAAmB;;;;EAAuC,CAAC;AAExE,eAAO,MAAM,qBAAqB;;;;;;;iBAGhC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEzE,eAAO,MAAM,kBAAkB,aAAiC,CAAC;AAEjE,eAAO,MAAM,gBAAgB;;;;;;;;iBAQ3B,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAI/D,wDAAwD;AACxD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,mEAAmE;AACnE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CASnE;AAID;;;GAGG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,MAAM,EACV,MAAM,GAAE,aAAsB,GAC7B,OAAO,CAAC,WAAW,CAAC,CAQtB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,eAAe,EACtB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC,CAOxB"}
|
package/dist/lib/tasting.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { PrvrsError } from './errors.js';
|
|
3
|
+
import { getInventory } from './inventory.js';
|
|
4
|
+
import { createParchmentClient, unwrapParchment } from './parchment.js';
|
|
3
5
|
// ─── Zod schemas ──────────────────────────────────────────────────────────────
|
|
4
6
|
export const tastingFilterSchema = z.enum(['user', 'supplier', 'both']);
|
|
5
7
|
export const getTastingNotesSchema = z.object({
|
|
@@ -34,103 +36,21 @@ export function parseCuppingScore(raw, flag) {
|
|
|
34
36
|
* Get tasting notes for a bean by coffee_catalog ID.
|
|
35
37
|
* Combines supplier notes from coffee_catalog with user notes from green_coffee_inv.
|
|
36
38
|
*/
|
|
37
|
-
export async function getTastingNotes(
|
|
39
|
+
export async function getTastingNotes(id, filter = 'both') {
|
|
38
40
|
getTastingNotesSchema.parse({ bean_id: id, filter });
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
supplier: null,
|
|
43
|
-
user: null,
|
|
44
|
-
};
|
|
45
|
-
// ── Supplier notes (from coffee_catalog) ─────────────────────────
|
|
46
|
-
if (filter === 'supplier' || filter === 'both') {
|
|
47
|
-
const { data: catalogRow, error: catalogError } = await supabase
|
|
48
|
-
.from('coffee_catalog')
|
|
49
|
-
.select('id, name, processing, region, source, cupping_notes, ai_tasting_notes, ai_description')
|
|
50
|
-
.eq('id', id)
|
|
51
|
-
.single();
|
|
52
|
-
if (catalogError && catalogError.code !== 'PGRST116') {
|
|
53
|
-
throw catalogError;
|
|
54
|
-
}
|
|
55
|
-
if (catalogRow) {
|
|
56
|
-
result.supplier = {
|
|
57
|
-
source: 'supplier',
|
|
58
|
-
catalogId: catalogRow.id,
|
|
59
|
-
name: catalogRow.name ?? null,
|
|
60
|
-
processing: catalogRow.processing ?? null,
|
|
61
|
-
region: catalogRow.region ?? null,
|
|
62
|
-
cupping_notes: catalogRow.cupping_notes ?? null,
|
|
63
|
-
ai_tasting_notes: catalogRow.ai_tasting_notes ?? null,
|
|
64
|
-
ai_description: catalogRow.ai_description ?? null,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
// ── User notes (from green_coffee_inv) ───────────────────────────
|
|
69
|
-
if (filter === 'user' || filter === 'both') {
|
|
70
|
-
const { data: invRows, error: invError } = await supabase
|
|
71
|
-
.from('green_coffee_inv')
|
|
72
|
-
.select('id, catalog_id, cupping_notes, notes')
|
|
73
|
-
.eq('catalog_id', id)
|
|
74
|
-
.eq('user', userId)
|
|
75
|
-
.order('id', { ascending: false })
|
|
76
|
-
.limit(1);
|
|
77
|
-
if (invError)
|
|
78
|
-
throw invError;
|
|
79
|
-
if (invRows && invRows.length > 0) {
|
|
80
|
-
const row = invRows[0];
|
|
81
|
-
result.user = {
|
|
82
|
-
source: 'user',
|
|
83
|
-
inventoryId: row.id,
|
|
84
|
-
catalogId: row.catalog_id ?? null,
|
|
85
|
-
cupping_notes: row.cupping_notes ?? null,
|
|
86
|
-
notes: row.notes ?? null,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return result;
|
|
41
|
+
const client = await createParchmentClient('member');
|
|
42
|
+
const envelope = unwrapParchment(await client.tasting.get(String(id), { filter }), 'Tasting notes');
|
|
43
|
+
return envelope.data;
|
|
91
44
|
}
|
|
92
45
|
/**
|
|
93
|
-
* Rate
|
|
46
|
+
* Rate an owned inventory lot through the canonical Parchment API.
|
|
94
47
|
*/
|
|
95
|
-
export async function rateCoffee(
|
|
48
|
+
export async function rateCoffee(id, input, tokenOverride) {
|
|
96
49
|
const parsed = rateCoffeeSchema.parse(input);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
.eq('user', userId)
|
|
103
|
-
.single();
|
|
104
|
-
if (fetchError || !existing) {
|
|
105
|
-
throw new AuthError(`Inventory item ${id} not found or does not belong to you.`);
|
|
106
|
-
}
|
|
107
|
-
const cupping = {
|
|
108
|
-
aroma: parsed.aroma,
|
|
109
|
-
body: parsed.body,
|
|
110
|
-
acidity: parsed.acidity,
|
|
111
|
-
sweetness: parsed.sweetness,
|
|
112
|
-
aftertaste: parsed.aftertaste,
|
|
113
|
-
rated_at: new Date().toISOString(),
|
|
114
|
-
};
|
|
115
|
-
if (parsed.brewMethod !== undefined)
|
|
116
|
-
cupping.brew_method = parsed.brewMethod;
|
|
117
|
-
if (parsed.notes !== undefined)
|
|
118
|
-
cupping.notes = parsed.notes;
|
|
119
|
-
const { error: updateError } = await supabase
|
|
120
|
-
.from('green_coffee_inv')
|
|
121
|
-
.update({ cupping_notes: cupping })
|
|
122
|
-
.eq('id', id)
|
|
123
|
-
.eq('user', userId);
|
|
124
|
-
if (updateError)
|
|
125
|
-
throw updateError;
|
|
126
|
-
// Re-fetch the updated row
|
|
127
|
-
const { data, error } = await supabase
|
|
128
|
-
.from('green_coffee_inv')
|
|
129
|
-
.select('id, catalog_id, cupping_notes, notes, last_updated')
|
|
130
|
-
.eq('id', id)
|
|
131
|
-
.single();
|
|
132
|
-
if (error)
|
|
133
|
-
throw error;
|
|
134
|
-
return data;
|
|
50
|
+
const client = await createParchmentClient('member', tokenOverride);
|
|
51
|
+
unwrapParchment(await client.tasting.rate(id, parsed), 'Tasting rate');
|
|
52
|
+
// Preserve the public CLI/helper output contract: callers historically receive
|
|
53
|
+
// the refreshed inventory row rather than the mutation-specific API payload.
|
|
54
|
+
return getInventory(id, tokenOverride);
|
|
135
55
|
}
|
|
136
56
|
//# sourceMappingURL=tasting.js.map
|
package/dist/lib/tasting.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasting.js","sourceRoot":"","sources":["../../src/lib/tasting.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"tasting.js","sourceRoot":"","sources":["../../src/lib/tasting.ts"],"names":[],"mappings":"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"}
|
package/dist/program.js
CHANGED
|
@@ -96,7 +96,7 @@ Market intelligence (canonical API; entitled slices require Parchment Intelligen
|
|
|
96
96
|
procurement get Get a saved sourcing brief by id
|
|
97
97
|
procurement matches Page through catalog matches for a brief
|
|
98
98
|
|
|
99
|
-
Local and reference commands (no pre-existing
|
|
99
|
+
Local and reference commands (no pre-existing credentials required):
|
|
100
100
|
config list Show all config values
|
|
101
101
|
config get Get a config value
|
|
102
102
|
config set Set a config value
|
package/dist/types/index.d.ts
CHANGED
|
@@ -7,9 +7,9 @@ export interface GlobalOptions {
|
|
|
7
7
|
json?: boolean;
|
|
8
8
|
}
|
|
9
9
|
export interface StoredCredentials {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
apiKey: string;
|
|
11
|
+
keyId: string;
|
|
12
|
+
createdAt: string;
|
|
13
13
|
user: {
|
|
14
14
|
id: string;
|
|
15
15
|
email: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,gBAAiB,SAAQ,QAAQ;IAChD,KAAK,EAAE,IAAI,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@purveyors/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"description": "The official CLI for purveyors.io — coffee intelligence from your terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,8 +33,7 @@
|
|
|
33
33
|
"cli",
|
|
34
34
|
"purveyors",
|
|
35
35
|
"green-coffee",
|
|
36
|
-
"roasting"
|
|
37
|
-
"supabase"
|
|
36
|
+
"roasting"
|
|
38
37
|
],
|
|
39
38
|
"author": "Reed Whetstone",
|
|
40
39
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -57,8 +56,7 @@
|
|
|
57
56
|
},
|
|
58
57
|
"dependencies": {
|
|
59
58
|
"@clack/prompts": "^1.1.0",
|
|
60
|
-
"@purveyors/sdk": "^0.
|
|
61
|
-
"@supabase/supabase-js": "^2.49.1",
|
|
59
|
+
"@purveyors/sdk": "^0.9.0",
|
|
62
60
|
"chalk": "^5.4.1",
|
|
63
61
|
"commander": "^13.1.0",
|
|
64
62
|
"ora": "^8.2.0",
|
package/dist/lib/supabase.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { type SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
-
/**
|
|
3
|
-
* Create a Supabase client with no session (anonymous/unauthenticated).
|
|
4
|
-
* Used for login flows before we have a token.
|
|
5
|
-
*/
|
|
6
|
-
export declare function createAnonClient(): SupabaseClient;
|
|
7
|
-
/**
|
|
8
|
-
* Create a Supabase client initialized with stored credentials.
|
|
9
|
-
* Throws AuthError if no credentials are found.
|
|
10
|
-
*/
|
|
11
|
-
export declare function createAuthenticatedClient(): Promise<SupabaseClient>;
|
|
12
|
-
/**
|
|
13
|
-
* Validate stored credentials by making a lightweight Supabase auth call.
|
|
14
|
-
* Returns the user object if valid, null if expired/invalid.
|
|
15
|
-
*/
|
|
16
|
-
export declare function validateSession(): Promise<{
|
|
17
|
-
id: string;
|
|
18
|
-
email?: string;
|
|
19
|
-
role?: string;
|
|
20
|
-
expiresAt: number;
|
|
21
|
-
} | null>;
|
|
22
|
-
//# sourceMappingURL=supabase.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../src/lib/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAe1E;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAOjD;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,cAAc,CAAC,CAuCzE;AAED;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CAAC,CA0CR"}
|