@purveyors/cli 0.2.1 → 0.3.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.
Files changed (73) hide show
  1. package/dist/commands/catalog.d.ts +4 -56
  2. package/dist/commands/catalog.d.ts.map +1 -1
  3. package/dist/commands/catalog.js +14 -81
  4. package/dist/commands/catalog.js.map +1 -1
  5. package/dist/commands/inventory.d.ts +2 -25
  6. package/dist/commands/inventory.d.ts.map +1 -1
  7. package/dist/commands/inventory.js +47 -147
  8. package/dist/commands/inventory.js.map +1 -1
  9. package/dist/commands/roast.d.ts +2 -41
  10. package/dist/commands/roast.d.ts.map +1 -1
  11. package/dist/commands/roast.js +138 -125
  12. package/dist/commands/roast.js.map +1 -1
  13. package/dist/commands/sales.d.ts +2 -10
  14. package/dist/commands/sales.d.ts.map +1 -1
  15. package/dist/commands/sales.js +30 -109
  16. package/dist/commands/sales.js.map +1 -1
  17. package/dist/commands/tasting.d.ts +4 -38
  18. package/dist/commands/tasting.d.ts.map +1 -1
  19. package/dist/commands/tasting.js +18 -108
  20. package/dist/commands/tasting.js.map +1 -1
  21. package/dist/lib/artisan/db.d.ts +37 -0
  22. package/dist/lib/artisan/db.d.ts.map +1 -0
  23. package/dist/lib/artisan/db.js +51 -0
  24. package/dist/lib/artisan/db.js.map +1 -0
  25. package/dist/lib/artisan/import.d.ts +16 -0
  26. package/dist/lib/artisan/import.d.ts.map +1 -0
  27. package/dist/lib/artisan/import.js +447 -0
  28. package/dist/lib/artisan/import.js.map +1 -0
  29. package/dist/lib/artisan/index.d.ts +9 -0
  30. package/dist/lib/artisan/index.d.ts.map +1 -0
  31. package/dist/lib/artisan/index.js +7 -0
  32. package/dist/lib/artisan/index.js.map +1 -0
  33. package/dist/lib/artisan/parser.d.ts +19 -0
  34. package/dist/lib/artisan/parser.d.ts.map +1 -0
  35. package/dist/lib/artisan/parser.js +376 -0
  36. package/dist/lib/artisan/parser.js.map +1 -0
  37. package/dist/lib/artisan/temperature.d.ts +52 -0
  38. package/dist/lib/artisan/temperature.d.ts.map +1 -0
  39. package/dist/lib/artisan/temperature.js +101 -0
  40. package/dist/lib/artisan/temperature.js.map +1 -0
  41. package/dist/lib/artisan/types.d.ts +195 -0
  42. package/dist/lib/artisan/types.d.ts.map +1 -0
  43. package/dist/lib/artisan/types.js +35 -0
  44. package/dist/lib/artisan/types.js.map +1 -0
  45. package/dist/lib/artisan/validator.d.ts +14 -0
  46. package/dist/lib/artisan/validator.d.ts.map +1 -0
  47. package/dist/lib/artisan/validator.js +228 -0
  48. package/dist/lib/artisan/validator.js.map +1 -0
  49. package/dist/lib/catalog.d.ts +87 -0
  50. package/dist/lib/catalog.d.ts.map +1 -0
  51. package/dist/lib/catalog.js +111 -0
  52. package/dist/lib/catalog.js.map +1 -0
  53. package/dist/lib/index.d.ts +6 -0
  54. package/dist/lib/index.d.ts.map +1 -0
  55. package/dist/lib/index.js +11 -0
  56. package/dist/lib/index.js.map +1 -0
  57. package/dist/lib/inventory.d.ts +80 -0
  58. package/dist/lib/inventory.d.ts.map +1 -0
  59. package/dist/lib/inventory.js +205 -0
  60. package/dist/lib/inventory.js.map +1 -0
  61. package/dist/lib/roast.d.ts +127 -0
  62. package/dist/lib/roast.d.ts.map +1 -0
  63. package/dist/lib/roast.js +284 -0
  64. package/dist/lib/roast.js.map +1 -0
  65. package/dist/lib/sales.d.ts +53 -0
  66. package/dist/lib/sales.d.ts.map +1 -0
  67. package/dist/lib/sales.js +155 -0
  68. package/dist/lib/sales.js.map +1 -0
  69. package/dist/lib/tasting.d.ts +76 -0
  70. package/dist/lib/tasting.d.ts.map +1 -0
  71. package/dist/lib/tasting.js +136 -0
  72. package/dist/lib/tasting.js.map +1 -0
  73. package/package.json +13 -2
@@ -0,0 +1,111 @@
1
+ import { z } from 'zod';
2
+ // ─── Zod schemas ──────────────────────────────────────────────────────────────
3
+ export const searchCatalogSchema = z.object({
4
+ origin: z.string().optional(),
5
+ process: z.string().optional(),
6
+ priceMin: z.number().optional(),
7
+ priceMax: z.number().optional(),
8
+ flavor: z.string().optional(),
9
+ stocked: z.boolean().optional(),
10
+ limit: z.number().int().min(1).default(10),
11
+ });
12
+ export const getCatalogSchema = z.object({
13
+ id: z.number().int().positive(),
14
+ });
15
+ export const getCatalogStatsSchema = z.object({});
16
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
17
+ /**
18
+ * Strip PostgREST special characters from user-supplied filter values.
19
+ * Prevents injection into .or() filter strings where values are interpolated directly.
20
+ * Removes: ( ) , . * % that have meaning in PostgREST filter syntax.
21
+ */
22
+ export function sanitizeFilterValue(value) {
23
+ return value.replace(/[(),.*%]/g, '');
24
+ }
25
+ /**
26
+ * Aggregate stats from an array of catalog items.
27
+ * Pure function — no I/O, safe to unit test.
28
+ */
29
+ export function computeCatalogStats(items) {
30
+ const stocked = items.filter((i) => i.stocked === true).length;
31
+ const byOrigin = {};
32
+ for (const item of items) {
33
+ const key = item.country ?? item.continent ?? 'Unknown';
34
+ byOrigin[key] = (byOrigin[key] ?? 0) + 1;
35
+ }
36
+ const prices = items.map((i) => i.cost_lb).filter((p) => p !== null);
37
+ const avgPricePerLb = prices.length > 0
38
+ ? Math.round((prices.reduce((a, b) => a + b, 0) / prices.length) * 100) / 100
39
+ : null;
40
+ const priceRange = {
41
+ min: prices.length > 0 ? Math.min(...prices) : null,
42
+ max: prices.length > 0 ? Math.max(...prices) : null,
43
+ };
44
+ return { total: items.length, stocked, byOrigin, avgPricePerLb, priceRange };
45
+ }
46
+ // ─── Pure lib functions ───────────────────────────────────────────────────────
47
+ /**
48
+ * Search the coffee catalog with optional filters.
49
+ */
50
+ export async function searchCatalog(supabase, opts) {
51
+ const parsed = searchCatalogSchema.parse(opts);
52
+ let query = supabase.from('coffee_catalog').select('*');
53
+ if (parsed.origin) {
54
+ const o = sanitizeFilterValue(parsed.origin);
55
+ query = query.or(`country.ilike.%${o}%,continent.ilike.%${o}%,region.ilike.%${o}%`);
56
+ }
57
+ if (parsed.process) {
58
+ const p = sanitizeFilterValue(parsed.process);
59
+ query = query.ilike('processing', `%${p}%`);
60
+ }
61
+ if (parsed.priceMin !== undefined) {
62
+ query = query.gte('cost_lb', parsed.priceMin);
63
+ }
64
+ if (parsed.priceMax !== undefined) {
65
+ query = query.lte('cost_lb', parsed.priceMax);
66
+ }
67
+ if (parsed.flavor) {
68
+ const keywords = parsed.flavor
69
+ .split(',')
70
+ .map((k) => sanitizeFilterValue(k.trim()))
71
+ .filter(Boolean);
72
+ const flavorFilters = keywords
73
+ .flatMap((kw) => [
74
+ `description_short.ilike.%${kw}%`,
75
+ `description_long.ilike.%${kw}%`,
76
+ `cupping_notes.ilike.%${kw}%`,
77
+ `farm_notes.ilike.%${kw}%`,
78
+ ])
79
+ .join(',');
80
+ query = query.or(flavorFilters);
81
+ }
82
+ if (parsed.stocked) {
83
+ query = query.eq('stocked', true);
84
+ }
85
+ const { data, error } = await query.limit(parsed.limit);
86
+ if (error)
87
+ throw error;
88
+ return (data ?? []);
89
+ }
90
+ /**
91
+ * Fetch a single catalog item by ID.
92
+ */
93
+ export async function getCatalog(supabase, id) {
94
+ getCatalogSchema.parse({ id });
95
+ const { data, error } = await supabase.from('coffee_catalog').select('*').eq('id', id).single();
96
+ if (error)
97
+ throw error;
98
+ return data;
99
+ }
100
+ /**
101
+ * Fetch aggregate statistics for the coffee catalog.
102
+ */
103
+ export async function getCatalogStats(supabase) {
104
+ const { data, error } = await supabase
105
+ .from('coffee_catalog')
106
+ .select('id, country, continent, cost_lb, stocked');
107
+ if (error)
108
+ throw error;
109
+ return computeCatalogStats((data ?? []));
110
+ }
111
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/lib/catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export * from './catalog.js';
2
+ export * from './inventory.js';
3
+ export * from './roast.js';
4
+ export * from './sales.js';
5
+ export * from './tasting.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAMA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,11 @@
1
+ // Barrel export — re-exports all lib modules for convenience.
2
+ // Usage: import { searchCatalog, listInventory } from '@purveyors/cli/lib'
3
+ // Or use individual subpath imports:
4
+ // import { searchCatalog } from '@purveyors/cli/catalog'
5
+ // import { listInventory } from '@purveyors/cli/inventory'
6
+ export * from './catalog.js';
7
+ export * from './inventory.js';
8
+ export * from './roast.js';
9
+ export * from './sales.js';
10
+ export * from './tasting.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,2EAA2E;AAC3E,qCAAqC;AACrC,2DAA2D;AAC3D,6DAA6D;AAE7D,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,80 @@
1
+ import { z } from 'zod';
2
+ import type { SupabaseClient } from '@supabase/supabase-js';
3
+ export interface InventoryItem {
4
+ id: number;
5
+ rank: number | null;
6
+ notes: string | null;
7
+ cupping_notes: string | null;
8
+ purchase_date: string | null;
9
+ purchased_qty_lbs: number | null;
10
+ bean_cost: number | null;
11
+ tax_ship_cost: number | null;
12
+ last_updated: string;
13
+ user: string;
14
+ catalog_id: number | null;
15
+ stocked: boolean | null;
16
+ coffee_catalog: {
17
+ id: number;
18
+ name: string | null;
19
+ source: string | null;
20
+ country: string | null;
21
+ region: string | null;
22
+ processing: string | null;
23
+ cost_lb: number | null;
24
+ description_short: string | null;
25
+ stocked: boolean | null;
26
+ } | null;
27
+ }
28
+ export declare const INVENTORY_LIST_SELECT: string;
29
+ export declare const INVENTORY_DETAIL_SELECT: string;
30
+ export declare const listInventorySchema: z.ZodObject<{
31
+ stocked: z.ZodOptional<z.ZodBoolean>;
32
+ limit: z.ZodDefault<z.ZodNumber>;
33
+ }, z.core.$strip>;
34
+ export type ListInventoryInput = z.input<typeof listInventorySchema>;
35
+ export declare const getInventorySchema: z.ZodObject<{
36
+ id: z.ZodNumber;
37
+ }, z.core.$strip>;
38
+ export type GetInventoryInput = z.input<typeof getInventorySchema>;
39
+ export declare const addInventorySchema: z.ZodObject<{
40
+ catalogId: z.ZodNumber;
41
+ qty: z.ZodNumber;
42
+ cost: z.ZodOptional<z.ZodNumber>;
43
+ taxShip: z.ZodOptional<z.ZodNumber>;
44
+ notes: z.ZodOptional<z.ZodString>;
45
+ purchaseDate: z.ZodOptional<z.ZodString>;
46
+ }, z.core.$strip>;
47
+ export type AddInventoryInput = z.input<typeof addInventorySchema>;
48
+ export declare const updateInventorySchema: z.ZodObject<{
49
+ qty: z.ZodOptional<z.ZodNumber>;
50
+ cost: z.ZodOptional<z.ZodNumber>;
51
+ taxShip: z.ZodOptional<z.ZodNumber>;
52
+ notes: z.ZodOptional<z.ZodString>;
53
+ stocked: z.ZodOptional<z.ZodBoolean>;
54
+ }, z.core.$strip>;
55
+ export type UpdateInventoryInput = z.input<typeof updateInventorySchema>;
56
+ export declare const deleteInventorySchema: z.ZodObject<{
57
+ id: z.ZodNumber;
58
+ }, z.core.$strip>;
59
+ export type DeleteInventoryInput = z.input<typeof deleteInventorySchema>;
60
+ /**
61
+ * List green coffee inventory for a user.
62
+ */
63
+ export declare function listInventory(supabase: SupabaseClient, userId: string, opts: ListInventoryInput): Promise<InventoryItem[]>;
64
+ /**
65
+ * Fetch a single inventory item by ID (must belong to userId).
66
+ */
67
+ export declare function getInventory(supabase: SupabaseClient, userId: string, id: number): Promise<InventoryItem>;
68
+ /**
69
+ * Add a new inventory item for a user.
70
+ */
71
+ export declare function addInventory(supabase: SupabaseClient, userId: string, input: AddInventoryInput): Promise<InventoryItem>;
72
+ /**
73
+ * Update an existing inventory item (must belong to userId).
74
+ */
75
+ export declare function updateInventory(supabase: SupabaseClient, userId: string, id: number, input: UpdateInventoryInput): Promise<InventoryItem>;
76
+ /**
77
+ * Delete an inventory item (must belong to userId).
78
+ */
79
+ export declare function deleteInventory(supabase: SupabaseClient, userId: string, id: number): Promise<void>;
80
+ //# sourceMappingURL=inventory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inventory.d.ts","sourceRoot":"","sources":["../../src/lib/inventory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,205 @@
1
+ import { z } from 'zod';
2
+ import { AuthError, PrvrsError } from './errors.js';
3
+ // ─── Shared select columns ────────────────────────────────────────────────────
4
+ export const INVENTORY_LIST_SELECT = [
5
+ 'id',
6
+ 'rank',
7
+ 'notes',
8
+ 'cupping_notes',
9
+ 'purchase_date',
10
+ 'purchased_qty_lbs',
11
+ 'bean_cost',
12
+ 'tax_ship_cost',
13
+ 'last_updated',
14
+ 'user',
15
+ 'catalog_id',
16
+ 'stocked',
17
+ 'coffee_catalog!catalog_id (id, name, source, country, region, processing, cost_lb, description_short, stocked)',
18
+ ].join(', ');
19
+ export const INVENTORY_DETAIL_SELECT = [
20
+ 'id',
21
+ 'rank',
22
+ 'notes',
23
+ 'cupping_notes',
24
+ 'purchase_date',
25
+ 'purchased_qty_lbs',
26
+ 'bean_cost',
27
+ 'tax_ship_cost',
28
+ 'last_updated',
29
+ 'user',
30
+ 'catalog_id',
31
+ 'stocked',
32
+ 'coffee_catalog!catalog_id (id, name, source, country, region, processing, cost_lb, description_short, description_long, farm_notes, cupping_notes, stocked)',
33
+ ].join(', ');
34
+ // ─── Zod schemas ──────────────────────────────────────────────────────────────
35
+ export const listInventorySchema = z.object({
36
+ stocked: z.boolean().optional(),
37
+ limit: z.number().int().min(1).default(20),
38
+ });
39
+ export const getInventorySchema = z.object({
40
+ id: z.number().int().positive(),
41
+ });
42
+ export const addInventorySchema = z.object({
43
+ catalogId: z.number().int().positive(),
44
+ qty: z.number().positive(),
45
+ cost: z.number().optional(),
46
+ taxShip: z.number().optional(),
47
+ notes: z.string().optional(),
48
+ purchaseDate: z.string().optional(),
49
+ });
50
+ export const updateInventorySchema = z
51
+ .object({
52
+ qty: z.number().positive().optional(),
53
+ cost: z.number().optional(),
54
+ taxShip: z.number().optional(),
55
+ notes: z.string().optional(),
56
+ stocked: z.boolean().optional(),
57
+ })
58
+ .refine((v) => Object.keys(v).some((k) => v[k] !== undefined), {
59
+ message: 'No update fields provided. Pass at least one of: qty, cost, taxShip, notes, stocked.',
60
+ });
61
+ export const deleteInventorySchema = z.object({
62
+ id: z.number().int().positive(),
63
+ });
64
+ // ─── Pure lib functions ───────────────────────────────────────────────────────
65
+ /**
66
+ * List green coffee inventory for a user.
67
+ */
68
+ export async function listInventory(supabase, userId, opts) {
69
+ const parsed = listInventorySchema.parse(opts);
70
+ let query = supabase.from('green_coffee_inv').select(INVENTORY_LIST_SELECT).eq('user', userId);
71
+ if (parsed.stocked) {
72
+ query = query.eq('stocked', true);
73
+ }
74
+ const { data, error } = await query
75
+ .order('last_updated', { ascending: false })
76
+ .limit(parsed.limit);
77
+ if (error)
78
+ throw error;
79
+ return (data ?? []);
80
+ }
81
+ /**
82
+ * Fetch a single inventory item by ID (must belong to userId).
83
+ */
84
+ export async function getInventory(supabase, userId, id) {
85
+ getInventorySchema.parse({ id });
86
+ const { data, error } = await supabase
87
+ .from('green_coffee_inv')
88
+ .select(INVENTORY_DETAIL_SELECT)
89
+ .eq('id', id)
90
+ .eq('user', userId)
91
+ .single();
92
+ if (error) {
93
+ if (error.code === 'PGRST116') {
94
+ throw new AuthError(`Inventory item ${id} not found or does not belong to you.`);
95
+ }
96
+ throw error;
97
+ }
98
+ return data;
99
+ }
100
+ /**
101
+ * Add a new inventory item for a user.
102
+ */
103
+ export async function addInventory(supabase, userId, input) {
104
+ const parsed = addInventorySchema.parse(input);
105
+ const todayIso = () => new Date().toISOString().slice(0, 10);
106
+ const insertPayload = {
107
+ user: userId,
108
+ catalog_id: parsed.catalogId,
109
+ purchased_qty_lbs: parsed.qty,
110
+ purchase_date: parsed.purchaseDate ?? todayIso(),
111
+ };
112
+ if (parsed.cost !== undefined)
113
+ insertPayload.bean_cost = parsed.cost;
114
+ if (parsed.taxShip !== undefined)
115
+ insertPayload.tax_ship_cost = parsed.taxShip;
116
+ if (parsed.notes !== undefined)
117
+ insertPayload.notes = parsed.notes;
118
+ const { data: inserted, error: insertError } = await supabase
119
+ .from('green_coffee_inv')
120
+ .insert(insertPayload)
121
+ .select('id')
122
+ .single();
123
+ if (insertError)
124
+ throw insertError;
125
+ // Re-fetch with catalog join
126
+ const { data, error } = await supabase
127
+ .from('green_coffee_inv')
128
+ .select(INVENTORY_LIST_SELECT)
129
+ .eq('id', inserted.id)
130
+ .single();
131
+ if (error)
132
+ throw error;
133
+ return data;
134
+ }
135
+ /**
136
+ * Update an existing inventory item (must belong to userId).
137
+ */
138
+ export async function updateInventory(supabase, userId, id, input) {
139
+ getInventorySchema.parse({ id });
140
+ const parsed = updateInventorySchema.parse(input);
141
+ // Verify ownership
142
+ const { data: existing, error: fetchError } = await supabase
143
+ .from('green_coffee_inv')
144
+ .select('id')
145
+ .eq('id', id)
146
+ .eq('user', userId)
147
+ .single();
148
+ if (fetchError || !existing) {
149
+ throw new AuthError(`Inventory item ${id} not found or does not belong to you.`);
150
+ }
151
+ const updates = {};
152
+ if (parsed.qty !== undefined)
153
+ updates.purchased_qty_lbs = parsed.qty;
154
+ if (parsed.cost !== undefined)
155
+ updates.bean_cost = parsed.cost;
156
+ if (parsed.taxShip !== undefined)
157
+ updates.tax_ship_cost = parsed.taxShip;
158
+ if (parsed.notes !== undefined)
159
+ updates.notes = parsed.notes;
160
+ if (parsed.stocked !== undefined)
161
+ updates.stocked = parsed.stocked;
162
+ if (Object.keys(updates).length === 0) {
163
+ throw new PrvrsError('INVALID_ARGUMENT', 'No update fields provided. Pass at least one of: qty, cost, taxShip, notes, stocked.');
164
+ }
165
+ const { error: updateError } = await supabase
166
+ .from('green_coffee_inv')
167
+ .update(updates)
168
+ .eq('id', id)
169
+ .eq('user', userId);
170
+ if (updateError)
171
+ throw updateError;
172
+ // Re-fetch the updated row
173
+ const { data, error } = await supabase
174
+ .from('green_coffee_inv')
175
+ .select(INVENTORY_LIST_SELECT)
176
+ .eq('id', id)
177
+ .single();
178
+ if (error)
179
+ throw error;
180
+ return data;
181
+ }
182
+ /**
183
+ * Delete an inventory item (must belong to userId).
184
+ */
185
+ export async function deleteInventory(supabase, userId, id) {
186
+ deleteInventorySchema.parse({ id });
187
+ // Verify ownership
188
+ const { data: existing, error: fetchError } = await supabase
189
+ .from('green_coffee_inv')
190
+ .select('id')
191
+ .eq('id', id)
192
+ .eq('user', userId)
193
+ .single();
194
+ if (fetchError || !existing) {
195
+ throw new AuthError(`Inventory item ${id} not found or does not belong to you.`);
196
+ }
197
+ const { error: deleteError } = await supabase
198
+ .from('green_coffee_inv')
199
+ .delete()
200
+ .eq('id', id)
201
+ .eq('user', userId);
202
+ if (deleteError)
203
+ throw deleteError;
204
+ }
205
+ //# sourceMappingURL=inventory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inventory.js","sourceRoot":"","sources":["../../src/lib/inventory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ import { z } from 'zod';
2
+ import type { SupabaseClient } from '@supabase/supabase-js';
3
+ import type { ArtisanImportResult } from './artisan/import.js';
4
+ export interface RoastProfile {
5
+ roast_id: number;
6
+ batch_name: string | null;
7
+ coffee_id: number | null;
8
+ coffee_name: string | null;
9
+ roast_date: string | null;
10
+ oz_in: number | null;
11
+ oz_out: number | null;
12
+ weight_loss_percent: number | null;
13
+ roast_notes: string | null;
14
+ user: string;
15
+ last_updated: string;
16
+ roaster_type: string | null;
17
+ roaster_size: string | null;
18
+ temperature_unit: string | null;
19
+ charge_time: number | null;
20
+ drop_time: number | null;
21
+ fc_start_time: number | null;
22
+ fc_end_time: number | null;
23
+ fc_start_temp: number | null;
24
+ drop_temp: number | null;
25
+ charge_temp: number | null;
26
+ dry_percent: number | null;
27
+ maillard_percent: number | null;
28
+ development_percent: number | null;
29
+ total_roast_time: number | null;
30
+ data_source: string | null;
31
+ roast_uuid: string | null;
32
+ temperatures?: TemperatureEntry[];
33
+ events?: RoastEventEntry[];
34
+ }
35
+ export interface TemperatureEntry {
36
+ roast_id: number;
37
+ time_seconds: number;
38
+ bean_temp: number | null;
39
+ environmental_temp: number | null;
40
+ }
41
+ export interface RoastEventEntry {
42
+ roast_id: number;
43
+ time_seconds: number;
44
+ event_type: number | null;
45
+ event_value: string | null;
46
+ }
47
+ export declare const listRoastsSchema: z.ZodObject<{
48
+ coffeeId: z.ZodOptional<z.ZodNumber>;
49
+ limit: z.ZodDefault<z.ZodNumber>;
50
+ }, z.core.$strip>;
51
+ export type ListRoastsInput = z.input<typeof listRoastsSchema>;
52
+ export declare const getRoastSchema: z.ZodObject<{
53
+ id: z.ZodNumber;
54
+ includeTemps: z.ZodOptional<z.ZodBoolean>;
55
+ includeEvents: z.ZodOptional<z.ZodBoolean>;
56
+ }, z.core.$strip>;
57
+ export type GetRoastInput = z.input<typeof getRoastSchema>;
58
+ export declare const createRoastSchema: z.ZodObject<{
59
+ coffeeId: z.ZodNumber;
60
+ batchName: z.ZodOptional<z.ZodString>;
61
+ ozIn: z.ZodOptional<z.ZodNumber>;
62
+ ozOut: z.ZodOptional<z.ZodNumber>;
63
+ roastDate: z.ZodOptional<z.ZodString>;
64
+ notes: z.ZodOptional<z.ZodString>;
65
+ }, z.core.$strip>;
66
+ export type CreateRoastInput = z.input<typeof createRoastSchema>;
67
+ export declare const deleteRoastSchema: z.ZodObject<{
68
+ id: z.ZodNumber;
69
+ }, z.core.$strip>;
70
+ export type DeleteRoastInput = z.input<typeof deleteRoastSchema>;
71
+ /**
72
+ * List roast profiles for a user.
73
+ */
74
+ export declare function listRoasts(supabase: SupabaseClient, userId: string, opts: ListRoastsInput): Promise<RoastProfile[]>;
75
+ /**
76
+ * Fetch a single roast profile by ID (must belong to userId).
77
+ * Optionally includes temperature curve and roast events.
78
+ */
79
+ export declare function getRoast(supabase: SupabaseClient, userId: string, id: number, opts?: {
80
+ includeTemps?: boolean;
81
+ includeEvents?: boolean;
82
+ }): Promise<RoastProfile>;
83
+ /**
84
+ * Create a new roast profile (coffeeId must be an inventory item belonging to userId).
85
+ */
86
+ export declare function createRoast(supabase: SupabaseClient, userId: string, input: CreateRoastInput): Promise<RoastProfile>;
87
+ /**
88
+ * Delete a roast profile (must belong to userId).
89
+ */
90
+ export declare function deleteRoast(supabase: SupabaseClient, userId: string, id: number): Promise<void>;
91
+ export declare const importRoastSchema: z.ZodObject<{
92
+ fileContent: z.ZodString;
93
+ fileName: z.ZodString;
94
+ coffeeId: z.ZodNumber;
95
+ batchName: z.ZodOptional<z.ZodString>;
96
+ ozIn: z.ZodOptional<z.ZodNumber>;
97
+ roastNotes: z.ZodOptional<z.ZodString>;
98
+ }, z.core.$strip>;
99
+ export type ImportRoastInput = z.input<typeof importRoastSchema>;
100
+ export interface ImportRoastResult extends ArtisanImportResult {
101
+ roast_id: number;
102
+ batch_name: string;
103
+ coffee_name: string;
104
+ coffee_id: number;
105
+ }
106
+ /**
107
+ * Extract the input weight in ounces from an Artisan .alog weight array.
108
+ * Falls back to undefined if weight data is absent or unparseable.
109
+ *
110
+ * @param weight - The `weight` field from ArtisanRoastData: [input, output, unit]
111
+ */
112
+ export declare function extractOzFromAlog(weight: [number, number, string] | undefined): number | undefined;
113
+ /**
114
+ * Generate a default batch name: "{coffee_name} {YYYY-MM-DD}".
115
+ */
116
+ export declare function defaultBatchName(coffeeName: string, dateIso: string): string;
117
+ /**
118
+ * Import a roast from an Artisan .alog file in one step:
119
+ * 1. Verify inventory ownership + get coffee name
120
+ * 2. Create a new roast_profile row
121
+ * 3. Run the full Artisan import (temperatures, events, profile metadata)
122
+ * 4. Return the combined result
123
+ *
124
+ * The supabase client must already be authenticated as userId.
125
+ */
126
+ export declare function importRoastFromFile(supabase: SupabaseClient, userId: string, input: ImportRoastInput): Promise<ImportRoastResult>;
127
+ //# sourceMappingURL=roast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roast.d.ts","sourceRoot":"","sources":["../../src/lib/roast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAI/D,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAClC,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAYD,eAAO,MAAM,gBAAgB;;;iBAG3B,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE/D,eAAO,MAAM,cAAc;;;;iBAIzB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE3D,eAAO,MAAM,iBAAiB;;;;;;;iBAO5B,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAEjE,eAAO,MAAM,iBAAiB;;iBAE5B,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAIjE;;GAEG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,YAAY,EAAE,CAAC,CAczB;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,EACV,IAAI,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7D,OAAO,CAAC,YAAY,CAAC,CA0CvB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,YAAY,CAAC,CA2DvB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAID,eAAO,MAAM,iBAAiB;;;;;;;iBAO5B,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAEjE,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GAC3C,MAAM,GAAG,SAAS,CA0BpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,iBAAiB,CAAC,CAkF5B"}