@enyo-energy/energy-app-sdk 0.0.195 → 0.0.196
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/README.md +30 -1
- package/dist/cjs/energy-app.cjs +14 -0
- package/dist/cjs/energy-app.d.cts +13 -0
- package/dist/cjs/enyo-energy-app-sdk.d.cts +3 -0
- package/dist/cjs/implementations/onboarding-v2/onboarding-v2-provider-validators.cjs +167 -0
- package/dist/cjs/implementations/onboarding-v2/onboarding-v2-provider-validators.d.cts +86 -0
- package/dist/cjs/index.cjs +3 -0
- package/dist/cjs/index.d.cts +3 -0
- package/dist/cjs/packages/energy-app-onboarding-v2.cjs +2 -0
- package/dist/cjs/packages/energy-app-onboarding-v2.d.cts +128 -0
- package/dist/cjs/packages/energy-app-onboarding.d.cts +13 -6
- package/dist/cjs/types/enyo-onboarding-v2-provider.cjs +51 -0
- package/dist/cjs/types/enyo-onboarding-v2-provider.d.cts +105 -0
- package/dist/cjs/version.cjs +1 -1
- package/dist/cjs/version.d.cts +1 -1
- package/dist/energy-app.d.ts +13 -0
- package/dist/energy-app.js +14 -0
- package/dist/enyo-energy-app-sdk.d.ts +3 -0
- package/dist/implementations/onboarding-v2/onboarding-v2-provider-validators.d.ts +86 -0
- package/dist/implementations/onboarding-v2/onboarding-v2-provider-validators.js +161 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/packages/energy-app-onboarding-v2.d.ts +128 -0
- package/dist/packages/energy-app-onboarding-v2.js +1 -0
- package/dist/packages/energy-app-onboarding.d.ts +13 -6
- package/dist/types/enyo-onboarding-v2-provider.d.ts +105 -0
- package/dist/types/enyo-onboarding-v2-provider.js +48 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -172,7 +172,8 @@ The SDK exposes several layered building blocks. Pick the one that matches the k
|
|
|
172
172
|
| Manage electricity tariffs (default tariff, price per kWh) | [`useElectricityTariff()`](#useelectricitytariff-energyappelectricitytariff) |
|
|
173
173
|
| Register a PV system (kWp, DC strings, orientation) | [`usePvSystem()`](#usepvsystem-energyapppvsystem) |
|
|
174
174
|
| Discover capabilities of the active energy manager | [`useEnergyManager()`](#useenergymanager-energyappenergymanager) |
|
|
175
|
-
|
|
|
175
|
+
| Serve your v2 onboarding guides when the host asks for them | [`useOnboardingV2()`](#useonboardingv2-energyapponboardingv2) |
|
|
176
|
+
| Drive a multi-step onboarding flow (v1, deprecated) | [`useOnboarding()`](#useonboarding-energyapponboarding) |
|
|
176
177
|
| Allocate process-local sequential IDs | [`useSequenceGenerator()`](#usesequencegenerator-energyappsequencegenerator) |
|
|
177
178
|
| Manage retries with circuit-breaker semantics | [`RetryManager`](#retry-framework) |
|
|
178
179
|
| Keep an `applianceId` cache in sync with the SDK | [`ApplianceManager`](#appliance-management) |
|
|
@@ -1334,8 +1335,36 @@ Requires the `Savings` permission.
|
|
|
1334
1335
|
|
|
1335
1336
|
### Operational Utilities
|
|
1336
1337
|
|
|
1338
|
+
#### `useOnboardingV2(): EnergyAppOnboardingV2`
|
|
1339
|
+
|
|
1340
|
+
Serve the onboarding guides your app ships. Guides are **pulled, not published**: you register one handler, and the host calls it with "give me your v2 onboarding guides". You answer with the **complete set** or with **nothing** — there is no save, update or delete, and every answer replaces the host's picture of what your app offers.
|
|
1341
|
+
|
|
1342
|
+
```typescript
|
|
1343
|
+
await energyApp.useOnboardingV2().registerOnboardingGuidesHandler(async (request) => {
|
|
1344
|
+
const result = { requestId: request.requestId, guides: buildGuides() };
|
|
1345
|
+
|
|
1346
|
+
const { ok, errors } = validateOnboardingV2GuidesResult(result, {
|
|
1347
|
+
files: packageDefinition.files,
|
|
1348
|
+
});
|
|
1349
|
+
if (!ok) {
|
|
1350
|
+
console.error('onboarding guides invalid', errors);
|
|
1351
|
+
return null; // keep whatever the host already has
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
return result;
|
|
1355
|
+
});
|
|
1356
|
+
```
|
|
1357
|
+
|
|
1358
|
+
`null` and `[]` are **not** the same answer: `[]` says "I genuinely have no guides" and drops the host's cached ones, `null` says "I cannot answer right now" and leaves them alone. Use `null` for transient failures. The host stops waiting after `request.timeoutMs`, so build the guides in memory rather than fetching them.
|
|
1359
|
+
|
|
1360
|
+
Each guide must carry the `vendorId`, `modelIds` and `startVariant` it applies to — that is how the host selects one for a run, and there is no publish step left to bind them. See [ONBOARDING.md](./ONBOARDING.md#serving-guides-the-host-pulls-the-app-never-publishes) for the full v2 model.
|
|
1361
|
+
|
|
1362
|
+
Not permission-gated.
|
|
1363
|
+
|
|
1337
1364
|
#### `useOnboarding(): EnergyAppOnboarding`
|
|
1338
1365
|
|
|
1366
|
+
> **Deprecated** — the v1 model. New guides use the v2 graph model and are served through [`useOnboardingV2()`](#useonboardingv2-energyapponboardingv2).
|
|
1367
|
+
|
|
1339
1368
|
Drive a multi-step onboarding guide — start / advance / back / skip / cancel, persist responses, and observe step transitions.
|
|
1340
1369
|
|
|
1341
1370
|
```typescript
|
package/dist/cjs/energy-app.cjs
CHANGED
|
@@ -117,6 +117,20 @@ class EnergyApp {
|
|
|
117
117
|
useOnboarding() {
|
|
118
118
|
return this.energyAppSdk.useOnboarding();
|
|
119
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Gets the Onboarding v2 API for serving this app's onboarding guides.
|
|
122
|
+
*
|
|
123
|
+
* Guides are pulled rather than published: the app registers one handler and
|
|
124
|
+
* the host calls it with "give me your v2 onboarding guides", receiving the
|
|
125
|
+
* complete current set or nothing. There is no save, update or delete —
|
|
126
|
+
* every answer replaces the host's picture of what this app offers.
|
|
127
|
+
*
|
|
128
|
+
* Available to every app — this API is not permission-gated.
|
|
129
|
+
* @returns The Onboarding v2 API instance
|
|
130
|
+
*/
|
|
131
|
+
useOnboardingV2() {
|
|
132
|
+
return this.energyAppSdk.useOnboardingV2();
|
|
133
|
+
}
|
|
120
134
|
/**
|
|
121
135
|
* Gets the Secret Manager API for retrieving secrets from the developer organization.
|
|
122
136
|
* Provides methods to fetch secrets that have been configured in the developer org's secret store.
|
|
@@ -16,6 +16,7 @@ import { EnergyAppNotification } from "./packages/energy-app-notification.cjs";
|
|
|
16
16
|
import { EnergyAppSecretManager } from "./packages/energy-app-secret-manager.cjs";
|
|
17
17
|
import { EnergyAppLocation } from "./packages/energy-app-location.cjs";
|
|
18
18
|
import { EnergyAppOnboarding } from "./packages/energy-app-onboarding.cjs";
|
|
19
|
+
import { EnergyAppOnboardingV2 } from "./packages/energy-app-onboarding-v2.cjs";
|
|
19
20
|
import { EnergyAppTimeseries } from "./packages/energy-app-timeseries.cjs";
|
|
20
21
|
import { EnyoPackageChannel } from "./enyo-package-channel.cjs";
|
|
21
22
|
import { EnergyAppEnergyManager } from "./packages/energy-app-energy-manager.cjs";
|
|
@@ -99,6 +100,18 @@ export declare class EnergyApp implements EnyoEnergyAppSdk {
|
|
|
99
100
|
useElectricityPrices(): EnergyAppEnergyPrices;
|
|
100
101
|
useNotification(): EnergyAppNotification;
|
|
101
102
|
useOnboarding(): EnergyAppOnboarding;
|
|
103
|
+
/**
|
|
104
|
+
* Gets the Onboarding v2 API for serving this app's onboarding guides.
|
|
105
|
+
*
|
|
106
|
+
* Guides are pulled rather than published: the app registers one handler and
|
|
107
|
+
* the host calls it with "give me your v2 onboarding guides", receiving the
|
|
108
|
+
* complete current set or nothing. There is no save, update or delete —
|
|
109
|
+
* every answer replaces the host's picture of what this app offers.
|
|
110
|
+
*
|
|
111
|
+
* Available to every app — this API is not permission-gated.
|
|
112
|
+
* @returns The Onboarding v2 API instance
|
|
113
|
+
*/
|
|
114
|
+
useOnboardingV2(): EnergyAppOnboardingV2;
|
|
102
115
|
/**
|
|
103
116
|
* Gets the Secret Manager API for retrieving secrets from the developer organization.
|
|
104
117
|
* Provides methods to fetch secrets that have been configured in the developer org's secret store.
|
|
@@ -15,6 +15,7 @@ import { EnergyAppNotification } from "./packages/energy-app-notification.cjs";
|
|
|
15
15
|
import { EnergyAppSecretManager } from "./packages/energy-app-secret-manager.cjs";
|
|
16
16
|
import { EnergyAppLocation } from "./packages/energy-app-location.cjs";
|
|
17
17
|
import { EnergyAppOnboarding } from "./packages/energy-app-onboarding.cjs";
|
|
18
|
+
import { EnergyAppOnboardingV2 } from "./packages/energy-app-onboarding-v2.cjs";
|
|
18
19
|
import { EnergyAppTimeseries } from "./packages/energy-app-timeseries.cjs";
|
|
19
20
|
import { EnyoPackageChannel } from "./enyo-package-channel.cjs";
|
|
20
21
|
import { EnergyAppEnergyManager } from "./packages/energy-app-energy-manager.cjs";
|
|
@@ -106,6 +107,8 @@ export interface EnyoEnergyAppSdk {
|
|
|
106
107
|
useLocation: () => EnergyAppLocation;
|
|
107
108
|
/** Get the Onboarding API */
|
|
108
109
|
useOnboarding: () => EnergyAppOnboarding;
|
|
110
|
+
/** Get the Onboarding v2 API for registering the handler the host calls to collect this app's onboarding guides */
|
|
111
|
+
useOnboardingV2: () => EnergyAppOnboardingV2;
|
|
109
112
|
/** Get the Timeseries API for querying historical energy data */
|
|
110
113
|
useTimeseries: () => EnergyAppTimeseries;
|
|
111
114
|
/** Get the Energy Manager API for retrieving energy manager info and capabilities */
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Client-side validation for an {@link EnyoOnboardingV2GuidesResult} — the whole
|
|
4
|
+
* answer an app hands back when the host asks for its v2 onboarding guides.
|
|
5
|
+
*
|
|
6
|
+
* {@link validateOnboardingGuideV2} checks one guide's graph. This checks the
|
|
7
|
+
* *set*: that every guide in it is publishable, that each one says which
|
|
8
|
+
* vendor/model/start-variant it applies to, and that no two of them claim the
|
|
9
|
+
* same one. Those last two only become checkable here, because a guide is now
|
|
10
|
+
* selected out of an app's own answer rather than bound to a catalog entry at
|
|
11
|
+
* publish time — a guide with no binding can never be chosen for a device, and
|
|
12
|
+
* two guides with the same binding leave the host with no way to pick.
|
|
13
|
+
*
|
|
14
|
+
* `errors` mean the answer is not fit to return; `warnings` are advisory. Use
|
|
15
|
+
* {@link validateOnboardingV2GuidesResult} for the non-throwing result, or
|
|
16
|
+
* {@link assertValidOnboardingV2GuidesResult} to throw.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.OnboardingV2GuidesValidationError = void 0;
|
|
20
|
+
exports.validateOnboardingV2GuidesResult = validateOnboardingV2GuidesResult;
|
|
21
|
+
exports.assertValidOnboardingV2GuidesResult = assertValidOnboardingV2GuidesResult;
|
|
22
|
+
const onboarding_v2_validators_js_1 = require("./onboarding-v2-validators.cjs");
|
|
23
|
+
/**
|
|
24
|
+
* Thrown by {@link assertValidOnboardingV2GuidesResult} when an answer fails
|
|
25
|
+
* validation. The message lists every blocking error so callers can surface
|
|
26
|
+
* them directly.
|
|
27
|
+
*/
|
|
28
|
+
class OnboardingV2GuidesValidationError extends Error {
|
|
29
|
+
/** The individual blocking errors that caused the failure. */
|
|
30
|
+
errors;
|
|
31
|
+
/**
|
|
32
|
+
* @param errors - The blocking validation errors.
|
|
33
|
+
*/
|
|
34
|
+
constructor(errors) {
|
|
35
|
+
super(`Invalid onboarding guides result (v2):\n- ${errors.join('\n- ')}`);
|
|
36
|
+
this.name = 'OnboardingV2GuidesValidationError';
|
|
37
|
+
this.errors = errors;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.OnboardingV2GuidesValidationError = OnboardingV2GuidesValidationError;
|
|
41
|
+
/**
|
|
42
|
+
* Placeholder used in a binding key for a guide that names no model — it applies
|
|
43
|
+
* to every model of its vendor, and therefore collides with any other such guide
|
|
44
|
+
* for the same vendor and start variant.
|
|
45
|
+
*/
|
|
46
|
+
const ANY_MODEL = '*';
|
|
47
|
+
/**
|
|
48
|
+
* A short human-readable label for a guide, for use in messages.
|
|
49
|
+
*
|
|
50
|
+
* Prefers the first translated title, since ids are not required at guide level;
|
|
51
|
+
* falls back to the start variant so a titleless guide is still identifiable.
|
|
52
|
+
*
|
|
53
|
+
* @param guide - The guide to label.
|
|
54
|
+
* @param index - Its position in the answer's `guides` array.
|
|
55
|
+
* @returns A message prefix such as ``guides[2] ("Wallbox über OCPP")``.
|
|
56
|
+
*/
|
|
57
|
+
function guideLabel(guide, index) {
|
|
58
|
+
const title = guide.title?.[0]?.value;
|
|
59
|
+
return `guides[${index}] (${title ? `"${title}"` : (guide.startVariant ?? '?')})`;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Every (vendor, model, start variant) binding a guide claims.
|
|
63
|
+
*
|
|
64
|
+
* A guide with several `modelIds` claims one binding per model, so two guides
|
|
65
|
+
* that overlap on a single model collide even when the rest of their model lists
|
|
66
|
+
* differ.
|
|
67
|
+
*
|
|
68
|
+
* @param guide - The guide to derive bindings for.
|
|
69
|
+
* @returns The binding keys, or an empty array when the guide names no vendor.
|
|
70
|
+
*/
|
|
71
|
+
function bindingKeys(guide) {
|
|
72
|
+
if (!guide.vendorId)
|
|
73
|
+
return [];
|
|
74
|
+
const models = guide.modelIds?.length ? guide.modelIds : [ANY_MODEL];
|
|
75
|
+
return models.map((modelId) => `${guide.vendorId}|${modelId}|${guide.startVariant}`);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Validates a complete guides answer: the envelope, every guide in it, and the
|
|
79
|
+
* bindings across them.
|
|
80
|
+
*
|
|
81
|
+
* Each guide is run through {@link validateOnboardingGuideV2}, and its errors
|
|
82
|
+
* and warnings are surfaced here prefixed with the guide's position — pass the
|
|
83
|
+
* declaring package's `files` in `context` to have image references resolved
|
|
84
|
+
* rather than merely reported.
|
|
85
|
+
*
|
|
86
|
+
* An empty `guides` array is valid but warned about: it is the deliberate
|
|
87
|
+
* statement "I have no guides, drop the ones you cached". An app that meant
|
|
88
|
+
* "I cannot answer right now" must resolve its handler with `null` instead.
|
|
89
|
+
*
|
|
90
|
+
* @param result - The answer the handler is about to return.
|
|
91
|
+
* @param context - Optional {@link OnboardingV2ValidationContext} every guide is
|
|
92
|
+
* checked against.
|
|
93
|
+
* @returns The {@link OnboardingV2GuidesValidationResult}.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* const result = {requestId: request.requestId, guides: buildGuides()};
|
|
98
|
+
* const {ok, errors, warnings} = validateOnboardingV2GuidesResult(result, {
|
|
99
|
+
* files: packageDefinition.files,
|
|
100
|
+
* });
|
|
101
|
+
* if (!ok) {
|
|
102
|
+
* console.error('onboarding guides invalid', errors);
|
|
103
|
+
* return null;
|
|
104
|
+
* }
|
|
105
|
+
* warnings.forEach((w) => console.warn('onboarding guides:', w));
|
|
106
|
+
* return result;
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
function validateOnboardingV2GuidesResult(result, context) {
|
|
110
|
+
const errors = [];
|
|
111
|
+
const warnings = [];
|
|
112
|
+
if (!result?.requestId) {
|
|
113
|
+
errors.push('`requestId` is required and must echo the request.');
|
|
114
|
+
}
|
|
115
|
+
if (!Array.isArray(result?.guides)) {
|
|
116
|
+
errors.push('`guides` must be an array — resolve the handler with `null` to answer "nothing".');
|
|
117
|
+
return { ok: false, errors, warnings };
|
|
118
|
+
}
|
|
119
|
+
if (result.guides.length === 0) {
|
|
120
|
+
warnings.push('Empty `guides` retires every guide the host cached for this app. ' +
|
|
121
|
+
'Resolve the handler with `null` instead if the intent was "no answer right now".');
|
|
122
|
+
}
|
|
123
|
+
// Which guide(s) claimed each binding, so a collision can name both sides.
|
|
124
|
+
const claimedBy = new Map();
|
|
125
|
+
for (const [i, guide] of result.guides.entries()) {
|
|
126
|
+
const at = guideLabel(guide, i);
|
|
127
|
+
const guideResult = (0, onboarding_v2_validators_js_1.validateOnboardingGuideV2)(guide, context);
|
|
128
|
+
errors.push(...guideResult.errors.map((e) => `${at}: ${e}`));
|
|
129
|
+
warnings.push(...guideResult.warnings.map((w) => `${at}: ${w}`));
|
|
130
|
+
if (!guide.vendorId) {
|
|
131
|
+
warnings.push(`${at}: no vendorId — the host matches a run by vendor, model and start variant, ` +
|
|
132
|
+
'so an unbound guide can never be selected.');
|
|
133
|
+
}
|
|
134
|
+
else if (!guide.modelIds?.length) {
|
|
135
|
+
warnings.push(`${at}: no modelIds — this guide applies to every model of "${guide.vendorId}".`);
|
|
136
|
+
}
|
|
137
|
+
for (const key of bindingKeys(guide)) {
|
|
138
|
+
const previous = claimedBy.get(key);
|
|
139
|
+
if (previous) {
|
|
140
|
+
errors.push(`${at}: binding "${key}" is already claimed by ${previous} — ` +
|
|
141
|
+
'the host cannot choose between two guides for the same vendor, model and start variant.');
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
claimedBy.set(key, at);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return { ok: errors.length === 0, errors, warnings };
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Like {@link validateOnboardingV2GuidesResult}, but throws
|
|
152
|
+
* {@link OnboardingV2GuidesValidationError} when there are blocking errors.
|
|
153
|
+
* Warnings never throw; the validated answer is returned on success for
|
|
154
|
+
* chaining.
|
|
155
|
+
*
|
|
156
|
+
* @param result - The answer the handler is about to return.
|
|
157
|
+
* @param context - Optional {@link OnboardingV2ValidationContext}, as for
|
|
158
|
+
* {@link validateOnboardingV2GuidesResult}.
|
|
159
|
+
* @returns The same answer when it has no blocking errors.
|
|
160
|
+
* @throws {OnboardingV2GuidesValidationError} When validation produces any error.
|
|
161
|
+
*/
|
|
162
|
+
function assertValidOnboardingV2GuidesResult(result, context) {
|
|
163
|
+
const { ok, errors } = validateOnboardingV2GuidesResult(result, context);
|
|
164
|
+
if (!ok)
|
|
165
|
+
throw new OnboardingV2GuidesValidationError(errors);
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side validation for an {@link EnyoOnboardingV2GuidesResult} — the whole
|
|
3
|
+
* answer an app hands back when the host asks for its v2 onboarding guides.
|
|
4
|
+
*
|
|
5
|
+
* {@link validateOnboardingGuideV2} checks one guide's graph. This checks the
|
|
6
|
+
* *set*: that every guide in it is publishable, that each one says which
|
|
7
|
+
* vendor/model/start-variant it applies to, and that no two of them claim the
|
|
8
|
+
* same one. Those last two only become checkable here, because a guide is now
|
|
9
|
+
* selected out of an app's own answer rather than bound to a catalog entry at
|
|
10
|
+
* publish time — a guide with no binding can never be chosen for a device, and
|
|
11
|
+
* two guides with the same binding leave the host with no way to pick.
|
|
12
|
+
*
|
|
13
|
+
* `errors` mean the answer is not fit to return; `warnings` are advisory. Use
|
|
14
|
+
* {@link validateOnboardingV2GuidesResult} for the non-throwing result, or
|
|
15
|
+
* {@link assertValidOnboardingV2GuidesResult} to throw.
|
|
16
|
+
*/
|
|
17
|
+
import type { OnboardingV2ValidationContext } from './onboarding-v2-validators.cjs';
|
|
18
|
+
import type { EnyoOnboardingV2GuidesResult } from '../../types/enyo-onboarding-v2-provider.cjs';
|
|
19
|
+
/**
|
|
20
|
+
* Thrown by {@link assertValidOnboardingV2GuidesResult} when an answer fails
|
|
21
|
+
* validation. The message lists every blocking error so callers can surface
|
|
22
|
+
* them directly.
|
|
23
|
+
*/
|
|
24
|
+
export declare class OnboardingV2GuidesValidationError extends Error {
|
|
25
|
+
/** The individual blocking errors that caused the failure. */
|
|
26
|
+
readonly errors: string[];
|
|
27
|
+
/**
|
|
28
|
+
* @param errors - The blocking validation errors.
|
|
29
|
+
*/
|
|
30
|
+
constructor(errors: string[]);
|
|
31
|
+
}
|
|
32
|
+
/** The outcome of validating an {@link EnyoOnboardingV2GuidesResult}. */
|
|
33
|
+
export interface OnboardingV2GuidesValidationResult {
|
|
34
|
+
/** True when there are no blocking `errors` (warnings are still allowed). */
|
|
35
|
+
ok: boolean;
|
|
36
|
+
/** Blocking problems — the answer should not be returned to the host. */
|
|
37
|
+
errors: string[];
|
|
38
|
+
/** Advisory problems — allowed, but usually worth fixing. */
|
|
39
|
+
warnings: string[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Validates a complete guides answer: the envelope, every guide in it, and the
|
|
43
|
+
* bindings across them.
|
|
44
|
+
*
|
|
45
|
+
* Each guide is run through {@link validateOnboardingGuideV2}, and its errors
|
|
46
|
+
* and warnings are surfaced here prefixed with the guide's position — pass the
|
|
47
|
+
* declaring package's `files` in `context` to have image references resolved
|
|
48
|
+
* rather than merely reported.
|
|
49
|
+
*
|
|
50
|
+
* An empty `guides` array is valid but warned about: it is the deliberate
|
|
51
|
+
* statement "I have no guides, drop the ones you cached". An app that meant
|
|
52
|
+
* "I cannot answer right now" must resolve its handler with `null` instead.
|
|
53
|
+
*
|
|
54
|
+
* @param result - The answer the handler is about to return.
|
|
55
|
+
* @param context - Optional {@link OnboardingV2ValidationContext} every guide is
|
|
56
|
+
* checked against.
|
|
57
|
+
* @returns The {@link OnboardingV2GuidesValidationResult}.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const result = {requestId: request.requestId, guides: buildGuides()};
|
|
62
|
+
* const {ok, errors, warnings} = validateOnboardingV2GuidesResult(result, {
|
|
63
|
+
* files: packageDefinition.files,
|
|
64
|
+
* });
|
|
65
|
+
* if (!ok) {
|
|
66
|
+
* console.error('onboarding guides invalid', errors);
|
|
67
|
+
* return null;
|
|
68
|
+
* }
|
|
69
|
+
* warnings.forEach((w) => console.warn('onboarding guides:', w));
|
|
70
|
+
* return result;
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare function validateOnboardingV2GuidesResult(result: EnyoOnboardingV2GuidesResult, context?: OnboardingV2ValidationContext): OnboardingV2GuidesValidationResult;
|
|
74
|
+
/**
|
|
75
|
+
* Like {@link validateOnboardingV2GuidesResult}, but throws
|
|
76
|
+
* {@link OnboardingV2GuidesValidationError} when there are blocking errors.
|
|
77
|
+
* Warnings never throw; the validated answer is returned on success for
|
|
78
|
+
* chaining.
|
|
79
|
+
*
|
|
80
|
+
* @param result - The answer the handler is about to return.
|
|
81
|
+
* @param context - Optional {@link OnboardingV2ValidationContext}, as for
|
|
82
|
+
* {@link validateOnboardingV2GuidesResult}.
|
|
83
|
+
* @returns The same answer when it has no blocking errors.
|
|
84
|
+
* @throws {OnboardingV2GuidesValidationError} When validation produces any error.
|
|
85
|
+
*/
|
|
86
|
+
export declare function assertValidOnboardingV2GuidesResult(result: EnyoOnboardingV2GuidesResult, context?: OnboardingV2ValidationContext): EnyoOnboardingV2GuidesResult;
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -93,6 +93,9 @@ __exportStar(require("./packages/energy-app-onboarding.cjs"), exports);
|
|
|
93
93
|
__exportStar(require("./types/enyo-onboarding-v2.cjs"), exports);
|
|
94
94
|
__exportStar(require("./implementations/onboarding-v2/define-onboarding-guide-v2.cjs"), exports);
|
|
95
95
|
__exportStar(require("./implementations/onboarding-v2/onboarding-v2-validators.cjs"), exports);
|
|
96
|
+
__exportStar(require("./types/enyo-onboarding-v2-provider.cjs"), exports);
|
|
97
|
+
__exportStar(require("./packages/energy-app-onboarding-v2.cjs"), exports);
|
|
98
|
+
__exportStar(require("./implementations/onboarding-v2/onboarding-v2-provider-validators.cjs"), exports);
|
|
96
99
|
__exportStar(require("./implementations/files/define-public-file.cjs"), exports);
|
|
97
100
|
__exportStar(require("./implementations/files/public-file-validators.cjs"), exports);
|
|
98
101
|
__exportStar(require("./types/enyo-retry-manager.cjs"), exports);
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -77,6 +77,9 @@ export * from './packages/energy-app-onboarding.cjs';
|
|
|
77
77
|
export * from './types/enyo-onboarding-v2.cjs';
|
|
78
78
|
export * from './implementations/onboarding-v2/define-onboarding-guide-v2.cjs';
|
|
79
79
|
export * from './implementations/onboarding-v2/onboarding-v2-validators.cjs';
|
|
80
|
+
export * from './types/enyo-onboarding-v2-provider.cjs';
|
|
81
|
+
export * from './packages/energy-app-onboarding-v2.cjs';
|
|
82
|
+
export * from './implementations/onboarding-v2/onboarding-v2-provider-validators.cjs';
|
|
80
83
|
export * from './implementations/files/define-public-file.cjs';
|
|
81
84
|
export * from './implementations/files/public-file-validators.cjs';
|
|
82
85
|
export * from './types/enyo-retry-manager.cjs';
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { EnyoOnboardingV2GuidesRequest, EnyoOnboardingV2GuidesResult } from '../types/enyo-onboarding-v2-provider.cjs';
|
|
2
|
+
/**
|
|
3
|
+
* Handler the host calls to collect every onboarding guide (v2) an app ships.
|
|
4
|
+
*
|
|
5
|
+
* The handler builds the guides and resolves — that promise is the whole
|
|
6
|
+
* protocol. There is no per-guide save, update or delete call: each invocation
|
|
7
|
+
* returns the app's *complete* current set, and the host replaces what it knew
|
|
8
|
+
* with the answer. A guide is retired by leaving it out of the array.
|
|
9
|
+
*
|
|
10
|
+
* Answer from memory. The host owns the clock and stops waiting after
|
|
11
|
+
* {@link EnyoOnboardingV2GuidesRequest.timeoutMs}, and an abandoned handler is
|
|
12
|
+
* never told, so a handler that fetches guides over the network on every call
|
|
13
|
+
* will eventually be the reason an installer sees no guide.
|
|
14
|
+
*
|
|
15
|
+
* **`null` is not the same as an empty array.** Resolve with `null` (or reject)
|
|
16
|
+
* to say "I am not answering right now" — the host keeps whatever it cached.
|
|
17
|
+
* Resolve with an empty `guides` array to say "I genuinely have no guides" —
|
|
18
|
+
* the host drops the ones it cached. Use `null` for the transient case, never
|
|
19
|
+
* an empty array.
|
|
20
|
+
*
|
|
21
|
+
* Registering a handler requires no permission.
|
|
22
|
+
*
|
|
23
|
+
* @param request - Who is asking, the correlation id, and the time budget.
|
|
24
|
+
* @returns A promise resolving to the app's complete guide set, or `null` to
|
|
25
|
+
* leave the host's cached guides untouched.
|
|
26
|
+
*/
|
|
27
|
+
export type EnyoOnboardingV2GuidesHandler = (request: EnyoOnboardingV2GuidesRequest) => Promise<EnyoOnboardingV2GuidesResult | null>;
|
|
28
|
+
/**
|
|
29
|
+
* Interface for answering the host's "give me your v2 onboarding guides"
|
|
30
|
+
* question.
|
|
31
|
+
*
|
|
32
|
+
* Guides are **pulled, not pushed**. The app registers one handler here and the
|
|
33
|
+
* host calls it — when the package is installed or updated, when it syncs its
|
|
34
|
+
* catalog, and when an installer starts a run. The app never publishes a guide
|
|
35
|
+
* and never deletes one: it simply answers with whatever set it currently
|
|
36
|
+
* offers, and the host's picture is replaced by that answer.
|
|
37
|
+
*
|
|
38
|
+
* That inversion is the point. A guide lives in the app's source next to the
|
|
39
|
+
* code it describes, so shipping a new package version ships the corrected
|
|
40
|
+
* guide with it — there is no separate publish step to forget and no stored
|
|
41
|
+
* copy to drift out of date. It also lets the guide set be *computed*: an app
|
|
42
|
+
* can return a different variant depending on which firmware it supports, or
|
|
43
|
+
* omit a guide for hardware it no longer handles, without any host-side
|
|
44
|
+
* bookkeeping.
|
|
45
|
+
*
|
|
46
|
+
* Author the guides with `defineOnboardingGuideV2()` and check them with
|
|
47
|
+
* `validateOnboardingV2GuidesResult()` before returning — a guide with blocking
|
|
48
|
+
* errors is dropped by the host, and dropped silently is the worst way to find
|
|
49
|
+
* out.
|
|
50
|
+
*
|
|
51
|
+
* This API is available to every app — it is not permission-gated.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const guides = [
|
|
56
|
+
* defineOnboardingGuideV2({
|
|
57
|
+
* title: t('Wallbox über OCPP', 'Wallbox via OCPP'),
|
|
58
|
+
* startVariant: EnyoOnboardingV2StartVariant.ManualSetup,
|
|
59
|
+
* requiresNetworkScan: false,
|
|
60
|
+
* startStepId: 'enter-url',
|
|
61
|
+
* steps: [ ... ],
|
|
62
|
+
* vendorId: 'acme',
|
|
63
|
+
* modelIds: ['ac22'],
|
|
64
|
+
* }),
|
|
65
|
+
* ];
|
|
66
|
+
*
|
|
67
|
+
* energyApp.useOnboardingV2().registerOnboardingGuidesHandler(async (request) => {
|
|
68
|
+
* const result = {requestId: request.requestId, guides};
|
|
69
|
+
* const {ok, errors} = validateOnboardingV2GuidesResult(result, {
|
|
70
|
+
* files: packageDefinition.files,
|
|
71
|
+
* });
|
|
72
|
+
* if (!ok) {
|
|
73
|
+
* console.error('onboarding guides invalid', errors);
|
|
74
|
+
* return null; // keep whatever the host already has
|
|
75
|
+
* }
|
|
76
|
+
* return result;
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export interface EnergyAppOnboardingV2 {
|
|
81
|
+
/**
|
|
82
|
+
* Registers the handler the host calls to collect this app's v2 onboarding
|
|
83
|
+
* guides.
|
|
84
|
+
*
|
|
85
|
+
* One handler per package: registering again replaces the previous one, so a
|
|
86
|
+
* hot-reloading app does not accumulate stale handlers. Register during
|
|
87
|
+
* startup — a request that arrives before registration is answered as
|
|
88
|
+
* *nothing*, which leaves the host's cached guides in place but means a
|
|
89
|
+
* freshly installed app offers no guide until it registers.
|
|
90
|
+
*
|
|
91
|
+
* @param handler - Callback invoked once per guide request.
|
|
92
|
+
* @returns Promise that resolves once the handler is registered with the host.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* const onboarding = energyApp.useOnboardingV2();
|
|
97
|
+
* await onboarding.registerOnboardingGuidesHandler(async (request) => ({
|
|
98
|
+
* requestId: request.requestId,
|
|
99
|
+
* guides: buildGuides(),
|
|
100
|
+
* }));
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
registerOnboardingGuidesHandler(handler: EnyoOnboardingV2GuidesHandler): Promise<void>;
|
|
104
|
+
/**
|
|
105
|
+
* Removes the registered handler.
|
|
106
|
+
*
|
|
107
|
+
* After deregistration the host no longer asks this package for guides. Its
|
|
108
|
+
* cached guides are left as they were — deregistering is not a way to retire
|
|
109
|
+
* them; return an empty `guides` array for that. If no handler is registered
|
|
110
|
+
* this operation is a no-op.
|
|
111
|
+
*
|
|
112
|
+
* @returns Promise that resolves once the handler has been removed.
|
|
113
|
+
*/
|
|
114
|
+
deregisterOnboardingGuidesHandler(): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Asks the host to call the registered handler again now, instead of waiting
|
|
117
|
+
* for its next sync.
|
|
118
|
+
*
|
|
119
|
+
* For the case where the app's guide set changed after startup — a firmware
|
|
120
|
+
* capability was discovered, a vendor account was linked — and the app wants
|
|
121
|
+
* the host's picture updated without a restart. It is a request to re-pull,
|
|
122
|
+
* not a push: the host still calls the handler, and the handler still
|
|
123
|
+
* returns the complete set.
|
|
124
|
+
*
|
|
125
|
+
* @returns Promise that resolves once the host has taken the new answer.
|
|
126
|
+
*/
|
|
127
|
+
refreshOnboardingGuides(): Promise<void>;
|
|
128
|
+
}
|
|
@@ -6,10 +6,15 @@ import { EnyoOnboardingGuide, EnyoOnboardingGuideCategory, EnyoOnboardingStep, E
|
|
|
6
6
|
* Supports multiple parallel guides identified by their unique guideName.
|
|
7
7
|
*
|
|
8
8
|
* @deprecated This runtime surface operates on the v1 {@link EnyoOnboardingGuide}
|
|
9
|
-
* model
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* model, and on the push lifecycle that goes with it — the app saves, updates and
|
|
10
|
+
* removes guides, and the host stores a copy that can drift.
|
|
11
|
+
*
|
|
12
|
+
* New guides are authored with the v2 graph model
|
|
13
|
+
* ({@link EnyoOnboardingV2Guide} / `defineOnboardingGuideV2()`) and served
|
|
14
|
+
* through {@link EnergyAppOnboardingV2}, which inverts the direction: the app
|
|
15
|
+
* registers one handler and the host calls it for the complete set. There is
|
|
16
|
+
* deliberately no `saveOnboardingGuideV2` — nothing to publish, nothing to keep
|
|
17
|
+
* in sync. v1 remains supported for backward compatibility.
|
|
13
18
|
*/
|
|
14
19
|
export interface EnergyAppOnboarding {
|
|
15
20
|
/**
|
|
@@ -30,8 +35,10 @@ export interface EnergyAppOnboarding {
|
|
|
30
35
|
* });
|
|
31
36
|
* ```
|
|
32
37
|
*
|
|
33
|
-
* @deprecated Saves a v1 {@link EnyoOnboardingGuide}.
|
|
34
|
-
*
|
|
38
|
+
* @deprecated Saves a v1 {@link EnyoOnboardingGuide}. v2 guides are not saved
|
|
39
|
+
* at all — register a handler with
|
|
40
|
+
* {@link EnergyAppOnboardingV2.registerOnboardingGuidesHandler} and return
|
|
41
|
+
* them when the host asks.
|
|
35
42
|
*/
|
|
36
43
|
saveOnboardingGuide(guide: EnyoOnboardingGuide): Promise<void>;
|
|
37
44
|
/**
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Onboarding guide **v2 provisioning** — the host asking an energy app to hand
|
|
4
|
+
* over the guides it ships.
|
|
5
|
+
*
|
|
6
|
+
* This inverts how guides used to reach enyo. Previously an app *pushed* its
|
|
7
|
+
* guides out (the v1 {@link EnergyAppOnboarding.saveOnboardingGuide} surface,
|
|
8
|
+
* and the guide editor's create/update calls): the app decided when to publish,
|
|
9
|
+
* the host stored a copy, and the two could drift — a guide fixed in the app's
|
|
10
|
+
* source stayed stale on the host until someone remembered to re-publish it.
|
|
11
|
+
*
|
|
12
|
+
* The v2 model *pulls* instead. The app registers one handler
|
|
13
|
+
* ({@link EnyoOnboardingV2GuidesHandler}) and the host calls it with
|
|
14
|
+
* "give me your v2 onboarding guides". The app answers with **all** of them or
|
|
15
|
+
* with **nothing** — there is no partial answer and no per-guide lifecycle to
|
|
16
|
+
* keep in sync, because every call replaces the host's whole picture of what
|
|
17
|
+
* this app offers. Deleting a guide is deleting it from the returned array.
|
|
18
|
+
*
|
|
19
|
+
* The app is the single source of truth; the host caches at most a snapshot of
|
|
20
|
+
* the last answer.
|
|
21
|
+
*
|
|
22
|
+
* Pure type declarations (no runtime logic). Register the handler through
|
|
23
|
+
* {@link EnergyAppOnboardingV2} (`../packages/energy-app-onboarding-v2.ts`) and
|
|
24
|
+
* check an answer before returning it with `validateOnboardingV2GuidesResult()`
|
|
25
|
+
* (`../implementations/onboarding-v2/onboarding-v2-provider-validators.ts`).
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.EnyoOnboardingV2GuidesOriginEnum = void 0;
|
|
29
|
+
/**
|
|
30
|
+
* Who asked for the guides. One handler serves every caller, so an app builds
|
|
31
|
+
* its guides once; this field exists so an app can tell a routine catalog
|
|
32
|
+
* refresh apart from a request made while an installer is standing in front of
|
|
33
|
+
* a device.
|
|
34
|
+
*/
|
|
35
|
+
var EnyoOnboardingV2GuidesOriginEnum;
|
|
36
|
+
(function (EnyoOnboardingV2GuidesOriginEnum) {
|
|
37
|
+
/**
|
|
38
|
+
* The host is refreshing its catalog of what this app offers — on install,
|
|
39
|
+
* on update, or on a periodic sync. Not time-critical, and nobody is
|
|
40
|
+
* waiting on a screen.
|
|
41
|
+
*/
|
|
42
|
+
EnyoOnboardingV2GuidesOriginEnum["CatalogSync"] = "catalog-sync";
|
|
43
|
+
/**
|
|
44
|
+
* An installer is starting an onboarding run and the host needs the current
|
|
45
|
+
* guide for the device in front of them. Answer fast: this call is on the
|
|
46
|
+
* critical path of a screen.
|
|
47
|
+
*/
|
|
48
|
+
EnyoOnboardingV2GuidesOriginEnum["OnboardingStart"] = "onboarding-start";
|
|
49
|
+
/** A user or support agent explicitly asked the host to re-read the guides. */
|
|
50
|
+
EnyoOnboardingV2GuidesOriginEnum["UserRequest"] = "user-request";
|
|
51
|
+
})(EnyoOnboardingV2GuidesOriginEnum || (exports.EnyoOnboardingV2GuidesOriginEnum = EnyoOnboardingV2GuidesOriginEnum = {}));
|