@milldr/crono 0.1.0 → 0.2.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 (50) hide show
  1. package/README.md +128 -0
  2. package/dist/commands/add.d.ts +9 -0
  3. package/dist/commands/add.d.ts.map +1 -0
  4. package/dist/commands/add.js +65 -0
  5. package/dist/commands/add.js.map +1 -0
  6. package/dist/commands/export.d.ts +8 -0
  7. package/dist/commands/export.d.ts.map +1 -0
  8. package/dist/commands/export.js +142 -0
  9. package/dist/commands/export.js.map +1 -0
  10. package/dist/commands/log.d.ts +6 -0
  11. package/dist/commands/log.d.ts.map +1 -0
  12. package/dist/commands/log.js +40 -0
  13. package/dist/commands/log.js.map +1 -0
  14. package/dist/config.d.ts +2 -0
  15. package/dist/config.d.ts.map +1 -1
  16. package/dist/config.js.map +1 -1
  17. package/dist/cronometer/auth.d.ts +31 -0
  18. package/dist/cronometer/auth.d.ts.map +1 -0
  19. package/dist/cronometer/auth.js +151 -0
  20. package/dist/cronometer/auth.js.map +1 -0
  21. package/dist/cronometer/export.d.ts +22 -0
  22. package/dist/cronometer/export.d.ts.map +1 -0
  23. package/dist/cronometer/export.js +83 -0
  24. package/dist/cronometer/export.js.map +1 -0
  25. package/dist/cronometer/parse.d.ts +35 -0
  26. package/dist/cronometer/parse.d.ts.map +1 -0
  27. package/dist/cronometer/parse.js +158 -0
  28. package/dist/cronometer/parse.js.map +1 -0
  29. package/dist/index.js +33 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/kernel/add-custom-food.d.ts +22 -0
  32. package/dist/kernel/add-custom-food.d.ts.map +1 -0
  33. package/dist/kernel/add-custom-food.js +314 -0
  34. package/dist/kernel/add-custom-food.js.map +1 -0
  35. package/dist/kernel/client.d.ts +15 -0
  36. package/dist/kernel/client.d.ts.map +1 -1
  37. package/dist/kernel/client.js +92 -1
  38. package/dist/kernel/client.js.map +1 -1
  39. package/dist/kernel/log-food.d.ts +17 -0
  40. package/dist/kernel/log-food.d.ts.map +1 -0
  41. package/dist/kernel/log-food.js +230 -0
  42. package/dist/kernel/log-food.js.map +1 -0
  43. package/dist/kernel/login.d.ts.map +1 -1
  44. package/dist/kernel/login.js +24 -1
  45. package/dist/kernel/login.js.map +1 -1
  46. package/package.json +5 -1
  47. package/dist/debug-nav.d.ts +0 -2
  48. package/dist/debug-nav.d.ts.map +0 -1
  49. package/dist/debug-nav.js +0 -99
  50. package/dist/debug-nav.js.map +0 -1
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # 🍎 crono
2
2
 
3
+ [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/milldr)
4
+
3
5
  CLI for Cronometer automation via [Kernel.sh](https://kernel.sh).
4
6
 
5
7
  Cronometer has no public API, so crono automates the web UI through Kernel.sh browser automation. Log macros from your terminal in seconds.
@@ -101,6 +103,69 @@ crono quick-add -p 30 -c 100 -f 20
101
103
  crono quick-add -p 30 -c 50 -f 15 --meal Dinner
102
104
  ```
103
105
 
106
+ ### `crono add custom-food`
107
+
108
+ Create a custom food in Cronometer with specified macros.
109
+
110
+ ```bash
111
+ crono add custom-food <name> [options]
112
+ ```
113
+
114
+ **Options:**
115
+
116
+ | Flag | Long | Description |
117
+ | ---- | --------------- | ------------------------------------------- |
118
+ | `-p` | `--protein <g>` | Grams of protein |
119
+ | `-c` | `--carbs <g>` | Grams of carbohydrates |
120
+ | `-f` | `--fat <g>` | Grams of fat |
121
+ | | `--log [meal]` | Also log to diary (optionally specify meal) |
122
+
123
+ At least one macro flag (`-p`, `-c`, or `-f`) is required.
124
+
125
+ **Examples:**
126
+
127
+ ```bash
128
+ # Create a custom food with all macros
129
+ crono add custom-food "Wendy's Chicken Sandwich" -p 50 -c 100 -f 50
130
+
131
+ # Just protein and carbs
132
+ crono add custom-food "Post-Workout Shake" -p 40 -c 60
133
+
134
+ # Create and immediately log to Uncategorized
135
+ crono add custom-food "Wendy's Chicken Sandwich" -p 50 -c 100 -f 50 --log
136
+
137
+ # Create and immediately log to Dinner
138
+ crono add custom-food "Wendy's Chicken Sandwich" -p 50 -c 100 -f 50 --log Dinner
139
+ ```
140
+
141
+ ### `crono log`
142
+
143
+ Log a saved food to your diary by name. Works with custom foods, custom recipes, and database items.
144
+
145
+ ```bash
146
+ crono log <name> [options]
147
+ ```
148
+
149
+ **Options:**
150
+
151
+ | Flag | Long | Description |
152
+ | ---- | -------------------- | ------------------------------------------------ |
153
+ | `-m` | `--meal <name>` | Meal category (Breakfast, Lunch, Dinner, Snacks) |
154
+ | `-s` | `--servings <count>` | Number of servings (default: 1) |
155
+
156
+ **Examples:**
157
+
158
+ ```bash
159
+ # Log a custom food
160
+ crono log "Wendy's Chicken Sandwich"
161
+
162
+ # Log to a specific meal
163
+ crono log "Wendy's Chicken Sandwich" -m Dinner
164
+
165
+ # Log multiple servings
166
+ crono log "Post-Workout Shake" -s 2 -m Snacks
167
+ ```
168
+
104
169
  ### `crono weight`
105
170
 
106
171
  Check your weight from Cronometer. Defaults to today if no date or range is specified.
@@ -188,6 +253,63 @@ crono diary -r 7d --json
188
253
  # → [{"date":"2026-02-11","calories":1847,"protein":168,"carbs":142,"fat":58}, ...]
189
254
  ```
190
255
 
256
+ ### `crono export`
257
+
258
+ Export data directly from Cronometer's API — no browser automation, much faster than `diary` or `weight`.
259
+
260
+ ```bash
261
+ crono export <type> [options]
262
+ ```
263
+
264
+ **Types:**
265
+
266
+ | Type | Description |
267
+ | ------------ | ----------------------------------- |
268
+ | `nutrition` | Daily nutrition totals (macros) |
269
+ | `exercises` | Exercise entries with duration/cals |
270
+ | `biometrics` | Biometric measurements (weight, BP) |
271
+
272
+ **Options:**
273
+
274
+ | Flag | Long | Description |
275
+ | ---- | ----------------- | ----------------------------------------- |
276
+ | `-d` | `--date <date>` | Date (YYYY-MM-DD) |
277
+ | `-r` | `--range <range>` | Range (7d, 30d, or YYYY-MM-DD:YYYY-MM-DD) |
278
+ | | `--csv` | Output as raw CSV |
279
+ | | `--json` | Output as JSON |
280
+
281
+ `-d` and `-r` are mutually exclusive. `--csv` and `--json` are mutually exclusive.
282
+
283
+ **Examples:**
284
+
285
+ ```bash
286
+ # Today's nutrition
287
+ crono export nutrition
288
+ # → 1847 kcal | P: 168g | C: 142g | F: 58g
289
+
290
+ # Last 7 days of nutrition as JSON
291
+ crono export nutrition -r 7d --json
292
+
293
+ # Today's exercises
294
+ crono export exercises
295
+ # → Running: 30 min, 350 kcal
296
+
297
+ # Biometrics for last 30 days
298
+ crono export biometrics -r 30d
299
+ # → 2026-02-11: Weight: 212.5 lbs
300
+ # → 2026-02-09: Blood Pressure: 120/80 mmHg
301
+
302
+ # Raw CSV export
303
+ crono export nutrition -r 30d --csv
304
+ ```
305
+
306
+ **GWT overrides:** If Cronometer updates break the export, override GWT values in `~/.config/crono/config.json` or via environment variables:
307
+
308
+ ```bash
309
+ export CRONO_GWT_PERMUTATION=<new-value>
310
+ export CRONO_GWT_HEADER=<new-value>
311
+ ```
312
+
191
313
  ## Requirements
192
314
 
193
315
  - Node.js 18+
@@ -214,6 +336,12 @@ npm test
214
336
  npm run build
215
337
  ```
216
338
 
339
+ ## Support
340
+
341
+ I build and maintain projects like crono in my free time as personal hobbies. They're completely free and always will be. If you find this useful and want to show some support, feel free to buy me a coffee:
342
+
343
+ [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/milldr)
344
+
217
345
  ## License
218
346
 
219
347
  MIT
@@ -0,0 +1,9 @@
1
+ export interface AddCustomFoodOptions {
2
+ protein?: number;
3
+ carbs?: number;
4
+ fat?: number;
5
+ total?: number;
6
+ log?: string | boolean;
7
+ }
8
+ export declare function addCustomFood(name: string, options: AddCustomFoodOptions): Promise<void>;
9
+ //# sourceMappingURL=add.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAID,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAsEf"}
@@ -0,0 +1,65 @@
1
+ import * as p from "@clack/prompts";
2
+ import { getKernelClient } from "../kernel/client.js";
3
+ const VALID_MEALS = ["breakfast", "lunch", "dinner", "snacks"];
4
+ export async function addCustomFood(name, options) {
5
+ // Validate at least one macro is provided
6
+ if (!options.protein && !options.carbs && !options.fat) {
7
+ p.log.error("At least one macro (-p, -c, or -f) is required");
8
+ process.exit(1);
9
+ }
10
+ // Validate --log meal if specified as a string
11
+ if (typeof options.log === "string") {
12
+ const normalizedMeal = options.log.toLowerCase();
13
+ if (!VALID_MEALS.includes(normalizedMeal)) {
14
+ p.log.error(`Invalid meal "${options.log}". Use: Breakfast, Lunch, Dinner, or Snacks`);
15
+ process.exit(1);
16
+ }
17
+ }
18
+ // Calculate total calories
19
+ const calories = options.total ??
20
+ (options.protein ?? 0) * 4 +
21
+ (options.carbs ?? 0) * 4 +
22
+ (options.fat ?? 0) * 9;
23
+ // Build macro display
24
+ const macroParts = [];
25
+ macroParts.push(`${calories} cal`);
26
+ if (options.protein)
27
+ macroParts.push(`P: ${options.protein}g`);
28
+ if (options.carbs)
29
+ macroParts.push(`C: ${options.carbs}g`);
30
+ if (options.fat)
31
+ macroParts.push(`F: ${options.fat}g`);
32
+ const macroDisplay = macroParts.join(" | ");
33
+ const logMeal = options.log
34
+ ? typeof options.log === "string"
35
+ ? options.log.charAt(0).toUpperCase() + options.log.slice(1).toLowerCase()
36
+ : "Uncategorized"
37
+ : null;
38
+ p.intro("🍎 crono add");
39
+ const s = p.spinner();
40
+ s.start("Connecting...");
41
+ try {
42
+ const kernel = await getKernelClient();
43
+ await kernel.addCustomFood({
44
+ name,
45
+ protein: options.protein,
46
+ carbs: options.carbs,
47
+ fat: options.fat,
48
+ calories,
49
+ log: options.log,
50
+ }, (msg) => s.message(msg));
51
+ s.stop("Done.");
52
+ if (logMeal) {
53
+ p.outro(`Created and logged: ${name} (${macroDisplay}) → ${logMeal}`);
54
+ }
55
+ else {
56
+ p.outro(`Created custom food: ${name} (${macroDisplay})`);
57
+ }
58
+ }
59
+ catch (error) {
60
+ s.stop("Failed.");
61
+ p.log.error(`Failed to create custom food: ${error}`);
62
+ process.exit(1);
63
+ }
64
+ }
65
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export interface ExportOptions {
2
+ date?: string;
3
+ range?: string;
4
+ csv?: boolean;
5
+ json?: boolean;
6
+ }
7
+ export declare function exportCmd(type: string, options: ExportOptions): Promise<void>;
8
+ //# sourceMappingURL=export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CAwGf"}
@@ -0,0 +1,142 @@
1
+ import * as p from "@clack/prompts";
2
+ import { exportData } from "../cronometer/export.js";
3
+ import { parseNutrition, parseExercises, parseBiometrics, } from "../cronometer/parse.js";
4
+ import { parseDate, parseRange, todayStr } from "../utils/date.js";
5
+ const VALID_TYPES = ["nutrition", "exercises", "biometrics"];
6
+ export async function exportCmd(type, options) {
7
+ // Validate type
8
+ if (!VALID_TYPES.includes(type)) {
9
+ p.log.error("Unknown export type. Use: nutrition, exercises, biometrics");
10
+ process.exit(1);
11
+ }
12
+ // Validate mutual exclusivity
13
+ if (options.date && options.range) {
14
+ p.log.error("-d and -r are mutually exclusive");
15
+ process.exit(1);
16
+ }
17
+ if (options.csv && options.json) {
18
+ p.log.error("--csv and --json are mutually exclusive");
19
+ process.exit(1);
20
+ }
21
+ // Resolve date range
22
+ let start;
23
+ let end;
24
+ let isRange = false;
25
+ try {
26
+ if (options.range) {
27
+ isRange = true;
28
+ const range = parseRange(options.range);
29
+ start = range.start;
30
+ end = range.end;
31
+ }
32
+ else if (options.date) {
33
+ start = parseDate(options.date);
34
+ end = start;
35
+ }
36
+ else {
37
+ start = todayStr();
38
+ end = start;
39
+ }
40
+ }
41
+ catch (error) {
42
+ p.log.error(String(error instanceof Error ? error.message : error));
43
+ process.exit(1);
44
+ }
45
+ const silent = options.json || options.csv;
46
+ if (!silent) {
47
+ p.intro("🍎 crono export");
48
+ }
49
+ const s = silent ? null : p.spinner();
50
+ s?.start("Connecting...");
51
+ try {
52
+ const csv = await exportData(type, start, end, (msg) => s?.message(msg));
53
+ s?.stop("Done.");
54
+ // Raw CSV passthrough
55
+ if (options.csv) {
56
+ console.log(csv);
57
+ return;
58
+ }
59
+ // Parse and output
60
+ const exportType = type;
61
+ if (exportType === "nutrition") {
62
+ const entries = parseNutrition(csv);
63
+ if (entries.length === 0) {
64
+ if (!silent)
65
+ p.outro("No nutrition data found for the requested dates");
66
+ return;
67
+ }
68
+ if (options.json) {
69
+ console.log(JSON.stringify(isRange ? entries : entries[0], null, 2));
70
+ }
71
+ else {
72
+ formatNutrition(entries, isRange);
73
+ }
74
+ }
75
+ else if (exportType === "exercises") {
76
+ const entries = parseExercises(csv);
77
+ if (entries.length === 0) {
78
+ if (!silent)
79
+ p.outro("No exercises data found for the requested dates");
80
+ return;
81
+ }
82
+ if (options.json) {
83
+ console.log(JSON.stringify(isRange ? entries : entries, null, 2));
84
+ }
85
+ else {
86
+ formatExercises(entries, isRange);
87
+ }
88
+ }
89
+ else {
90
+ const entries = parseBiometrics(csv);
91
+ if (entries.length === 0) {
92
+ if (!silent)
93
+ p.outro("No biometrics data found for the requested dates");
94
+ return;
95
+ }
96
+ if (options.json) {
97
+ console.log(JSON.stringify(isRange ? entries : entries, null, 2));
98
+ }
99
+ else {
100
+ formatBiometrics(entries, isRange);
101
+ }
102
+ }
103
+ }
104
+ catch (error) {
105
+ s?.stop("Failed.");
106
+ p.log.error(`${error instanceof Error ? error.message : error}`);
107
+ process.exit(1);
108
+ }
109
+ }
110
+ function formatNutrition(entries, isRange) {
111
+ if (!isRange) {
112
+ const e = entries[0];
113
+ p.outro(`${e.calories} kcal | P: ${e.protein}g | C: ${e.carbs}g | F: ${e.fat}g`);
114
+ return;
115
+ }
116
+ for (const e of entries) {
117
+ p.log.info(`${e.date}: ${e.calories} kcal | P: ${e.protein}g | C: ${e.carbs}g | F: ${e.fat}g`);
118
+ }
119
+ }
120
+ function formatExercises(entries, isRange) {
121
+ if (!isRange) {
122
+ for (const e of entries) {
123
+ p.outro(`${e.exercise}: ${e.minutes} min, ${e.caloriesBurned} kcal`);
124
+ }
125
+ return;
126
+ }
127
+ for (const e of entries) {
128
+ p.log.info(`${e.date}: ${e.exercise}: ${e.minutes} min, ${e.caloriesBurned} kcal`);
129
+ }
130
+ }
131
+ function formatBiometrics(entries, isRange) {
132
+ if (!isRange) {
133
+ for (const e of entries) {
134
+ p.outro(`${e.metric}: ${e.amount} ${e.unit}`);
135
+ }
136
+ return;
137
+ }
138
+ for (const e of entries) {
139
+ p.log.info(`${e.date}: ${e.metric}: ${e.amount} ${e.unit}`);
140
+ }
141
+ }
142
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface LogOptions {
2
+ meal?: string;
3
+ servings?: number;
4
+ }
5
+ export declare function log(name: string, options: LogOptions): Promise<void>;
6
+ //# sourceMappingURL=log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/commands/log.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAID,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA6C1E"}
@@ -0,0 +1,40 @@
1
+ import * as p from "@clack/prompts";
2
+ import { getKernelClient } from "../kernel/client.js";
3
+ const VALID_MEALS = ["breakfast", "lunch", "dinner", "snacks"];
4
+ export async function log(name, options) {
5
+ // Validate meal if provided
6
+ if (options.meal) {
7
+ const normalizedMeal = options.meal.toLowerCase();
8
+ if (!VALID_MEALS.includes(normalizedMeal)) {
9
+ p.log.error(`Invalid meal "${options.meal}". Use: Breakfast, Lunch, Dinner, or Snacks`);
10
+ process.exit(1);
11
+ }
12
+ }
13
+ // Validate servings if provided
14
+ if (options.servings !== undefined && options.servings <= 0) {
15
+ p.log.error("Servings must be a positive number");
16
+ process.exit(1);
17
+ }
18
+ const mealLabel = options.meal
19
+ ? options.meal.charAt(0).toUpperCase() + options.meal.slice(1).toLowerCase()
20
+ : "Uncategorized";
21
+ p.intro("🍎 crono log");
22
+ const s = p.spinner();
23
+ s.start("Connecting...");
24
+ try {
25
+ const kernel = await getKernelClient();
26
+ await kernel.logFood({
27
+ name,
28
+ meal: options.meal,
29
+ servings: options.servings,
30
+ }, (msg) => s.message(msg));
31
+ s.stop("Done.");
32
+ p.outro(`Logged: ${name} → ${mealLabel}`);
33
+ }
34
+ catch (error) {
35
+ s.stop("Failed.");
36
+ p.log.error(`Failed to log food: ${error}`);
37
+ process.exit(1);
38
+ }
39
+ }
40
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/commands/log.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAOtD,MAAM,WAAW,GAAG,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAE/D,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAY,EAAE,OAAmB;IACzD,4BAA4B;IAC5B,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAClD,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAC1C,CAAC,CAAC,GAAG,CAAC,KAAK,CACT,iBAAiB,OAAO,CAAC,IAAI,6CAA6C,CAC3E,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC;QAC5D,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI;QAC5B,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;QAC5E,CAAC,CAAC,eAAe,CAAC;IAEpB,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAEzB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAC;QACvC,MAAM,MAAM,CAAC,OAAO,CAClB;YACE,IAAI;YACJ,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,EACD,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CACxB,CAAC;QAEF,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChB,CAAC,CAAC,KAAK,CAAC,WAAW,IAAI,MAAM,SAAS,EAAE,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,uBAAuB,KAAK,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
package/dist/config.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export interface CronoConfig {
2
2
  kernelProfile?: string;
3
3
  defaultMeal?: string;
4
+ gwtPermutation?: string;
5
+ gwtHeader?: string;
4
6
  }
5
7
  /**
6
8
  * Load configuration from disk.
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAcD;;GAEG;AACH,wBAAgB,UAAU,IAAI,WAAW,CAaxC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAGpD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAcD;;GAEG;AACH,wBAAgB,UAAU,IAAI,WAAW,CAaxC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAGpD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAO5B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AACvD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEpD;;GAEG;AACH,SAAS,eAAe;IACtB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,eAAe,EAAE,CAAC;IAElB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAmB;IAC5C,eAAe,EAAE,CAAC;IAClB,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AACtC,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAS5B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AACvD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEpD;;GAEG;AACH,SAAS,eAAe;IACtB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,eAAe,EAAE,CAAC;IAElB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAmB;IAC5C,eAAe,EAAE,CAAC;IAClB,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Direct HTTP authentication with Cronometer.
3
+ *
4
+ * Three-step flow:
5
+ * 1. GET /login/ — parse anticsrf token and JSESSIONID cookie
6
+ * 2. POST /login — form-encoded login, get sesnonce cookie
7
+ * 3. POST /cronometer/app — GWT RPC authenticate, get user ID
8
+ */
9
+ export interface CronometerSession {
10
+ cookies: string;
11
+ sesnonce: string;
12
+ userId: number;
13
+ }
14
+ /** Extract a named cookie value from a set-cookie header array. */
15
+ export declare function extractCookie(headers: Headers, name: string): string | null;
16
+ /** Collect all cookies from set-cookie headers as "name=value; name2=value2" string. */
17
+ export declare function collectCookies(headers: Headers): string;
18
+ /** Merge two cookie strings, with later values overriding earlier ones. */
19
+ export declare function mergeCookies(a: string, b: string): string;
20
+ /** Parse the anticsrf token from Cronometer's login page HTML. */
21
+ export declare function parseAnticsrf(html: string): string | null;
22
+ /** Extract user ID from GWT authenticate response. */
23
+ export declare function parseUserId(body: string): number | null;
24
+ /** Build GWT RPC body for the authenticate call. */
25
+ export declare function buildAuthenticateBody(gwtHeader: string): string;
26
+ /**
27
+ * Authenticate with Cronometer via HTTP.
28
+ * Returns a session object with cookies and user ID.
29
+ */
30
+ export declare function login(username: string, password: string, gwtPermutation?: string, gwtHeader?: string): Promise<CronometerSession>;
31
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/cronometer/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO3E;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAQvD;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CASzD;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGzD;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKvD;AAED,oDAAoD;AACpD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG/D;AAcD;;;GAGG;AACH,wBAAsB,KAAK,CACzB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,cAAc,CAAC,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC,CA2F5B"}