@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.
Files changed (30) hide show
  1. package/README.md +30 -1
  2. package/dist/cjs/energy-app.cjs +14 -0
  3. package/dist/cjs/energy-app.d.cts +13 -0
  4. package/dist/cjs/enyo-energy-app-sdk.d.cts +3 -0
  5. package/dist/cjs/implementations/onboarding-v2/onboarding-v2-provider-validators.cjs +167 -0
  6. package/dist/cjs/implementations/onboarding-v2/onboarding-v2-provider-validators.d.cts +86 -0
  7. package/dist/cjs/index.cjs +3 -0
  8. package/dist/cjs/index.d.cts +3 -0
  9. package/dist/cjs/packages/energy-app-onboarding-v2.cjs +2 -0
  10. package/dist/cjs/packages/energy-app-onboarding-v2.d.cts +128 -0
  11. package/dist/cjs/packages/energy-app-onboarding.d.cts +13 -6
  12. package/dist/cjs/types/enyo-onboarding-v2-provider.cjs +51 -0
  13. package/dist/cjs/types/enyo-onboarding-v2-provider.d.cts +105 -0
  14. package/dist/cjs/version.cjs +1 -1
  15. package/dist/cjs/version.d.cts +1 -1
  16. package/dist/energy-app.d.ts +13 -0
  17. package/dist/energy-app.js +14 -0
  18. package/dist/enyo-energy-app-sdk.d.ts +3 -0
  19. package/dist/implementations/onboarding-v2/onboarding-v2-provider-validators.d.ts +86 -0
  20. package/dist/implementations/onboarding-v2/onboarding-v2-provider-validators.js +161 -0
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.js +3 -0
  23. package/dist/packages/energy-app-onboarding-v2.d.ts +128 -0
  24. package/dist/packages/energy-app-onboarding-v2.js +1 -0
  25. package/dist/packages/energy-app-onboarding.d.ts +13 -6
  26. package/dist/types/enyo-onboarding-v2-provider.d.ts +105 -0
  27. package/dist/types/enyo-onboarding-v2-provider.js +48 -0
  28. package/dist/version.d.ts +1 -1
  29. package/dist/version.js +1 -1
  30. 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
- | Drive a multi-step onboarding flow | [`useOnboarding()`](#useonboarding-energyapponboarding) |
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
@@ -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;
@@ -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);
@@ -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,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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. New guides should be authored with the v2 graph model
10
- * ({@link EnyoOnboardingV2Guide} / `defineOnboardingGuideV2()`); a v2 runtime
11
- * method (`saveOnboardingGuideV2`) will be added in a follow-up task. v1 remains
12
- * supported for backward compatibility.
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}. A v2 equivalent
34
- * (`saveOnboardingGuideV2`) accepting {@link EnyoOnboardingV2Guide} is planned.
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 = {}));