@simonarcher/fika-types 2.3.1 → 2.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.
- package/dist/bean-scans.d.ts +8 -0
- package/dist/brewMethodTarget.d.ts +42 -0
- package/dist/brewMethodTarget.js +95 -0
- package/dist/coffee.d.ts +8 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/supabase.d.ts +3 -0
- package/package.json +1 -1
package/dist/bean-scans.d.ts
CHANGED
|
@@ -42,6 +42,14 @@ export interface BeanScanAiDraft {
|
|
|
42
42
|
variety: string | null;
|
|
43
43
|
roastDate: string | null;
|
|
44
44
|
weightG: number | null;
|
|
45
|
+
/**
|
|
46
|
+
* FIK-193 — high-level brew-method intent extracted from the bag.
|
|
47
|
+
* One of the four values from `BrewMethodTarget` in
|
|
48
|
+
* `./brewMethodTarget` (literal duplicated to keep the file self-contained).
|
|
49
|
+
* Mobile prefills the AddBean picker from this; admin shows it in the
|
|
50
|
+
* AI vision comparison panel for curator override.
|
|
51
|
+
*/
|
|
52
|
+
brewMethodTarget: "espresso" | "filter" | "omni" | "unknown" | null;
|
|
45
53
|
model: string;
|
|
46
54
|
latencyMs: number;
|
|
47
55
|
extractedAt: string;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { BrewMethod } from "./coffee";
|
|
2
|
+
/**
|
|
3
|
+
* High-level brew-method intent for a coffee bag (FIK-193).
|
|
4
|
+
*
|
|
5
|
+
* Most specialty bags state how the roaster intends the bean to be brewed:
|
|
6
|
+
* `Espresso`, `Filter`, both ("omni"), or unspecified. The four-value
|
|
7
|
+
* enum below is the user-facing concept; `coffee_beans.brew_recommendations`
|
|
8
|
+
* (BrewMethod[]) is where it lives in the DB. Use the helpers in this file
|
|
9
|
+
* to project between the two so all consumers agree.
|
|
10
|
+
*/
|
|
11
|
+
export type BrewMethodTarget = "espresso" | "filter" | "omni" | "unknown";
|
|
12
|
+
export declare const BREW_METHOD_TARGET_VALUES: readonly BrewMethodTarget[];
|
|
13
|
+
/**
|
|
14
|
+
* BrewMethod tokens that count as "filter-style" when projecting an array
|
|
15
|
+
* back to a high-level intent. Includes the canonical `Filter` enum plus
|
|
16
|
+
* pour-over / drip variants users see on bags. Lower-cased on lookup so
|
|
17
|
+
* casing differences in legacy data don't break the projection.
|
|
18
|
+
*/
|
|
19
|
+
export declare const FILTER_METHOD_TOKENS: readonly ["Filter", "Pour Over", "Aeropress", "V60", "Kalita", "Chemex", "Clever"];
|
|
20
|
+
export declare const ESPRESSO_METHOD_TOKENS: readonly ["Espresso"];
|
|
21
|
+
/**
|
|
22
|
+
* READ-side projection: BrewMethod[] (or anything roughly array-shaped) →
|
|
23
|
+
* one of the four high-level intents.
|
|
24
|
+
*
|
|
25
|
+
* - has Espresso AND any filter-style token → `omni`
|
|
26
|
+
* - only Espresso → `espresso`
|
|
27
|
+
* - only filter-style → `filter`
|
|
28
|
+
* - empty / null / no recognised tokens → `unknown`
|
|
29
|
+
*/
|
|
30
|
+
export declare function brewMethodTargetFromArray(arr: readonly string[] | null | undefined): BrewMethodTarget;
|
|
31
|
+
/**
|
|
32
|
+
* WRITE-side projection: BrewMethodTarget → BrewMethod[] suitable for
|
|
33
|
+
* `coffee_beans.brew_recommendations`. Title Case to match the 96 existing
|
|
34
|
+
* prod rows. `unknown` writes `null` (no array) so we don't flood the column
|
|
35
|
+
* with placeholder data.
|
|
36
|
+
*/
|
|
37
|
+
export declare function brewRecommendationsFromTarget(target: BrewMethodTarget | null | undefined): BrewMethod[] | null;
|
|
38
|
+
/**
|
|
39
|
+
* Narrow an arbitrary string to BrewMethodTarget if it's one of the four
|
|
40
|
+
* known values, else null. Useful when reading off the wire / DB.
|
|
41
|
+
*/
|
|
42
|
+
export declare function asBrewMethodTarget(v: string | null | undefined): BrewMethodTarget | null;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ESPRESSO_METHOD_TOKENS = exports.FILTER_METHOD_TOKENS = exports.BREW_METHOD_TARGET_VALUES = void 0;
|
|
4
|
+
exports.brewMethodTargetFromArray = brewMethodTargetFromArray;
|
|
5
|
+
exports.brewRecommendationsFromTarget = brewRecommendationsFromTarget;
|
|
6
|
+
exports.asBrewMethodTarget = asBrewMethodTarget;
|
|
7
|
+
exports.BREW_METHOD_TARGET_VALUES = [
|
|
8
|
+
"espresso",
|
|
9
|
+
"filter",
|
|
10
|
+
"omni",
|
|
11
|
+
"unknown",
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* BrewMethod tokens that count as "filter-style" when projecting an array
|
|
15
|
+
* back to a high-level intent. Includes the canonical `Filter` enum plus
|
|
16
|
+
* pour-over / drip variants users see on bags. Lower-cased on lookup so
|
|
17
|
+
* casing differences in legacy data don't break the projection.
|
|
18
|
+
*/
|
|
19
|
+
exports.FILTER_METHOD_TOKENS = [
|
|
20
|
+
"Filter",
|
|
21
|
+
"Pour Over",
|
|
22
|
+
"Aeropress",
|
|
23
|
+
"V60",
|
|
24
|
+
"Kalita",
|
|
25
|
+
"Chemex",
|
|
26
|
+
"Clever",
|
|
27
|
+
];
|
|
28
|
+
exports.ESPRESSO_METHOD_TOKENS = ["Espresso"];
|
|
29
|
+
const lc = (s) => s.trim().toLowerCase();
|
|
30
|
+
const FILTER_SET = new Set(exports.FILTER_METHOD_TOKENS.map(lc));
|
|
31
|
+
const ESPRESSO_SET = new Set(exports.ESPRESSO_METHOD_TOKENS.map(lc));
|
|
32
|
+
/**
|
|
33
|
+
* READ-side projection: BrewMethod[] (or anything roughly array-shaped) →
|
|
34
|
+
* one of the four high-level intents.
|
|
35
|
+
*
|
|
36
|
+
* - has Espresso AND any filter-style token → `omni`
|
|
37
|
+
* - only Espresso → `espresso`
|
|
38
|
+
* - only filter-style → `filter`
|
|
39
|
+
* - empty / null / no recognised tokens → `unknown`
|
|
40
|
+
*/
|
|
41
|
+
function brewMethodTargetFromArray(arr) {
|
|
42
|
+
if (!arr || arr.length === 0)
|
|
43
|
+
return "unknown";
|
|
44
|
+
let hasEspresso = false;
|
|
45
|
+
let hasFilter = false;
|
|
46
|
+
for (const raw of arr) {
|
|
47
|
+
if (typeof raw !== "string")
|
|
48
|
+
continue;
|
|
49
|
+
const v = lc(raw);
|
|
50
|
+
if (ESPRESSO_SET.has(v))
|
|
51
|
+
hasEspresso = true;
|
|
52
|
+
if (FILTER_SET.has(v))
|
|
53
|
+
hasFilter = true;
|
|
54
|
+
}
|
|
55
|
+
if (hasEspresso && hasFilter)
|
|
56
|
+
return "omni";
|
|
57
|
+
if (hasEspresso)
|
|
58
|
+
return "espresso";
|
|
59
|
+
if (hasFilter)
|
|
60
|
+
return "filter";
|
|
61
|
+
return "unknown";
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* WRITE-side projection: BrewMethodTarget → BrewMethod[] suitable for
|
|
65
|
+
* `coffee_beans.brew_recommendations`. Title Case to match the 96 existing
|
|
66
|
+
* prod rows. `unknown` writes `null` (no array) so we don't flood the column
|
|
67
|
+
* with placeholder data.
|
|
68
|
+
*/
|
|
69
|
+
function brewRecommendationsFromTarget(target) {
|
|
70
|
+
switch (target) {
|
|
71
|
+
case "espresso":
|
|
72
|
+
return ["Espresso"];
|
|
73
|
+
case "filter":
|
|
74
|
+
return ["Filter"];
|
|
75
|
+
case "omni":
|
|
76
|
+
return ["Espresso", "Filter"];
|
|
77
|
+
case "unknown":
|
|
78
|
+
case null:
|
|
79
|
+
case undefined:
|
|
80
|
+
default:
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Narrow an arbitrary string to BrewMethodTarget if it's one of the four
|
|
86
|
+
* known values, else null. Useful when reading off the wire / DB.
|
|
87
|
+
*/
|
|
88
|
+
function asBrewMethodTarget(v) {
|
|
89
|
+
if (!v)
|
|
90
|
+
return null;
|
|
91
|
+
const lower = lc(v);
|
|
92
|
+
return exports.BREW_METHOD_TARGET_VALUES.includes(lower)
|
|
93
|
+
? lower
|
|
94
|
+
: null;
|
|
95
|
+
}
|
package/dist/coffee.d.ts
CHANGED
|
@@ -196,6 +196,14 @@ export interface SubmissionCoffeeBeanData {
|
|
|
196
196
|
tastingNotes?: string[];
|
|
197
197
|
isDecaf: boolean;
|
|
198
198
|
decafMethod?: DecafMethod;
|
|
199
|
+
/**
|
|
200
|
+
* FIK-193 — high-level brew-method intent the user picked on AddBean
|
|
201
|
+
* (or that AI vision extracted). Projected to
|
|
202
|
+
* `coffee_beans.brew_recommendations` on curator approval. The literal
|
|
203
|
+
* is duplicated here to keep this file's BrewMethod-adjacent types
|
|
204
|
+
* self-contained; the canonical type lives in `./brewMethodTarget`.
|
|
205
|
+
*/
|
|
206
|
+
brewMethodTarget?: "espresso" | "filter" | "omni" | "unknown" | null;
|
|
199
207
|
userId: string;
|
|
200
208
|
status: "inReview" | "approved" | "rejected";
|
|
201
209
|
active: boolean;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -18,6 +18,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
18
18
|
__exportStar(require("./shop"), exports);
|
|
19
19
|
// Export all coffee-related types
|
|
20
20
|
__exportStar(require("./coffee"), exports);
|
|
21
|
+
// Export brew-method-target enum + projection helpers (FIK-193)
|
|
22
|
+
__exportStar(require("./brewMethodTarget"), exports);
|
|
21
23
|
// Export bag-scan types (design surface; bean_scans table not yet migrated)
|
|
22
24
|
__exportStar(require("./bean-scans"), exports);
|
|
23
25
|
// Export all farm-related types
|
package/dist/supabase.d.ts
CHANGED
|
@@ -337,6 +337,7 @@ export type Database = {
|
|
|
337
337
|
Row: {
|
|
338
338
|
active: boolean | null;
|
|
339
339
|
bean_id: string | null;
|
|
340
|
+
brew_method_target: string | null;
|
|
340
341
|
country: string | null;
|
|
341
342
|
created_at: string | null;
|
|
342
343
|
decaf_method: string | null;
|
|
@@ -359,6 +360,7 @@ export type Database = {
|
|
|
359
360
|
Insert: {
|
|
360
361
|
active?: boolean | null;
|
|
361
362
|
bean_id?: string | null;
|
|
363
|
+
brew_method_target?: string | null;
|
|
362
364
|
country?: string | null;
|
|
363
365
|
created_at?: string | null;
|
|
364
366
|
decaf_method?: string | null;
|
|
@@ -381,6 +383,7 @@ export type Database = {
|
|
|
381
383
|
Update: {
|
|
382
384
|
active?: boolean | null;
|
|
383
385
|
bean_id?: string | null;
|
|
386
|
+
brew_method_target?: string | null;
|
|
384
387
|
country?: string | null;
|
|
385
388
|
created_at?: string | null;
|
|
386
389
|
decaf_method?: string | null;
|