@nebulahome/package-sdk 1.4.0 → 1.6.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/CHANGELOG.md +27 -0
- package/README.md +67 -10
- package/dist/chunks/context.d.ts +37 -1
- package/dist/chunks/node-build.js +2 -1
- package/dist/chunks/node-config.js +14 -4
- package/dist/chunks/props.d.ts +5 -1
- package/dist/chunks/version.js +1 -1
- package/dist/index.d.ts +21 -2
- package/dist/index.js +17 -1
- package/dist/server.d.ts +2 -2
- package/dist/testing.d.ts +18 -1
- package/dist/testing.js +277 -185
- package/dist/ui.d.ts +66 -2
- package/dist/ui.js +34 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,33 @@
|
|
|
3
3
|
The SDK's version is the version of the package API the platform implements: a minor version adds
|
|
4
4
|
to it, a major one breaks it, and a patch leaves it as it is.
|
|
5
5
|
|
|
6
|
+
## 1.6.0
|
|
7
|
+
|
|
8
|
+
- **The background.** `ui.background: defineBackground({ component, description })` is a
|
|
9
|
+
component the interface draws on every page, out of sight, for as long as somebody is signed in
|
|
10
|
+
and the package runs - for what must outlive a page, sound playing in the browser above all. It
|
|
11
|
+
is unmounted when the package stops, is turned off or removed, and mounted afresh by an update,
|
|
12
|
+
so what it starts belongs in effects. Its `description` (1-256 characters) is shown on the
|
|
13
|
+
package's page; the manifest records it as `ui.background`.
|
|
14
|
+
- **`<Floating open label onClose?>`** draws a window of the package over the interface's pages,
|
|
15
|
+
from its background, page or card: in a corner of the page beside the rail, thrown from corner to
|
|
16
|
+
corner with a small bounce, one a package, hidden on the package's own page and on a phone.
|
|
17
|
+
`onClose` gives it a close button and says what closing does.
|
|
18
|
+
|
|
19
|
+
## 1.5.0
|
|
20
|
+
|
|
21
|
+
- **The live channel.** A package's server and its open interfaces talk over the interface's own
|
|
22
|
+
socket, both ways, with no polling and no HTTP rate limit. On the server
|
|
23
|
+
`ctx.live.publish(topic, data, { isRetained })` sends to every interface following the topic -
|
|
24
|
+
a retained message is handed at once to whoever follows it later - and
|
|
25
|
+
`ctx.live.onMessage(topic, { input }, handler)` hears what they send, with who sent it. In the
|
|
26
|
+
interface `usePackageLive(topic)` follows a topic (one subscription however many components
|
|
27
|
+
follow it) and `usePackageSend()` sends. Whoever may read packages may follow and send. Topics
|
|
28
|
+
are a letter, then letters, digits and `.`, `_`, `:`, `-`; a message is at most 1 MB from the
|
|
29
|
+
server, 64 KB from an interface, which sends at most 50 a second.
|
|
30
|
+
- `createTestContext()` records what is published (`published`) and sends a message as the
|
|
31
|
+
interface would (`sendLive`).
|
|
32
|
+
|
|
6
33
|
## 1.4.0
|
|
7
34
|
|
|
8
35
|
- **Toasts.** `useToast()` from `@nebulahome/package-sdk/ui` shows the interface's own toasts -
|
package/README.md
CHANGED
|
@@ -156,18 +156,75 @@ try {
|
|
|
156
156
|
}
|
|
157
157
|
```
|
|
158
158
|
|
|
159
|
+
## The live channel
|
|
160
|
+
|
|
161
|
+
Messages between the server and its open interfaces over the interface's own socket, both ways,
|
|
162
|
+
with no polling and no HTTP rate limit (since 1.5). Whoever may read packages follows and sends.
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
// on the server: what every page and card draws, kept for whoever opens one later
|
|
166
|
+
ctx.live.publish('overview', overviewOf(), { isRetained: true });
|
|
167
|
+
|
|
168
|
+
// and what the interface sends, with who sent it
|
|
169
|
+
ctx.live.onMessage('player.report', { input: reportSchema }, (report, { caller }) => {
|
|
170
|
+
ctx.live.publish(`player.${report.playerId}`, orderFor(report));
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
const { data, isConnected } = usePackageLive<Overview>('overview'); // one subscription per page
|
|
176
|
+
const send = usePackageSend();
|
|
177
|
+
|
|
178
|
+
send('player.report', { playerId, position });
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
A topic is a letter, then letters, digits and `.`, `_`, `:`, `-`; a message from the server is at
|
|
182
|
+
most 1 MB as JSON, one from the interface 64 KB, and an interface sends at most 50 a second.
|
|
183
|
+
Nothing answers a message: a call that wants an answer or an error stays `usePackageCall`.
|
|
184
|
+
|
|
185
|
+
## The background and floating windows
|
|
186
|
+
|
|
187
|
+
A component drawn on every page for as long as somebody is signed in and the package runs, for
|
|
188
|
+
what must outlive a page, and a window floating over the pages (since 1.6):
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
// nebula.config.ts
|
|
192
|
+
ui: {
|
|
193
|
+
background: defineBackground({
|
|
194
|
+
component: () => import('./src/ui/background.js'),
|
|
195
|
+
description: 'Keeps music playing in this browser when you leave the Music page.',
|
|
196
|
+
}),
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
// src/ui/background.tsx: every hook works here; start things in effects, the unmount stops them
|
|
202
|
+
export default function Background() {
|
|
203
|
+
const { t } = useTranslation();
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<Floating open={isPlaying} label={t('mini.label', 'Now playing')}>
|
|
207
|
+
<MiniPlayer />
|
|
208
|
+
</Floating>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The window rests in a corner of the page beside the rail and is thrown from corner to corner; it is
|
|
214
|
+
hidden on the package's own page and on a phone. `onClose` gives it a close button.
|
|
215
|
+
|
|
159
216
|
## Entry points
|
|
160
217
|
|
|
161
|
-
| Import | What
|
|
162
|
-
| ------------------------- |
|
|
163
|
-
| `@nebulahome/package-sdk` | `definePackage`, `defineSettings`, `defineCard`, `defineEntityType`, `definePage`, `defineContainer`, `defineCompose`, `field`, entity id helpers, `SDK_VERSION`, the value types.
|
|
164
|
-
| `/server` | `defineServer`, and the context `start` is given: settings (live or restart), devices and entities, typed custom entities, the rest of the house and its past, methods for the interface, services between packages.
|
|
165
|
-
| `/ui` | The props of a page, a card and an entity view; hooks for the package, its methods, its settings, the house, its areas, its past and its pictures, the viewer, the theme, its strings; navigation inside the package's page and the platform's. |
|
|
166
|
-
| `/sun` | Where the sun is at any moment, by the platform's own formulas.
|
|
167
|
-
| `/components` | The part of the interface's design system a package may draw with.
|
|
168
|
-
| `/vite` | `nebula()`, the Vite plugin that builds both halves: the interface in chunks with its CSS scoped to the package, the server bundled whole.
|
|
169
|
-
| `/testing` | `createTestContext()`: run `start` in a unit test, every effect recorded.
|
|
170
|
-
| `/styles.css` | The interface's Tailwind tokens, to `@reference`.
|
|
218
|
+
| Import | What |
|
|
219
|
+
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
220
|
+
| `@nebulahome/package-sdk` | `definePackage`, `defineSettings`, `defineCard`, `defineEntityType`, `definePage`, `defineBackground`, `defineContainer`, `defineCompose`, `field`, entity id helpers, `SDK_VERSION`, the value types. |
|
|
221
|
+
| `/server` | `defineServer`, and the context `start` is given: settings (live or restart), devices and entities, typed custom entities, the rest of the house and its past, methods and the live channel for the interface, services between packages. |
|
|
222
|
+
| `/ui` | The props of a page, a background, a card and an entity view; `Floating`; hooks for the package, its methods and live topics, its settings, the house, its areas, its past and its pictures, the viewer, the theme, its strings; navigation inside the package's page and the platform's. |
|
|
223
|
+
| `/sun` | Where the sun is at any moment, by the platform's own formulas. |
|
|
224
|
+
| `/components` | The part of the interface's design system a package may draw with. |
|
|
225
|
+
| `/vite` | `nebula()`, the Vite plugin that builds both halves: the interface in chunks with its CSS scoped to the package, the server bundled whole. |
|
|
226
|
+
| `/testing` | `createTestContext()`: run `start` in a unit test, every effect recorded. |
|
|
227
|
+
| `/styles.css` | The interface's Tailwind tokens, to `@reference`. |
|
|
171
228
|
|
|
172
229
|
The `nebulahome-package` command checks, builds and packs a package:
|
|
173
230
|
|
package/dist/chunks/context.d.ts
CHANGED
|
@@ -255,6 +255,25 @@ type RpcMethod = {
|
|
|
255
255
|
readonly input: Schema<TInput>;
|
|
256
256
|
}, handler: (input: TInput, call: RpcCall) => Awaitable<JsonValue | undefined>): void;
|
|
257
257
|
};
|
|
258
|
+
/** How a live message is sent. Since 1.5. */
|
|
259
|
+
type LivePublishOptions = {
|
|
260
|
+
/**
|
|
261
|
+
* Kept by the platform, and handed at once to an interface that follows the topic later, until
|
|
262
|
+
* the next retained message on it replaces it: for the state a page draws. Off by default.
|
|
263
|
+
*/
|
|
264
|
+
readonly isRetained?: boolean;
|
|
265
|
+
};
|
|
266
|
+
/** What a live message's handler is told besides the message: who sent it. Since 1.5. */
|
|
267
|
+
type LiveCall = {
|
|
268
|
+
readonly caller: RpcCaller;
|
|
269
|
+
};
|
|
270
|
+
/** Hearing one topic of the package's interfaces' live messages. Since 1.5. */
|
|
271
|
+
type LiveOnMessage = {
|
|
272
|
+
(topic: string, handler: (data: JsonValue, call: LiveCall) => Awaitable<void>): Unsubscribe;
|
|
273
|
+
<TInput>(topic: string, options: {
|
|
274
|
+
readonly input: Schema<TInput>;
|
|
275
|
+
}, handler: (data: TInput, call: LiveCall) => Awaitable<void>): Unsubscribe;
|
|
276
|
+
};
|
|
258
277
|
/** Offering a service. */
|
|
259
278
|
type ServiceProvide = {
|
|
260
279
|
(name: string, handler: (input: unknown, call: ServiceCall) => Awaitable<JsonValue | undefined>): void;
|
|
@@ -403,6 +422,23 @@ type ServerContext<TSettings = undefined> = {
|
|
|
403
422
|
/** Registers a method its interface calls; a name registered twice throws. */
|
|
404
423
|
readonly method: RpcMethod;
|
|
405
424
|
};
|
|
425
|
+
/**
|
|
426
|
+
* The live channel to its open interfaces, over the interface's own socket: no polling, no
|
|
427
|
+
* HTTP rate limit. Whoever may read packages hears it and may send to it. Since 1.5.
|
|
428
|
+
*/
|
|
429
|
+
readonly live: {
|
|
430
|
+
/**
|
|
431
|
+
* Sends a message to every open interface following the topic. A topic is a letter, then
|
|
432
|
+
* letters, digits and `.`, `_`, `:`, `-` (128 at most); a message is at most 1 MB as JSON.
|
|
433
|
+
* One that is not is logged, not sent.
|
|
434
|
+
*/
|
|
435
|
+
readonly publish: (topic: string, data: JsonValue, options?: LivePublishOptions) => void;
|
|
436
|
+
/**
|
|
437
|
+
* Hears what its interfaces send on a topic (`usePackageSend`); a topic heard twice throws.
|
|
438
|
+
* A message its schema refuses is logged and dropped: nobody waits for an answer.
|
|
439
|
+
*/
|
|
440
|
+
readonly onMessage: LiveOnMessage;
|
|
441
|
+
};
|
|
406
442
|
readonly services: {
|
|
407
443
|
/** Answers a service other packages call; a name provided twice, or reserved, throws. */
|
|
408
444
|
readonly provide: ServiceProvide;
|
|
@@ -411,4 +447,4 @@ type ServerContext<TSettings = undefined> = {
|
|
|
411
447
|
};
|
|
412
448
|
};
|
|
413
449
|
//#endregion
|
|
414
|
-
export {
|
|
450
|
+
export { TelemetryRead as A, ServerSettings as C, SettingsChange as D, ServiceProvide as E, StandardResult as F, StandardSchemaV1 as I, SafeParser as M, Schema as N, StateChange as O, SchemaIssue as P, ServerContext as S, ServiceCallFunction as T, ReportOptions as _, CustomEntityInput as a, RpcCaller as b, EntityInput as c, HistoryRead as d, LiveCall as f, Logger as g, LogMethod as h, CustomEntities as i, Unsubscribe as j, SyncResult as k, EntitySnapshot as l, LivePublishOptions as m, CapabilityEntityInput as n, DeviceInput as o, LiveOnMessage as p, CustomCommand as r, EntityFilter as s, Awaitable as t, HistoryAnswer as u, RpcAccess as v, ServiceCall as w, RpcMethod as x, RpcCall as y };
|
|
@@ -6850,7 +6850,7 @@ function composeFileProblems(text, settingKeys) {
|
|
|
6850
6850
|
* the two are compared before a package is installed or started (PACKAGES_DOCS.md 11).
|
|
6851
6851
|
*/
|
|
6852
6852
|
/** The SDK's own version, `1.0.0`. */
|
|
6853
|
-
const SDK_VERSION = "1.
|
|
6853
|
+
const SDK_VERSION = "1.6.0";
|
|
6854
6854
|
//#endregion
|
|
6855
6855
|
//#region src/vite/catalogues.ts
|
|
6856
6856
|
/**
|
|
@@ -12911,6 +12911,7 @@ function uiEntryCode(configPath, catalogues) {
|
|
|
12911
12911
|
" kind: 'nebula.ui',",
|
|
12912
12912
|
` sdk: ${JSON.stringify(SDK_VERSION)},`,
|
|
12913
12913
|
" page: ui.page?.component,",
|
|
12914
|
+
" background: ui.background?.component,",
|
|
12914
12915
|
" cards: ui.cards ?? {},",
|
|
12915
12916
|
" entityViews: ui.entityViews ?? {},",
|
|
12916
12917
|
" locales: {",
|
|
@@ -6313,7 +6313,12 @@ const packageUiSchema = strictObject({
|
|
|
6313
6313
|
/** The cards it adds to the dashboard editor. */
|
|
6314
6314
|
cards: array(packageCardSchema).max(16).default([]),
|
|
6315
6315
|
/** Which of its entity types it draws itself, on an entity's page. */
|
|
6316
|
-
entityViews: array(localIdSchema).max(16).default([])
|
|
6316
|
+
entityViews: array(localIdSchema).max(16).default([]),
|
|
6317
|
+
/**
|
|
6318
|
+
* A component it draws on every page, for as long as somebody is signed in, and what it does in
|
|
6319
|
+
* a sentence its page shows. Since package SDK 1.6.
|
|
6320
|
+
*/
|
|
6321
|
+
background: strictObject({ description: string().min(1).max(256) }).nullable().default(null)
|
|
6317
6322
|
});
|
|
6318
6323
|
/**
|
|
6319
6324
|
* The words that appear more than once in a list.
|
|
@@ -6736,15 +6741,18 @@ function containersOf(containers, found) {
|
|
|
6736
6741
|
* @param cardIds - The ids of the declared cards.
|
|
6737
6742
|
* @param typeIds - The ids of the declared entity types.
|
|
6738
6743
|
* @param found - Where problems go.
|
|
6739
|
-
* @returns Whether it has a page, its sidebar entry, and the types it draws.
|
|
6744
|
+
* @returns Whether it has a page, its sidebar entry, its background, and the types it draws.
|
|
6740
6745
|
*/
|
|
6741
6746
|
function boundUi(ui, cardIds, typeIds, found) {
|
|
6742
6747
|
const bound = isRecord(ui) ? ui : {};
|
|
6743
6748
|
const page = bound["page"];
|
|
6749
|
+
const background = bound["background"];
|
|
6744
6750
|
const cards = isRecord(bound["cards"]) ? bound["cards"] : {};
|
|
6745
6751
|
const views = isRecord(bound["entityViews"]) ? bound["entityViews"] : {};
|
|
6746
6752
|
if (page !== void 0 && (!isRecord(page) || page["kind"] !== "page")) found.add("ui.page", "must be a page, declared with definePage");
|
|
6747
6753
|
if (isRecord(page) && typeof page["component"] !== "function") found.add("ui.page.component", "must load the page's component: () => import('./page.js')");
|
|
6754
|
+
if (background !== void 0 && (!isRecord(background) || background["kind"] !== "background")) found.add("ui.background", "must be a background, declared with defineBackground");
|
|
6755
|
+
if (isRecord(background) && typeof background["component"] !== "function") found.add("ui.background.component", "must load the background's component: () => import('./background.js')");
|
|
6748
6756
|
for (const id of cardIds) if (typeof cards[id] !== "function") found.add(`ui.cards.${id}`, "the card has no component: () => import('./card.js')");
|
|
6749
6757
|
for (const id of Object.keys(cards).filter((each) => !cardIds.includes(each))) found.add(`ui.cards.${id}`, "is not one of the declared cards");
|
|
6750
6758
|
for (const [id, loader] of Object.entries(views)) if (!typeIds.includes(id)) found.add(`ui.entityViews.${id}`, "is not one of the declared entity types");
|
|
@@ -6753,8 +6761,9 @@ function boundUi(ui, cardIds, typeIds, found) {
|
|
|
6753
6761
|
return {
|
|
6754
6762
|
page: isRecord(page),
|
|
6755
6763
|
sidebar: isRecord(page) ? page["sidebar"] : void 0,
|
|
6764
|
+
background: isRecord(background) ? { description: background["description"] } : null,
|
|
6756
6765
|
entityViews,
|
|
6757
|
-
hasUi: isRecord(page) || cardIds.length > 0 || entityViews.length > 0
|
|
6766
|
+
hasUi: isRecord(page) || isRecord(background) || cardIds.length > 0 || entityViews.length > 0
|
|
6758
6767
|
};
|
|
6759
6768
|
}
|
|
6760
6769
|
/**
|
|
@@ -6821,7 +6830,8 @@ function generatePackage(definition, options) {
|
|
|
6821
6830
|
page: ui.page,
|
|
6822
6831
|
...ui.sidebar === void 0 ? {} : { sidebar: ui.sidebar },
|
|
6823
6832
|
cards,
|
|
6824
|
-
entityViews: ui.entityViews
|
|
6833
|
+
entityViews: ui.entityViews,
|
|
6834
|
+
...ui.background === null ? {} : { background: ui.background }
|
|
6825
6835
|
} } : {},
|
|
6826
6836
|
...settingFields.length > 0 ? { setup: releasePath(RELEASE_PATHS.setup) } : {},
|
|
6827
6837
|
containers,
|
package/dist/chunks/props.d.ts
CHANGED
|
@@ -43,6 +43,10 @@ type Loader<TProps> = () => Promise<PackageComponent<TProps> | {
|
|
|
43
43
|
type PageProps = {
|
|
44
44
|
readonly packageId: string;
|
|
45
45
|
};
|
|
46
|
+
/** What the package's background is given. Since 1.6. */
|
|
47
|
+
type BackgroundProps = {
|
|
48
|
+
readonly packageId: string;
|
|
49
|
+
};
|
|
46
50
|
/** What a card is given. */
|
|
47
51
|
type CardProps<TCard extends CardDefinition = CardDefinition> = {
|
|
48
52
|
readonly packageId: string;
|
|
@@ -65,4 +69,4 @@ type EntityViewProps<TType extends EntityTypeDefinition = EntityTypeDefinition>
|
|
|
65
69
|
readonly type: TType['id'];
|
|
66
70
|
};
|
|
67
71
|
//#endregion
|
|
68
|
-
export {
|
|
72
|
+
export { PackageComponent as a, CardPadding as c, SizeOf as d, defineCard as f, Loader as i, CardSize as l, CardProps as n, PageProps as o, EntityViewProps as r, CardDefinition as s, BackgroundProps as t, OptionsOf as u };
|
package/dist/chunks/version.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
import { $ as PlaybackState, A as SecretOptions, B as field, C as ListField, D as NumberOptions, E as NumberField, F as TextOptions, G as CapabilityState, H as CapabilityCommands, I as TimestampField, J as CustomValue, K as CapabilityStates, L as TimestampOptions, M as ShownWhen, N as Simplify, O as OptionField, P as TextField, Q as LawnMowerActivity, R as ValueField, S as FormValues, T as NoFields, U as CapabilityName, V as CapabilityCommand, W as CapabilityParams, X as EntityStateClass, Y as DeclaredCapabilities, Z as ImageContentType, _ as ChoiceOption, a as SettingsOf, at as VacuumActivity, b as Field, c as CommandDeclaration, ct as EntityDomain, d as EntityTypeDefinition, dt as isEntityId, et as ReportedCapabilityState, f as ValuesOf, ft as parseEntityId, g as ChoiceField, h as BooleanOptions, i as SettingsDefinition, it as ThermostatMode, j as SettingField, k as SecretField, l as CommandDeclarations, lt as EntityId, m as BooleanField, n as JsonPrimitive, nt as SelectOption, o as defineSettings, ot as VacuumRoom, p as defineEntityType, q as CommandableCapability, r as JsonValue, rt as ThermostatAction, s as ArgsOf, st as ENTITY_DOMAINS, t as JsonObject, tt as ReportedStates, u as CommandsOf, ut as ParsedEntityId, v as ChoiceOptions, w as ListOptions, x as Fields, y as EntityValues, z as ValueOfField } from "./chunks/json.js";
|
|
2
|
-
import { a as
|
|
2
|
+
import { a as PackageComponent, c as CardPadding, d as SizeOf, f as defineCard, i as Loader, l as CardSize, n as CardProps, o as PageProps, r as EntityViewProps, s as CardDefinition, t as BackgroundProps, u as OptionsOf } from "./chunks/props.js";
|
|
3
|
+
//#region src/definitions/background.d.ts
|
|
4
|
+
/** The package's background, as declared. */
|
|
5
|
+
type BackgroundDefinition = {
|
|
6
|
+
readonly kind: 'background';
|
|
7
|
+
readonly component: Loader<BackgroundProps>;
|
|
8
|
+
/** What it does, in a sentence the package's page shows. At most 256 characters. */
|
|
9
|
+
readonly description: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Declares the package's background. A package has at most one: `ui.background` is a single
|
|
13
|
+
* field.
|
|
14
|
+
*
|
|
15
|
+
* @param background - Its component's loader, and what it does.
|
|
16
|
+
* @returns The background, for `definePackage`'s `ui.background`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function defineBackground(background: Omit<BackgroundDefinition, 'kind'>): BackgroundDefinition;
|
|
19
|
+
//#endregion
|
|
3
20
|
//#region src/definitions/containers.d.ts
|
|
4
21
|
/**
|
|
5
22
|
* `defineContainer` and `defineCompose`: what a package runs beside or instead of its process
|
|
@@ -145,6 +162,8 @@ type PackageRequires = {
|
|
|
145
162
|
type PackageUi<TCards extends readonly CardDefinition[], TTypes extends readonly EntityTypeDefinition[]> = {
|
|
146
163
|
/** Its own page. */
|
|
147
164
|
readonly page?: PageDefinition;
|
|
165
|
+
/** What it draws on every page, for as long as somebody is signed in. Since 1.6. */
|
|
166
|
+
readonly background?: BackgroundDefinition;
|
|
148
167
|
/** A component for every declared card, by its id. */
|
|
149
168
|
readonly cards?: { readonly [TId in TCards[number]['id']]: Loader<CardPropsFor<TCards, TId>>; };
|
|
150
169
|
/** Views of the entity types it draws itself, by their ids. */
|
|
@@ -202,4 +221,4 @@ export declare function definePackage<const TCards extends readonly CardDefiniti
|
|
|
202
221
|
/** The SDK's own version, `1.0.0`. */
|
|
203
222
|
export declare const SDK_VERSION: string;
|
|
204
223
|
//#endregion
|
|
205
|
-
export { type ArgsOf, type BooleanField, type BooleanOptions, type CapabilityCommand, type CapabilityCommands, type CapabilityName, type CapabilityParams, type CapabilityState, type CapabilityStates, type CardDefinition, type CardPadding, type CardProps, type CardSize, type ChoiceField, type ChoiceOption, type ChoiceOptions, type CommandDeclaration, type CommandDeclarations, type CommandableCapability, type CommandsOf, type ComposeDefinition, type ContainerCondition, type ContainerDefinition, type ContainerPort, type CustomValue, type DeclaredCapabilities, ENTITY_DOMAINS, type EntityDomain, type EntityId, type EntityStateClass, type EntityTypeDefinition, type EntityValues, type EntityViewProps, type Field, type Fields, type FormValues, type ImageContentType, type JsonObject, type JsonPrimitive, type JsonValue, type LawnMowerActivity, type ListField, type ListOptions, type Loader, type NoFields, type NumberField, type NumberOptions, type OptionField, type OptionsOf, type PackageCategory, type PackageComponent, type PackageConfig, type PackageDefinition, type PackageRequires, type PackageUi, type PageDefinition, type PageProps, type ParsedEntityId, type PlaybackState, type ReportedCapabilityState, type ReportedStates, type SecretField, type SecretOptions, type SelectOption, type SettingField, type SettingPlaceholder, type SettingsDefinition, type SettingsOf, type ShownWhen, type SidebarEntry, type Simplify, type SizeOf, type TextField, type TextOptions, type ThermostatAction, type ThermostatMode, type TimestampField, type TimestampOptions, type VacuumActivity, type VacuumRoom, type ValueField, type ValueOfField, type ValuesOf, type When, defineCard, defineEntityType, defineSettings, field, isEntityId, parseEntityId };
|
|
224
|
+
export { type ArgsOf, type BackgroundDefinition, type BackgroundProps, type BooleanField, type BooleanOptions, type CapabilityCommand, type CapabilityCommands, type CapabilityName, type CapabilityParams, type CapabilityState, type CapabilityStates, type CardDefinition, type CardPadding, type CardProps, type CardSize, type ChoiceField, type ChoiceOption, type ChoiceOptions, type CommandDeclaration, type CommandDeclarations, type CommandableCapability, type CommandsOf, type ComposeDefinition, type ContainerCondition, type ContainerDefinition, type ContainerPort, type CustomValue, type DeclaredCapabilities, ENTITY_DOMAINS, type EntityDomain, type EntityId, type EntityStateClass, type EntityTypeDefinition, type EntityValues, type EntityViewProps, type Field, type Fields, type FormValues, type ImageContentType, type JsonObject, type JsonPrimitive, type JsonValue, type LawnMowerActivity, type ListField, type ListOptions, type Loader, type NoFields, type NumberField, type NumberOptions, type OptionField, type OptionsOf, type PackageCategory, type PackageComponent, type PackageConfig, type PackageDefinition, type PackageRequires, type PackageUi, type PageDefinition, type PageProps, type ParsedEntityId, type PlaybackState, type ReportedCapabilityState, type ReportedStates, type SecretField, type SecretOptions, type SelectOption, type SettingField, type SettingPlaceholder, type SettingsDefinition, type SettingsOf, type ShownWhen, type SidebarEntry, type Simplify, type SizeOf, type TextField, type TextOptions, type ThermostatAction, type ThermostatMode, type TimestampField, type TimestampOptions, type VacuumActivity, type VacuumRoom, type ValueField, type ValueOfField, type ValuesOf, type When, defineCard, defineEntityType, defineSettings, field, isEntityId, parseEntityId };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
import { t as SDK_VERSION } from "./chunks/version.js";
|
|
2
|
+
//#region src/definitions/background.ts
|
|
3
|
+
/**
|
|
4
|
+
* Declares the package's background. A package has at most one: `ui.background` is a single
|
|
5
|
+
* field.
|
|
6
|
+
*
|
|
7
|
+
* @param background - Its component's loader, and what it does.
|
|
8
|
+
* @returns The background, for `definePackage`'s `ui.background`.
|
|
9
|
+
*/
|
|
10
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
11
|
+
function defineBackground(background) {
|
|
12
|
+
return {
|
|
13
|
+
...background,
|
|
14
|
+
kind: "background"
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
2
18
|
//#region src/definitions/card.ts
|
|
3
19
|
/**
|
|
4
20
|
* Declares a card.
|
|
@@ -240,4 +256,4 @@ const field = {
|
|
|
240
256
|
})
|
|
241
257
|
};
|
|
242
258
|
//#endregion
|
|
243
|
-
export { ENTITY_DOMAINS, SDK_VERSION, defineCard, defineCompose, defineContainer, defineEntityType, definePackage, definePage, defineSettings, field, isEntityId, parseEntityId };
|
|
259
|
+
export { ENTITY_DOMAINS, SDK_VERSION, defineBackground, defineCard, defineCompose, defineContainer, defineEntityType, definePackage, definePage, defineSettings, field, isEntityId, parseEntityId };
|
package/dist/server.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as SettingsDefinition } from "./chunks/json.js";
|
|
2
2
|
import { a as TelemetryResolution, i as TelemetryPoint, n as HistorySeries, r as StateHistoryPoint, t as ChangeCause } from "./chunks/history.js";
|
|
3
|
-
import { A as
|
|
3
|
+
import { A as TelemetryRead, C as ServerSettings, D as SettingsChange, E as ServiceProvide, F as StandardResult, I as StandardSchemaV1, M as SafeParser, N as Schema, O as StateChange, P as SchemaIssue, S as ServerContext, T as ServiceCallFunction, _ as ReportOptions, a as CustomEntityInput, b as RpcCaller, c as EntityInput, d as HistoryRead, f as LiveCall, g as Logger, h as LogMethod, i as CustomEntities, j as Unsubscribe, k as SyncResult, l as EntitySnapshot, m as LivePublishOptions, n as CapabilityEntityInput, o as DeviceInput, p as LiveOnMessage, r as CustomCommand, s as EntityFilter, t as Awaitable, u as HistoryAnswer, v as RpcAccess, w as ServiceCall, x as RpcMethod, y as RpcCall } from "./chunks/context.js";
|
|
4
4
|
//#region src/server/index.d.ts
|
|
5
5
|
/** What stops what `start` opened. */
|
|
6
6
|
export type Stop = () => Awaitable<void>;
|
|
@@ -28,4 +28,4 @@ export type ServerDefinition<TSettings extends SettingsDefinition | undefined =
|
|
|
28
28
|
*/
|
|
29
29
|
export declare function defineServer<TSettings extends SettingsDefinition | undefined = undefined>(server: Omit<ServerDefinition<TSettings>, 'kind' | 'sdk'>): ServerDefinition<TSettings>;
|
|
30
30
|
//#endregion
|
|
31
|
-
export type { Awaitable, CapabilityEntityInput, ChangeCause, CustomCommand, CustomEntities, CustomEntityInput, DeviceInput, EntityFilter, EntityInput, EntitySnapshot, HistoryAnswer, HistoryRead, HistorySeries, LogMethod, Logger, ReportOptions, RpcAccess, RpcCall, RpcCaller, RpcMethod, SafeParser, Schema, SchemaIssue, ServerContext, ServerSettings, ServiceCall, ServiceCallFunction, ServiceProvide, SettingsChange, StandardResult, StandardSchemaV1, StateChange, StateHistoryPoint, SyncResult, TelemetryPoint, TelemetryRead, TelemetryResolution, Unsubscribe };
|
|
31
|
+
export type { Awaitable, CapabilityEntityInput, ChangeCause, CustomCommand, CustomEntities, CustomEntityInput, DeviceInput, EntityFilter, EntityInput, EntitySnapshot, HistoryAnswer, HistoryRead, HistorySeries, LiveCall, LiveOnMessage, LivePublishOptions, LogMethod, Logger, ReportOptions, RpcAccess, RpcCall, RpcCaller, RpcMethod, SafeParser, Schema, SchemaIssue, ServerContext, ServerSettings, ServiceCall, ServiceCallFunction, ServiceProvide, SettingsChange, StandardResult, StandardSchemaV1, StateChange, StateHistoryPoint, SyncResult, TelemetryPoint, TelemetryRead, TelemetryResolution, Unsubscribe };
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { V as CapabilityCommand, et as ReportedCapabilityState, i as SettingsDefinition, lt as EntityId, r as JsonValue, t as JsonObject } from "./chunks/json.js";
|
|
2
2
|
import { i as TelemetryPoint, r as StateHistoryPoint } from "./chunks/history.js";
|
|
3
|
-
import {
|
|
3
|
+
import { O as StateChange, S as ServerContext, _ as ReportOptions, b as RpcCaller, l as EntitySnapshot, o as DeviceInput, t as Awaitable } from "./chunks/context.js";
|
|
4
4
|
//#region src/testing/index.d.ts
|
|
5
5
|
/** What a test context starts with. */
|
|
6
6
|
export type TestContextOptions<TSettings extends SettingsDefinition | undefined> = {
|
|
@@ -30,6 +30,12 @@ export type RecordedReport = {
|
|
|
30
30
|
readonly state: ReportedCapabilityState;
|
|
31
31
|
readonly options?: ReportOptions;
|
|
32
32
|
};
|
|
33
|
+
/** One live message the package sent its interfaces. */
|
|
34
|
+
export type RecordedLiveMessage = {
|
|
35
|
+
readonly topic: string;
|
|
36
|
+
readonly data: JsonValue;
|
|
37
|
+
readonly isRetained: boolean;
|
|
38
|
+
};
|
|
33
39
|
/** One line the package logged. */
|
|
34
40
|
export type RecordedLog = {
|
|
35
41
|
readonly level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
@@ -55,6 +61,17 @@ export type TestContext<TSettings extends SettingsDefinition | undefined> = {
|
|
|
55
61
|
};
|
|
56
62
|
/** Every line logged. */
|
|
57
63
|
readonly logs: readonly RecordedLog[];
|
|
64
|
+
/** Every live message published and sent, in order. */
|
|
65
|
+
readonly published: readonly RecordedLiveMessage[];
|
|
66
|
+
/**
|
|
67
|
+
* Sends the package a live message as its interface would, through the topic's schema.
|
|
68
|
+
*
|
|
69
|
+
* @param topic - The topic.
|
|
70
|
+
* @param data - The message.
|
|
71
|
+
* @param caller - Who sends; a test user when not said.
|
|
72
|
+
* @returns Once handled; rejects when nothing hears the topic or its schema refuses it.
|
|
73
|
+
*/
|
|
74
|
+
readonly sendLive: (topic: string, data: JsonValue, caller?: RpcCaller) => Promise<void>;
|
|
58
75
|
/**
|
|
59
76
|
* Routes a command as the platform would: to the entity type's handler for a custom one, to
|
|
60
77
|
* `devices.onCommand` otherwise.
|
package/dist/testing.js
CHANGED
|
@@ -99,6 +99,9 @@ const TEST_CALLER = {
|
|
|
99
99
|
username: "test",
|
|
100
100
|
role: "owner"
|
|
101
101
|
};
|
|
102
|
+
/** A live topic, and the most a live message may carry as JSON, as the platform has them. */
|
|
103
|
+
const LIVE_TOPIC_PATTERN = /^[a-z][a-zA-Z0-9._:-]{0,127}$/;
|
|
104
|
+
const LIVE_MAX_BYTES = 1e6;
|
|
102
105
|
/**
|
|
103
106
|
* Says whether a value is a record.
|
|
104
107
|
*
|
|
@@ -149,6 +152,8 @@ function createTestContext(options = {}) {
|
|
|
149
152
|
const methods = /* @__PURE__ */ new Map();
|
|
150
153
|
const services = /* @__PURE__ */ new Map();
|
|
151
154
|
const answers = /* @__PURE__ */ new Map();
|
|
155
|
+
const published = [];
|
|
156
|
+
const liveHandlers = /* @__PURE__ */ new Map();
|
|
152
157
|
const customHandlers = /* @__PURE__ */ new Map();
|
|
153
158
|
const settingsHandlers = /* @__PURE__ */ new Set();
|
|
154
159
|
const subscriptions = /* @__PURE__ */ new Set();
|
|
@@ -309,6 +314,68 @@ function createTestContext(options = {}) {
|
|
|
309
314
|
});
|
|
310
315
|
}
|
|
311
316
|
/**
|
|
317
|
+
* Hears a live topic.
|
|
318
|
+
*
|
|
319
|
+
* @param topic - The topic.
|
|
320
|
+
* @param optionsOrHandler - What a message takes, or what to do with one.
|
|
321
|
+
* @param handler - What to do with one, after its schema.
|
|
322
|
+
* @returns What stops it hearing.
|
|
323
|
+
* @throws {Error} When the topic is not one, is heard already, or there is no handler.
|
|
324
|
+
*/
|
|
325
|
+
function onLiveMessage(topic, optionsOrHandler, handler) {
|
|
326
|
+
/**
|
|
327
|
+
* Says whether a message is the topic's: its schema checked it, or it takes any.
|
|
328
|
+
*
|
|
329
|
+
* @param data - The message.
|
|
330
|
+
* @returns True.
|
|
331
|
+
*/
|
|
332
|
+
const isInput = (data) => data === data;
|
|
333
|
+
const hear = typeof optionsOrHandler === "function" ? optionsOrHandler : handler;
|
|
334
|
+
if (!LIVE_TOPIC_PATTERN.test(topic)) throw new Error(`${topic} is not a live topic: a letter first, then letters, digits, .:_-`);
|
|
335
|
+
if (liveHandlers.has(topic)) throw new Error(`The live topic ${topic} is heard already`);
|
|
336
|
+
if (hear === void 0) throw new Error(`The live topic ${topic} has no handler`);
|
|
337
|
+
liveHandlers.set(topic, {
|
|
338
|
+
input: typeof optionsOrHandler === "function" ? void 0 : optionsOrHandler.input,
|
|
339
|
+
/**
|
|
340
|
+
* Hands the handler the message, once checked.
|
|
341
|
+
*
|
|
342
|
+
* @param data - The message.
|
|
343
|
+
* @param call - Who sent it.
|
|
344
|
+
* @returns Once handled.
|
|
345
|
+
* @throws {Error} Never: every message is the topic's.
|
|
346
|
+
*/
|
|
347
|
+
handler: (data, call) => {
|
|
348
|
+
if (!isInput(data)) throw new Error(`${topic} was handed what it does not take`);
|
|
349
|
+
return hear(data, call);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
return () => {
|
|
353
|
+
liveHandlers.delete(topic);
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Publishes a live message, or logs why it cannot, as the platform does.
|
|
358
|
+
*
|
|
359
|
+
* @param topic - The topic.
|
|
360
|
+
* @param data - The message.
|
|
361
|
+
* @param options - Whether it is retained.
|
|
362
|
+
*/
|
|
363
|
+
const publishLive = (topic, data, options = {}) => {
|
|
364
|
+
if (!LIVE_TOPIC_PATTERN.test(topic)) {
|
|
365
|
+
ctx.logger.error({ topic }, "A live message was not sent: that is not a topic");
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
if (new TextEncoder().encode(JSON.stringify(data)).length > LIVE_MAX_BYTES) {
|
|
369
|
+
ctx.logger.error({ topic }, "A live message was not sent: it is larger than 1 MB");
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
published.push({
|
|
373
|
+
topic,
|
|
374
|
+
data,
|
|
375
|
+
isRetained: options.isRetained === true
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
/**
|
|
312
379
|
* Calls a service.
|
|
313
380
|
*
|
|
314
381
|
* @param target - The package or service.
|
|
@@ -329,215 +396,220 @@ function createTestContext(options = {}) {
|
|
|
329
396
|
if (!checked.isValid) throw new Error(`${target}.${name} answered what was not asked: ${checked.message}`);
|
|
330
397
|
return checked.value;
|
|
331
398
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
399
|
+
const ctx = {
|
|
400
|
+
id,
|
|
401
|
+
version: options.version ?? "0.0.0",
|
|
402
|
+
platform: { version: "0.0.0-test" },
|
|
403
|
+
sdk: { version: SDK_VERSION },
|
|
404
|
+
/**
|
|
405
|
+
* The settings as they stand.
|
|
406
|
+
*
|
|
407
|
+
* @returns Them.
|
|
408
|
+
*/
|
|
409
|
+
get settings() {
|
|
410
|
+
return settingsNow();
|
|
411
|
+
},
|
|
412
|
+
/**
|
|
413
|
+
* Hears live changes of the settings.
|
|
414
|
+
*
|
|
415
|
+
* @param handler - What hears them.
|
|
416
|
+
* @returns What stops it hearing.
|
|
417
|
+
*/
|
|
418
|
+
onSettingsChange: (handler) => {
|
|
419
|
+
settingsHandlers.add(handler);
|
|
420
|
+
return () => {
|
|
421
|
+
settingsHandlers.delete(handler);
|
|
422
|
+
};
|
|
423
|
+
},
|
|
424
|
+
dataDir: options.dataDir ?? `/tmp/${id}/data`,
|
|
425
|
+
cacheDir: options.cacheDir ?? `/tmp/${id}/cache`,
|
|
426
|
+
signal: abort.signal,
|
|
427
|
+
logger: loggerWith({}),
|
|
428
|
+
/**
|
|
429
|
+
* One of the package's entities' ids.
|
|
430
|
+
*
|
|
431
|
+
* @param domain - Its domain.
|
|
432
|
+
* @param objectId - What follows the prefix.
|
|
433
|
+
* @returns The id.
|
|
434
|
+
*/
|
|
435
|
+
entityId: (domain, objectId) => `${domain}.${prefix}${objectId}`,
|
|
436
|
+
objectIdOf,
|
|
437
|
+
devices: {
|
|
338
438
|
/**
|
|
339
|
-
*
|
|
439
|
+
* Records the devices, and answers as the platform would.
|
|
340
440
|
*
|
|
341
|
-
* @
|
|
441
|
+
* @param devices - Every device.
|
|
442
|
+
* @returns What was written.
|
|
342
443
|
*/
|
|
343
|
-
|
|
344
|
-
|
|
444
|
+
sync: async (devices) => {
|
|
445
|
+
synced = devices;
|
|
446
|
+
return Promise.resolve({
|
|
447
|
+
devices: devices.map((device) => ({
|
|
448
|
+
deviceId: `device-${device.externalId}`,
|
|
449
|
+
externalId: device.externalId,
|
|
450
|
+
entityIds: device.entities.map((entity) => `${"type" in entity ? "custom" : entity.domain}.${prefix}${entity.objectId}`)
|
|
451
|
+
})),
|
|
452
|
+
refused: [],
|
|
453
|
+
kept: []
|
|
454
|
+
});
|
|
345
455
|
},
|
|
346
456
|
/**
|
|
347
|
-
*
|
|
457
|
+
* Records a report.
|
|
348
458
|
*
|
|
349
|
-
* @param
|
|
350
|
-
* @
|
|
459
|
+
* @param entityId - The entity.
|
|
460
|
+
* @param state - Its state.
|
|
461
|
+
* @param reportOptions - Its attributes and availability.
|
|
462
|
+
*/
|
|
463
|
+
report: (entityId, state, reportOptions) => {
|
|
464
|
+
reports.push({
|
|
465
|
+
entityId,
|
|
466
|
+
state,
|
|
467
|
+
...reportOptions === void 0 ? {} : { options: reportOptions }
|
|
468
|
+
});
|
|
469
|
+
},
|
|
470
|
+
/**
|
|
471
|
+
* Takes the handler of commands.
|
|
472
|
+
*
|
|
473
|
+
* @param handler - The handler.
|
|
474
|
+
* @returns What removes it.
|
|
475
|
+
* @throws {Error} When there is one already.
|
|
351
476
|
*/
|
|
352
|
-
|
|
353
|
-
|
|
477
|
+
onCommand: (handler) => {
|
|
478
|
+
if (commandHandler !== void 0) throw new Error("devices.onCommand has a handler already");
|
|
479
|
+
commandHandler = handler;
|
|
354
480
|
return () => {
|
|
355
|
-
|
|
481
|
+
commandHandler = void 0;
|
|
356
482
|
};
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
/**
|
|
486
|
+
* The entities of one of the package's entity types.
|
|
487
|
+
*
|
|
488
|
+
* @param type - The entity type.
|
|
489
|
+
* @returns Their ids, reports and commands.
|
|
490
|
+
*/
|
|
491
|
+
custom: (type) => ({
|
|
362
492
|
/**
|
|
363
|
-
*
|
|
493
|
+
* The id of one of its entities of this type.
|
|
364
494
|
*
|
|
365
|
-
* @param domain - Its domain.
|
|
366
495
|
* @param objectId - What follows the prefix.
|
|
367
496
|
* @returns The id.
|
|
368
497
|
*/
|
|
369
|
-
entityId: (
|
|
370
|
-
objectIdOf,
|
|
371
|
-
devices: {
|
|
372
|
-
/**
|
|
373
|
-
* Records the devices, and answers as the platform would.
|
|
374
|
-
*
|
|
375
|
-
* @param devices - Every device.
|
|
376
|
-
* @returns What was written.
|
|
377
|
-
*/
|
|
378
|
-
sync: async (devices) => {
|
|
379
|
-
synced = devices;
|
|
380
|
-
return Promise.resolve({
|
|
381
|
-
devices: devices.map((device) => ({
|
|
382
|
-
deviceId: `device-${device.externalId}`,
|
|
383
|
-
externalId: device.externalId,
|
|
384
|
-
entityIds: device.entities.map((entity) => `${"type" in entity ? "custom" : entity.domain}.${prefix}${entity.objectId}`)
|
|
385
|
-
})),
|
|
386
|
-
refused: [],
|
|
387
|
-
kept: []
|
|
388
|
-
});
|
|
389
|
-
},
|
|
390
|
-
/**
|
|
391
|
-
* Records a report.
|
|
392
|
-
*
|
|
393
|
-
* @param entityId - The entity.
|
|
394
|
-
* @param state - Its state.
|
|
395
|
-
* @param reportOptions - Its attributes and availability.
|
|
396
|
-
*/
|
|
397
|
-
report: (entityId, state, reportOptions) => {
|
|
398
|
-
reports.push({
|
|
399
|
-
entityId,
|
|
400
|
-
state,
|
|
401
|
-
...reportOptions === void 0 ? {} : { options: reportOptions }
|
|
402
|
-
});
|
|
403
|
-
},
|
|
404
|
-
/**
|
|
405
|
-
* Takes the handler of commands.
|
|
406
|
-
*
|
|
407
|
-
* @param handler - The handler.
|
|
408
|
-
* @returns What removes it.
|
|
409
|
-
* @throws {Error} When there is one already.
|
|
410
|
-
*/
|
|
411
|
-
onCommand: (handler) => {
|
|
412
|
-
if (commandHandler !== void 0) throw new Error("devices.onCommand has a handler already");
|
|
413
|
-
commandHandler = handler;
|
|
414
|
-
return () => {
|
|
415
|
-
commandHandler = void 0;
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
},
|
|
498
|
+
entityId: (objectId) => `custom.${prefix}${objectId}`,
|
|
419
499
|
/**
|
|
420
|
-
*
|
|
500
|
+
* Records a report of an entity's values.
|
|
421
501
|
*
|
|
422
|
-
* @param
|
|
423
|
-
* @
|
|
502
|
+
* @param entityId - The entity.
|
|
503
|
+
* @param entityValues - Its values.
|
|
504
|
+
* @param reportOptions - Its attributes and availability.
|
|
424
505
|
*/
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
*/
|
|
432
|
-
entityId: (objectId) => `custom.${prefix}${objectId}`,
|
|
433
|
-
/**
|
|
434
|
-
* Records a report of an entity's values.
|
|
435
|
-
*
|
|
436
|
-
* @param entityId - The entity.
|
|
437
|
-
* @param entityValues - Its values.
|
|
438
|
-
* @param reportOptions - Its attributes and availability.
|
|
439
|
-
*/
|
|
440
|
-
report: (entityId, entityValues, reportOptions) => {
|
|
441
|
-
reports.push({
|
|
442
|
-
entityId,
|
|
443
|
-
state: { custom: { values: Object.fromEntries(Object.entries(entityValues).filter((entry) => isCustomValue(entry[1]))) } },
|
|
444
|
-
...reportOptions === void 0 ? {} : { options: reportOptions }
|
|
445
|
-
});
|
|
446
|
-
},
|
|
447
|
-
/**
|
|
448
|
-
* Takes the handler of one of the type's commands.
|
|
449
|
-
*
|
|
450
|
-
* @param command - The command's id.
|
|
451
|
-
* @param handler - The handler.
|
|
452
|
-
* @returns What removes it.
|
|
453
|
-
* @throws {Error} When the command has one already.
|
|
454
|
-
*/
|
|
455
|
-
onCommand: (command, handler) => {
|
|
456
|
-
const key = `${type.id}:${command}`;
|
|
457
|
-
/**
|
|
458
|
-
* Says whether a command's arguments are its own: the platform checked them against
|
|
459
|
-
* the entity type before routing it.
|
|
460
|
-
*
|
|
461
|
-
* @param args - The arguments.
|
|
462
|
-
* @returns True for a record.
|
|
463
|
-
*/
|
|
464
|
-
const isArgs = (args) => isRecord(args);
|
|
465
|
-
if (customHandlers.has(key)) throw new Error(`${type.id} has a handler for ${command} already`);
|
|
466
|
-
customHandlers.set(key, (call) => {
|
|
467
|
-
if (!isArgs(call.args)) throw new Error(`${command} was sent without arguments`);
|
|
468
|
-
return handler({
|
|
469
|
-
entityId: call.entityId,
|
|
470
|
-
objectId: call.objectId,
|
|
471
|
-
args: call.args
|
|
472
|
-
});
|
|
473
|
-
});
|
|
474
|
-
return () => {
|
|
475
|
-
customHandlers.delete(key);
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
}),
|
|
479
|
-
entities: {
|
|
480
|
-
/**
|
|
481
|
-
* One entity of the house.
|
|
482
|
-
*
|
|
483
|
-
* @param entityId - The entity.
|
|
484
|
-
* @returns It, or undefined.
|
|
485
|
-
*/
|
|
486
|
-
get: async (entityId) => Promise.resolve(entities.get(entityId)),
|
|
487
|
-
/**
|
|
488
|
-
* The entities a filter names.
|
|
489
|
-
*
|
|
490
|
-
* @param filter - Which.
|
|
491
|
-
* @returns Them.
|
|
492
|
-
*/
|
|
493
|
-
list: async (filter = {}) => Promise.resolve([...entities.values()].filter((each) => matches(filter, each.entityId))),
|
|
494
|
-
/**
|
|
495
|
-
* Hears changes of the entities a filter names.
|
|
496
|
-
*
|
|
497
|
-
* @param filter - Which.
|
|
498
|
-
* @param handler - What hears them.
|
|
499
|
-
* @returns What stops it hearing.
|
|
500
|
-
*/
|
|
501
|
-
subscribe: (filter, handler) => {
|
|
502
|
-
const subscription = {
|
|
503
|
-
filter,
|
|
504
|
-
handler
|
|
505
|
-
};
|
|
506
|
-
subscriptions.add(subscription);
|
|
507
|
-
return () => {
|
|
508
|
-
subscriptions.delete(subscription);
|
|
509
|
-
};
|
|
510
|
-
}
|
|
506
|
+
report: (entityId, entityValues, reportOptions) => {
|
|
507
|
+
reports.push({
|
|
508
|
+
entityId,
|
|
509
|
+
state: { custom: { values: Object.fromEntries(Object.entries(entityValues).filter((entry) => isCustomValue(entry[1]))) } },
|
|
510
|
+
...reportOptions === void 0 ? {} : { options: reportOptions }
|
|
511
|
+
});
|
|
511
512
|
},
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
513
|
+
/**
|
|
514
|
+
* Takes the handler of one of the type's commands.
|
|
515
|
+
*
|
|
516
|
+
* @param command - The command's id.
|
|
517
|
+
* @param handler - The handler.
|
|
518
|
+
* @returns What removes it.
|
|
519
|
+
* @throws {Error} When the command has one already.
|
|
520
|
+
*/
|
|
521
|
+
onCommand: (command, handler) => {
|
|
522
|
+
const key = `${type.id}:${command}`;
|
|
520
523
|
/**
|
|
521
|
-
*
|
|
524
|
+
* Says whether a command's arguments are its own: the platform checked them against
|
|
525
|
+
* the entity type before routing it.
|
|
522
526
|
*
|
|
523
|
-
* @param
|
|
524
|
-
* @returns
|
|
527
|
+
* @param args - The arguments.
|
|
528
|
+
* @returns True for a record.
|
|
525
529
|
*/
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
530
|
+
const isArgs = (args) => isRecord(args);
|
|
531
|
+
if (customHandlers.has(key)) throw new Error(`${type.id} has a handler for ${command} already`);
|
|
532
|
+
customHandlers.set(key, (call) => {
|
|
533
|
+
if (!isArgs(call.args)) throw new Error(`${command} was sent without arguments`);
|
|
534
|
+
return handler({
|
|
535
|
+
entityId: call.entityId,
|
|
536
|
+
objectId: call.objectId,
|
|
537
|
+
args: call.args
|
|
532
538
|
});
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
provide,
|
|
538
|
-
call: callService
|
|
539
|
+
});
|
|
540
|
+
return () => {
|
|
541
|
+
customHandlers.delete(key);
|
|
542
|
+
};
|
|
539
543
|
}
|
|
544
|
+
}),
|
|
545
|
+
entities: {
|
|
546
|
+
/**
|
|
547
|
+
* One entity of the house.
|
|
548
|
+
*
|
|
549
|
+
* @param entityId - The entity.
|
|
550
|
+
* @returns It, or undefined.
|
|
551
|
+
*/
|
|
552
|
+
get: async (entityId) => Promise.resolve(entities.get(entityId)),
|
|
553
|
+
/**
|
|
554
|
+
* The entities a filter names.
|
|
555
|
+
*
|
|
556
|
+
* @param filter - Which.
|
|
557
|
+
* @returns Them.
|
|
558
|
+
*/
|
|
559
|
+
list: async (filter = {}) => Promise.resolve([...entities.values()].filter((each) => matches(filter, each.entityId))),
|
|
560
|
+
/**
|
|
561
|
+
* Hears changes of the entities a filter names.
|
|
562
|
+
*
|
|
563
|
+
* @param filter - Which.
|
|
564
|
+
* @param handler - What hears them.
|
|
565
|
+
* @returns What stops it hearing.
|
|
566
|
+
*/
|
|
567
|
+
subscribe: (filter, handler) => {
|
|
568
|
+
const subscription = {
|
|
569
|
+
filter,
|
|
570
|
+
handler
|
|
571
|
+
};
|
|
572
|
+
subscriptions.add(subscription);
|
|
573
|
+
return () => {
|
|
574
|
+
subscriptions.delete(subscription);
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
},
|
|
578
|
+
history: {
|
|
579
|
+
/**
|
|
580
|
+
* The changes of some entities in a window.
|
|
581
|
+
*
|
|
582
|
+
* @param read - Which, when, how many.
|
|
583
|
+
* @returns Them, oldest first.
|
|
584
|
+
*/
|
|
585
|
+
states: async (read) => Promise.resolve(readWindow(read, (entityId) => histories.get(entityId)?.states ?? [])),
|
|
586
|
+
/**
|
|
587
|
+
* The readings of some entities in a window, as given: a test gives the buckets it wants.
|
|
588
|
+
*
|
|
589
|
+
* @param read - Which, when, how many, at which resolution.
|
|
590
|
+
* @returns Them, oldest first, and the resolution.
|
|
591
|
+
*/
|
|
592
|
+
telemetry: async (read) => {
|
|
593
|
+
const span = new Date(read.to).getTime() - new Date(read.from).getTime();
|
|
594
|
+
const resolution = read.resolution === void 0 || read.resolution === "auto" ? resolutionFor(span) : read.resolution;
|
|
595
|
+
return Promise.resolve({
|
|
596
|
+
...readWindow(read, (entityId) => histories.get(entityId)?.telemetry ?? []),
|
|
597
|
+
resolution
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
},
|
|
601
|
+
rpc: { method: rpcMethod },
|
|
602
|
+
live: {
|
|
603
|
+
publish: publishLive,
|
|
604
|
+
onMessage: onLiveMessage
|
|
540
605
|
},
|
|
606
|
+
services: {
|
|
607
|
+
provide,
|
|
608
|
+
call: callService
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
return {
|
|
612
|
+
ctx,
|
|
541
613
|
/**
|
|
542
614
|
* The last list of devices.
|
|
543
615
|
*
|
|
@@ -555,6 +627,26 @@ function createTestContext(options = {}) {
|
|
|
555
627
|
last: (entityId) => reports.findLast((each) => each.entityId === entityId)?.state
|
|
556
628
|
},
|
|
557
629
|
logs,
|
|
630
|
+
published,
|
|
631
|
+
/**
|
|
632
|
+
* Sends the package a live message.
|
|
633
|
+
*
|
|
634
|
+
* @param topic - The topic.
|
|
635
|
+
* @param data - The message.
|
|
636
|
+
* @param caller - Who sends.
|
|
637
|
+
* @throws {Error} When nothing hears the topic, or its schema refuses the message.
|
|
638
|
+
*/
|
|
639
|
+
sendLive: async (topic, data, caller = TEST_CALLER) => {
|
|
640
|
+
const heard = liveHandlers.get(topic);
|
|
641
|
+
if (heard === void 0) throw new Error(`Nothing hears the live topic ${topic}`);
|
|
642
|
+
if (heard.input === void 0) {
|
|
643
|
+
await heard.handler(data, { caller });
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
const checked = await check(heard.input, data);
|
|
647
|
+
if (!checked.isValid) throw new Error(`${topic} refused its message: ${checked.message}`);
|
|
648
|
+
await heard.handler(checked.value, { caller });
|
|
649
|
+
},
|
|
558
650
|
/**
|
|
559
651
|
* Routes a command.
|
|
560
652
|
*
|
package/dist/ui.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { G as CapabilityState, H as CapabilityCommands, S as FormValues, Y as DeclaredCapabilities, ct as EntityDomain, d as EntityTypeDefinition, f as ValuesOf, i as SettingsDefinition, lt as EntityId, q as CommandableCapability, r as JsonValue, s as ArgsOf, t as JsonObject, u as CommandsOf, z as ValueOfField } from "./chunks/json.js";
|
|
2
|
-
import {
|
|
2
|
+
import { n as CardProps, o as PageProps, r as EntityViewProps, t as BackgroundProps } from "./chunks/props.js";
|
|
3
3
|
import { a as TelemetryResolution, i as TelemetryPoint, n as HistorySeries, r as StateHistoryPoint, t as ChangeCause } from "./chunks/history.js";
|
|
4
4
|
import { AnchorHTMLAttributes, ComponentType, ReactElement, ReactNode } from "react";
|
|
5
5
|
//#region src/ui/types.d.ts
|
|
@@ -164,6 +164,23 @@ type RpcOptions = {
|
|
|
164
164
|
/** False holds the read back. */
|
|
165
165
|
readonly isEnabled?: boolean;
|
|
166
166
|
};
|
|
167
|
+
/** How a live topic is followed. Since 1.5. */
|
|
168
|
+
type LiveOptions = {
|
|
169
|
+
/** False stops following it. */
|
|
170
|
+
readonly isEnabled?: boolean;
|
|
171
|
+
};
|
|
172
|
+
/** A live topic of the package's server, as it stands. Since 1.5. */
|
|
173
|
+
type LiveState<TData> = {
|
|
174
|
+
/** The last message on it: the retained one at first, if there is one; undefined until then. */
|
|
175
|
+
readonly data: TData | undefined;
|
|
176
|
+
/** Whether the interface's socket is open: messages sent while it is not are lost. */
|
|
177
|
+
readonly isConnected: boolean;
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* Sends the package's server a message on a topic (`ctx.live.onMessage`), over the interface's
|
|
181
|
+
* socket; nothing answers it. Since 1.5.
|
|
182
|
+
*/
|
|
183
|
+
type PackageSend = (topic: string, data: JsonValue) => void;
|
|
167
184
|
/** A call of one of the package's methods, on demand. */
|
|
168
185
|
type PackageCall = <TData = JsonValue>(method: string, input?: JsonValue) => Promise<TData>;
|
|
169
186
|
/** How a mutation is made. */
|
|
@@ -298,6 +315,20 @@ type PlatformLinkProps = LinkAttributes & {
|
|
|
298
315
|
type PageActionsProps = {
|
|
299
316
|
readonly children?: ReactNode;
|
|
300
317
|
};
|
|
318
|
+
/**
|
|
319
|
+
* A window of the package floating over the interface's pages, in a corner of the page beside the
|
|
320
|
+
* rail: one a package, thrown from corner to corner, hidden on the package's own page and on a
|
|
321
|
+
* phone. Since 1.6.
|
|
322
|
+
*/
|
|
323
|
+
type FloatingProps = {
|
|
324
|
+
/** Whether it is shown. */
|
|
325
|
+
readonly open: boolean;
|
|
326
|
+
/** What a screen reader calls it, in the viewer's language. */
|
|
327
|
+
readonly label: string;
|
|
328
|
+
/** What closing it does; without it the window has no close button. */
|
|
329
|
+
readonly onClose?: () => void;
|
|
330
|
+
readonly children?: ReactNode;
|
|
331
|
+
};
|
|
301
332
|
/** What a toast says. Since 1.4. */
|
|
302
333
|
type ToastMessage = {
|
|
303
334
|
/** A few words, no full stop. */
|
|
@@ -360,6 +391,12 @@ type UiHost = {
|
|
|
360
391
|
readonly useAreaActions: () => AreaActions;
|
|
361
392
|
/** Since 1.4. */
|
|
362
393
|
readonly useToast: () => Toasts;
|
|
394
|
+
/** Since 1.5. */
|
|
395
|
+
readonly usePackageLive: <TData = JsonValue>(topic: string, options?: LiveOptions) => LiveState<TData>;
|
|
396
|
+
/** Since 1.5. */
|
|
397
|
+
readonly usePackageSend: () => PackageSend;
|
|
398
|
+
/** Since 1.6. */
|
|
399
|
+
readonly Floating: ComponentType<FloatingProps>;
|
|
363
400
|
};
|
|
364
401
|
//#endregion
|
|
365
402
|
//#region src/ui/index.d.ts
|
|
@@ -489,6 +526,23 @@ export declare function useAreaActions(): AreaActions;
|
|
|
489
526
|
* @returns One function per kind: `success`, `warning`, `error`, `info`.
|
|
490
527
|
*/
|
|
491
528
|
export declare function useToast(): Toasts;
|
|
529
|
+
/**
|
|
530
|
+
* Follows a live topic of the package's server (`ctx.live.publish`), over the interface's own
|
|
531
|
+
* socket: the retained message at once, then every message as it is sent, with no polling and
|
|
532
|
+
* no HTTP rate limit. Every component following one topic shares one subscription. Since 1.5.
|
|
533
|
+
*
|
|
534
|
+
* @param topic - The topic.
|
|
535
|
+
* @param options - Whether to follow it.
|
|
536
|
+
* @returns The last message, and whether the socket is open.
|
|
537
|
+
*/
|
|
538
|
+
export declare function usePackageLive<TData = JsonValue>(topic: string, options?: LiveOptions): LiveState<TData>;
|
|
539
|
+
/**
|
|
540
|
+
* Sends the package's server messages over the interface's socket (`ctx.live.onMessage`): for
|
|
541
|
+
* what goes often and wants no answer. A call that wants one stays `usePackageCall`. Since 1.5.
|
|
542
|
+
*
|
|
543
|
+
* @returns What sends one.
|
|
544
|
+
*/
|
|
545
|
+
export declare function usePackageSend(): PackageSend;
|
|
492
546
|
/**
|
|
493
547
|
* A camera's latest still, fetched again every so often, or an image entity's picture, fetched
|
|
494
548
|
* again when it changes: an address an `<img>` shows, let go of when a newer one replaces it.
|
|
@@ -550,5 +604,15 @@ export declare function PlatformLink(props: PlatformLinkProps): ReactElement;
|
|
|
550
604
|
* @returns The actions.
|
|
551
605
|
*/
|
|
552
606
|
export declare function PageActions(props: PageActionsProps): ReactElement;
|
|
607
|
+
/**
|
|
608
|
+
* A window floating over the interface's pages, from the package's background, page or card -
|
|
609
|
+
* drawn while the component that draws it is, so a background's outlives every page. The
|
|
610
|
+
* interface gives the frame, the throwing from corner to corner and the close button; what is
|
|
611
|
+
* inside is the package's own. Since 1.6.
|
|
612
|
+
*
|
|
613
|
+
* @param props - Whether it is shown, what it is called, what closing it does, and what it holds.
|
|
614
|
+
* @returns The window.
|
|
615
|
+
*/
|
|
616
|
+
export declare function Floating(props: FloatingProps): ReactElement;
|
|
553
617
|
//#endregion
|
|
554
|
-
export type { AreaActions, AreaDraft, AreaKind, AreaView, CardProps, ChangeCause, CustomEntityState, EntitiesFilter, EntityPicture, EntityView, EntityViewProps, History, HistoryQuery, HistorySeries, HistoryWindow, Locale, Mutation, MutationOptions, PackageCall, PackageInfo, PackageLinkProps, PackageNavigate, PackageRoute, PackageSettings, PageActionsProps, PageProps, PictureOptions, PlatformLinkProps, PlatformNavigate, PlatformTarget, PluralEnglish, RpcOptions, RpcState, SendCommand, SettingsPatch, StateHistoryPoint, Telemetry, TelemetryPoint, TelemetryQuery, TelemetryResolution, Theme, ToastMessage, Toasts, Translate, Translation, TranslationValues, UiHost, Viewer, VisibleSettings };
|
|
618
|
+
export type { AreaActions, AreaDraft, AreaKind, AreaView, BackgroundProps, CardProps, ChangeCause, CustomEntityState, EntitiesFilter, EntityPicture, EntityView, EntityViewProps, FloatingProps, History, HistoryQuery, HistorySeries, HistoryWindow, LiveOptions, LiveState, Locale, Mutation, MutationOptions, PackageCall, PackageInfo, PackageLinkProps, PackageNavigate, PackageRoute, PackageSend, PackageSettings, PageActionsProps, PageProps, PictureOptions, PlatformLinkProps, PlatformNavigate, PlatformTarget, PluralEnglish, RpcOptions, RpcState, SendCommand, SettingsPatch, StateHistoryPoint, Telemetry, TelemetryPoint, TelemetryQuery, TelemetryResolution, Theme, ToastMessage, Toasts, Translate, Translation, TranslationValues, UiHost, Viewer, VisibleSettings };
|
package/dist/ui.js
CHANGED
|
@@ -221,6 +221,27 @@ function useToast() {
|
|
|
221
221
|
return ui("useToast", "1.4")();
|
|
222
222
|
}
|
|
223
223
|
/**
|
|
224
|
+
* Follows a live topic of the package's server (`ctx.live.publish`), over the interface's own
|
|
225
|
+
* socket: the retained message at once, then every message as it is sent, with no polling and
|
|
226
|
+
* no HTTP rate limit. Every component following one topic shares one subscription. Since 1.5.
|
|
227
|
+
*
|
|
228
|
+
* @param topic - The topic.
|
|
229
|
+
* @param options - Whether to follow it.
|
|
230
|
+
* @returns The last message, and whether the socket is open.
|
|
231
|
+
*/
|
|
232
|
+
function usePackageLive(topic, options) {
|
|
233
|
+
return ui("usePackageLive", "1.5")(topic, options);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Sends the package's server messages over the interface's socket (`ctx.live.onMessage`): for
|
|
237
|
+
* what goes often and wants no answer. A call that wants one stays `usePackageCall`. Since 1.5.
|
|
238
|
+
*
|
|
239
|
+
* @returns What sends one.
|
|
240
|
+
*/
|
|
241
|
+
function usePackageSend() {
|
|
242
|
+
return ui("usePackageSend", "1.5")();
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
224
245
|
* A camera's latest still, fetched again every so often, or an image entity's picture, fetched
|
|
225
246
|
* again when it changes: an address an `<img>` shows, let go of when a newer one replaces it.
|
|
226
247
|
*
|
|
@@ -299,5 +320,17 @@ function PlatformLink(props) {
|
|
|
299
320
|
function PageActions(props) {
|
|
300
321
|
return createElement(ui("PageActions", "1.3"), props);
|
|
301
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* A window floating over the interface's pages, from the package's background, page or card -
|
|
325
|
+
* drawn while the component that draws it is, so a background's outlives every page. The
|
|
326
|
+
* interface gives the frame, the throwing from corner to corner and the close button; what is
|
|
327
|
+
* inside is the package's own. Since 1.6.
|
|
328
|
+
*
|
|
329
|
+
* @param props - Whether it is shown, what it is called, what closing it does, and what it holds.
|
|
330
|
+
* @returns The window.
|
|
331
|
+
*/
|
|
332
|
+
function Floating(props) {
|
|
333
|
+
return createElement(ui("Floating", "1.6"), props);
|
|
334
|
+
}
|
|
302
335
|
//#endregion
|
|
303
|
-
export { PackageLink, PageActions, PlatformLink, useAreaActions, useAreas, useCommand, useCustomEntity, useEntities, useEntity, useEntityPicture, useLocale, usePackage, usePackageCall, usePackageMutation, usePackageNavigate, usePackageRoute, usePackageRpc, usePackageSettings, usePlatformNavigate, usePortalContainer, useStateHistory, useTelemetry, useTheme, useToast, useTranslation, useViewer };
|
|
336
|
+
export { Floating, PackageLink, PageActions, PlatformLink, useAreaActions, useAreas, useCommand, useCustomEntity, useEntities, useEntity, useEntityPicture, useLocale, usePackage, usePackageCall, usePackageLive, usePackageMutation, usePackageNavigate, usePackageRoute, usePackageRpc, usePackageSend, usePackageSettings, usePlatformNavigate, usePortalContainer, useStateHistory, useTelemetry, useTheme, useToast, useTranslation, useViewer };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nebulahome/package-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Write a NebulaHome package: declare it, build it, and run it on the platform.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -100,10 +100,10 @@
|
|
|
100
100
|
"vitest": "^4.1.11",
|
|
101
101
|
"yaml": "^2.9.0",
|
|
102
102
|
"zod": "^4.5.4",
|
|
103
|
-
"@nebulahome/
|
|
104
|
-
"@nebulahome/
|
|
105
|
-
"@nebulahome/eslint-config": "2026.10.0-alpha.
|
|
106
|
-
"@nebulahome/ui": "2026.10.0-alpha.
|
|
103
|
+
"@nebulahome/tsconfig": "2026.10.0-alpha.32",
|
|
104
|
+
"@nebulahome/contracts": "2026.10.0-alpha.32",
|
|
105
|
+
"@nebulahome/eslint-config": "2026.10.0-alpha.32",
|
|
106
|
+
"@nebulahome/ui": "2026.10.0-alpha.32"
|
|
107
107
|
},
|
|
108
108
|
"scripts": {
|
|
109
109
|
"build": "tsdown && node scripts/build-styles.js",
|