@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.
- package/dist/cjs/energy-app-package-definition.d.cts +12 -0
- package/dist/cjs/implementations/onboarding-v2/define-onboarding-guide-v2.cjs +90 -0
- package/dist/cjs/implementations/onboarding-v2/define-onboarding-guide-v2.d.cts +78 -1
- package/dist/cjs/implementations/onboarding-v2/onboarding-v2-validators.cjs +119 -0
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.d.cts +2 -0
- package/dist/cjs/packages/energy-app-interval.d.cts +1 -1
- package/dist/cjs/packages/energy-app-onboarding-v2.d.cts +54 -0
- package/dist/cjs/types/enyo-appliance.cjs +9 -1
- package/dist/cjs/types/enyo-appliance.d.cts +11 -3
- package/dist/cjs/types/enyo-data-bus-value.d.cts +2 -1
- package/dist/cjs/types/enyo-onboarding-v2-device-select.cjs +29 -0
- package/dist/cjs/types/enyo-onboarding-v2-device-select.d.cts +105 -0
- package/dist/cjs/types/enyo-onboarding-v2-validation.cjs +29 -0
- package/dist/cjs/types/enyo-onboarding-v2-validation.d.cts +108 -0
- package/dist/cjs/types/enyo-onboarding-v2.cjs +66 -1
- package/dist/cjs/types/enyo-onboarding-v2.d.cts +190 -7
- package/dist/cjs/version.cjs +1 -1
- package/dist/cjs/version.d.cts +1 -1
- package/dist/energy-app-package-definition.d.ts +12 -0
- package/dist/implementations/onboarding-v2/define-onboarding-guide-v2.d.ts +78 -1
- package/dist/implementations/onboarding-v2/define-onboarding-guide-v2.js +90 -0
- package/dist/implementations/onboarding-v2/onboarding-v2-validators.js +120 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/packages/energy-app-interval.d.ts +1 -1
- package/dist/packages/energy-app-onboarding-v2.d.ts +54 -0
- package/dist/types/enyo-appliance.d.ts +11 -3
- package/dist/types/enyo-appliance.js +9 -1
- package/dist/types/enyo-data-bus-value.d.ts +2 -1
- package/dist/types/enyo-onboarding-v2-device-select.d.ts +105 -0
- package/dist/types/enyo-onboarding-v2-device-select.js +28 -0
- package/dist/types/enyo-onboarding-v2-validation.d.ts +108 -0
- package/dist/types/enyo-onboarding-v2-validation.js +28 -0
- package/dist/types/enyo-onboarding-v2.d.ts +190 -7
- package/dist/types/enyo-onboarding-v2.js +65 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- 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
|
/**
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -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);
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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 });
|