@ikalogic/at1000 0.8.0 → 0.10.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 (81) hide show
  1. package/README.md +77 -0
  2. package/build/at1000-6CjGQqmM.cjs +3 -0
  3. package/build/at1000-6CjGQqmM.cjs.map +1 -0
  4. package/build/at1000-C9erttrI.mjs +3 -0
  5. package/build/at1000-C9erttrI.mjs.map +1 -0
  6. package/build/browser.cjs +1 -1
  7. package/build/browser.cjs.map +1 -1
  8. package/build/browser.d.cts +2 -2
  9. package/build/browser.d.mts +2 -2
  10. package/build/browser.mjs +1 -1
  11. package/build/browser.mjs.map +1 -1
  12. package/build/{events-RRtuVpdW.d.cts → events-BVDWI2tr.d.cts} +10 -1
  13. package/build/events-BVDWI2tr.d.cts.map +1 -0
  14. package/build/{events-RRtuVpdW.d.mts → events-BVDWI2tr.d.mts} +10 -1
  15. package/build/events-BVDWI2tr.d.mts.map +1 -0
  16. package/build/events.cjs +1 -1
  17. package/build/events.d.cts +1 -1
  18. package/build/events.d.mts +1 -1
  19. package/build/events.mjs +1 -1
  20. package/build/hmi-Chid1Vvo.d.mts +236 -0
  21. package/build/hmi-Chid1Vvo.d.mts.map +1 -0
  22. package/build/hmi-OyVDyqU-.d.cts +236 -0
  23. package/build/hmi-OyVDyqU-.d.cts.map +1 -0
  24. package/build/hmi.cjs +1 -1
  25. package/build/hmi.cjs.map +1 -1
  26. package/build/hmi.d.cts +2 -2
  27. package/build/hmi.d.mts +2 -2
  28. package/build/hmi.mjs +1 -1
  29. package/build/hmi.mjs.map +1 -1
  30. package/build/{host-TBM8TT7q.d.cts → host-C1Zl1RyR.d.cts} +27 -5
  31. package/build/host-C1Zl1RyR.d.cts.map +1 -0
  32. package/build/{host-BjLI2rbR.d.mts → host-DCfMkBnq.d.mts} +27 -5
  33. package/build/host-DCfMkBnq.d.mts.map +1 -0
  34. package/build/management-BqW9gGfM.mjs +7 -0
  35. package/build/management-BqW9gGfM.mjs.map +1 -0
  36. package/build/management-CIr8us5E.cjs +7 -0
  37. package/build/management-CIr8us5E.cjs.map +1 -0
  38. package/build/management.cjs +1 -1
  39. package/build/management.d.cts +17 -1
  40. package/build/management.d.cts.map +1 -1
  41. package/build/management.d.mts +17 -1
  42. package/build/management.d.mts.map +1 -1
  43. package/build/management.mjs +1 -1
  44. package/build/node.cjs +1 -1
  45. package/build/node.cjs.map +1 -1
  46. package/build/node.d.cts +2 -2
  47. package/build/node.d.mts +2 -2
  48. package/build/node.mjs +1 -1
  49. package/build/node.mjs.map +1 -1
  50. package/build/package-BAite5L5.mjs +2 -0
  51. package/build/package-BAite5L5.mjs.map +1 -0
  52. package/build/{package-BMXokpna.cjs → package-BmyGanoB.cjs} +2 -2
  53. package/build/package-BmyGanoB.cjs.map +1 -0
  54. package/build/{session-qWW9mqWH.d.cts → session-DbV_F9Wz.d.cts} +2 -2
  55. package/build/{session-qWW9mqWH.d.cts.map → session-DbV_F9Wz.d.cts.map} +1 -1
  56. package/build/{session-qWW9mqWH.d.mts → session-DbV_F9Wz.d.mts} +2 -2
  57. package/build/{session-qWW9mqWH.d.mts.map → session-DbV_F9Wz.d.mts.map} +1 -1
  58. package/build/session.cjs +1 -1
  59. package/build/session.d.cts +1 -1
  60. package/build/session.d.mts +1 -1
  61. package/build/session.mjs +1 -1
  62. package/package.json +1 -1
  63. package/build/at1000-CoQUADtx.mjs +0 -3
  64. package/build/at1000-CoQUADtx.mjs.map +0 -1
  65. package/build/at1000-CyFs4TGI.cjs +0 -3
  66. package/build/at1000-CyFs4TGI.cjs.map +0 -1
  67. package/build/events-RRtuVpdW.d.cts.map +0 -1
  68. package/build/events-RRtuVpdW.d.mts.map +0 -1
  69. package/build/hmi-BEMiVKDF.d.cts +0 -151
  70. package/build/hmi-BEMiVKDF.d.cts.map +0 -1
  71. package/build/hmi-BEMiVKDF.d.mts +0 -151
  72. package/build/hmi-BEMiVKDF.d.mts.map +0 -1
  73. package/build/host-BjLI2rbR.d.mts.map +0 -1
  74. package/build/host-TBM8TT7q.d.cts.map +0 -1
  75. package/build/management-CEL202P0.mjs +0 -7
  76. package/build/management-CEL202P0.mjs.map +0 -1
  77. package/build/management-hyOL3JnM.cjs +0 -7
  78. package/build/management-hyOL3JnM.cjs.map +0 -1
  79. package/build/package-BMXokpna.cjs.map +0 -1
  80. package/build/package-D7Y23M8-.mjs +0 -2
  81. package/build/package-D7Y23M8-.mjs.map +0 -1
@@ -0,0 +1,236 @@
1
+ import { i as EventsApi } from "./events-BVDWI2tr.mjs";
2
+ import { UpFetch } from "up-fetch";
3
+ import * as v from "valibot";
4
+ //#region src/api/hmi.d.ts
5
+ declare const screenText: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxLengthAction<string, 1024, undefined>]>;
6
+ type ScreenText = v.InferOutput<typeof screenText>;
7
+ declare const text: v.ObjectSchema<{
8
+ readonly text: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxLengthAction<string, 1024, undefined>]>;
9
+ }, undefined>;
10
+ declare const color: v.ObjectSchema<{
11
+ readonly text: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.LengthAction<string, 7, undefined>, v.HexColorAction<string, undefined>]>, undefined>;
12
+ readonly progress: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.LengthAction<string, 7, undefined>, v.HexColorAction<string, undefined>]>, undefined>;
13
+ readonly background: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.LengthAction<string, 7, undefined>, v.HexColorAction<string, undefined>]>, undefined>;
14
+ }, undefined>;
15
+ type Color = v.InferOutput<typeof color>;
16
+ declare const progressValue: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.MinValueAction<number, 0, undefined>, v.MaxValueAction<number, 100, undefined>]>;
17
+ type ProgressValue = v.InferOutput<typeof progressValue>;
18
+ declare const progress: v.ObjectSchema<{
19
+ readonly progress: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.MinValueAction<number, 0, undefined>, v.MaxValueAction<number, 100, undefined>]>;
20
+ }, undefined>;
21
+ type Progress = v.InferOutput<typeof progress>;
22
+ declare const playbackConfiguration: v.ObjectSchema<{
23
+ readonly sound_id: v.PicklistSchema<["success", "warning", "failure", "notification_1", "notification_2", "imperial_march"], undefined>;
24
+ readonly volume: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.MinValueAction<number, 0, undefined>, v.MaxValueAction<number, 100, undefined>]>;
25
+ }, undefined>;
26
+ type PlaybackConfiguration = v.InferOutput<typeof playbackConfiguration>;
27
+ declare const internalKnobEvent: v.ObjectSchema<{
28
+ readonly button_pressed: v.BooleanSchema<undefined>;
29
+ readonly button_held: v.BooleanSchema<undefined>;
30
+ readonly rotation_delta: v.NumberSchema<undefined>;
31
+ }, undefined>;
32
+ declare const knobEvent: Omit<v.ObjectSchema<{
33
+ readonly button_pressed: v.BooleanSchema<undefined>;
34
+ readonly button_held: v.BooleanSchema<undefined>;
35
+ readonly rotation_delta: v.NumberSchema<undefined>;
36
+ }, undefined>, "entries" | "~run" | "~standard" | "~types"> & {
37
+ readonly entries: Omit<{
38
+ readonly button_pressed: v.BooleanSchema<undefined>;
39
+ readonly button_held: v.BooleanSchema<undefined>;
40
+ readonly rotation_delta: v.NumberSchema<undefined>;
41
+ }, "button_held">;
42
+ readonly "~standard": v.StandardProps<{
43
+ button_pressed: boolean;
44
+ rotation_delta: number;
45
+ }, {
46
+ button_pressed: boolean;
47
+ rotation_delta: number;
48
+ }>;
49
+ readonly "~run": (dataset: v.UnknownDataset, config: v.Config<v.BaseIssue<unknown>>) => v.OutputDataset<{
50
+ button_pressed: boolean;
51
+ rotation_delta: number;
52
+ }, v.BooleanIssue | v.NumberIssue | v.ObjectIssue>;
53
+ readonly "~types"?: {
54
+ readonly input: {
55
+ button_pressed: boolean;
56
+ rotation_delta: number;
57
+ };
58
+ readonly output: {
59
+ button_pressed: boolean;
60
+ rotation_delta: number;
61
+ };
62
+ readonly issue: v.BooleanIssue | v.NumberIssue | v.ObjectIssue;
63
+ } | undefined;
64
+ };
65
+ type KnobEvent = v.InferOutput<typeof knobEvent>;
66
+ declare const promptChoice: v.ObjectSchema<{
67
+ readonly label: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxBytesAction<string, 64, undefined>, v.RegexAction<string, "Choice labels must not be blank">, v.CheckAction<string, "Choice labels must not contain control characters">]>;
68
+ readonly color: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.LengthAction<string, 7, undefined>, v.HexColorAction<string, undefined>]>, undefined>;
69
+ }, undefined>;
70
+ type PromptChoice = v.InferOutput<typeof promptChoice>;
71
+ declare const promptRequest: v.SchemaWithPipe<readonly [v.ObjectSchema<{
72
+ readonly text: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxBytesAction<string, 256, undefined>, v.RegexAction<string, "Prompt text must not be blank">, v.CheckAction<string, "Prompt text permits line feeds but no other control characters">]>;
73
+ readonly choices: v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.UnionSchema<[v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxBytesAction<string, 64, undefined>, v.RegexAction<string, "Choice labels must not be blank">, v.CheckAction<string, "Choice labels must not contain control characters">]>, v.ObjectSchema<{
74
+ readonly label: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxBytesAction<string, 64, undefined>, v.RegexAction<string, "Choice labels must not be blank">, v.CheckAction<string, "Choice labels must not contain control characters">]>;
75
+ readonly color: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.LengthAction<string, 7, undefined>, v.HexColorAction<string, undefined>]>, undefined>;
76
+ }, undefined>], undefined>, v.TransformAction<string | {
77
+ label: string;
78
+ color?: string | undefined;
79
+ }, {
80
+ label: string;
81
+ color?: string | undefined;
82
+ }>]>, undefined>, v.MinLengthAction<{
83
+ label: string;
84
+ color?: string | undefined;
85
+ }[], 1, undefined>, v.MaxLengthAction<{
86
+ label: string;
87
+ color?: string | undefined;
88
+ }[], 32, undefined>]>;
89
+ readonly default_index: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>, v.MaxValueAction<number, 31, undefined>]>, undefined>;
90
+ readonly timeout_ms: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1000, undefined>, v.MaxValueAction<number, 1800000, undefined>]>, undefined>;
91
+ }, undefined>, v.CheckAction<{
92
+ text: string;
93
+ choices: {
94
+ label: string;
95
+ color?: string | undefined;
96
+ }[];
97
+ default_index?: number | undefined;
98
+ timeout_ms?: number | undefined;
99
+ }, "default_index must be below the number of choices">]>;
100
+ /** Wire shape, where every choice is an object. */
101
+ type PromptRequest = v.InferOutput<typeof promptRequest>;
102
+ /** Accepted shape, where a choice may be a bare label string. */
103
+ type PromptRequestInput = v.InferInput<typeof promptRequest>;
104
+ declare const promptSelection: v.ObjectSchema<{
105
+ readonly label: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxBytesAction<string, 64, undefined>, v.RegexAction<string, "Choice labels must not be blank">, v.CheckAction<string, "Choice labels must not contain control characters">]>;
106
+ readonly index: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>, v.MaxValueAction<number, 31, undefined>]>;
107
+ }, undefined>;
108
+ type PromptSelection = v.InferOutput<typeof promptSelection>;
109
+ /**
110
+ * `selection` is always present: the choice under the knob while pending, the
111
+ * confirmed choice when selected, and the last highlighted choice when the prompt
112
+ * was cancelled or timed out.
113
+ */
114
+ declare const promptState: v.ObjectSchema<{
115
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
116
+ readonly status: v.PicklistSchema<["pending", "selected", "cancelled", "timed_out"], undefined>;
117
+ readonly selection: v.ObjectSchema<{
118
+ readonly label: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxBytesAction<string, 64, undefined>, v.RegexAction<string, "Choice labels must not be blank">, v.CheckAction<string, "Choice labels must not contain control characters">]>;
119
+ readonly index: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>, v.MaxValueAction<number, 31, undefined>]>;
120
+ }, undefined>;
121
+ readonly reason: v.OptionalSchema<v.PicklistSchema<["client_cancelled", "session_ended", "panel_exit", "display_replaced"], undefined>, undefined>;
122
+ }, undefined>;
123
+ type PromptState = v.InferOutput<typeof promptState>;
124
+ type PromptStatus = PromptState['status'];
125
+ /** @hideconstructor */
126
+ declare class HmiApi {
127
+ private readonly fetch;
128
+ private readonly events;
129
+ constructor(fetch: UpFetch, events: EventsApi);
130
+ /**
131
+ * Resets the HMI.
132
+ */
133
+ reset(): Promise<void>;
134
+ /**
135
+ * Shows a single-choice prompt on the LCD and waits for the operator to answer.
136
+ *
137
+ * A choice may be a bare label string. `default_index` selects the initially
138
+ * highlighted choice and defaults to 0. Screen changes, resets, knob reads, and
139
+ * other prompts conflict while the prompt is pending.
140
+ *
141
+ * The wait rides the `hmi.prompt` event. Every event re-arms a
142
+ * `timeout_ms + 2000 ms` window, and a window that expires costs one read before
143
+ * the wait resumes: the device deadline stops as soon as the operator turns the
144
+ * knob, so a prompt somebody is answering is never abandoned locally.
145
+ *
146
+ * Cancellation and timeout are results. HTTP errors and local aborts reject the
147
+ * promise. On failure, cancellation is attempted without replacing the original
148
+ * error.
149
+ */
150
+ prompt(request: PromptRequestInput, options?: {
151
+ signal?: AbortSignal;
152
+ }): Promise<PromptState>;
153
+ private createPrompt;
154
+ private getPrompt;
155
+ private cancelPrompt;
156
+ /** Settles with `work`, or rejects as soon as `signal` aborts. */
157
+ private untilAborted;
158
+ /**
159
+ * Access the screen API.
160
+ * @returns The screen instance.
161
+ */
162
+ screen(): Screen;
163
+ /**
164
+ * Access the audio API.
165
+ * @returns The audio instance.
166
+ */
167
+ audio(): Audio;
168
+ /**
169
+ * Access the knob API.
170
+ * @returns The knob instance.
171
+ */
172
+ knob(): Knob;
173
+ }
174
+ /** @hideconstructor */
175
+ declare class Screen {
176
+ private readonly fetch;
177
+ constructor(fetch: UpFetch);
178
+ /**
179
+ * Prints text to the screen.
180
+ * @param data The text to print.
181
+ * @returns The printed text.
182
+ */
183
+ print(data: ScreenText): Promise<string>;
184
+ /**
185
+ * Sets the screen colors.
186
+ * @param colors The colors to set.
187
+ * @returns The updated colors.
188
+ */
189
+ colors(colors: Color): Promise<Color>;
190
+ /**
191
+ * Sets the screen progress.
192
+ * @param data The progress value to set.
193
+ * @returns The updated progress.
194
+ */
195
+ progress(data: ProgressValue): Promise<Progress>;
196
+ /**
197
+ * Clears the screen.
198
+ */
199
+ clear(): Promise<void>;
200
+ /**
201
+ * Clears the text on the screen.
202
+ */
203
+ clear_text(): Promise<void>;
204
+ }
205
+ /** @hideconstructor */
206
+ declare class Audio {
207
+ private readonly fetch;
208
+ constructor(fetch: UpFetch);
209
+ /**
210
+ * Plays a sound.
211
+ * @param config The configuration (sound_id, volume).
212
+ * @returns The play configuration.
213
+ */
214
+ play(config: PlaybackConfiguration): Promise<PlaybackConfiguration>;
215
+ }
216
+ /** @hideconstructor */
217
+ declare class Knob {
218
+ private readonly fetch;
219
+ constructor(fetch: UpFetch);
220
+ read_event: () => Promise<{
221
+ button_pressed: boolean;
222
+ button_held: boolean;
223
+ rotation_delta: number;
224
+ }>;
225
+ is_button_held: () => Promise<boolean>;
226
+ is_knob_turned: () => Promise<boolean>;
227
+ /**
228
+ * Waits for a knob event and returns it.
229
+ * @param timeout_ms The timeout in milliseconds.
230
+ * @returns The knob event or null if the timeout was reached.
231
+ */
232
+ wait_event(timeout_ms?: number): Promise<KnobEvent | null>;
233
+ }
234
+ //#endregion
235
+ export { text as S, color as _, KnobEvent as a, progress as b, ProgressValue as c, PromptRequestInput as d, PromptSelection as f, ScreenText as g, Screen as h, Knob as i, PromptChoice as l, PromptStatus as m, Color as n, PlaybackConfiguration as o, PromptState as p, HmiApi as r, Progress as s, Audio as t, PromptRequest as u, internalKnobEvent as v, promptState as x, playbackConfiguration as y };
236
+ //# sourceMappingURL=hmi-Chid1Vvo.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hmi-Chid1Vvo.d.mts","names":[],"sources":["../src/api/hmi.ts"],"mappings":";;;;cAKM,YAAU,EAAA,yBAAA,EAAA,yBAAA,EAAA;KACJ,aAAa,EAAE,mBAAmB;cAEjC,MAAI,EAAA;;;cAIJ,OAAK,EAAA;;;;;KAKN,QAAQ,EAAE,mBAAmB;cAEnC,eAAa,EAAA,yBAAA,EAAA,yBAAA,EAAA,sCAAA,EAAA;KACP,gBAAgB,EAAE,mBAAmB;cACpC,UAAQ,EAAA;;;KACT,WAAW,EAAE,mBAAmB;cAE/B,uBAAqB,EAAA;;;;KAOtB,wBAAwB,EAAE,mBAAmB;cAE5C,mBAAiB,EAAA;;;;;cAKxB,WAAS,KAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KACH,YAAY,EAAE,mBAAmB;cASvC,cAAY,EAAA;;;;KACN,eAAe,EAAE,mBAAmB;cAS1C,eAAa,EAAA,yBAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsBP,gBAAgB,EAAE,mBAAmB;;KAErC,qBAAqB,EAAE,kBAAkB;cAE/C,iBAAe,EAAA;;;;KACT,kBAAkB,EAAE,mBAAmB;;;;;;cAOtC,aAAW,EAAA;;;;;;;;;KAQZ,cAAc,EAAE,mBAAmB;KACnC,eAAe;;cAQd;mBACkB;mBAAiC;EAA9D,YAA6B,OAAO,SAA0B,QAAQ;;;;EAKtE,SAAS;;;;;;;;;;;;;;;;;EAoBH,OACJ,SAAS,oBACT;IAAY,SAAS;MACpB,QAAQ;UAoEH;UAQA;UAIA;;UAQM;;;;;EAkBd,UAAU;;;;;EAQV,SAAS;;;;;EAQT,QAAQ;;;cAMG;mBACkB;EAA7B,YAA6B,OAAO;;;;;;EAO9B,MAAM,MAAM,aAAa;;;;;;EAc/B,OAAO,QAAQ,QAAQ,QAAQ;;;;;;EAazB,SAAS,MAAM,gBAAgB,QAAQ;;;;EAkB7C,SAAS;;;;EAOT,cAAc;;;cAMH;mBACkB;EAA7B,YAA6B,OAAO;;;;;;EAO9B,KAAK,QAAQ,wBAAwB,QAAQ;;;cAUxC;mBACkB;EAA7B,YAA6B,OAAO;EAEpC,kBAAU;;;;;EAEV,sBAAc;EACd,sBAAc;;;;;;EAOR,WAAW,sBAAsB,QAAQ"}
@@ -0,0 +1,236 @@
1
+ import { i as EventsApi } from "./events-BVDWI2tr.cjs";
2
+ import { UpFetch } from "up-fetch";
3
+ import * as v from "valibot";
4
+ //#region src/api/hmi.d.ts
5
+ declare const screenText: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxLengthAction<string, 1024, undefined>]>;
6
+ type ScreenText = v.InferOutput<typeof screenText>;
7
+ declare const text: v.ObjectSchema<{
8
+ readonly text: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxLengthAction<string, 1024, undefined>]>;
9
+ }, undefined>;
10
+ declare const color: v.ObjectSchema<{
11
+ readonly text: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.LengthAction<string, 7, undefined>, v.HexColorAction<string, undefined>]>, undefined>;
12
+ readonly progress: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.LengthAction<string, 7, undefined>, v.HexColorAction<string, undefined>]>, undefined>;
13
+ readonly background: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.LengthAction<string, 7, undefined>, v.HexColorAction<string, undefined>]>, undefined>;
14
+ }, undefined>;
15
+ type Color = v.InferOutput<typeof color>;
16
+ declare const progressValue: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.MinValueAction<number, 0, undefined>, v.MaxValueAction<number, 100, undefined>]>;
17
+ type ProgressValue = v.InferOutput<typeof progressValue>;
18
+ declare const progress: v.ObjectSchema<{
19
+ readonly progress: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.MinValueAction<number, 0, undefined>, v.MaxValueAction<number, 100, undefined>]>;
20
+ }, undefined>;
21
+ type Progress = v.InferOutput<typeof progress>;
22
+ declare const playbackConfiguration: v.ObjectSchema<{
23
+ readonly sound_id: v.PicklistSchema<["success", "warning", "failure", "notification_1", "notification_2", "imperial_march"], undefined>;
24
+ readonly volume: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.MinValueAction<number, 0, undefined>, v.MaxValueAction<number, 100, undefined>]>;
25
+ }, undefined>;
26
+ type PlaybackConfiguration = v.InferOutput<typeof playbackConfiguration>;
27
+ declare const internalKnobEvent: v.ObjectSchema<{
28
+ readonly button_pressed: v.BooleanSchema<undefined>;
29
+ readonly button_held: v.BooleanSchema<undefined>;
30
+ readonly rotation_delta: v.NumberSchema<undefined>;
31
+ }, undefined>;
32
+ declare const knobEvent: Omit<v.ObjectSchema<{
33
+ readonly button_pressed: v.BooleanSchema<undefined>;
34
+ readonly button_held: v.BooleanSchema<undefined>;
35
+ readonly rotation_delta: v.NumberSchema<undefined>;
36
+ }, undefined>, "entries" | "~run" | "~standard" | "~types"> & {
37
+ readonly entries: Omit<{
38
+ readonly button_pressed: v.BooleanSchema<undefined>;
39
+ readonly button_held: v.BooleanSchema<undefined>;
40
+ readonly rotation_delta: v.NumberSchema<undefined>;
41
+ }, "button_held">;
42
+ readonly "~standard": v.StandardProps<{
43
+ button_pressed: boolean;
44
+ rotation_delta: number;
45
+ }, {
46
+ button_pressed: boolean;
47
+ rotation_delta: number;
48
+ }>;
49
+ readonly "~run": (dataset: v.UnknownDataset, config: v.Config<v.BaseIssue<unknown>>) => v.OutputDataset<{
50
+ button_pressed: boolean;
51
+ rotation_delta: number;
52
+ }, v.BooleanIssue | v.NumberIssue | v.ObjectIssue>;
53
+ readonly "~types"?: {
54
+ readonly input: {
55
+ button_pressed: boolean;
56
+ rotation_delta: number;
57
+ };
58
+ readonly output: {
59
+ button_pressed: boolean;
60
+ rotation_delta: number;
61
+ };
62
+ readonly issue: v.BooleanIssue | v.NumberIssue | v.ObjectIssue;
63
+ } | undefined;
64
+ };
65
+ type KnobEvent = v.InferOutput<typeof knobEvent>;
66
+ declare const promptChoice: v.ObjectSchema<{
67
+ readonly label: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxBytesAction<string, 64, undefined>, v.RegexAction<string, "Choice labels must not be blank">, v.CheckAction<string, "Choice labels must not contain control characters">]>;
68
+ readonly color: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.LengthAction<string, 7, undefined>, v.HexColorAction<string, undefined>]>, undefined>;
69
+ }, undefined>;
70
+ type PromptChoice = v.InferOutput<typeof promptChoice>;
71
+ declare const promptRequest: v.SchemaWithPipe<readonly [v.ObjectSchema<{
72
+ readonly text: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxBytesAction<string, 256, undefined>, v.RegexAction<string, "Prompt text must not be blank">, v.CheckAction<string, "Prompt text permits line feeds but no other control characters">]>;
73
+ readonly choices: v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.UnionSchema<[v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxBytesAction<string, 64, undefined>, v.RegexAction<string, "Choice labels must not be blank">, v.CheckAction<string, "Choice labels must not contain control characters">]>, v.ObjectSchema<{
74
+ readonly label: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxBytesAction<string, 64, undefined>, v.RegexAction<string, "Choice labels must not be blank">, v.CheckAction<string, "Choice labels must not contain control characters">]>;
75
+ readonly color: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.LengthAction<string, 7, undefined>, v.HexColorAction<string, undefined>]>, undefined>;
76
+ }, undefined>], undefined>, v.TransformAction<string | {
77
+ label: string;
78
+ color?: string | undefined;
79
+ }, {
80
+ label: string;
81
+ color?: string | undefined;
82
+ }>]>, undefined>, v.MinLengthAction<{
83
+ label: string;
84
+ color?: string | undefined;
85
+ }[], 1, undefined>, v.MaxLengthAction<{
86
+ label: string;
87
+ color?: string | undefined;
88
+ }[], 32, undefined>]>;
89
+ readonly default_index: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>, v.MaxValueAction<number, 31, undefined>]>, undefined>;
90
+ readonly timeout_ms: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 1000, undefined>, v.MaxValueAction<number, 1800000, undefined>]>, undefined>;
91
+ }, undefined>, v.CheckAction<{
92
+ text: string;
93
+ choices: {
94
+ label: string;
95
+ color?: string | undefined;
96
+ }[];
97
+ default_index?: number | undefined;
98
+ timeout_ms?: number | undefined;
99
+ }, "default_index must be below the number of choices">]>;
100
+ /** Wire shape, where every choice is an object. */
101
+ type PromptRequest = v.InferOutput<typeof promptRequest>;
102
+ /** Accepted shape, where a choice may be a bare label string. */
103
+ type PromptRequestInput = v.InferInput<typeof promptRequest>;
104
+ declare const promptSelection: v.ObjectSchema<{
105
+ readonly label: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxBytesAction<string, 64, undefined>, v.RegexAction<string, "Choice labels must not be blank">, v.CheckAction<string, "Choice labels must not contain control characters">]>;
106
+ readonly index: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>, v.MaxValueAction<number, 31, undefined>]>;
107
+ }, undefined>;
108
+ type PromptSelection = v.InferOutput<typeof promptSelection>;
109
+ /**
110
+ * `selection` is always present: the choice under the knob while pending, the
111
+ * confirmed choice when selected, and the last highlighted choice when the prompt
112
+ * was cancelled or timed out.
113
+ */
114
+ declare const promptState: v.ObjectSchema<{
115
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
116
+ readonly status: v.PicklistSchema<["pending", "selected", "cancelled", "timed_out"], undefined>;
117
+ readonly selection: v.ObjectSchema<{
118
+ readonly label: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxBytesAction<string, 64, undefined>, v.RegexAction<string, "Choice labels must not be blank">, v.CheckAction<string, "Choice labels must not contain control characters">]>;
119
+ readonly index: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>, v.MaxValueAction<number, 31, undefined>]>;
120
+ }, undefined>;
121
+ readonly reason: v.OptionalSchema<v.PicklistSchema<["client_cancelled", "session_ended", "panel_exit", "display_replaced"], undefined>, undefined>;
122
+ }, undefined>;
123
+ type PromptState = v.InferOutput<typeof promptState>;
124
+ type PromptStatus = PromptState['status'];
125
+ /** @hideconstructor */
126
+ declare class HmiApi {
127
+ private readonly fetch;
128
+ private readonly events;
129
+ constructor(fetch: UpFetch, events: EventsApi);
130
+ /**
131
+ * Resets the HMI.
132
+ */
133
+ reset(): Promise<void>;
134
+ /**
135
+ * Shows a single-choice prompt on the LCD and waits for the operator to answer.
136
+ *
137
+ * A choice may be a bare label string. `default_index` selects the initially
138
+ * highlighted choice and defaults to 0. Screen changes, resets, knob reads, and
139
+ * other prompts conflict while the prompt is pending.
140
+ *
141
+ * The wait rides the `hmi.prompt` event. Every event re-arms a
142
+ * `timeout_ms + 2000 ms` window, and a window that expires costs one read before
143
+ * the wait resumes: the device deadline stops as soon as the operator turns the
144
+ * knob, so a prompt somebody is answering is never abandoned locally.
145
+ *
146
+ * Cancellation and timeout are results. HTTP errors and local aborts reject the
147
+ * promise. On failure, cancellation is attempted without replacing the original
148
+ * error.
149
+ */
150
+ prompt(request: PromptRequestInput, options?: {
151
+ signal?: AbortSignal;
152
+ }): Promise<PromptState>;
153
+ private createPrompt;
154
+ private getPrompt;
155
+ private cancelPrompt;
156
+ /** Settles with `work`, or rejects as soon as `signal` aborts. */
157
+ private untilAborted;
158
+ /**
159
+ * Access the screen API.
160
+ * @returns The screen instance.
161
+ */
162
+ screen(): Screen;
163
+ /**
164
+ * Access the audio API.
165
+ * @returns The audio instance.
166
+ */
167
+ audio(): Audio;
168
+ /**
169
+ * Access the knob API.
170
+ * @returns The knob instance.
171
+ */
172
+ knob(): Knob;
173
+ }
174
+ /** @hideconstructor */
175
+ declare class Screen {
176
+ private readonly fetch;
177
+ constructor(fetch: UpFetch);
178
+ /**
179
+ * Prints text to the screen.
180
+ * @param data The text to print.
181
+ * @returns The printed text.
182
+ */
183
+ print(data: ScreenText): Promise<string>;
184
+ /**
185
+ * Sets the screen colors.
186
+ * @param colors The colors to set.
187
+ * @returns The updated colors.
188
+ */
189
+ colors(colors: Color): Promise<Color>;
190
+ /**
191
+ * Sets the screen progress.
192
+ * @param data The progress value to set.
193
+ * @returns The updated progress.
194
+ */
195
+ progress(data: ProgressValue): Promise<Progress>;
196
+ /**
197
+ * Clears the screen.
198
+ */
199
+ clear(): Promise<void>;
200
+ /**
201
+ * Clears the text on the screen.
202
+ */
203
+ clear_text(): Promise<void>;
204
+ }
205
+ /** @hideconstructor */
206
+ declare class Audio {
207
+ private readonly fetch;
208
+ constructor(fetch: UpFetch);
209
+ /**
210
+ * Plays a sound.
211
+ * @param config The configuration (sound_id, volume).
212
+ * @returns The play configuration.
213
+ */
214
+ play(config: PlaybackConfiguration): Promise<PlaybackConfiguration>;
215
+ }
216
+ /** @hideconstructor */
217
+ declare class Knob {
218
+ private readonly fetch;
219
+ constructor(fetch: UpFetch);
220
+ read_event: () => Promise<{
221
+ button_pressed: boolean;
222
+ button_held: boolean;
223
+ rotation_delta: number;
224
+ }>;
225
+ is_button_held: () => Promise<boolean>;
226
+ is_knob_turned: () => Promise<boolean>;
227
+ /**
228
+ * Waits for a knob event and returns it.
229
+ * @param timeout_ms The timeout in milliseconds.
230
+ * @returns The knob event or null if the timeout was reached.
231
+ */
232
+ wait_event(timeout_ms?: number): Promise<KnobEvent | null>;
233
+ }
234
+ //#endregion
235
+ export { text as S, color as _, KnobEvent as a, progress as b, ProgressValue as c, PromptRequestInput as d, PromptSelection as f, ScreenText as g, Screen as h, Knob as i, PromptChoice as l, PromptStatus as m, Color as n, PlaybackConfiguration as o, PromptState as p, HmiApi as r, Progress as s, Audio as t, PromptRequest as u, internalKnobEvent as v, promptState as x, playbackConfiguration as y };
236
+ //# sourceMappingURL=hmi-OyVDyqU-.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hmi-OyVDyqU-.d.cts","names":[],"sources":["../src/api/hmi.ts"],"mappings":";;;;cAKM,YAAU,EAAA,yBAAA,EAAA,yBAAA,EAAA;KACJ,aAAa,EAAE,mBAAmB;cAEjC,MAAI,EAAA;;;cAIJ,OAAK,EAAA;;;;;KAKN,QAAQ,EAAE,mBAAmB;cAEnC,eAAa,EAAA,yBAAA,EAAA,yBAAA,EAAA,sCAAA,EAAA;KACP,gBAAgB,EAAE,mBAAmB;cACpC,UAAQ,EAAA;;;KACT,WAAW,EAAE,mBAAmB;cAE/B,uBAAqB,EAAA;;;;KAOtB,wBAAwB,EAAE,mBAAmB;cAE5C,mBAAiB,EAAA;;;;;cAKxB,WAAS,KAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KACH,YAAY,EAAE,mBAAmB;cASvC,cAAY,EAAA;;;;KACN,eAAe,EAAE,mBAAmB;cAS1C,eAAa,EAAA,yBAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsBP,gBAAgB,EAAE,mBAAmB;;KAErC,qBAAqB,EAAE,kBAAkB;cAE/C,iBAAe,EAAA;;;;KACT,kBAAkB,EAAE,mBAAmB;;;;;;cAOtC,aAAW,EAAA;;;;;;;;;KAQZ,cAAc,EAAE,mBAAmB;KACnC,eAAe;;cAQd;mBACkB;mBAAiC;EAA9D,YAA6B,OAAO,SAA0B,QAAQ;;;;EAKtE,SAAS;;;;;;;;;;;;;;;;;EAoBH,OACJ,SAAS,oBACT;IAAY,SAAS;MACpB,QAAQ;UAoEH;UAQA;UAIA;;UAQM;;;;;EAkBd,UAAU;;;;;EAQV,SAAS;;;;;EAQT,QAAQ;;;cAMG;mBACkB;EAA7B,YAA6B,OAAO;;;;;;EAO9B,MAAM,MAAM,aAAa;;;;;;EAc/B,OAAO,QAAQ,QAAQ,QAAQ;;;;;;EAazB,SAAS,MAAM,gBAAgB,QAAQ;;;;EAkB7C,SAAS;;;;EAOT,cAAc;;;cAMH;mBACkB;EAA7B,YAA6B,OAAO;;;;;;EAO9B,KAAK,QAAQ,wBAAwB,QAAQ;;;cAUxC;mBACkB;EAA7B,YAA6B,OAAO;EAEpC,kBAAU;;;;;EAEV,sBAAc;EACd,sBAAc;;;;;;EAOR,WAAW,sBAAsB,QAAQ"}
package/build/hmi.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./rolldown-runtime-BocRIvOZ.cjs");let t=require("valibot");t=e.t(t,1);const n=t.pipe(t.string(),t.maxLength(1024)),r=t.object({text:n}),i=t.optional(t.pipe(t.string(),t.length(7),t.hexColor())),a=t.object({text:i,progress:i,background:i}),o=t.pipe(t.number(),t.minValue(0),t.maxValue(100)),s=t.object({progress:o}),c=t.object({sound_id:t.picklist([`success`,`warning`,`failure`,`notification_1`,`notification_2`,`imperial_march`]),volume:t.pipe(t.number(),t.minValue(0),t.maxValue(100))}),l=t.object({button_pressed:t.boolean(),button_held:t.boolean(),rotation_delta:t.number()});t.omit(l,[`button_held`]);var u=class{fetch;constructor(e){this.fetch=e}reset(){return this.fetch(`/hmi/reset`,{method:`POST`,parseResponse:()=>{}})}screen(){return new d(this.fetch)}audio(){return new f(this.fetch)}knob(){return new p(this.fetch)}},d=class{fetch;constructor(e){this.fetch=e}async print(e){return(await this.fetch(`/hmi/screen/text`,{method:`POST`,body:t.parse(r,{text:e}),schema:r})).text}colors(e){return this.fetch(`/hmi/screen/colors`,{method:`PATCH`,body:t.parse(a,e),schema:a})}async progress(e){return e==0?await this.fetch(`/hmi/screen/progress`,{method:`DELETE`,parseResponse:()=>({progress:0})}):this.fetch(`/hmi/screen/progress`,{method:`PUT`,body:t.parse(s,{progress:e}),schema:s})}clear(){return this.fetch(`/hmi/screen/clear`,{method:`POST`,parseResponse:()=>{}})}clear_text(){return this.fetch(`/hmi/screen/text`,{method:`DELETE`,parseResponse:()=>{}})}},f=class{fetch;constructor(e){this.fetch=e}async play(e){return this.fetch(`/hmi/speaker/play`,{method:`POST`,body:t.parse(c,e),schema:c})}},p=class{fetch;constructor(e){this.fetch=e}read_event=()=>this.fetch(`/hmi/knob/get_knob_event`,{schema:l});is_button_held=async()=>(await this.read_event()).button_held;is_knob_turned=async()=>Math.abs((await this.read_event()).rotation_delta)>=4;async wait_event(e){await this.read_event();let t=0,n=Math.min(50,(e??500)/10),r=Date.now();for(;e===void 0||Date.now()-r<e;){let e=await this.read_event();if(t+=e.rotation_delta,e.button_pressed||Math.abs(t)>=4)return{button_pressed:e.button_pressed,rotation_delta:Math.sign(t)};await new Promise(e=>setTimeout(e,n))}return null}};exports.Audio=f,exports.HmiApi=u,exports.Knob=p,exports.Screen=d,exports.color=a,exports.internalKnobEvent=l,exports.playbackConfiguration=c,exports.progress=s,exports.text=r;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./rolldown-runtime-BocRIvOZ.cjs");let t=require("valibot");t=e.t(t,1);const n=t.pipe(t.string(),t.maxLength(1024)),r=t.object({text:n}),i=t.optional(t.pipe(t.string(),t.length(7),t.hexColor())),a=t.object({text:i,progress:i,background:i}),o=t.pipe(t.number(),t.minValue(0),t.maxValue(100)),s=t.object({progress:o}),c=t.object({sound_id:t.picklist([`success`,`warning`,`failure`,`notification_1`,`notification_2`,`imperial_march`]),volume:t.pipe(t.number(),t.minValue(0),t.maxValue(100))}),l=t.object({button_pressed:t.boolean(),button_held:t.boolean(),rotation_delta:t.number()});t.omit(l,[`button_held`]);const u=t.pipe(t.string(),t.maxBytes(64),t.regex(/\S/u,`Choice labels must not be blank`),t.check(e=>!/\p{Cc}/u.test(e),`Choice labels must not contain control characters`)),d=t.pipe(t.number(),t.integer(),t.minValue(0),t.maxValue(31)),f=t.object({label:u,color:i}),p=t.pipe(t.union([u,f]),t.transform(e=>typeof e==`string`?{label:e}:e)),m=t.pipe(t.object({text:t.pipe(t.string(),t.maxBytes(256),t.regex(/\S/u,`Prompt text must not be blank`),t.check(e=>!/[^\P{Cc}\n]/u.test(e),`Prompt text permits line feeds but no other control characters`)),choices:t.pipe(t.array(p),t.minLength(1),t.maxLength(32)),default_index:t.optional(d),timeout_ms:t.optional(t.pipe(t.number(),t.integer(),t.minValue(1e3),t.maxValue(18e5)))}),t.check(e=>e.default_index===void 0||e.default_index<e.choices.length,`default_index must be below the number of choices`)),h=t.object({label:u,index:d}),g=t.object({id:t.pipe(t.string(),t.minLength(1)),status:t.picklist([`pending`,`selected`,`cancelled`,`timed_out`]),selection:h,reason:t.optional(t.picklist([`client_cancelled`,`session_ended`,`panel_exit`,`display_replaced`]))});var _=class{fetch;events;constructor(e,t){this.fetch=e,this.events=t}reset(){return this.fetch(`/hmi/reset`,{method:`POST`,parseResponse:()=>{}})}async prompt(e,t){let n=t?.signal;n?.throwIfAborted();let r=(e.timeout_ms??6e4)+2e3,i,a,o=!1;try{let t=await this.createPrompt(e);i=t.id,n?.throwIfAborted();let s=[],c;a=this.events.on(`hmi.prompt`,e=>{e.data.id===t.id&&(s.push(e.data),c?.())}),o=!this.events.connected,await this.events.connect();let l=async()=>{if(s.length===0){let{promise:e,resolve:t}=Promise.withResolvers(),i=setTimeout(t,r);c=t;try{await this.untilAborted(e,n)}finally{clearTimeout(i),c=void 0}}return s.shift()},u=await this.untilAborted(this.getPrompt(t.id),n);for(;u.status===`pending`;)u=await l()??await this.untilAborted(this.getPrompt(t.id),n);return u}catch(e){if(i!==void 0)try{await this.cancelPrompt(i)}catch{}throw e}finally{a?.(),o&&this.events.close()}}createPrompt(e){return this.fetch(`/hmi/prompts`,{method:`POST`,body:t.parse(m,e),schema:g})}getPrompt(e){return this.fetch(`/hmi/prompts/${encodeURIComponent(e)}`,{schema:g})}cancelPrompt(e){return this.fetch(`/hmi/prompts/${encodeURIComponent(e)}`,{method:`DELETE`,schema:g})}async untilAborted(e,t){if(!t)return await e;let n;try{let r=new Promise((e,r)=>{n=()=>r(t.reason),t.addEventListener(`abort`,n,{once:!0})});return await Promise.race([e,r])}finally{n&&t.removeEventListener(`abort`,n)}}screen(){return new v(this.fetch)}audio(){return new y(this.fetch)}knob(){return new b(this.fetch)}},v=class{fetch;constructor(e){this.fetch=e}async print(e){return(await this.fetch(`/hmi/screen/text`,{method:`POST`,body:t.parse(r,{text:e}),schema:r})).text}colors(e){return this.fetch(`/hmi/screen/colors`,{method:`PATCH`,body:t.parse(a,e),schema:a})}async progress(e){return e==0?await this.fetch(`/hmi/screen/progress`,{method:`DELETE`,parseResponse:()=>({progress:0})}):this.fetch(`/hmi/screen/progress`,{method:`PUT`,body:t.parse(s,{progress:e}),schema:s})}clear(){return this.fetch(`/hmi/screen/clear`,{method:`POST`,parseResponse:()=>{}})}clear_text(){return this.fetch(`/hmi/screen/text`,{method:`DELETE`,parseResponse:()=>{}})}},y=class{fetch;constructor(e){this.fetch=e}async play(e){return this.fetch(`/hmi/speaker/play`,{method:`POST`,body:t.parse(c,e),schema:c})}},b=class{fetch;constructor(e){this.fetch=e}read_event=()=>this.fetch(`/hmi/knob/get_knob_event`,{schema:l});is_button_held=async()=>(await this.read_event()).button_held;is_knob_turned=async()=>Math.abs((await this.read_event()).rotation_delta)>=4;async wait_event(e){await this.read_event();let t=0,n=Math.min(50,(e??500)/10),r=Date.now();for(;e===void 0||Date.now()-r<e;){let e=await this.read_event();if(t+=e.rotation_delta,e.button_pressed||Math.abs(t)>=4)return{button_pressed:e.button_pressed,rotation_delta:Math.sign(t)};await new Promise(e=>setTimeout(e,n))}return null}};exports.Audio=y,exports.HmiApi=_,exports.Knob=b,exports.Screen=v,exports.color=a,exports.internalKnobEvent=l,exports.playbackConfiguration=c,exports.progress=s,exports.promptState=g,exports.text=r;
2
2
  //# sourceMappingURL=hmi.cjs.map
package/build/hmi.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"hmi.cjs","names":["v"],"sources":["../src/api/hmi.ts"],"sourcesContent":["import type { UpFetch } from 'up-fetch';\nimport * as v from 'valibot';\n\nconst screenText = v.pipe(v.string(), v.maxLength(1024));\nexport type ScreenText = v.InferOutput<typeof screenText>;\n\nexport const text = v.object({ text: screenText });\ntype Text = v.InferOutput<typeof text>;\n\nconst optionalHexColor = v.optional(v.pipe(v.string(), v.length(7), v.hexColor()));\nexport const color = v.object({\n text: optionalHexColor,\n progress: optionalHexColor,\n background: optionalHexColor,\n});\nexport type Color = v.InferOutput<typeof color>;\n\nconst progressValue = v.pipe(v.number(), v.minValue(0), v.maxValue(100));\nexport type ProgressValue = v.InferOutput<typeof progressValue>;\nexport const progress = v.object({ progress: progressValue });\nexport type Progress = v.InferOutput<typeof progress>;\n\nexport const playbackConfiguration = v.object({\n sound_id: v.picklist(\n ['success', 'warning', 'failure', 'notification_1', 'notification_2',\n 'imperial_march'] as const,\n ),\n volume: v.pipe(v.number(), v.minValue(0), v.maxValue(100)),\n});\nexport type PlaybackConfiguration = v.InferOutput<typeof playbackConfiguration>;\n\nexport const internalKnobEvent = v.object({\n button_pressed: v.boolean(),\n button_held: v.boolean(),\n rotation_delta: v.number(),\n});\nconst knobEvent = v.omit(internalKnobEvent, ['button_held']);\nexport type KnobEvent = v.InferOutput<typeof knobEvent>;\n\n/** @hideconstructor */\nexport class HmiApi {\n constructor(private readonly fetch: UpFetch) {}\n\n /**\n * Resets the HMI.\n */\n reset(): Promise<void> {\n return this.fetch('/hmi/reset', { method: 'POST', parseResponse: () => {} });\n }\n\n /**\n * Access the screen API.\n * @returns The screen instance.\n */\n screen(): Screen {\n return new Screen(this.fetch);\n }\n\n /**\n * Access the audio API.\n * @returns The audio instance.\n */\n audio(): Audio {\n return new Audio(this.fetch);\n }\n\n /**\n * Access the knob API.\n * @returns The knob instance.\n */\n knob(): Knob {\n return new Knob(this.fetch);\n }\n}\n\n/** @hideconstructor */\nexport class Screen {\n constructor(private readonly fetch: UpFetch) {}\n\n /**\n * Prints text to the screen.\n * @param data The text to print.\n * @returns The printed text.\n */\n async print(data: ScreenText): Promise<string> {\n return (await this.fetch('/hmi/screen/text', {\n method: 'POST',\n body: v.parse(text, { text: data } satisfies Text),\n schema: text,\n }))\n .text;\n }\n\n /**\n * Sets the screen colors.\n * @param colors The colors to set.\n * @returns The updated colors.\n */\n colors(colors: Color): Promise<Color> {\n return this.fetch('/hmi/screen/colors', {\n method: 'PATCH',\n body: v.parse(color, colors satisfies Color),\n schema: color,\n });\n }\n\n /**\n * Sets the screen progress.\n * @param data The progress value to set.\n * @returns The updated progress.\n */\n async progress(data: ProgressValue): Promise<Progress> {\n if (data == 0) {\n return await this.fetch('/hmi/screen/progress', {\n method: 'DELETE',\n parseResponse: () => ({ progress: 0 }),\n });\n }\n\n return this.fetch('/hmi/screen/progress', {\n method: 'PUT',\n body: v.parse(progress, { progress: data } satisfies Progress),\n schema: progress,\n });\n }\n\n /**\n * Clears the screen.\n */\n clear(): Promise<void> {\n return this.fetch('/hmi/screen/clear', { method: 'POST', parseResponse: () => {} });\n }\n\n /**\n * Clears the text on the screen.\n */\n clear_text(): Promise<void> {\n return this.fetch('/hmi/screen/text', { method: 'DELETE', parseResponse: () => {} });\n }\n}\n\n/** @hideconstructor */\nexport class Audio {\n constructor(private readonly fetch: UpFetch) {}\n\n /**\n * Plays a sound.\n * @param config The configuration (sound_id, volume).\n * @returns The play configuration.\n */\n async play(config: PlaybackConfiguration): Promise<PlaybackConfiguration> {\n return this.fetch('/hmi/speaker/play', {\n method: 'POST',\n body: v.parse(playbackConfiguration, config),\n schema: playbackConfiguration,\n });\n }\n}\n\n/** @hideconstructor */\nexport class Knob {\n constructor(private readonly fetch: UpFetch) {}\n\n read_event = () => this.fetch('/hmi/knob/get_knob_event', { schema: internalKnobEvent });\n\n is_button_held = async () => (await this.read_event()).button_held;\n is_knob_turned = async () => Math.abs((await this.read_event()).rotation_delta) >= 4;\n\n /**\n * Waits for a knob event and returns it.\n * @param timeout_ms The timeout in milliseconds.\n * @returns The knob event or null if the timeout was reached.\n */\n async wait_event(timeout_ms?: number): Promise<KnobEvent | null> {\n await this.read_event(); // Discard any previous events\n let delta = 0;\n\n const interval = Math.min(50, (timeout_ms ?? 500) / 10);\n\n const startTime = Date.now();\n while (timeout_ms !== undefined ? Date.now() - startTime < timeout_ms : true) {\n const knobEvent = await this.read_event();\n delta += knobEvent.rotation_delta;\n\n if (knobEvent.button_pressed || Math.abs(delta) >= 4) {\n return { button_pressed: knobEvent.button_pressed, rotation_delta: Math.sign(delta) };\n }\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n\n return null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"hmi.cjs","names":["v"],"sources":["../src/api/hmi.ts"],"sourcesContent":["import type { UpFetch } from 'up-fetch';\nimport * as v from 'valibot';\n\nimport type { EventsApi } from './events';\n\nconst screenText = v.pipe(v.string(), v.maxLength(1024));\nexport type ScreenText = v.InferOutput<typeof screenText>;\n\nexport const text = v.object({ text: screenText });\ntype Text = v.InferOutput<typeof text>;\n\nconst optionalHexColor = v.optional(v.pipe(v.string(), v.length(7), v.hexColor()));\nexport const color = v.object({\n text: optionalHexColor,\n progress: optionalHexColor,\n background: optionalHexColor,\n});\nexport type Color = v.InferOutput<typeof color>;\n\nconst progressValue = v.pipe(v.number(), v.minValue(0), v.maxValue(100));\nexport type ProgressValue = v.InferOutput<typeof progressValue>;\nexport const progress = v.object({ progress: progressValue });\nexport type Progress = v.InferOutput<typeof progress>;\n\nexport const playbackConfiguration = v.object({\n sound_id: v.picklist(\n ['success', 'warning', 'failure', 'notification_1', 'notification_2',\n 'imperial_march'] as const,\n ),\n volume: v.pipe(v.number(), v.minValue(0), v.maxValue(100)),\n});\nexport type PlaybackConfiguration = v.InferOutput<typeof playbackConfiguration>;\n\nexport const internalKnobEvent = v.object({\n button_pressed: v.boolean(),\n button_held: v.boolean(),\n rotation_delta: v.number(),\n});\nconst knobEvent = v.omit(internalKnobEvent, ['button_held']);\nexport type KnobEvent = v.InferOutput<typeof knobEvent>;\n\nconst promptLabel = v.pipe(\n v.string(),\n v.maxBytes(64),\n v.regex(/\\S/u, 'Choice labels must not be blank'),\n v.check((value) => !/\\p{Cc}/u.test(value), 'Choice labels must not contain control characters'),\n);\nconst promptIndex = v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(31));\nconst promptChoice = v.object({ label: promptLabel, color: optionalHexColor });\nexport type PromptChoice = v.InferOutput<typeof promptChoice>;\n\n// A choice may be written as a bare label. Position identifies a choice, so two\n// choices may carry the same label.\nconst promptChoiceInput = v.pipe(\n v.union([promptLabel, promptChoice]),\n v.transform((choice): PromptChoice => (typeof choice === 'string' ? { label: choice } : choice)),\n);\n\nconst promptRequest = v.pipe(\n v.object({\n text: v.pipe(\n v.string(),\n v.maxBytes(256),\n v.regex(/\\S/u, 'Prompt text must not be blank'),\n v.check(\n (value) => !/[^\\P{Cc}\\n]/u.test(value),\n 'Prompt text permits line feeds but no other control characters',\n ),\n ),\n choices: v.pipe(v.array(promptChoiceInput), v.minLength(1), v.maxLength(32)),\n default_index: v.optional(promptIndex),\n timeout_ms: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1000), v.maxValue(1800000))),\n }),\n v.check(\n (request) =>\n request.default_index === undefined || request.default_index < request.choices.length,\n 'default_index must be below the number of choices',\n ),\n);\n/** Wire shape, where every choice is an object. */\nexport type PromptRequest = v.InferOutput<typeof promptRequest>;\n/** Accepted shape, where a choice may be a bare label string. */\nexport type PromptRequestInput = v.InferInput<typeof promptRequest>;\n\nconst promptSelection = v.object({ label: promptLabel, index: promptIndex });\nexport type PromptSelection = v.InferOutput<typeof promptSelection>;\n\n/**\n * `selection` is always present: the choice under the knob while pending, the\n * confirmed choice when selected, and the last highlighted choice when the prompt\n * was cancelled or timed out.\n */\nexport const promptState = v.object({\n id: v.pipe(v.string(), v.minLength(1)),\n status: v.picklist(['pending', 'selected', 'cancelled', 'timed_out']),\n selection: promptSelection,\n reason: v.optional(\n v.picklist(['client_cancelled', 'session_ended', 'panel_exit', 'display_replaced']),\n ),\n});\nexport type PromptState = v.InferOutput<typeof promptState>;\nexport type PromptStatus = PromptState['status'];\n\n// The device deadline applied when `timeout_ms` is omitted, and the slack the local\n// event window adds on top of it.\nconst defaultPromptTimeoutMs = 60_000;\nconst promptEventGraceMs = 2_000;\n\n/** @hideconstructor */\nexport class HmiApi {\n constructor(private readonly fetch: UpFetch, private readonly events: EventsApi) {}\n\n /**\n * Resets the HMI.\n */\n reset(): Promise<void> {\n return this.fetch('/hmi/reset', { method: 'POST', parseResponse: () => {} });\n }\n\n /**\n * Shows a single-choice prompt on the LCD and waits for the operator to answer.\n *\n * A choice may be a bare label string. `default_index` selects the initially\n * highlighted choice and defaults to 0. Screen changes, resets, knob reads, and\n * other prompts conflict while the prompt is pending.\n *\n * The wait rides the `hmi.prompt` event. Every event re-arms a\n * `timeout_ms + 2000 ms` window, and a window that expires costs one read before\n * the wait resumes: the device deadline stops as soon as the operator turns the\n * knob, so a prompt somebody is answering is never abandoned locally.\n *\n * Cancellation and timeout are results. HTTP errors and local aborts reject the\n * promise. On failure, cancellation is attempted without replacing the original\n * error.\n */\n async prompt(\n request: PromptRequestInput,\n options?: { signal?: AbortSignal },\n ): Promise<PromptState> {\n const signal = options?.signal;\n signal?.throwIfAborted();\n const windowMs = (request.timeout_ms ?? defaultPromptTimeoutMs) + promptEventGraceMs;\n\n let id: string | undefined;\n let unsubscribe: (() => void) | undefined;\n let openedEvents = false;\n try {\n // Do not abort creation: its response supplies the ID needed for cancellation.\n const created = await this.createPrompt(request);\n id = created.id;\n signal?.throwIfAborted();\n\n // Subscribing after creation cannot lose anything, because the read below\n // covers the gap. That is cheaper than ordering the socket before the POST.\n const inbox: PromptState[] = [];\n let wake: (() => void) | undefined;\n unsubscribe = this.events.on('hmi.prompt', (event) => {\n if (event.data.id !== created.id) return;\n inbox.push(event.data);\n wake?.();\n });\n openedEvents = !this.events.connected;\n await this.events.connect();\n\n // Resolves the next state for this prompt, or undefined once the window expires.\n // The inbox, not the resolution value, carries the events, so a second event\n // arriving before the waiter resumes cannot be dropped.\n const nextEvent = async (): Promise<PromptState | undefined> => {\n if (inbox.length === 0) {\n const { promise, resolve } = Promise.withResolvers<void>();\n const timer = setTimeout(resolve, windowMs);\n wake = resolve;\n try {\n await this.untilAborted(promise, signal);\n } finally {\n clearTimeout(timer);\n wake = undefined;\n }\n }\n return inbox.shift();\n };\n\n let state = await this.untilAborted(this.getPrompt(created.id), signal);\n while (state.status === 'pending') {\n // An empty window means a stalled or reconnecting socket, never a reason to\n // cancel: read once, then wait again.\n const delivered = await nextEvent();\n state = delivered ?? await this.untilAborted(this.getPrompt(created.id), signal);\n }\n return state;\n } catch (error) {\n if (id !== undefined) {\n try {\n await this.cancelPrompt(id);\n } catch {\n // The server deadline still applies if cancellation cannot reach the device.\n }\n }\n throw error;\n } finally {\n unsubscribe?.();\n // A socket the application opened stays open; it may still be listening.\n if (openedEvents) this.events.close();\n }\n }\n\n private createPrompt(request: PromptRequestInput): Promise<PromptState> {\n return this.fetch('/hmi/prompts', {\n method: 'POST',\n body: v.parse(promptRequest, request),\n schema: promptState,\n });\n }\n\n private getPrompt(id: string): Promise<PromptState> {\n return this.fetch(`/hmi/prompts/${encodeURIComponent(id)}`, { schema: promptState });\n }\n\n private cancelPrompt(id: string): Promise<PromptState> {\n return this.fetch(`/hmi/prompts/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n schema: promptState,\n });\n }\n\n /** Settles with `work`, or rejects as soon as `signal` aborts. */\n private async untilAborted<T>(work: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return await work;\n let onAbort: (() => void) | undefined;\n try {\n const aborted = new Promise<never>((_, reject) => {\n onAbort = () => reject(signal.reason);\n signal.addEventListener('abort', onAbort, { once: true });\n });\n return await Promise.race([work, aborted]);\n } finally {\n if (onAbort) signal.removeEventListener('abort', onAbort);\n }\n }\n\n /**\n * Access the screen API.\n * @returns The screen instance.\n */\n screen(): Screen {\n return new Screen(this.fetch);\n }\n\n /**\n * Access the audio API.\n * @returns The audio instance.\n */\n audio(): Audio {\n return new Audio(this.fetch);\n }\n\n /**\n * Access the knob API.\n * @returns The knob instance.\n */\n knob(): Knob {\n return new Knob(this.fetch);\n }\n}\n\n/** @hideconstructor */\nexport class Screen {\n constructor(private readonly fetch: UpFetch) {}\n\n /**\n * Prints text to the screen.\n * @param data The text to print.\n * @returns The printed text.\n */\n async print(data: ScreenText): Promise<string> {\n return (await this.fetch('/hmi/screen/text', {\n method: 'POST',\n body: v.parse(text, { text: data } satisfies Text),\n schema: text,\n }))\n .text;\n }\n\n /**\n * Sets the screen colors.\n * @param colors The colors to set.\n * @returns The updated colors.\n */\n colors(colors: Color): Promise<Color> {\n return this.fetch('/hmi/screen/colors', {\n method: 'PATCH',\n body: v.parse(color, colors satisfies Color),\n schema: color,\n });\n }\n\n /**\n * Sets the screen progress.\n * @param data The progress value to set.\n * @returns The updated progress.\n */\n async progress(data: ProgressValue): Promise<Progress> {\n if (data == 0) {\n return await this.fetch('/hmi/screen/progress', {\n method: 'DELETE',\n parseResponse: () => ({ progress: 0 }),\n });\n }\n\n return this.fetch('/hmi/screen/progress', {\n method: 'PUT',\n body: v.parse(progress, { progress: data } satisfies Progress),\n schema: progress,\n });\n }\n\n /**\n * Clears the screen.\n */\n clear(): Promise<void> {\n return this.fetch('/hmi/screen/clear', { method: 'POST', parseResponse: () => {} });\n }\n\n /**\n * Clears the text on the screen.\n */\n clear_text(): Promise<void> {\n return this.fetch('/hmi/screen/text', { method: 'DELETE', parseResponse: () => {} });\n }\n}\n\n/** @hideconstructor */\nexport class Audio {\n constructor(private readonly fetch: UpFetch) {}\n\n /**\n * Plays a sound.\n * @param config The configuration (sound_id, volume).\n * @returns The play configuration.\n */\n async play(config: PlaybackConfiguration): Promise<PlaybackConfiguration> {\n return this.fetch('/hmi/speaker/play', {\n method: 'POST',\n body: v.parse(playbackConfiguration, config),\n schema: playbackConfiguration,\n });\n }\n}\n\n/** @hideconstructor */\nexport class Knob {\n constructor(private readonly fetch: UpFetch) {}\n\n read_event = () => this.fetch('/hmi/knob/get_knob_event', { schema: internalKnobEvent });\n\n is_button_held = async () => (await this.read_event()).button_held;\n is_knob_turned = async () => Math.abs((await this.read_event()).rotation_delta) >= 4;\n\n /**\n * Waits for a knob event and returns it.\n * @param timeout_ms The timeout in milliseconds.\n * @returns The knob event or null if the timeout was reached.\n */\n async wait_event(timeout_ms?: number): Promise<KnobEvent | null> {\n await this.read_event(); // Discard any previous events\n let delta = 0;\n\n const interval = Math.min(50, (timeout_ms ?? 500) / 10);\n\n const startTime = Date.now();\n while (timeout_ms !== undefined ? Date.now() - startTime < timeout_ms : true) {\n const knobEvent = await this.read_event();\n delta += knobEvent.rotation_delta;\n\n if (knobEvent.button_pressed || Math.abs(delta) >= 4) {\n return { button_pressed: knobEvent.button_pressed, rotation_delta: Math.sign(delta) };\n }\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n\n return null;\n }\n}\n"],"mappings":"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"}
package/build/hmi.d.cts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as KnobEvent, c as ProgressValue, d as color, f as internalKnobEvent, h as text, i as Knob, l as Screen, m as progress, n as Color, o as PlaybackConfiguration, p as playbackConfiguration, r as HmiApi, s as Progress, t as Audio, u as ScreenText } from "./hmi-BEMiVKDF.cjs";
2
- export { Audio, Color, HmiApi, Knob, KnobEvent, PlaybackConfiguration, Progress, ProgressValue, Screen, ScreenText, color, internalKnobEvent, playbackConfiguration, progress, text };
1
+ import { S as text, _ as color, a as KnobEvent, b as progress, c as ProgressValue, d as PromptRequestInput, f as PromptSelection, g as ScreenText, h as Screen, i as Knob, l as PromptChoice, m as PromptStatus, n as Color, o as PlaybackConfiguration, p as PromptState, r as HmiApi, s as Progress, t as Audio, u as PromptRequest, v as internalKnobEvent, x as promptState, y as playbackConfiguration } from "./hmi-OyVDyqU-.cjs";
2
+ export { Audio, Color, HmiApi, Knob, KnobEvent, PlaybackConfiguration, Progress, ProgressValue, PromptChoice, PromptRequest, PromptRequestInput, PromptSelection, PromptState, PromptStatus, Screen, ScreenText, color, internalKnobEvent, playbackConfiguration, progress, promptState, text };
package/build/hmi.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as KnobEvent, c as ProgressValue, d as color, f as internalKnobEvent, h as text, i as Knob, l as Screen, m as progress, n as Color, o as PlaybackConfiguration, p as playbackConfiguration, r as HmiApi, s as Progress, t as Audio, u as ScreenText } from "./hmi-BEMiVKDF.mjs";
2
- export { Audio, Color, HmiApi, Knob, KnobEvent, PlaybackConfiguration, Progress, ProgressValue, Screen, ScreenText, color, internalKnobEvent, playbackConfiguration, progress, text };
1
+ import { S as text, _ as color, a as KnobEvent, b as progress, c as ProgressValue, d as PromptRequestInput, f as PromptSelection, g as ScreenText, h as Screen, i as Knob, l as PromptChoice, m as PromptStatus, n as Color, o as PlaybackConfiguration, p as PromptState, r as HmiApi, s as Progress, t as Audio, u as PromptRequest, v as internalKnobEvent, x as promptState, y as playbackConfiguration } from "./hmi-Chid1Vvo.mjs";
2
+ export { Audio, Color, HmiApi, Knob, KnobEvent, PlaybackConfiguration, Progress, ProgressValue, PromptChoice, PromptRequest, PromptRequestInput, PromptSelection, PromptState, PromptStatus, Screen, ScreenText, color, internalKnobEvent, playbackConfiguration, progress, promptState, text };
package/build/hmi.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import*as e from"valibot";const t=e.pipe(e.string(),e.maxLength(1024)),n=e.object({text:t}),r=e.optional(e.pipe(e.string(),e.length(7),e.hexColor())),i=e.object({text:r,progress:r,background:r}),a=e.pipe(e.number(),e.minValue(0),e.maxValue(100)),o=e.object({progress:a}),s=e.object({sound_id:e.picklist([`success`,`warning`,`failure`,`notification_1`,`notification_2`,`imperial_march`]),volume:e.pipe(e.number(),e.minValue(0),e.maxValue(100))}),c=e.object({button_pressed:e.boolean(),button_held:e.boolean(),rotation_delta:e.number()});e.omit(c,[`button_held`]);var l=class{fetch;constructor(e){this.fetch=e}reset(){return this.fetch(`/hmi/reset`,{method:`POST`,parseResponse:()=>{}})}screen(){return new u(this.fetch)}audio(){return new d(this.fetch)}knob(){return new f(this.fetch)}},u=class{fetch;constructor(e){this.fetch=e}async print(t){return(await this.fetch(`/hmi/screen/text`,{method:`POST`,body:e.parse(n,{text:t}),schema:n})).text}colors(t){return this.fetch(`/hmi/screen/colors`,{method:`PATCH`,body:e.parse(i,t),schema:i})}async progress(t){return t==0?await this.fetch(`/hmi/screen/progress`,{method:`DELETE`,parseResponse:()=>({progress:0})}):this.fetch(`/hmi/screen/progress`,{method:`PUT`,body:e.parse(o,{progress:t}),schema:o})}clear(){return this.fetch(`/hmi/screen/clear`,{method:`POST`,parseResponse:()=>{}})}clear_text(){return this.fetch(`/hmi/screen/text`,{method:`DELETE`,parseResponse:()=>{}})}},d=class{fetch;constructor(e){this.fetch=e}async play(t){return this.fetch(`/hmi/speaker/play`,{method:`POST`,body:e.parse(s,t),schema:s})}},f=class{fetch;constructor(e){this.fetch=e}read_event=()=>this.fetch(`/hmi/knob/get_knob_event`,{schema:c});is_button_held=async()=>(await this.read_event()).button_held;is_knob_turned=async()=>Math.abs((await this.read_event()).rotation_delta)>=4;async wait_event(e){await this.read_event();let t=0,n=Math.min(50,(e??500)/10),r=Date.now();for(;e===void 0||Date.now()-r<e;){let e=await this.read_event();if(t+=e.rotation_delta,e.button_pressed||Math.abs(t)>=4)return{button_pressed:e.button_pressed,rotation_delta:Math.sign(t)};await new Promise(e=>setTimeout(e,n))}return null}};export{d as Audio,l as HmiApi,f as Knob,u as Screen,i as color,c as internalKnobEvent,s as playbackConfiguration,o as progress,n as text};
1
+ import*as e from"valibot";const t=e.pipe(e.string(),e.maxLength(1024)),n=e.object({text:t}),r=e.optional(e.pipe(e.string(),e.length(7),e.hexColor())),i=e.object({text:r,progress:r,background:r}),a=e.pipe(e.number(),e.minValue(0),e.maxValue(100)),o=e.object({progress:a}),s=e.object({sound_id:e.picklist([`success`,`warning`,`failure`,`notification_1`,`notification_2`,`imperial_march`]),volume:e.pipe(e.number(),e.minValue(0),e.maxValue(100))}),c=e.object({button_pressed:e.boolean(),button_held:e.boolean(),rotation_delta:e.number()});e.omit(c,[`button_held`]);const l=e.pipe(e.string(),e.maxBytes(64),e.regex(/\S/u,`Choice labels must not be blank`),e.check(e=>!/\p{Cc}/u.test(e),`Choice labels must not contain control characters`)),u=e.pipe(e.number(),e.integer(),e.minValue(0),e.maxValue(31)),d=e.object({label:l,color:r}),f=e.pipe(e.union([l,d]),e.transform(e=>typeof e==`string`?{label:e}:e)),p=e.pipe(e.object({text:e.pipe(e.string(),e.maxBytes(256),e.regex(/\S/u,`Prompt text must not be blank`),e.check(e=>!/[^\P{Cc}\n]/u.test(e),`Prompt text permits line feeds but no other control characters`)),choices:e.pipe(e.array(f),e.minLength(1),e.maxLength(32)),default_index:e.optional(u),timeout_ms:e.optional(e.pipe(e.number(),e.integer(),e.minValue(1e3),e.maxValue(18e5)))}),e.check(e=>e.default_index===void 0||e.default_index<e.choices.length,`default_index must be below the number of choices`)),m=e.object({label:l,index:u}),h=e.object({id:e.pipe(e.string(),e.minLength(1)),status:e.picklist([`pending`,`selected`,`cancelled`,`timed_out`]),selection:m,reason:e.optional(e.picklist([`client_cancelled`,`session_ended`,`panel_exit`,`display_replaced`]))});var g=class{fetch;events;constructor(e,t){this.fetch=e,this.events=t}reset(){return this.fetch(`/hmi/reset`,{method:`POST`,parseResponse:()=>{}})}async prompt(e,t){let n=t?.signal;n?.throwIfAborted();let r=(e.timeout_ms??6e4)+2e3,i,a,o=!1;try{let t=await this.createPrompt(e);i=t.id,n?.throwIfAborted();let s=[],c;a=this.events.on(`hmi.prompt`,e=>{e.data.id===t.id&&(s.push(e.data),c?.())}),o=!this.events.connected,await this.events.connect();let l=async()=>{if(s.length===0){let{promise:e,resolve:t}=Promise.withResolvers(),i=setTimeout(t,r);c=t;try{await this.untilAborted(e,n)}finally{clearTimeout(i),c=void 0}}return s.shift()},u=await this.untilAborted(this.getPrompt(t.id),n);for(;u.status===`pending`;)u=await l()??await this.untilAborted(this.getPrompt(t.id),n);return u}catch(e){if(i!==void 0)try{await this.cancelPrompt(i)}catch{}throw e}finally{a?.(),o&&this.events.close()}}createPrompt(t){return this.fetch(`/hmi/prompts`,{method:`POST`,body:e.parse(p,t),schema:h})}getPrompt(e){return this.fetch(`/hmi/prompts/${encodeURIComponent(e)}`,{schema:h})}cancelPrompt(e){return this.fetch(`/hmi/prompts/${encodeURIComponent(e)}`,{method:`DELETE`,schema:h})}async untilAborted(e,t){if(!t)return await e;let n;try{let r=new Promise((e,r)=>{n=()=>r(t.reason),t.addEventListener(`abort`,n,{once:!0})});return await Promise.race([e,r])}finally{n&&t.removeEventListener(`abort`,n)}}screen(){return new _(this.fetch)}audio(){return new v(this.fetch)}knob(){return new y(this.fetch)}},_=class{fetch;constructor(e){this.fetch=e}async print(t){return(await this.fetch(`/hmi/screen/text`,{method:`POST`,body:e.parse(n,{text:t}),schema:n})).text}colors(t){return this.fetch(`/hmi/screen/colors`,{method:`PATCH`,body:e.parse(i,t),schema:i})}async progress(t){return t==0?await this.fetch(`/hmi/screen/progress`,{method:`DELETE`,parseResponse:()=>({progress:0})}):this.fetch(`/hmi/screen/progress`,{method:`PUT`,body:e.parse(o,{progress:t}),schema:o})}clear(){return this.fetch(`/hmi/screen/clear`,{method:`POST`,parseResponse:()=>{}})}clear_text(){return this.fetch(`/hmi/screen/text`,{method:`DELETE`,parseResponse:()=>{}})}},v=class{fetch;constructor(e){this.fetch=e}async play(t){return this.fetch(`/hmi/speaker/play`,{method:`POST`,body:e.parse(s,t),schema:s})}},y=class{fetch;constructor(e){this.fetch=e}read_event=()=>this.fetch(`/hmi/knob/get_knob_event`,{schema:c});is_button_held=async()=>(await this.read_event()).button_held;is_knob_turned=async()=>Math.abs((await this.read_event()).rotation_delta)>=4;async wait_event(e){await this.read_event();let t=0,n=Math.min(50,(e??500)/10),r=Date.now();for(;e===void 0||Date.now()-r<e;){let e=await this.read_event();if(t+=e.rotation_delta,e.button_pressed||Math.abs(t)>=4)return{button_pressed:e.button_pressed,rotation_delta:Math.sign(t)};await new Promise(e=>setTimeout(e,n))}return null}};export{v as Audio,g as HmiApi,y as Knob,_ as Screen,i as color,c as internalKnobEvent,s as playbackConfiguration,o as progress,h as promptState,n as text};
2
2
  //# sourceMappingURL=hmi.mjs.map