@purveyors/cli 0.2.1 → 0.4.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 (95) 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/config.d.ts +7 -0
  6. package/dist/commands/config.d.ts.map +1 -0
  7. package/dist/commands/config.js +82 -0
  8. package/dist/commands/config.js.map +1 -0
  9. package/dist/commands/inventory.d.ts +2 -25
  10. package/dist/commands/inventory.d.ts.map +1 -1
  11. package/dist/commands/inventory.js +109 -149
  12. package/dist/commands/inventory.js.map +1 -1
  13. package/dist/commands/roast.d.ts +2 -41
  14. package/dist/commands/roast.d.ts.map +1 -1
  15. package/dist/commands/roast.js +445 -126
  16. package/dist/commands/roast.js.map +1 -1
  17. package/dist/commands/sales.d.ts +2 -10
  18. package/dist/commands/sales.d.ts.map +1 -1
  19. package/dist/commands/sales.js +100 -112
  20. package/dist/commands/sales.js.map +1 -1
  21. package/dist/commands/tasting.d.ts +4 -38
  22. package/dist/commands/tasting.d.ts.map +1 -1
  23. package/dist/commands/tasting.js +93 -116
  24. package/dist/commands/tasting.js.map +1 -1
  25. package/dist/index.js +8 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/lib/ai.d.ts +36 -0
  28. package/dist/lib/ai.d.ts.map +1 -0
  29. package/dist/lib/ai.js +38 -0
  30. package/dist/lib/ai.js.map +1 -0
  31. package/dist/lib/artisan/db.d.ts +37 -0
  32. package/dist/lib/artisan/db.d.ts.map +1 -0
  33. package/dist/lib/artisan/db.js +51 -0
  34. package/dist/lib/artisan/db.js.map +1 -0
  35. package/dist/lib/artisan/import.d.ts +16 -0
  36. package/dist/lib/artisan/import.d.ts.map +1 -0
  37. package/dist/lib/artisan/import.js +447 -0
  38. package/dist/lib/artisan/import.js.map +1 -0
  39. package/dist/lib/artisan/index.d.ts +9 -0
  40. package/dist/lib/artisan/index.d.ts.map +1 -0
  41. package/dist/lib/artisan/index.js +7 -0
  42. package/dist/lib/artisan/index.js.map +1 -0
  43. package/dist/lib/artisan/parser.d.ts +19 -0
  44. package/dist/lib/artisan/parser.d.ts.map +1 -0
  45. package/dist/lib/artisan/parser.js +376 -0
  46. package/dist/lib/artisan/parser.js.map +1 -0
  47. package/dist/lib/artisan/temperature.d.ts +52 -0
  48. package/dist/lib/artisan/temperature.d.ts.map +1 -0
  49. package/dist/lib/artisan/temperature.js +101 -0
  50. package/dist/lib/artisan/temperature.js.map +1 -0
  51. package/dist/lib/artisan/types.d.ts +195 -0
  52. package/dist/lib/artisan/types.d.ts.map +1 -0
  53. package/dist/lib/artisan/types.js +35 -0
  54. package/dist/lib/artisan/types.js.map +1 -0
  55. package/dist/lib/artisan/validator.d.ts +14 -0
  56. package/dist/lib/artisan/validator.d.ts.map +1 -0
  57. package/dist/lib/artisan/validator.js +228 -0
  58. package/dist/lib/artisan/validator.js.map +1 -0
  59. package/dist/lib/catalog.d.ts +87 -0
  60. package/dist/lib/catalog.d.ts.map +1 -0
  61. package/dist/lib/catalog.js +111 -0
  62. package/dist/lib/catalog.js.map +1 -0
  63. package/dist/lib/config.d.ts +26 -0
  64. package/dist/lib/config.d.ts.map +1 -1
  65. package/dist/lib/config.js +59 -0
  66. package/dist/lib/config.js.map +1 -1
  67. package/dist/lib/index.d.ts +6 -0
  68. package/dist/lib/index.d.ts.map +1 -0
  69. package/dist/lib/index.js +11 -0
  70. package/dist/lib/index.js.map +1 -0
  71. package/dist/lib/interactive/forms.d.ts +33 -0
  72. package/dist/lib/interactive/forms.d.ts.map +1 -0
  73. package/dist/lib/interactive/forms.js +139 -0
  74. package/dist/lib/interactive/forms.js.map +1 -0
  75. package/dist/lib/interactive/watch.d.ts +66 -0
  76. package/dist/lib/interactive/watch.d.ts.map +1 -0
  77. package/dist/lib/interactive/watch.js +494 -0
  78. package/dist/lib/interactive/watch.js.map +1 -0
  79. package/dist/lib/inventory.d.ts +80 -0
  80. package/dist/lib/inventory.d.ts.map +1 -0
  81. package/dist/lib/inventory.js +205 -0
  82. package/dist/lib/inventory.js.map +1 -0
  83. package/dist/lib/roast.d.ts +127 -0
  84. package/dist/lib/roast.d.ts.map +1 -0
  85. package/dist/lib/roast.js +284 -0
  86. package/dist/lib/roast.js.map +1 -0
  87. package/dist/lib/sales.d.ts +53 -0
  88. package/dist/lib/sales.d.ts.map +1 -0
  89. package/dist/lib/sales.js +155 -0
  90. package/dist/lib/sales.js.map +1 -0
  91. package/dist/lib/tasting.d.ts +76 -0
  92. package/dist/lib/tasting.d.ts.map +1 -0
  93. package/dist/lib/tasting.js +136 -0
  94. package/dist/lib/tasting.js.map +1 -0
  95. package/package.json +15 -2
@@ -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":"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"}
@@ -0,0 +1,284 @@
1
+ import { z } from 'zod';
2
+ import { AuthError, PrvrsError } from './errors.js';
3
+ import { importArtisanData } from './artisan/import.js';
4
+ // ─── Shared select columns ────────────────────────────────────────────────────
5
+ const ROAST_LIST_SELECT = 'roast_id, batch_name, coffee_id, coffee_name, roast_date, oz_in, oz_out, weight_loss_percent, roast_notes, roaster_type, roaster_size, temperature_unit, total_roast_time, development_percent, data_source, last_updated';
6
+ const ROAST_DETAIL_SELECT = 'roast_id, batch_name, coffee_id, coffee_name, roast_date, oz_in, oz_out, weight_loss_percent, roast_notes, roaster_type, total_roast_time, data_source, last_updated';
7
+ // ─── Zod schemas ──────────────────────────────────────────────────────────────
8
+ export const listRoastsSchema = z.object({
9
+ coffeeId: z.number().int().positive().optional(),
10
+ limit: z.number().int().min(1).default(20),
11
+ });
12
+ export const getRoastSchema = z.object({
13
+ id: z.number().int().positive(),
14
+ includeTemps: z.boolean().optional(),
15
+ includeEvents: z.boolean().optional(),
16
+ });
17
+ export const createRoastSchema = z.object({
18
+ coffeeId: z.number().int().positive(),
19
+ batchName: z.string().optional(),
20
+ ozIn: z.number().positive().optional(),
21
+ ozOut: z.number().positive().optional(),
22
+ roastDate: z.string().optional(),
23
+ notes: z.string().optional(),
24
+ });
25
+ export const deleteRoastSchema = z.object({
26
+ id: z.number().int().positive(),
27
+ });
28
+ // ─── Pure lib functions ───────────────────────────────────────────────────────
29
+ /**
30
+ * List roast profiles for a user.
31
+ */
32
+ export async function listRoasts(supabase, userId, opts) {
33
+ const parsed = listRoastsSchema.parse(opts);
34
+ let query = supabase.from('roast_profiles').select(ROAST_LIST_SELECT).eq('user', userId);
35
+ if (parsed.coffeeId !== undefined) {
36
+ query = query.eq('coffee_id', parsed.coffeeId);
37
+ }
38
+ const { data, error } = await query.order('roast_date', { ascending: false }).limit(parsed.limit);
39
+ if (error)
40
+ throw error;
41
+ return (data ?? []);
42
+ }
43
+ /**
44
+ * Fetch a single roast profile by ID (must belong to userId).
45
+ * Optionally includes temperature curve and roast events.
46
+ */
47
+ export async function getRoast(supabase, userId, id, opts = {}) {
48
+ getRoastSchema.parse({ id, ...opts });
49
+ const { data: profile, error: profileError } = await supabase
50
+ .from('roast_profiles')
51
+ .select('*')
52
+ .eq('roast_id', id)
53
+ .eq('user', userId)
54
+ .single();
55
+ if (profileError) {
56
+ if (profileError.code === 'PGRST116') {
57
+ throw new AuthError(`Roast profile ${id} not found or does not belong to you.`);
58
+ }
59
+ throw profileError;
60
+ }
61
+ const result = { ...profile };
62
+ if (opts.includeTemps) {
63
+ const { data: temps, error: tempError } = await supabase
64
+ .from('roast_temperatures')
65
+ .select('roast_id, time_seconds, bean_temp, environmental_temp')
66
+ .eq('roast_id', id)
67
+ .order('time_seconds', { ascending: true });
68
+ if (tempError)
69
+ throw tempError;
70
+ result.temperatures = (temps ?? []);
71
+ }
72
+ if (opts.includeEvents) {
73
+ const { data: events, error: eventsError } = await supabase
74
+ .from('roast_events')
75
+ .select('roast_id, time_seconds, event_type, event_value')
76
+ .eq('roast_id', id)
77
+ .order('time_seconds', { ascending: true });
78
+ if (eventsError)
79
+ throw eventsError;
80
+ result.events = (events ?? []);
81
+ }
82
+ return result;
83
+ }
84
+ /**
85
+ * Create a new roast profile (coffeeId must be an inventory item belonging to userId).
86
+ */
87
+ export async function createRoast(supabase, userId, input) {
88
+ const parsed = createRoastSchema.parse(input);
89
+ const todayIso = () => new Date().toISOString().slice(0, 10);
90
+ // Verify ownership of the inventory item and get coffee name for default batch name
91
+ const { data: invItem, error: invError } = await supabase
92
+ .from('green_coffee_inv')
93
+ .select('id, coffee_catalog!catalog_id (name)')
94
+ .eq('id', parsed.coffeeId)
95
+ .eq('user', userId)
96
+ .single();
97
+ if (invError || !invItem) {
98
+ throw new AuthError(`Inventory item ${parsed.coffeeId} not found or does not belong to you.`);
99
+ }
100
+ const roastDate = parsed.roastDate ?? todayIso();
101
+ let batchName = parsed.batchName;
102
+ if (!batchName) {
103
+ const catalogRaw = invItem.coffee_catalog;
104
+ const catalog = Array.isArray(catalogRaw) ? (catalogRaw[0] ?? null) : catalogRaw;
105
+ const coffeeName = catalog?.name ?? `Coffee #${parsed.coffeeId}`;
106
+ batchName = `${coffeeName} — ${roastDate}`;
107
+ }
108
+ const insertPayload = {
109
+ user: userId,
110
+ coffee_id: parsed.coffeeId,
111
+ batch_name: batchName,
112
+ roast_date: roastDate,
113
+ };
114
+ if (parsed.ozIn !== undefined)
115
+ insertPayload.oz_in = parsed.ozIn;
116
+ if (parsed.ozOut !== undefined)
117
+ insertPayload.oz_out = parsed.ozOut;
118
+ if (parsed.notes !== undefined)
119
+ insertPayload.roast_notes = parsed.notes;
120
+ const { data: inserted, error: insertError } = await supabase
121
+ .from('roast_profiles')
122
+ .insert(insertPayload)
123
+ .select('roast_id')
124
+ .single();
125
+ if (insertError)
126
+ throw insertError;
127
+ // Re-fetch the full row
128
+ const { data, error } = await supabase
129
+ .from('roast_profiles')
130
+ .select(ROAST_DETAIL_SELECT)
131
+ .eq('roast_id', inserted.roast_id)
132
+ .single();
133
+ if (error)
134
+ throw error;
135
+ return data;
136
+ }
137
+ /**
138
+ * Delete a roast profile (must belong to userId).
139
+ */
140
+ export async function deleteRoast(supabase, userId, id) {
141
+ deleteRoastSchema.parse({ id });
142
+ if (isNaN(id)) {
143
+ throw new PrvrsError('INVALID_ARGUMENT', `Invalid roast ID: "${id}".`);
144
+ }
145
+ // Verify ownership
146
+ const { data: existing, error: fetchError } = await supabase
147
+ .from('roast_profiles')
148
+ .select('roast_id')
149
+ .eq('roast_id', id)
150
+ .eq('user', userId)
151
+ .single();
152
+ if (fetchError || !existing) {
153
+ throw new AuthError(`Roast profile ${id} not found or does not belong to you.`);
154
+ }
155
+ const { error: deleteError } = await supabase
156
+ .from('roast_profiles')
157
+ .delete()
158
+ .eq('roast_id', id)
159
+ .eq('user', userId);
160
+ if (deleteError)
161
+ throw deleteError;
162
+ }
163
+ // ─── Roast import from .alog file ─────────────────────────────────────────────
164
+ export const importRoastSchema = z.object({
165
+ fileContent: z.string().min(1),
166
+ fileName: z.string().min(1),
167
+ coffeeId: z.number().int().positive(),
168
+ batchName: z.string().optional(),
169
+ ozIn: z.number().positive().optional(),
170
+ roastNotes: z.string().optional(),
171
+ });
172
+ /**
173
+ * Extract the input weight in ounces from an Artisan .alog weight array.
174
+ * Falls back to undefined if weight data is absent or unparseable.
175
+ *
176
+ * @param weight - The `weight` field from ArtisanRoastData: [input, output, unit]
177
+ */
178
+ export function extractOzFromAlog(weight) {
179
+ if (!weight || !Array.isArray(weight) || weight.length < 3)
180
+ return undefined;
181
+ const [inputWeight, , unit] = weight;
182
+ if (typeof inputWeight !== 'number' || inputWeight <= 0)
183
+ return undefined;
184
+ if (typeof unit !== 'string')
185
+ return undefined;
186
+ const unitLower = unit.toLowerCase();
187
+ if (unitLower === 'g' || unitLower === 'gr' || unitLower === 'gram' || unitLower === 'grams') {
188
+ return inputWeight / 28.3495;
189
+ }
190
+ if (unitLower === 'oz' || unitLower === 'ounce' || unitLower === 'ounces') {
191
+ return inputWeight;
192
+ }
193
+ if (unitLower === 'kg' || unitLower === 'kilogram' || unitLower === 'kilograms') {
194
+ return inputWeight * 35.274;
195
+ }
196
+ if (unitLower === 'lb' ||
197
+ unitLower === 'lbs' ||
198
+ unitLower === 'pound' ||
199
+ unitLower === 'pounds') {
200
+ return inputWeight * 16;
201
+ }
202
+ // Unknown unit — return undefined rather than a wrong number
203
+ return undefined;
204
+ }
205
+ /**
206
+ * Generate a default batch name: "{coffee_name} {YYYY-MM-DD}".
207
+ */
208
+ export function defaultBatchName(coffeeName, dateIso) {
209
+ return `${coffeeName} ${dateIso}`;
210
+ }
211
+ /**
212
+ * Import a roast from an Artisan .alog file in one step:
213
+ * 1. Verify inventory ownership + get coffee name
214
+ * 2. Create a new roast_profile row
215
+ * 3. Run the full Artisan import (temperatures, events, profile metadata)
216
+ * 4. Return the combined result
217
+ *
218
+ * The supabase client must already be authenticated as userId.
219
+ */
220
+ export async function importRoastFromFile(supabase, userId, input) {
221
+ const parsed = importRoastSchema.parse(input);
222
+ // 1. Verify ownership and get coffee name
223
+ const { data: invItem, error: invError } = await supabase
224
+ .from('green_coffee_inv')
225
+ .select('id, coffee_catalog!catalog_id (name)')
226
+ .eq('id', parsed.coffeeId)
227
+ .eq('user', userId)
228
+ .single();
229
+ if (invError || !invItem) {
230
+ throw new AuthError(`Inventory item ${parsed.coffeeId} not found or does not belong to you.`);
231
+ }
232
+ const catalogRaw = invItem.coffee_catalog;
233
+ const catalog = Array.isArray(catalogRaw) ? (catalogRaw[0] ?? null) : catalogRaw;
234
+ const coffeeName = catalog?.name ?? `Coffee #${parsed.coffeeId}`;
235
+ // 2. Extract roast date + weight from the .alog if not provided by caller
236
+ let artisanRaw;
237
+ try {
238
+ // Light pre-parse to grab roastdate and weight without a full import cycle.
239
+ // We import parseArtisanFile lazily here to keep imports tidy.
240
+ const { parseArtisanFile } = await import('./artisan/import.js');
241
+ const artisan = await parseArtisanFile(parsed.fileContent, parsed.fileName);
242
+ artisanRaw = artisan;
243
+ }
244
+ catch {
245
+ // Pre-parse failure is non-fatal here; the real import will surface the error
246
+ }
247
+ const roastDate = artisanRaw?.roastdate ?? new Date().toISOString().slice(0, 10);
248
+ let ozIn = parsed.ozIn;
249
+ if (ozIn === undefined && artisanRaw?.weight) {
250
+ ozIn = extractOzFromAlog(artisanRaw.weight);
251
+ }
252
+ const batchName = parsed.batchName ?? defaultBatchName(coffeeName, roastDate);
253
+ // 3. Create roast_profile row
254
+ const insertPayload = {
255
+ user: userId,
256
+ coffee_id: parsed.coffeeId,
257
+ coffee_name: coffeeName,
258
+ batch_name: batchName,
259
+ roast_date: roastDate,
260
+ data_source: 'artisan_import',
261
+ };
262
+ if (ozIn !== undefined)
263
+ insertPayload.oz_in = ozIn;
264
+ if (parsed.roastNotes !== undefined)
265
+ insertPayload.roast_notes = parsed.roastNotes;
266
+ const { data: inserted, error: insertError } = await supabase
267
+ .from('roast_profiles')
268
+ .insert(insertPayload)
269
+ .select('roast_id')
270
+ .single();
271
+ if (insertError)
272
+ throw insertError;
273
+ const roastId = inserted.roast_id;
274
+ // 4. Run the full Artisan import (updates profile metadata + writes temps/events)
275
+ const importResult = await importArtisanData(supabase, roastId, userId, parsed.fileContent, parsed.fileName);
276
+ return {
277
+ ...importResult,
278
+ roast_id: roastId,
279
+ batch_name: batchName,
280
+ coffee_name: coffeeName,
281
+ coffee_id: parsed.coffeeId,
282
+ };
283
+ }
284
+ //# sourceMappingURL=roast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roast.js","sourceRoot":"","sources":["../../src/lib/roast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAmDxD,iFAAiF;AAEjF,MAAM,iBAAiB,GACrB,2NAA2N,CAAC;AAE9N,MAAM,mBAAmB,GACvB,sKAAsK,CAAC;AAEzK,iFAAiF;AAEjF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAChD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CAC3C,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAC/B,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACpC,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CACtC,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACrC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACtC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACvC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AAIH,iFAAiF;AAEjF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,QAAwB,EACxB,MAAc,EACd,IAAqB;IAErB,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAE5C,IAAI,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEzF,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAClC,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAElG,IAAI,KAAK;QAAE,MAAM,KAAK,CAAC;IAEvB,OAAO,CAAC,IAAI,IAAI,EAAE,CAAmB,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,QAAwB,EACxB,MAAc,EACd,EAAU,EACV,OAA4D,EAAE;IAE9D,cAAc,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IAEtC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,MAAM,QAAQ;SAC1D,IAAI,CAAC,gBAAgB,CAAC;SACtB,MAAM,CAAC,GAAG,CAAC;SACX,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC;SAClB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;SAClB,MAAM,EAAE,CAAC;IAEZ,IAAI,YAAY,EAAE,CAAC;QACjB,IAAI,YAAY,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACrC,MAAM,IAAI,SAAS,CAAC,iBAAiB,EAAE,uCAAuC,CAAC,CAAC;QAClF,CAAC;QACD,MAAM,YAAY,CAAC;IACrB,CAAC;IAED,MAAM,MAAM,GAAiB,EAAE,GAAG,OAAO,EAAE,CAAC;IAE5C,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,QAAQ;aACrD,IAAI,CAAC,oBAAoB,CAAC;aAC1B,MAAM,CAAC,uDAAuD,CAAC;aAC/D,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC;aAClB,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE9C,IAAI,SAAS;YAAE,MAAM,SAAS,CAAC;QAC/B,MAAM,CAAC,YAAY,GAAG,CAAC,KAAK,IAAI,EAAE,CAAuB,CAAC;IAC5D,CAAC;IAED,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,QAAQ;aACxD,IAAI,CAAC,cAAc,CAAC;aACpB,MAAM,CAAC,iDAAiD,CAAC;aACzD,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC;aAClB,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE9C,IAAI,WAAW;YAAE,MAAM,WAAW,CAAC;QACnC,MAAM,CAAC,MAAM,GAAG,CAAC,MAAM,IAAI,EAAE,CAAsB,CAAC;IACtD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAwB,EACxB,MAAc,EACd,KAAuB;IAEvB,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAE9C,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAE7D,oFAAoF;IACpF,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,QAAQ;SACtD,IAAI,CAAC,kBAAkB,CAAC;SACxB,MAAM,CAAC,sCAAsC,CAAC;SAC9C,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC;SACzB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;SAClB,MAAM,EAAE,CAAC;IAEZ,IAAI,QAAQ,IAAI,CAAC,OAAO,EAAE,CAAC;QACzB,MAAM,IAAI,SAAS,CAAC,kBAAkB,MAAM,CAAC,QAAQ,uCAAuC,CAAC,CAAC;IAChG,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,QAAQ,EAAE,CAAC;IAEjD,IAAI,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IACjC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,UAAU,GAAG,OAAO,CAAC,cAGnB,CAAC;QACT,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;QACjF,MAAM,UAAU,GAAG,OAAO,EAAE,IAAI,IAAI,WAAW,MAAM,CAAC,QAAQ,EAAE,CAAC;QACjE,SAAS,GAAG,GAAG,UAAU,MAAM,SAAS,EAAE,CAAC;IAC7C,CAAC;IAED,MAAM,aAAa,GAA4B;QAC7C,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,MAAM,CAAC,QAAQ;QAC1B,UAAU,EAAE,SAAS;QACrB,UAAU,EAAE,SAAS;KACtB,CAAC;IAEF,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAAE,aAAa,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC;IACjE,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS;QAAE,aAAa,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;IACpE,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS;QAAE,aAAa,CAAC,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC;IAEzE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,QAAQ;SAC1D,IAAI,CAAC,gBAAgB,CAAC;SACtB,MAAM,CAAC,aAAa,CAAC;SACrB,MAAM,CAAC,UAAU,CAAC;SAClB,MAAM,EAAE,CAAC;IAEZ,IAAI,WAAW;QAAE,MAAM,WAAW,CAAC;IAEnC,wBAAwB;IACxB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ;SACnC,IAAI,CAAC,gBAAgB,CAAC;SACtB,MAAM,CAAC,mBAAmB,CAAC;SAC3B,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,QAAQ,CAAC;SACjC,MAAM,EAAE,CAAC;IAEZ,IAAI,KAAK;QAAE,MAAM,KAAK,CAAC;IAEvB,OAAO,IAAoB,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAwB,EACxB,MAAc,EACd,EAAU;IAEV,iBAAiB,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAEhC,IAAI,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QACd,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAE,sBAAsB,EAAE,IAAI,CAAC,CAAC;IACzE,CAAC;IAED,mBAAmB;IACnB,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,QAAQ;SACzD,IAAI,CAAC,gBAAgB,CAAC;SACtB,MAAM,CAAC,UAAU,CAAC;SAClB,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC;SAClB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;SAClB,MAAM,EAAE,CAAC;IAEZ,IAAI,UAAU,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,SAAS,CAAC,iBAAiB,EAAE,uCAAuC,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,QAAQ;SAC1C,IAAI,CAAC,gBAAgB,CAAC;SACtB,MAAM,EAAE;SACR,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC;SAClB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEtB,IAAI,WAAW;QAAE,MAAM,WAAW,CAAC;AACrC,CAAC;AAED,iFAAiF;AAEjF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACrC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACtC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAClC,CAAC,CAAC;AAWH;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAA4C;IAE5C,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC7E,MAAM,CAAC,WAAW,EAAE,AAAD,EAAG,IAAI,CAAC,GAAG,MAAM,CAAC;IACrC,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1E,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAE/C,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;QAC7F,OAAO,WAAW,GAAG,OAAO,CAAC;IAC/B,CAAC;IACD,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,OAAO,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;QAC1E,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,UAAU,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;QAChF,OAAO,WAAW,GAAG,MAAM,CAAC;IAC9B,CAAC;IACD,IACE,SAAS,KAAK,IAAI;QAClB,SAAS,KAAK,KAAK;QACnB,SAAS,KAAK,OAAO;QACrB,SAAS,KAAK,QAAQ,EACtB,CAAC;QACD,OAAO,WAAW,GAAG,EAAE,CAAC;IAC1B,CAAC;IACD,6DAA6D;IAC7D,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,OAAe;IAClE,OAAO,GAAG,UAAU,IAAI,OAAO,EAAE,CAAC;AACpC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAwB,EACxB,MAAc,EACd,KAAuB;IAEvB,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAE9C,0CAA0C;IAC1C,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,QAAQ;SACtD,IAAI,CAAC,kBAAkB,CAAC;SACxB,MAAM,CAAC,sCAAsC,CAAC;SAC9C,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC;SACzB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;SAClB,MAAM,EAAE,CAAC;IAEZ,IAAI,QAAQ,IAAI,CAAC,OAAO,EAAE,CAAC;QACzB,MAAM,IAAI,SAAS,CAAC,kBAAkB,MAAM,CAAC,QAAQ,uCAAuC,CAAC,CAAC;IAChG,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,cAGnB,CAAC;IACT,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IACjF,MAAM,UAAU,GAAG,OAAO,EAAE,IAAI,IAAI,WAAW,MAAM,CAAC,QAAQ,EAAE,CAAC;IAEjE,0EAA0E;IAC1E,IAAI,UAA+C,CAAC;IACpD,IAAI,CAAC;QACH,4EAA4E;QAC5E,+DAA+D;QAC/D,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;QACjE,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5E,UAAU,GAAG,OAA6C,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,8EAA8E;IAChF,CAAC;IAED,MAAM,SAAS,GACZ,UAAU,EAAE,SAAgC,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEzF,IAAI,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACvB,IAAI,IAAI,KAAK,SAAS,IAAI,UAAU,EAAE,MAAM,EAAE,CAAC;QAC7C,IAAI,GAAG,iBAAiB,CAAC,UAAU,CAAC,MAAkC,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,gBAAgB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAE9E,8BAA8B;IAC9B,MAAM,aAAa,GAA4B;QAC7C,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,MAAM,CAAC,QAAQ;QAC1B,WAAW,EAAE,UAAU;QACvB,UAAU,EAAE,SAAS;QACrB,UAAU,EAAE,SAAS;QACrB,WAAW,EAAE,gBAAgB;KAC9B,CAAC;IACF,IAAI,IAAI,KAAK,SAAS;QAAE,aAAa,CAAC,KAAK,GAAG,IAAI,CAAC;IACnD,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS;QAAE,aAAa,CAAC,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;IAEnF,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,QAAQ;SAC1D,IAAI,CAAC,gBAAgB,CAAC;SACtB,MAAM,CAAC,aAAa,CAAC;SACrB,MAAM,CAAC,UAAU,CAAC;SAClB,MAAM,EAAE,CAAC;IAEZ,IAAI,WAAW;QAAE,MAAM,WAAW,CAAC;IAEnC,MAAM,OAAO,GAAY,QAAiC,CAAC,QAAQ,CAAC;IAEpE,kFAAkF;IAClF,MAAM,YAAY,GAAG,MAAM,iBAAiB,CAC1C,QAAQ,EACR,OAAO,EACP,MAAM,EACN,MAAM,CAAC,WAAW,EAClB,MAAM,CAAC,QAAQ,CAChB,CAAC;IAEF,OAAO;QACL,GAAG,YAAY;QACf,QAAQ,EAAE,OAAO;QACjB,UAAU,EAAE,SAAS;QACrB,WAAW,EAAE,UAAU;QACvB,SAAS,EAAE,MAAM,CAAC,QAAQ;KAC3B,CAAC;AACJ,CAAC"}