@wat-toolbox/wat 0.1.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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -0
  3. package/dist/cli/commands/availability.d.ts +10 -0
  4. package/dist/cli/commands/availability.d.ts.map +1 -0
  5. package/dist/cli/commands/availability.js +83 -0
  6. package/dist/cli/commands/availability.js.map +1 -0
  7. package/dist/cli/commands/bookings.d.ts +12 -0
  8. package/dist/cli/commands/bookings.d.ts.map +1 -0
  9. package/dist/cli/commands/bookings.js +195 -0
  10. package/dist/cli/commands/bookings.js.map +1 -0
  11. package/dist/cli/commands/config.d.ts +7 -0
  12. package/dist/cli/commands/config.d.ts.map +1 -0
  13. package/dist/cli/commands/config.js +59 -0
  14. package/dist/cli/commands/config.js.map +1 -0
  15. package/dist/cli/commands/login.d.ts +11 -0
  16. package/dist/cli/commands/login.d.ts.map +1 -0
  17. package/dist/cli/commands/login.js +127 -0
  18. package/dist/cli/commands/login.js.map +1 -0
  19. package/dist/cli/commands/logout.d.ts +8 -0
  20. package/dist/cli/commands/logout.d.ts.map +1 -0
  21. package/dist/cli/commands/logout.js +38 -0
  22. package/dist/cli/commands/logout.js.map +1 -0
  23. package/dist/cli/commands/rooms.d.ts +22 -0
  24. package/dist/cli/commands/rooms.d.ts.map +1 -0
  25. package/dist/cli/commands/rooms.js +76 -0
  26. package/dist/cli/commands/rooms.js.map +1 -0
  27. package/dist/cli/commands/whoami.d.ts +6 -0
  28. package/dist/cli/commands/whoami.d.ts.map +1 -0
  29. package/dist/cli/commands/whoami.js +37 -0
  30. package/dist/cli/commands/whoami.js.map +1 -0
  31. package/dist/cli/index.d.ts +22 -0
  32. package/dist/cli/index.d.ts.map +1 -0
  33. package/dist/cli/index.js +61 -0
  34. package/dist/cli/index.js.map +1 -0
  35. package/dist/cli/utils/output.d.ts +28 -0
  36. package/dist/cli/utils/output.d.ts.map +1 -0
  37. package/dist/cli/utils/output.js +40 -0
  38. package/dist/cli/utils/output.js.map +1 -0
  39. package/dist/cli/utils/require-key.d.ts +6 -0
  40. package/dist/cli/utils/require-key.d.ts.map +1 -0
  41. package/dist/cli/utils/require-key.js +18 -0
  42. package/dist/cli/utils/require-key.js.map +1 -0
  43. package/dist/utils/api-client.d.ts +35 -0
  44. package/dist/utils/api-client.d.ts.map +1 -0
  45. package/dist/utils/api-client.js +98 -0
  46. package/dist/utils/api-client.js.map +1 -0
  47. package/dist/utils/auth-flow-client.d.ts +60 -0
  48. package/dist/utils/auth-flow-client.d.ts.map +1 -0
  49. package/dist/utils/auth-flow-client.js +28 -0
  50. package/dist/utils/auth-flow-client.js.map +1 -0
  51. package/dist/utils/config.d.ts +95 -0
  52. package/dist/utils/config.d.ts.map +1 -0
  53. package/dist/utils/config.js +246 -0
  54. package/dist/utils/config.js.map +1 -0
  55. package/dist/utils/rooms-client.d.ts +70 -0
  56. package/dist/utils/rooms-client.d.ts.map +1 -0
  57. package/dist/utils/rooms-client.js +59 -0
  58. package/dist/utils/rooms-client.js.map +1 -0
  59. package/dist/utils/time.d.ts +37 -0
  60. package/dist/utils/time.d.ts.map +1 -0
  61. package/dist/utils/time.js +130 -0
  62. package/dist/utils/time.js.map +1 -0
  63. package/package.json +54 -0
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Time interpretation for the CLI (plan §8).
3
+ *
4
+ * A bare `--start "2026-06-09T10:00"` is read as **Europe/Brussels** wall-clock
5
+ * by default (matching the UI), converted to a UTC instant for the API. Rules:
6
+ *
7
+ * - A value that already carries a UTC `Z` or a numeric offset (`+02:00`,
8
+ * `-0500`) is an absolute instant — honored as-is.
9
+ * - A bare local value (`YYYY-MM-DDTHH:mm[:ss]`, or with a space) is interpreted
10
+ * in the given IANA zone (default Europe/Brussels, override with `--tz`),
11
+ * DST-safe, and converted to UTC.
12
+ *
13
+ * The CLI prints times back in the SAME zone it accepted, so what a member types
14
+ * and what they see never disagree. No external dependency: the zone offset is
15
+ * derived from `Intl.DateTimeFormat`, which is DST-correct.
16
+ */
17
+ export const DEFAULT_TZ = 'Europe/Brussels';
18
+ /** True when a datetime string carries an explicit offset or `Z` (absolute). */
19
+ export function hasExplicitOffset(value) {
20
+ const trimmed = value.trim();
21
+ // Only the TIME portion (after the `T`/space) may carry an offset. A bare
22
+ // date like `2026-06-09` must NOT be mistaken for one (its `-09` is a month/day
23
+ // separator, not a `-09:00` offset).
24
+ const timePart = /[T ](\d{2}:\d{2}(?::\d{2})?)(.*)$/.exec(trimmed);
25
+ if (!timePart)
26
+ return false;
27
+ const suffix = timePart[2];
28
+ // `Z`, or `+HH`, `+HH:MM`, `+HHMM` (likewise `-`) immediately after the time.
29
+ return /^([zZ]|[+-]\d{2}(:?\d{2})?)$/.test(suffix);
30
+ }
31
+ /**
32
+ * Compute the offset (in minutes, east-of-UTC positive) of an IANA time zone at
33
+ * a given UTC instant. Derived from the difference between the same instant
34
+ * formatted as the zone's local wall-clock and the UTC wall-clock — DST-safe.
35
+ */
36
+ function zoneOffsetMinutes(instant, timeZone) {
37
+ const dtf = new Intl.DateTimeFormat('en-US', {
38
+ timeZone,
39
+ hour12: false,
40
+ year: 'numeric',
41
+ month: '2-digit',
42
+ day: '2-digit',
43
+ hour: '2-digit',
44
+ minute: '2-digit',
45
+ second: '2-digit'
46
+ });
47
+ const parts = dtf.formatToParts(instant);
48
+ const get = (type) => Number(parts.find((p) => p.type === type)?.value);
49
+ let hour = get('hour');
50
+ if (hour === 24)
51
+ hour = 0; // some engines emit 24 for midnight
52
+ // The wall-clock the zone shows for this instant, expressed as a UTC timestamp.
53
+ const asUTC = Date.UTC(get('year'), get('month') - 1, get('day'), hour, get('minute'), get('second'));
54
+ return Math.round((asUTC - instant.getTime()) / 60000);
55
+ }
56
+ /**
57
+ * Parse the wall-clock fields out of a bare local datetime string.
58
+ * Accepts `YYYY-MM-DDTHH:mm`, `YYYY-MM-DDTHH:mm:ss`, or a space separator.
59
+ * Returns null when the shape is not a bare local datetime.
60
+ */
61
+ function parseLocalParts(value) {
62
+ const m = /^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})(?::(\d{2}))?$/.exec(value.trim());
63
+ if (!m)
64
+ return null;
65
+ return {
66
+ y: Number(m[1]),
67
+ mo: Number(m[2]),
68
+ d: Number(m[3]),
69
+ h: Number(m[4]),
70
+ mi: Number(m[5]),
71
+ s: m[6] ? Number(m[6]) : 0
72
+ };
73
+ }
74
+ /**
75
+ * Resolve a datetime argument to an absolute instant.
76
+ *
77
+ * @param value the raw `--start` / `--end` / `--from` / `--to` argument
78
+ * @param tz the IANA zone for bare local values (default Europe/Brussels)
79
+ */
80
+ export function parseDateTimeArg(value, tz = DEFAULT_TZ) {
81
+ const trimmed = value.trim();
82
+ // 1) Explicit offset / Z → an absolute instant. Honor it as-is.
83
+ if (hasExplicitOffset(trimmed)) {
84
+ const date = new Date(trimmed);
85
+ if (Number.isNaN(date.getTime())) {
86
+ throw new Error(`Invalid datetime: "${value}"`);
87
+ }
88
+ return { date, zone: tz, interpretedLocal: false };
89
+ }
90
+ // 2) Bare local datetime → interpret in `tz`.
91
+ const parts = parseLocalParts(trimmed);
92
+ if (parts) {
93
+ // First guess: treat the wall-clock as if it were UTC, then correct by the
94
+ // zone's offset at that approximate instant (DST-safe to a one-pass refine).
95
+ const guessUTC = Date.UTC(parts.y, parts.mo - 1, parts.d, parts.h, parts.mi, parts.s);
96
+ const off1 = zoneOffsetMinutes(new Date(guessUTC), tz);
97
+ let utcMs = guessUTC - off1 * 60000;
98
+ // Refine once in case the first guess landed on the wrong side of a DST jump.
99
+ const off2 = zoneOffsetMinutes(new Date(utcMs), tz);
100
+ if (off2 !== off1)
101
+ utcMs = guessUTC - off2 * 60000;
102
+ return { date: new Date(utcMs), zone: tz, interpretedLocal: true };
103
+ }
104
+ // 3) Date-only (`YYYY-MM-DD`) → midnight in `tz`.
105
+ if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
106
+ return parseDateTimeArg(`${trimmed}T00:00:00`, tz);
107
+ }
108
+ // 4) Last resort: let the JS engine try (e.g. RFC-ish strings).
109
+ const date = new Date(trimmed);
110
+ if (Number.isNaN(date.getTime())) {
111
+ throw new Error(`Invalid datetime: "${value}"`);
112
+ }
113
+ return { date, zone: tz, interpretedLocal: false };
114
+ }
115
+ /** Format an instant as a wall-clock string in the given zone (round-trip display). */
116
+ export function formatInZone(date, tz = DEFAULT_TZ) {
117
+ const dtf = new Intl.DateTimeFormat('en-GB', {
118
+ timeZone: tz,
119
+ hour12: false,
120
+ year: 'numeric',
121
+ month: '2-digit',
122
+ day: '2-digit',
123
+ hour: '2-digit',
124
+ minute: '2-digit'
125
+ });
126
+ const parts = dtf.formatToParts(date);
127
+ const get = (type) => parts.find((p) => p.type === type)?.value ?? '';
128
+ return `${get('year')}-${get('month')}-${get('day')} ${get('hour')}:${get('minute')} (${tz})`;
129
+ }
130
+ //# sourceMappingURL=time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.js","sourceRoot":"","sources":["../../src/utils/time.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@wat-toolbox/wat",
3
+ "version": "0.1.0",
4
+ "description": "wat — book WAT meeting rooms from the terminal. Email-OTP login, API-key auth, dev/prod targeting.",
5
+ "type": "module",
6
+ "bin": {
7
+ "wat": "./dist/cli/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "test": "vitest run",
15
+ "test:watch": "vitest",
16
+ "prepublishOnly": "npm run build && npm test"
17
+ },
18
+ "keywords": [
19
+ "cli",
20
+ "wat",
21
+ "rooms",
22
+ "booking",
23
+ "codika",
24
+ "otp"
25
+ ],
26
+ "author": {
27
+ "name": "Codika",
28
+ "email": "team@codika.io",
29
+ "url": "https://codika.io"
30
+ },
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/WATbeta/wat-cli.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/WATbeta/wat-cli/issues"
38
+ },
39
+ "homepage": "https://github.com/WATbeta/wat-cli#readme",
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "dependencies": {
44
+ "commander": "^12.0.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^22.0.0",
48
+ "typescript": "^5.4.0",
49
+ "vitest": "^3.0.0"
50
+ },
51
+ "engines": {
52
+ "node": ">=20.0.0"
53
+ }
54
+ }