@enyo-energy/energy-app-sdk 1.6.0 → 1.8.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 (39) hide show
  1. package/dist/cjs/energy-app-package-definition.d.cts +12 -0
  2. package/dist/cjs/implementations/onboarding-v2/define-onboarding-guide-v2.cjs +90 -0
  3. package/dist/cjs/implementations/onboarding-v2/define-onboarding-guide-v2.d.cts +78 -1
  4. package/dist/cjs/implementations/onboarding-v2/onboarding-v2-validators.cjs +119 -0
  5. package/dist/cjs/index.cjs +2 -0
  6. package/dist/cjs/index.d.cts +2 -0
  7. package/dist/cjs/packages/energy-app-interval.d.cts +1 -1
  8. package/dist/cjs/packages/energy-app-onboarding-v2.d.cts +54 -0
  9. package/dist/cjs/types/enyo-appliance.cjs +9 -1
  10. package/dist/cjs/types/enyo-appliance.d.cts +11 -3
  11. package/dist/cjs/types/enyo-data-bus-value.d.cts +2 -1
  12. package/dist/cjs/types/enyo-onboarding-v2-device-select.cjs +29 -0
  13. package/dist/cjs/types/enyo-onboarding-v2-device-select.d.cts +105 -0
  14. package/dist/cjs/types/enyo-onboarding-v2-validation.cjs +29 -0
  15. package/dist/cjs/types/enyo-onboarding-v2-validation.d.cts +108 -0
  16. package/dist/cjs/types/enyo-onboarding-v2.cjs +66 -1
  17. package/dist/cjs/types/enyo-onboarding-v2.d.cts +190 -7
  18. package/dist/cjs/version.cjs +1 -1
  19. package/dist/cjs/version.d.cts +1 -1
  20. package/dist/energy-app-package-definition.d.ts +12 -0
  21. package/dist/implementations/onboarding-v2/define-onboarding-guide-v2.d.ts +78 -1
  22. package/dist/implementations/onboarding-v2/define-onboarding-guide-v2.js +90 -0
  23. package/dist/implementations/onboarding-v2/onboarding-v2-validators.js +120 -1
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.js +2 -0
  26. package/dist/packages/energy-app-interval.d.ts +1 -1
  27. package/dist/packages/energy-app-onboarding-v2.d.ts +54 -0
  28. package/dist/types/enyo-appliance.d.ts +11 -3
  29. package/dist/types/enyo-appliance.js +9 -1
  30. package/dist/types/enyo-data-bus-value.d.ts +2 -1
  31. package/dist/types/enyo-onboarding-v2-device-select.d.ts +105 -0
  32. package/dist/types/enyo-onboarding-v2-device-select.js +28 -0
  33. package/dist/types/enyo-onboarding-v2-validation.d.ts +108 -0
  34. package/dist/types/enyo-onboarding-v2-validation.js +28 -0
  35. package/dist/types/enyo-onboarding-v2.d.ts +190 -7
  36. package/dist/types/enyo-onboarding-v2.js +65 -0
  37. package/dist/version.d.ts +1 -1
  38. package/dist/version.js +1 -1
  39. package/package.json +1 -1
@@ -261,6 +261,18 @@ export interface EnergyAppPackageCompatibilityVendor {
261
261
  vendorName: string;
262
262
  /** Models from this vendor that the package supports */
263
263
  models: EnergyAppPackageCompatibilityModel[];
264
+ /**
265
+ * Marks this package as the default Energy App for the vendor when no
266
+ * concrete model has been selected.
267
+ *
268
+ * During onboarding a user may only know the manufacturer of their device,
269
+ * not its exact model. When several packages declare compatibility with the
270
+ * same vendor, the one flagged with `default: true` is the app the enyo
271
+ * Store and onboarding flows pick in that case. Set it on at most one
272
+ * package per vendor; omit it (or set `false`) when the package should only
273
+ * be offered for an explicitly selected model.
274
+ */
275
+ defaultEnergyApp?: boolean;
264
276
  }
265
277
  /**
266
278
  * A file published together with an Energy App package and served publicly
@@ -67,6 +67,62 @@ exports.onboardingV2Block = {
67
67
  * @param items - One translated entry per bullet (de/en).
68
68
  */
69
69
  bullets: (id, items) => ({ id, type: enyo_onboarding_v2_js_1.EnyoOnboardingV2BlockType.Bullets, items }),
70
+ /**
71
+ * A select block — a dropdown whose answer is recorded, not branched on.
72
+ *
73
+ * Use this, not {@link block.choice}, when the answer is data rather than a
74
+ * route: a choice needs one outgoing transition per option, so forty models
75
+ * would mean forty transitions to the same step.
76
+ *
77
+ * @param id - Stable block id, unique within the guide.
78
+ * @param label - Translated field label (de/en).
79
+ * @param options - The selectable options; unique values, at least one.
80
+ * @param opts - Optional `defaultValue`, `help` and `required`.
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * block.select('model', t('Modell', 'Model'), [
85
+ * {value: 'sb-3-0', label: t('Sunny Boy 3.0', 'Sunny Boy 3.0')},
86
+ * {value: 'sb-5-0', label: t('Sunny Boy 5.0', 'Sunny Boy 5.0')},
87
+ * ], {required: true})
88
+ * ```
89
+ */
90
+ select: (id, label, options, opts) => ({
91
+ id,
92
+ type: enyo_onboarding_v2_js_1.EnyoOnboardingV2BlockType.Select,
93
+ label,
94
+ options,
95
+ ...(opts?.defaultValue !== undefined ? { defaultValue: opts.defaultValue } : {}),
96
+ ...(opts?.help ? { help: opts.help } : {}),
97
+ ...(opts?.required !== undefined ? { required: opts.required } : {}),
98
+ }),
99
+ /**
100
+ * A credentials block — label/value pairs the installer transcribes into the
101
+ * device or a vendor portal.
102
+ *
103
+ * Passive content: it routes nothing, so a step whose only non-content block
104
+ * is this one still leaves through its single `continue` handle.
105
+ *
106
+ * @param id - Stable block id, unique within the guide.
107
+ * @param credentials - The label/value pairs. At least one.
108
+ * @param options - Optional heading, note, and copy-button toggle.
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * block.credentials('creds', [
113
+ * {label: t('Benutzername', 'Username'), value: 'enyo'},
114
+ * {label: t('Passwort', 'Password'), value: generated, secret: true},
115
+ * ], {title: t('Zugangsdaten', 'Credentials')})
116
+ * ```
117
+ */
118
+ credentials: (id, credentials, options) => ({
119
+ id,
120
+ type: enyo_onboarding_v2_js_1.EnyoOnboardingV2BlockType.Credentials,
121
+ credentials,
122
+ copyable: options?.copyable ?? true,
123
+ ...(options?.title ? { title: options.title } : {}),
124
+ ...(options?.description ? { description: options.description } : {}),
125
+ }),
70
126
  /**
71
127
  * An image block addressing an externally hosted image by URL.
72
128
  *
@@ -217,6 +273,40 @@ exports.onboardingV2Block = {
217
273
  label,
218
274
  outcomes,
219
275
  }),
276
+ /**
277
+ * A device-select block: the installer picks the device being onboarded from
278
+ * everything the run has found.
279
+ *
280
+ * Use it whenever a scan can turn up more than one candidate. A
281
+ * {@link block.networkScan} branches on found/not-found but binds nothing,
282
+ * so without this the run does not know *which* device it is working on —
283
+ * and {@link EnyoOnboardingV2DeviceSelection.Current} and
284
+ * {@link EnyoOnboardingV2DynamicKind.DeviceIp} have nothing to resolve
285
+ * against.
286
+ *
287
+ * The picker renders what discovery found, so the guide must have scanned:
288
+ * keep {@link EnyoOnboardingV2Guide.requiresNetworkScan} at its default, or
289
+ * place a {@link block.networkScan} ahead of this one.
290
+ *
291
+ * Outcome `value`s must be {@link EnyoOnboardingV2DeviceSelectOutcome}
292
+ * members; route `not-found` to troubleshooting rather than to a step that
293
+ * assumes a device exists.
294
+ *
295
+ * Register an {@link EnyoOnboardingV2DeviceSelectHandler} to turn the pick
296
+ * into appliances — the host awaits it and binds the run to the ids it
297
+ * returns. Without one the pick binds an address and nothing more.
298
+ *
299
+ * @param id - Stable block id, unique within the guide.
300
+ * @param label - Translated trigger button text (de/en).
301
+ * @param outcomes - The `selected` / `not-found` results; each is a routing handle.
302
+ */
303
+ deviceSelect: (id, label, outcomes) => ({
304
+ id,
305
+ type: enyo_onboarding_v2_js_1.EnyoOnboardingV2BlockType.Action,
306
+ action: enyo_onboarding_v2_js_1.EnyoOnboardingV2ActionKind.DeviceSelect,
307
+ label,
308
+ outcomes,
309
+ }),
220
310
  /**
221
311
  * An auth block: the installer signs into the energy app's own account
222
312
  * system (OAuth / vendor portal).
@@ -10,7 +10,7 @@
10
10
  * before publishing.
11
11
  */
12
12
  import type { EnyoOnboardingTranslatedContent } from '../../types/enyo-onboarding.cjs';
13
- import { EnyoOnboardingV2ActionKind, EnyoOnboardingV2ChoiceLayout, EnyoOnboardingV2DeviceSelection, EnyoOnboardingV2PauseReason } from '../../types/enyo-onboarding-v2.cjs';
13
+ import { EnyoOnboardingV2ActionKind, EnyoOnboardingV2Credential, EnyoOnboardingV2SelectOption, EnyoOnboardingV2ChoiceLayout, EnyoOnboardingV2DeviceSelection, EnyoOnboardingV2PauseReason } from '../../types/enyo-onboarding-v2.cjs';
14
14
  import type { EnyoOnboardingV2ActionOutcome, EnyoOnboardingV2AuthOutcome, EnyoOnboardingV2SetupField, EnyoOnboardingV2SetupOutcome, EnyoOnboardingV2SetupSkipHandle, EnyoOnboardingV2Block, EnyoOnboardingV2ChoiceOption, EnyoOnboardingV2DynamicKind, EnyoOnboardingV2Guide, EnyoOnboardingV2HintVariant, EnyoOnboardingV2InputOutcome, EnyoOnboardingV2InputValueType, EnyoOnboardingV2StartVariant, EnyoOnboardingV2Target, EnyoOnboardingV2Transition } from '../../types/enyo-onboarding-v2.cjs';
15
15
  /**
16
16
  * Identity helper that type-checks a v2 guide literal at definition time
@@ -45,6 +45,55 @@ export declare const onboardingV2Block: {
45
45
  * @param items - One translated entry per bullet (de/en).
46
46
  */
47
47
  bullets: (id: string, items: EnyoOnboardingTranslatedContent[][]) => EnyoOnboardingV2Block;
48
+ /**
49
+ * A select block — a dropdown whose answer is recorded, not branched on.
50
+ *
51
+ * Use this, not {@link block.choice}, when the answer is data rather than a
52
+ * route: a choice needs one outgoing transition per option, so forty models
53
+ * would mean forty transitions to the same step.
54
+ *
55
+ * @param id - Stable block id, unique within the guide.
56
+ * @param label - Translated field label (de/en).
57
+ * @param options - The selectable options; unique values, at least one.
58
+ * @param opts - Optional `defaultValue`, `help` and `required`.
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * block.select('model', t('Modell', 'Model'), [
63
+ * {value: 'sb-3-0', label: t('Sunny Boy 3.0', 'Sunny Boy 3.0')},
64
+ * {value: 'sb-5-0', label: t('Sunny Boy 5.0', 'Sunny Boy 5.0')},
65
+ * ], {required: true})
66
+ * ```
67
+ */
68
+ select: (id: string, label: EnyoOnboardingTranslatedContent[], options: EnyoOnboardingV2SelectOption[], opts?: {
69
+ defaultValue?: string;
70
+ help?: EnyoOnboardingTranslatedContent[];
71
+ required?: boolean;
72
+ }) => EnyoOnboardingV2Block;
73
+ /**
74
+ * A credentials block — label/value pairs the installer transcribes into the
75
+ * device or a vendor portal.
76
+ *
77
+ * Passive content: it routes nothing, so a step whose only non-content block
78
+ * is this one still leaves through its single `continue` handle.
79
+ *
80
+ * @param id - Stable block id, unique within the guide.
81
+ * @param credentials - The label/value pairs. At least one.
82
+ * @param options - Optional heading, note, and copy-button toggle.
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * block.credentials('creds', [
87
+ * {label: t('Benutzername', 'Username'), value: 'enyo'},
88
+ * {label: t('Passwort', 'Password'), value: generated, secret: true},
89
+ * ], {title: t('Zugangsdaten', 'Credentials')})
90
+ * ```
91
+ */
92
+ credentials: (id: string, credentials: EnyoOnboardingV2Credential[], options?: {
93
+ title?: EnyoOnboardingTranslatedContent[];
94
+ description?: EnyoOnboardingTranslatedContent[];
95
+ copyable?: boolean;
96
+ }) => EnyoOnboardingV2Block;
48
97
  /**
49
98
  * An image block addressing an externally hosted image by URL.
50
99
  *
@@ -169,6 +218,34 @@ export declare const onboardingV2Block: {
169
218
  * @param outcomes - The `paired` / `not-found` / `failure` results; each is a routing handle.
170
219
  */
171
220
  eebusPair: (id: string, label: EnyoOnboardingTranslatedContent[], outcomes: EnyoOnboardingV2ActionOutcome[]) => EnyoOnboardingV2Block;
221
+ /**
222
+ * A device-select block: the installer picks the device being onboarded from
223
+ * everything the run has found.
224
+ *
225
+ * Use it whenever a scan can turn up more than one candidate. A
226
+ * {@link block.networkScan} branches on found/not-found but binds nothing,
227
+ * so without this the run does not know *which* device it is working on —
228
+ * and {@link EnyoOnboardingV2DeviceSelection.Current} and
229
+ * {@link EnyoOnboardingV2DynamicKind.DeviceIp} have nothing to resolve
230
+ * against.
231
+ *
232
+ * The picker renders what discovery found, so the guide must have scanned:
233
+ * keep {@link EnyoOnboardingV2Guide.requiresNetworkScan} at its default, or
234
+ * place a {@link block.networkScan} ahead of this one.
235
+ *
236
+ * Outcome `value`s must be {@link EnyoOnboardingV2DeviceSelectOutcome}
237
+ * members; route `not-found` to troubleshooting rather than to a step that
238
+ * assumes a device exists.
239
+ *
240
+ * Register an {@link EnyoOnboardingV2DeviceSelectHandler} to turn the pick
241
+ * into appliances — the host awaits it and binds the run to the ids it
242
+ * returns. Without one the pick binds an address and nothing more.
243
+ *
244
+ * @param id - Stable block id, unique within the guide.
245
+ * @param label - Translated trigger button text (de/en).
246
+ * @param outcomes - The `selected` / `not-found` results; each is a routing handle.
247
+ */
248
+ deviceSelect: (id: string, label: EnyoOnboardingTranslatedContent[], outcomes: EnyoOnboardingV2ActionOutcome[]) => EnyoOnboardingV2Block;
172
249
  /**
173
250
  * An auth block: the installer signs into the energy app's own account
174
251
  * system (OAuth / vendor portal).
@@ -83,6 +83,8 @@ function validateOnboardingGuideV2(guide, context) {
83
83
  warnings.push(`${at}: no content blocks.`);
84
84
  validateActionBlocks(step, at, errors, warnings);
85
85
  validateLinkBlocks(step, at, errors, warnings);
86
+ validateCredentialsBlocks(step, at, errors, warnings);
87
+ validateSelectBlocks(step, at, errors, warnings);
86
88
  validateImageBlocks(step, at, errors, warnings, context);
87
89
  validateInputBlocks(step, at, errors, warnings);
88
90
  validateAuthBlocks(step, at, errors, warnings);
@@ -191,6 +193,9 @@ function validateActionBlocks(step, at, errors, warnings) {
191
193
  if (block.action === enyo_onboarding_v2_js_1.EnyoOnboardingV2ActionKind.OcppConnect) {
192
194
  validateOcppConnectOutcomes(block, at, errors);
193
195
  }
196
+ if (block.action === enyo_onboarding_v2_js_1.EnyoOnboardingV2ActionKind.DeviceSelect) {
197
+ validateDeviceSelectOutcomes(block, at, errors, warnings);
198
+ }
194
199
  if (block.action === enyo_onboarding_v2_js_1.EnyoOnboardingV2ActionKind.EebusPair) {
195
200
  validateEebusPairOutcomes(block, at, errors, warnings);
196
201
  }
@@ -247,6 +252,76 @@ function validateLinkBlocks(step, at, errors, warnings) {
247
252
  }
248
253
  }
249
254
  }
255
+ /**
256
+ * Validates the select blocks of a step.
257
+ *
258
+ * A select records an answer rather than routing on one, so the failures that
259
+ * matter are the ones that make the recorded value ambiguous or unreachable:
260
+ * duplicate option values (the app cannot tell which was picked) and a
261
+ * `defaultValue` naming no option (nothing is pre-selected, silently).
262
+ */
263
+ function validateSelectBlocks(step, at, errors, warnings) {
264
+ for (const block of step.blocks ?? []) {
265
+ if (block.type !== enyo_onboarding_v2_js_1.EnyoOnboardingV2BlockType.Select)
266
+ continue;
267
+ if (!block.label?.length) {
268
+ warnings.push(`${at}: select block "${block.id}" has no label.`);
269
+ }
270
+ if (!block.options?.length) {
271
+ errors.push(`${at}: select block "${block.id}" has no options.`);
272
+ continue;
273
+ }
274
+ if (block.options.length === 1) {
275
+ warnings.push(`${at}: select block "${block.id}" offers a single option — ` +
276
+ `there is nothing for the installer to choose.`);
277
+ }
278
+ const seen = new Set();
279
+ block.options.forEach((option, index) => {
280
+ if (!option.value?.trim()) {
281
+ errors.push(`${at}: select block "${block.id}" option ${index} has no value.`);
282
+ return;
283
+ }
284
+ if (seen.has(option.value)) {
285
+ errors.push(`${at}: select block "${block.id}" uses the option value ` +
286
+ `"${option.value}" more than once.`);
287
+ }
288
+ seen.add(option.value);
289
+ if (!option.label?.length) {
290
+ warnings.push(`${at}: select block "${block.id}" option "${option.value}" has no label.`);
291
+ }
292
+ });
293
+ if (block.defaultValue !== undefined && !seen.has(block.defaultValue)) {
294
+ errors.push(`${at}: select block "${block.id}" defaultValue "${block.defaultValue}" ` +
295
+ `matches no option.`);
296
+ }
297
+ }
298
+ }
299
+ /**
300
+ * Validates the credentials blocks of a step.
301
+ *
302
+ * A pair with no value is the failure that matters: it renders as an empty row,
303
+ * and the installer has nothing to type into the device. An untranslated label
304
+ * only degrades the display, so it is a warning.
305
+ */
306
+ function validateCredentialsBlocks(step, at, errors, warnings) {
307
+ for (const block of step.blocks ?? []) {
308
+ if (block.type !== enyo_onboarding_v2_js_1.EnyoOnboardingV2BlockType.Credentials)
309
+ continue;
310
+ if (!block.credentials?.length) {
311
+ errors.push(`${at}: credentials block "${block.id}" has no credentials.`);
312
+ continue;
313
+ }
314
+ block.credentials.forEach((credential, index) => {
315
+ if (!credential.value?.trim()) {
316
+ errors.push(`${at}: credentials block "${block.id}" entry ${index} has no value — ` +
317
+ `it would render as an empty row.`);
318
+ }
319
+ if (!credential.label?.length) {
320
+ warnings.push(`${at}: credentials block "${block.id}" entry ${index} has no label.`);
321
+ }
322
+ });
323
+ }
324
+ }
250
325
  /** An image-block `file` reference — the slug shape a package file is named with. */
251
326
  const FILE_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
252
327
  /**
@@ -366,6 +441,10 @@ function validateInputBlocks(step, at, errors, warnings) {
366
441
  if (!block.submitLabel?.length) {
367
442
  errors.push(`${at}: input block "${block.id}" has no submitLabel.`);
368
443
  }
444
+ if (block.validated && block.valueType === enyo_onboarding_v2_js_1.EnyoOnboardingV2InputValueType.IpAddress) {
445
+ errors.push(`${at}: input block "${block.id}" sets validated on an ip-address input — ` +
446
+ `the device test already produces the app's own verdict.`);
447
+ }
369
448
  const outcomes = block.outcomes ?? [];
370
449
  if (outcomes.length < 2) {
371
450
  errors.push(`${at}: input block "${block.id}" needs at least 2 outcomes.`);
@@ -432,6 +511,46 @@ function validateOcppConnectOutcomes(block, at, errors) {
432
511
  }
433
512
  }
434
513
  }
514
+ /** Every {@link EnyoOnboardingV2DeviceSelectOutcome} value. */
515
+ const DEVICE_SELECT_OUTCOMES = new Set(Object.values(enyo_onboarding_v2_js_1.EnyoOnboardingV2DeviceSelectOutcome));
516
+ /**
517
+ * Validates the outcomes of an {@link EnyoOnboardingV2ActionKind.DeviceSelect}
518
+ * block.
519
+ *
520
+ * The block reports one of two things — the installer picked a device, or the
521
+ * run came away without one — so its outcome `value`s are closed over
522
+ * {@link EnyoOnboardingV2DeviceSelectOutcome}. Anything else is an outcome that
523
+ * can never fire.
524
+ *
525
+ * A missing `selected` branch strands every successful pick, and a missing
526
+ * `not-found` branch strands the installer whose device is not in the list —
527
+ * both warnings rather than errors, so a guide can be staged step by step.
528
+ *
529
+ * @param block - The device-select action block being checked.
530
+ * @param at - Human-readable location prefix for messages.
531
+ * @param errors - Collector for blocking problems.
532
+ * @param warnings - Collector for advisory problems.
533
+ */
534
+ function validateDeviceSelectOutcomes(block, at, errors, warnings) {
535
+ const values = new Set();
536
+ for (const outcome of block.outcomes ?? []) {
537
+ if (!DEVICE_SELECT_OUTCOMES.has(outcome.value)) {
538
+ errors.push(`${at}: device-select block "${block.id}" has outcome value "${outcome.value}", which is not an EnyoOnboardingV2DeviceSelectOutcome member.`);
539
+ }
540
+ else if (values.has(outcome.value)) {
541
+ errors.push(`${at}: device-select block "${block.id}" wires outcome value "${outcome.value}" more than once.`);
542
+ }
543
+ values.add(outcome.value);
544
+ }
545
+ if (!values.has(enyo_onboarding_v2_js_1.EnyoOnboardingV2DeviceSelectOutcome.Selected)) {
546
+ warnings.push(`${at}: device-select block "${block.id}" has no "${enyo_onboarding_v2_js_1.EnyoOnboardingV2DeviceSelectOutcome.Selected}" outcome — ` +
547
+ 'a picked device would have nowhere to go.');
548
+ }
549
+ if (!values.has(enyo_onboarding_v2_js_1.EnyoOnboardingV2DeviceSelectOutcome.NotFound)) {
550
+ warnings.push(`${at}: device-select block "${block.id}" has no "${enyo_onboarding_v2_js_1.EnyoOnboardingV2DeviceSelectOutcome.NotFound}" outcome — ` +
551
+ 'an installer whose device is not in the list would be stranded.');
552
+ }
553
+ }
435
554
  /** Every {@link EnyoOnboardingV2EebusPairOutcome} value. */
436
555
  const EEBUS_PAIR_OUTCOMES = new Set(Object.values(enyo_onboarding_v2_js_1.EnyoOnboardingV2EebusPairOutcome));
437
556
  /**
@@ -103,6 +103,8 @@ __exportStar(require("./packages/energy-app-onboarding-v2.cjs"), exports);
103
103
  __exportStar(require("./implementations/onboarding-v2/onboarding-v2-provider-validators.cjs"), exports);
104
104
  __exportStar(require("./types/enyo-onboarding-v2-dynamic.cjs"), exports);
105
105
  __exportStar(require("./types/enyo-onboarding-v2-additional-setup.cjs"), exports);
106
+ __exportStar(require("./types/enyo-onboarding-v2-validation.cjs"), exports);
107
+ __exportStar(require("./types/enyo-onboarding-v2-device-select.cjs"), exports);
106
108
  __exportStar(require("./implementations/onboarding-v2/onboarding-v2-dynamic-validators.cjs"), exports);
107
109
  __exportStar(require("./implementations/files/define-public-file.cjs"), exports);
108
110
  __exportStar(require("./implementations/files/public-file-validators.cjs"), exports);
@@ -87,6 +87,8 @@ export * from './packages/energy-app-onboarding-v2.cjs';
87
87
  export * from './implementations/onboarding-v2/onboarding-v2-provider-validators.cjs';
88
88
  export * from './types/enyo-onboarding-v2-dynamic.cjs';
89
89
  export * from './types/enyo-onboarding-v2-additional-setup.cjs';
90
+ export * from './types/enyo-onboarding-v2-validation.cjs';
91
+ export * from './types/enyo-onboarding-v2-device-select.cjs';
90
92
  export * from './implementations/onboarding-v2/onboarding-v2-dynamic-validators.cjs';
91
93
  export * from './implementations/files/define-public-file.cjs';
92
94
  export * from './implementations/files/public-file-validators.cjs';
@@ -2,7 +2,7 @@
2
2
  * Supported interval durations for scheduled tasks.
3
3
  * Provides predefined time intervals from 1 second to 1 hour.
4
4
  */
5
- export type IntervalDuration = '1s' | '5s' | '10s' | '30s' | '1m' | '5m' | '1hr';
5
+ export type IntervalDuration = '1s' | '2s' | '3s' | '5s' | '10s' | '30s' | '1m' | '5m' | '1hr';
6
6
  /**
7
7
  * Interface for managing scheduled intervals in enyo packages.
8
8
  * Provides functionality to create and manage recurring tasks.
@@ -1,6 +1,8 @@
1
1
  import type { EnyoOnboardingV2GuidesRequest, EnyoOnboardingV2GuidesResult } from '../types/enyo-onboarding-v2-provider.cjs';
2
2
  import type { EnyoOnboardingV2DynamicRequest, EnyoOnboardingV2DynamicResult } from '../types/enyo-onboarding-v2-dynamic.cjs';
3
3
  import type { EnyoOnboardingV2AdditionalSetupRequest, EnyoOnboardingV2AdditionalSetupResult } from '../types/enyo-onboarding-v2-additional-setup.cjs';
4
+ import type { EnyoOnboardingV2ValidationHandler } from '../types/enyo-onboarding-v2-validation.cjs';
5
+ import type { EnyoOnboardingV2DeviceSelectHandler } from '../types/enyo-onboarding-v2-device-select.cjs';
4
6
  /**
5
7
  * Which run of a named guide an app means.
6
8
  *
@@ -428,4 +430,56 @@ export interface EnergyAppOnboardingV2 {
428
430
  * @returns Promise that resolves once the handler has been removed.
429
431
  */
430
432
  deregisterAdditionalSetupHandler(): Promise<void>;
433
+ /**
434
+ * Registers the handler the host calls to check a value typed into an
435
+ * {@link EnyoOnboardingV2InputBlock} that set
436
+ * {@link EnyoOnboardingV2InputBlock.validated}.
437
+ *
438
+ * One handler serves every validated input across all of this app's guides.
439
+ * Registering again replaces the previous one.
440
+ *
441
+ * A guide that declares `validated` blocks while no handler is registered is
442
+ * not broken — unanswered validation is treated as acceptance, exactly like
443
+ * a timeout — but nothing is checked, so register the handler before
444
+ * publishing guides that rely on it.
445
+ *
446
+ * @param handler - Called with the submitted value; answers valid or invalid
447
+ * @returns Promise that resolves once the handler is registered
448
+ */
449
+ registerInputValidationHandler(handler: EnyoOnboardingV2ValidationHandler): Promise<void>;
450
+ /**
451
+ * Removes the registered input validation handler. Validated inputs then
452
+ * accept every value, as if no handler had ever been registered.
453
+ *
454
+ * @returns Promise that resolves once the handler is removed
455
+ */
456
+ deregisterInputValidationHandler(): Promise<void>;
457
+ /**
458
+ * Registers the handler the host calls when an installer picks devices in an
459
+ * {@link EnyoOnboardingV2ActionKind.DeviceSelect} block, so the app can turn
460
+ * them into appliances and hand back the ids.
461
+ *
462
+ * The host awaits the answer and binds the run to the returned appliances,
463
+ * which is what fills `applianceId` for later dynamic and additional-setup
464
+ * requests on the same run.
465
+ *
466
+ * Optional. Without a handler the block still works — the run takes its
467
+ * `selected` branch and stays bound to the picked device — but no appliance
468
+ * is created, so a guide that ends there produces an address and nothing the
469
+ * energy manager can read or control.
470
+ *
471
+ * One handler serves every device-select block across all of this app's
472
+ * guides. Registering again replaces the previous one.
473
+ *
474
+ * @param handler - Called with the picked devices; answers with appliance ids
475
+ * @returns Promise that resolves once the handler is registered
476
+ */
477
+ registerDeviceSelectHandler(handler: EnyoOnboardingV2DeviceSelectHandler): Promise<void>;
478
+ /**
479
+ * Removes the registered device-select handler. Picks then create no
480
+ * appliances, as if no handler had ever been registered.
481
+ *
482
+ * @returns Promise that resolves once the handler is removed
483
+ */
484
+ deregisterDeviceSelectHandler(): Promise<void>;
431
485
  }
@@ -24,7 +24,9 @@ var EnyoApplianceStateEnum;
24
24
  * which describes connectivity. `Healthy` means the appliance is operating
25
25
  * normally; `Warning` means a non-blocking issue has been reported (the
26
26
  * appliance is still functional but should be inspected); `Faulted` means it
27
- * has reported an internal error and may need attention. Vendor- or
27
+ * has reported an internal error and may need attention; `Deactivated` means
28
+ * the appliance has been intentionally switched off from energy management and
29
+ * is neither monitored nor controlled until it is reactivated. Vendor- or
28
30
  * protocol-specific details should be conveyed via accompanying error codes.
29
31
  */
30
32
  var EnyoApplianceStatusEnum;
@@ -35,6 +37,12 @@ var EnyoApplianceStatusEnum;
35
37
  EnyoApplianceStatusEnum["Warning"] = "warning";
36
38
  /** Appliance has reported an internal fault */
37
39
  EnyoApplianceStatusEnum["Faulted"] = "faulted";
40
+ /**
41
+ * Appliance has been intentionally deactivated and is excluded from energy
42
+ * management. It is not controlled and its health is not evaluated until it
43
+ * is reactivated.
44
+ */
45
+ EnyoApplianceStatusEnum["Deactivated"] = "deactivated";
38
46
  })(EnyoApplianceStatusEnum || (exports.EnyoApplianceStatusEnum = EnyoApplianceStatusEnum = {}));
39
47
  var EnyoApplianceConnectionType;
40
48
  (function (EnyoApplianceConnectionType) {
@@ -33,7 +33,9 @@ export declare enum EnyoApplianceStateEnum {
33
33
  * which describes connectivity. `Healthy` means the appliance is operating
34
34
  * normally; `Warning` means a non-blocking issue has been reported (the
35
35
  * appliance is still functional but should be inspected); `Faulted` means it
36
- * has reported an internal error and may need attention. Vendor- or
36
+ * has reported an internal error and may need attention; `Deactivated` means
37
+ * the appliance has been intentionally switched off from energy management and
38
+ * is neither monitored nor controlled until it is reactivated. Vendor- or
37
39
  * protocol-specific details should be conveyed via accompanying error codes.
38
40
  */
39
41
  export declare enum EnyoApplianceStatusEnum {
@@ -42,7 +44,13 @@ export declare enum EnyoApplianceStatusEnum {
42
44
  /** Appliance is operating but has reported a non-blocking issue that should be inspected */
43
45
  Warning = "warning",
44
46
  /** Appliance has reported an internal fault */
45
- Faulted = "faulted"
47
+ Faulted = "faulted",
48
+ /**
49
+ * Appliance has been intentionally deactivated and is excluded from energy
50
+ * management. It is not controlled and its health is not evaluated until it
51
+ * is reactivated.
52
+ */
53
+ Deactivated = "deactivated"
46
54
  }
47
55
  /**
48
56
  * Severity classification for an {@link EnyoApplianceErrorCode}.
@@ -175,7 +183,7 @@ export interface EnyoApplianceMetadata {
175
183
  ipAddress?: string;
176
184
  /** Connection state */
177
185
  state?: EnyoApplianceStateEnum;
178
- /** Health status of the appliance (e.g. healthy or faulted) */
186
+ /** Health status of the appliance (e.g. healthy, faulted or deactivated) */
179
187
  status?: EnyoApplianceStatusEnum;
180
188
  network?: EnyoApplianceNetworkMetadata;
181
189
  modbus?: EnyoApplianceModbusMetadata;
@@ -593,7 +593,8 @@ export interface EnyoDataBusApplianceFlexibilityAnnouncementV1 extends EnyoDataB
593
593
  * provided together if they change in the same event. `errorCodes` carries
594
594
  * vendor- or protocol-specific codes that explain a transition into a
595
595
  * `warning` or `faulted` status; each entry's `severity` field indicates
596
- * which.
596
+ * which. A transition into `deactivated` is intentional and normally carries
597
+ * no error codes.
597
598
  */
598
599
  export interface EnyoDataBusApplianceStateUpdateV1 extends EnyoDataBusMessage {
599
600
  type: 'message';
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * Onboarding guide **v2 device selection** — the host handing an energy app the
4
+ * network devices an installer picked, and taking back the appliances the app
5
+ * made of them.
6
+ *
7
+ * An {@link EnyoOnboardingV2ActionKind.DeviceSelect} block answers "which of
8
+ * these is it?" and binds the run to the installer's pick. That binding is an
9
+ * address, not an appliance: nothing in the system yet represents the device as
10
+ * something the energy manager can read or control. This model closes that gap —
11
+ * the app is asked to turn the picked device(s) into appliances and answer with
12
+ * their ids, and the host binds the run to them so later steps have an
13
+ * `applianceId` to work with.
14
+ *
15
+ * **Distinct from {@link EnyoDeviceTestHandler}, which stays the right tool when
16
+ * the guide must branch.** A device test produces a verdict per device and an
17
+ * aggregate outcome the graph routes on — the app decides whether the device is
18
+ * usable. Here the installer already decided; there is no verdict, no branching,
19
+ * and the handler's only job is to produce appliances. Reach for the device test
20
+ * when "we could not use it" must lead somewhere different in the flow.
21
+ *
22
+ * Registering is optional. Without a handler the block still works: the run
23
+ * takes its `selected` branch and stays bound to the device, and no appliance is
24
+ * created.
25
+ *
26
+ * Pure type declarations (no runtime logic). Register the handler through
27
+ * {@link EnergyAppOnboardingV2} (`../packages/energy-app-onboarding-v2.ts`).
28
+ */
29
+ Object.defineProperty(exports, "__esModule", { value: true });