@camstack/addon-provider-ecowitt 0.2.155 → 0.2.156
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 +6 -0
- package/dist/addon.js +90 -61
- package/dist/addon.mjs +90 -61
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.156] - 2026-11-05
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Copying an integration into its record reads the leftover rows through the migration-only door and resolves their secrets in this addon
|
|
15
|
+
|
|
10
16
|
## [0.2.155] - 2026-11-04
|
|
11
17
|
|
|
12
18
|
### Changed
|
package/dist/addon.js
CHANGED
|
@@ -5984,7 +5984,7 @@ var ZodIssueCode$1 = {
|
|
|
5984
5984
|
var ZodFirstPartyTypeKind$1;
|
|
5985
5985
|
ZodFirstPartyTypeKind$1 || (ZodFirstPartyTypeKind$1 = {});
|
|
5986
5986
|
//#endregion
|
|
5987
|
-
//#region ../types/dist/sleep-
|
|
5987
|
+
//#region ../types/dist/sleep-9TIHFj1w.mjs
|
|
5988
5988
|
/**
|
|
5989
5989
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5990
5990
|
* window to float samples (D455).
|
|
@@ -7928,10 +7928,9 @@ var BaseAddon = class {
|
|
|
7928
7928
|
*
|
|
7929
7929
|
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
7930
7930
|
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
7931
|
-
* SHAPE of the form only — the values live
|
|
7932
|
-
* unchanged (`integrations.setSettings` for an account integration).
|
|
7931
|
+
* SHAPE of the form only — the values live on the instance record.
|
|
7933
7932
|
*/
|
|
7934
|
-
async
|
|
7933
|
+
async integrationFormSchema(_instance) {
|
|
7935
7934
|
return null;
|
|
7936
7935
|
}
|
|
7937
7936
|
/**
|
|
@@ -7977,7 +7976,7 @@ var BaseAddon = class {
|
|
|
7977
7976
|
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
7978
7977
|
*/
|
|
7979
7978
|
async getIntegrationFormSchema(instance, nodeId) {
|
|
7980
|
-
const scoped = await this.
|
|
7979
|
+
const scoped = await this.integrationFormSchema(instance);
|
|
7981
7980
|
if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
|
|
7982
7981
|
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
7983
7982
|
}
|
|
@@ -11951,7 +11950,7 @@ function userError(code, params, englishFallback) {
|
|
|
11951
11950
|
return new CamstackError(code, params, englishFallback);
|
|
11952
11951
|
}
|
|
11953
11952
|
//#endregion
|
|
11954
|
-
//#region ../types/dist/composition-
|
|
11953
|
+
//#region ../types/dist/composition-pOHbTzRB.mjs
|
|
11955
11954
|
/**
|
|
11956
11955
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11957
11956
|
*
|
|
@@ -14659,20 +14658,28 @@ async function moveIntegrationRowsToRecords(ports, spec) {
|
|
|
14659
14658
|
};
|
|
14660
14659
|
}
|
|
14661
14660
|
/**
|
|
14662
|
-
* The addon-side ports of `moveIntegrationRowsToRecords` (planning#416)
|
|
14663
|
-
* from its own process, so the
|
|
14664
|
-
* `
|
|
14665
|
-
*
|
|
14666
|
-
*
|
|
14661
|
+
* The addon-side ports of `moveIntegrationRowsToRecords` (planning#416). An addon runs the move
|
|
14662
|
+
* from its own process, so the leftover rows are reached through the migration-only door
|
|
14663
|
+
* (`migrations.readLegacyIntegrationRows` / `clearLegacyIntegrationRows`) on the hub's connection.
|
|
14664
|
+
* The door returns markers. This process is the owner, so it resolves and releases them with
|
|
14665
|
+
* `resolveSecretMarkers` — the same call the old settings door used — and only then asks the
|
|
14666
|
+
* door to delete the rows. The addon's own record kind is its records handle.
|
|
14667
14667
|
*/
|
|
14668
|
+
async function resolvedRows(stored, secrets) {
|
|
14669
|
+
if (secrets === null) return stored;
|
|
14670
|
+
const { value, unresolved } = await resolveSecretMarkers(stored, secrets);
|
|
14671
|
+
if (unresolved.length > 0) throw new Error(`${unresolved.length} secret(s) cannot be read from the keychain`);
|
|
14672
|
+
return value;
|
|
14673
|
+
}
|
|
14668
14674
|
function integrationRowsPortsOverApi(deps) {
|
|
14675
|
+
const secrets = deps.secrets ?? null;
|
|
14669
14676
|
return {
|
|
14670
14677
|
warn: (message) => deps.log.warn(message),
|
|
14671
14678
|
listIntegrations: async (addonId) => (await deps.api.list()).filter((i) => i.addonId === addonId).map((i) => ({
|
|
14672
14679
|
id: i.id,
|
|
14673
14680
|
name: i.name
|
|
14674
14681
|
})),
|
|
14675
|
-
readRows: (integrationId) => deps.api.
|
|
14682
|
+
readRows: async (integrationId) => resolvedRows(await deps.api.readLegacyIntegrationRows({ integrationId }), secrets),
|
|
14676
14683
|
putRecord: async (id, body) => {
|
|
14677
14684
|
if (await deps.records.get(id) !== null) return "exists";
|
|
14678
14685
|
try {
|
|
@@ -14691,15 +14698,17 @@ function integrationRowsPortsOverApi(deps) {
|
|
|
14691
14698
|
await deps.records.delete(id);
|
|
14692
14699
|
},
|
|
14693
14700
|
clearRows: async (integrationId) => {
|
|
14694
|
-
await deps.api.
|
|
14701
|
+
const refs = collectSecretMarkerRefs(await deps.api.readLegacyIntegrationRows({ integrationId }));
|
|
14702
|
+
if (refs.length > 0 && secrets !== null) await secrets.delete(refs);
|
|
14703
|
+
await deps.api.clearLegacyIntegrationRows({ integrationId });
|
|
14695
14704
|
}
|
|
14696
14705
|
};
|
|
14697
14706
|
}
|
|
14698
14707
|
function defaultIntegrationApiOver(api) {
|
|
14699
14708
|
return {
|
|
14700
14709
|
list: () => api.integrations.list.query(),
|
|
14701
|
-
|
|
14702
|
-
|
|
14710
|
+
readLegacyIntegrationRows: (input) => api.migrations.readLegacyIntegrationRows.query(input),
|
|
14711
|
+
clearLegacyIntegrationRows: (input) => api.migrations.clearLegacyIntegrationRows.mutate(input),
|
|
14703
14712
|
listDevices: (addonId) => api.deviceManager.listAll.query({
|
|
14704
14713
|
addonId,
|
|
14705
14714
|
projection: "slim"
|
|
@@ -50377,6 +50386,9 @@ var RunningProposalEvidenceSchema = object({
|
|
|
50377
50386
|
runsFound: number().int().nonnegative(),
|
|
50378
50387
|
pausesFound: number().int().nonnegative(),
|
|
50379
50388
|
longestPauseMs: number().nonnegative(),
|
|
50389
|
+
/** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
|
|
50390
|
+
pulsesFound: number().int().nonnegative(),
|
|
50391
|
+
longestPulseMs: number().nonnegative(),
|
|
50380
50392
|
idleFloorW: number(),
|
|
50381
50393
|
noiseCeilingW: number(),
|
|
50382
50394
|
plateauW: number(),
|
|
@@ -56243,11 +56255,7 @@ var CreateIntegrationInputSchema = object({
|
|
|
56243
56255
|
info: record(string(), unknown()).optional(),
|
|
56244
56256
|
/** `stableId` of the discovery candidate the form was seeded from (D984). */
|
|
56245
56257
|
originStableId: string().optional(),
|
|
56246
|
-
settings: record(string(), unknown()).optional()
|
|
56247
|
-
/** Keys of `settings` the form's schema declares secret (by type) — kept in
|
|
56248
|
-
* the keychain, not the table (D787). */
|
|
56249
|
-
secretKeys: array(string()).optional(),
|
|
56250
|
-
skipRestart: boolean().optional()
|
|
56258
|
+
settings: record(string(), unknown()).optional()
|
|
56251
56259
|
});
|
|
56252
56260
|
var UpdateIntegrationInputSchema = object({
|
|
56253
56261
|
id: string(),
|
|
@@ -56268,22 +56276,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
56268
56276
|
}), method(object({ id: string() }), DeleteIntegrationResultSchema, {
|
|
56269
56277
|
kind: "mutation",
|
|
56270
56278
|
auth: "admin"
|
|
56271
|
-
}), method(object({ id: string() }), record(string(), unknown()), { auth: "admin" }), method(object({
|
|
56272
|
-
id: string(),
|
|
56273
|
-
settings: record(string(), unknown()),
|
|
56274
|
-
/** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
|
|
56275
|
-
secretKeys: array(string()).optional(),
|
|
56276
|
-
/** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
|
|
56277
|
-
skipRestart: boolean().optional()
|
|
56278
|
-
}), object({ success: boolean() }), {
|
|
56279
|
-
kind: "mutation",
|
|
56280
|
-
auth: "admin"
|
|
56281
|
-
}), method(object({ id: string() }), object({
|
|
56282
|
-
rows: number().int().nonnegative(),
|
|
56283
|
-
secrets: number().int().nonnegative()
|
|
56284
|
-
}), {
|
|
56285
|
-
kind: "mutation",
|
|
56286
|
-
auth: "admin"
|
|
56287
56279
|
}), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
|
|
56288
56280
|
addonId: string(),
|
|
56289
56281
|
settings: record(string(), unknown())
|
|
@@ -59260,6 +59252,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
|
|
|
59260
59252
|
}), {
|
|
59261
59253
|
kind: "mutation",
|
|
59262
59254
|
auth: "admin"
|
|
59255
|
+
}), method(object({ integrationId: string().min(1) }), record(string(), unknown()), { auth: "admin" }), method(object({ integrationId: string().min(1) }), object({
|
|
59256
|
+
rows: number().int().nonnegative(),
|
|
59257
|
+
secrets: number().int().nonnegative()
|
|
59258
|
+
}), {
|
|
59259
|
+
kind: "mutation",
|
|
59260
|
+
auth: "admin"
|
|
59261
|
+
}), method(object({
|
|
59262
|
+
integrationId: string().min(1),
|
|
59263
|
+
patch: record(string(), unknown())
|
|
59264
|
+
}), object({ written: boolean() }), {
|
|
59265
|
+
kind: "mutation",
|
|
59266
|
+
auth: "admin"
|
|
59267
|
+
}), method(object({
|
|
59268
|
+
integrationId: string().min(1),
|
|
59269
|
+
keys: array(string().min(1))
|
|
59270
|
+
}), object({
|
|
59271
|
+
present: boolean(),
|
|
59272
|
+
removed: record(string(), unknown())
|
|
59273
|
+
}), {
|
|
59274
|
+
kind: "mutation",
|
|
59275
|
+
auth: "admin"
|
|
59263
59276
|
});
|
|
59264
59277
|
method(object({
|
|
59265
59278
|
sourceUrl: string(),
|
|
@@ -80678,11 +80691,15 @@ discriminatedUnion("kind", [object({
|
|
|
80678
80691
|
* 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
|
|
80679
80692
|
* near F. A device that is not near one level most of the time has no floor.
|
|
80680
80693
|
* 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
|
|
80681
|
-
* 3.
|
|
80682
|
-
*
|
|
80694
|
+
* 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
|
|
80695
|
+
* display waking): it is neither a run nor a pause. Among the remaining
|
|
80696
|
+
* episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
|
|
80697
|
+
* two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
|
|
80698
|
+
* a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
|
|
80699
|
+
* is no run.
|
|
80683
80700
|
* 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
|
|
80684
|
-
* grid a person would type; stop dwell covers the longest pause
|
|
80685
|
-
* covers the longest standby blip above T.
|
|
80701
|
+
* grid a person would type; stop dwell covers the longest pause and the
|
|
80702
|
+
* kind's floor; start dwell covers the longest pulse and standby blip above T.
|
|
80686
80703
|
* 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
|
|
80687
80704
|
* run must hold exactly one true interval and nothing may flap outside.
|
|
80688
80705
|
*/
|
|
@@ -80693,6 +80710,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
|
|
|
80693
80710
|
30 * SECOND_MS;
|
|
80694
80711
|
60 * SECOND_MS;
|
|
80695
80712
|
20 * MINUTE_MS$1;
|
|
80713
|
+
90 * SECOND_MS;
|
|
80714
|
+
30 * MINUTE_MS$1;
|
|
80715
|
+
10 * MINUTE_MS$1;
|
|
80716
|
+
DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
|
|
80696
80717
|
10 * SECOND_MS;
|
|
80697
80718
|
10 * SECOND_MS;
|
|
80698
80719
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
@@ -85977,13 +85998,6 @@ Object.freeze({
|
|
|
85977
85998
|
access: "create",
|
|
85978
85999
|
role: "admin"
|
|
85979
86000
|
},
|
|
85980
|
-
"integrations.clearSettings": {
|
|
85981
|
-
capName: "integrations",
|
|
85982
|
-
capScope: "system",
|
|
85983
|
-
addonId: null,
|
|
85984
|
-
access: "delete",
|
|
85985
|
-
role: "admin"
|
|
85986
|
-
},
|
|
85987
86001
|
"integrations.create": {
|
|
85988
86002
|
capName: "integrations",
|
|
85989
86003
|
capScope: "system",
|
|
@@ -86019,13 +86033,6 @@ Object.freeze({
|
|
|
86019
86033
|
access: "view",
|
|
86020
86034
|
role: "admin"
|
|
86021
86035
|
},
|
|
86022
|
-
"integrations.getSettings": {
|
|
86023
|
-
capName: "integrations",
|
|
86024
|
-
capScope: "system",
|
|
86025
|
-
addonId: null,
|
|
86026
|
-
access: "view",
|
|
86027
|
-
role: "admin"
|
|
86028
|
-
},
|
|
86029
86036
|
"integrations.list": {
|
|
86030
86037
|
capName: "integrations",
|
|
86031
86038
|
capScope: "system",
|
|
@@ -86033,13 +86040,6 @@ Object.freeze({
|
|
|
86033
86040
|
access: "view",
|
|
86034
86041
|
role: "admin"
|
|
86035
86042
|
},
|
|
86036
|
-
"integrations.setSettings": {
|
|
86037
|
-
capName: "integrations",
|
|
86038
|
-
capScope: "system",
|
|
86039
|
-
addonId: null,
|
|
86040
|
-
access: "create",
|
|
86041
|
-
role: "admin"
|
|
86042
|
-
},
|
|
86043
86043
|
"integrations.testConnection": {
|
|
86044
86044
|
capName: "integrations",
|
|
86045
86045
|
capScope: "system",
|
|
@@ -87034,6 +87034,13 @@ Object.freeze({
|
|
|
87034
87034
|
access: "view",
|
|
87035
87035
|
role: "admin"
|
|
87036
87036
|
},
|
|
87037
|
+
"migrations.clearLegacyIntegrationRows": {
|
|
87038
|
+
capName: "migrations",
|
|
87039
|
+
capScope: "system",
|
|
87040
|
+
addonId: null,
|
|
87041
|
+
access: "delete",
|
|
87042
|
+
role: "admin"
|
|
87043
|
+
},
|
|
87037
87044
|
"migrations.declareOwner": {
|
|
87038
87045
|
capName: "migrations",
|
|
87039
87046
|
capScope: "system",
|
|
@@ -87041,6 +87048,13 @@ Object.freeze({
|
|
|
87041
87048
|
access: "create",
|
|
87042
87049
|
role: "admin"
|
|
87043
87050
|
},
|
|
87051
|
+
"migrations.deleteLegacyIntegrationRowKeys": {
|
|
87052
|
+
capName: "migrations",
|
|
87053
|
+
capScope: "system",
|
|
87054
|
+
addonId: null,
|
|
87055
|
+
access: "delete",
|
|
87056
|
+
role: "admin"
|
|
87057
|
+
},
|
|
87044
87058
|
"migrations.dryRun": {
|
|
87045
87059
|
capName: "migrations",
|
|
87046
87060
|
capScope: "system",
|
|
@@ -87076,6 +87090,20 @@ Object.freeze({
|
|
|
87076
87090
|
access: "create",
|
|
87077
87091
|
role: "admin"
|
|
87078
87092
|
},
|
|
87093
|
+
"migrations.patchLegacyIntegrationRows": {
|
|
87094
|
+
capName: "migrations",
|
|
87095
|
+
capScope: "system",
|
|
87096
|
+
addonId: null,
|
|
87097
|
+
access: "create",
|
|
87098
|
+
role: "admin"
|
|
87099
|
+
},
|
|
87100
|
+
"migrations.readLegacyIntegrationRows": {
|
|
87101
|
+
capName: "migrations",
|
|
87102
|
+
capScope: "system",
|
|
87103
|
+
addonId: null,
|
|
87104
|
+
access: "view",
|
|
87105
|
+
role: "admin"
|
|
87106
|
+
},
|
|
87079
87107
|
"migrations.restorePreMigration": {
|
|
87080
87108
|
capName: "migrations",
|
|
87081
87109
|
capScope: "system",
|
|
@@ -105324,6 +105352,7 @@ var EcowittProviderAddon = class extends BaseDeviceProvider {
|
|
|
105324
105352
|
if (records === void 0) throw new Error("provider-ecowitt: ctx.records is required (hub-only addon)");
|
|
105325
105353
|
const rowsPorts = integrationRowsPortsOverApi({
|
|
105326
105354
|
api: defaultIntegrationApiOver(this.ctx.api),
|
|
105355
|
+
secrets: this.ctx.secrets ?? null,
|
|
105327
105356
|
records: records.kind({
|
|
105328
105357
|
name: ecowittConnectionsEntryKind.name,
|
|
105329
105358
|
declaration: ecowittConnectionsEntryKind.declaration,
|
package/dist/addon.mjs
CHANGED
|
@@ -5983,7 +5983,7 @@ var ZodIssueCode$1 = {
|
|
|
5983
5983
|
var ZodFirstPartyTypeKind$1;
|
|
5984
5984
|
ZodFirstPartyTypeKind$1 || (ZodFirstPartyTypeKind$1 = {});
|
|
5985
5985
|
//#endregion
|
|
5986
|
-
//#region ../types/dist/sleep-
|
|
5986
|
+
//#region ../types/dist/sleep-9TIHFj1w.mjs
|
|
5987
5987
|
/**
|
|
5988
5988
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5989
5989
|
* window to float samples (D455).
|
|
@@ -7927,10 +7927,9 @@ var BaseAddon = class {
|
|
|
7927
7927
|
*
|
|
7928
7928
|
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
7929
7929
|
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
7930
|
-
* SHAPE of the form only — the values live
|
|
7931
|
-
* unchanged (`integrations.setSettings` for an account integration).
|
|
7930
|
+
* SHAPE of the form only — the values live on the instance record.
|
|
7932
7931
|
*/
|
|
7933
|
-
async
|
|
7932
|
+
async integrationFormSchema(_instance) {
|
|
7934
7933
|
return null;
|
|
7935
7934
|
}
|
|
7936
7935
|
/**
|
|
@@ -7976,7 +7975,7 @@ var BaseAddon = class {
|
|
|
7976
7975
|
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
7977
7976
|
*/
|
|
7978
7977
|
async getIntegrationFormSchema(instance, nodeId) {
|
|
7979
|
-
const scoped = await this.
|
|
7978
|
+
const scoped = await this.integrationFormSchema(instance);
|
|
7980
7979
|
if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
|
|
7981
7980
|
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
7982
7981
|
}
|
|
@@ -11950,7 +11949,7 @@ function userError(code, params, englishFallback) {
|
|
|
11950
11949
|
return new CamstackError(code, params, englishFallback);
|
|
11951
11950
|
}
|
|
11952
11951
|
//#endregion
|
|
11953
|
-
//#region ../types/dist/composition-
|
|
11952
|
+
//#region ../types/dist/composition-pOHbTzRB.mjs
|
|
11954
11953
|
/**
|
|
11955
11954
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11956
11955
|
*
|
|
@@ -14658,20 +14657,28 @@ async function moveIntegrationRowsToRecords(ports, spec) {
|
|
|
14658
14657
|
};
|
|
14659
14658
|
}
|
|
14660
14659
|
/**
|
|
14661
|
-
* The addon-side ports of `moveIntegrationRowsToRecords` (planning#416)
|
|
14662
|
-
* from its own process, so the
|
|
14663
|
-
* `
|
|
14664
|
-
*
|
|
14665
|
-
*
|
|
14660
|
+
* The addon-side ports of `moveIntegrationRowsToRecords` (planning#416). An addon runs the move
|
|
14661
|
+
* from its own process, so the leftover rows are reached through the migration-only door
|
|
14662
|
+
* (`migrations.readLegacyIntegrationRows` / `clearLegacyIntegrationRows`) on the hub's connection.
|
|
14663
|
+
* The door returns markers. This process is the owner, so it resolves and releases them with
|
|
14664
|
+
* `resolveSecretMarkers` — the same call the old settings door used — and only then asks the
|
|
14665
|
+
* door to delete the rows. The addon's own record kind is its records handle.
|
|
14666
14666
|
*/
|
|
14667
|
+
async function resolvedRows(stored, secrets) {
|
|
14668
|
+
if (secrets === null) return stored;
|
|
14669
|
+
const { value, unresolved } = await resolveSecretMarkers(stored, secrets);
|
|
14670
|
+
if (unresolved.length > 0) throw new Error(`${unresolved.length} secret(s) cannot be read from the keychain`);
|
|
14671
|
+
return value;
|
|
14672
|
+
}
|
|
14667
14673
|
function integrationRowsPortsOverApi(deps) {
|
|
14674
|
+
const secrets = deps.secrets ?? null;
|
|
14668
14675
|
return {
|
|
14669
14676
|
warn: (message) => deps.log.warn(message),
|
|
14670
14677
|
listIntegrations: async (addonId) => (await deps.api.list()).filter((i) => i.addonId === addonId).map((i) => ({
|
|
14671
14678
|
id: i.id,
|
|
14672
14679
|
name: i.name
|
|
14673
14680
|
})),
|
|
14674
|
-
readRows: (integrationId) => deps.api.
|
|
14681
|
+
readRows: async (integrationId) => resolvedRows(await deps.api.readLegacyIntegrationRows({ integrationId }), secrets),
|
|
14675
14682
|
putRecord: async (id, body) => {
|
|
14676
14683
|
if (await deps.records.get(id) !== null) return "exists";
|
|
14677
14684
|
try {
|
|
@@ -14690,15 +14697,17 @@ function integrationRowsPortsOverApi(deps) {
|
|
|
14690
14697
|
await deps.records.delete(id);
|
|
14691
14698
|
},
|
|
14692
14699
|
clearRows: async (integrationId) => {
|
|
14693
|
-
await deps.api.
|
|
14700
|
+
const refs = collectSecretMarkerRefs(await deps.api.readLegacyIntegrationRows({ integrationId }));
|
|
14701
|
+
if (refs.length > 0 && secrets !== null) await secrets.delete(refs);
|
|
14702
|
+
await deps.api.clearLegacyIntegrationRows({ integrationId });
|
|
14694
14703
|
}
|
|
14695
14704
|
};
|
|
14696
14705
|
}
|
|
14697
14706
|
function defaultIntegrationApiOver(api) {
|
|
14698
14707
|
return {
|
|
14699
14708
|
list: () => api.integrations.list.query(),
|
|
14700
|
-
|
|
14701
|
-
|
|
14709
|
+
readLegacyIntegrationRows: (input) => api.migrations.readLegacyIntegrationRows.query(input),
|
|
14710
|
+
clearLegacyIntegrationRows: (input) => api.migrations.clearLegacyIntegrationRows.mutate(input),
|
|
14702
14711
|
listDevices: (addonId) => api.deviceManager.listAll.query({
|
|
14703
14712
|
addonId,
|
|
14704
14713
|
projection: "slim"
|
|
@@ -50376,6 +50385,9 @@ var RunningProposalEvidenceSchema = object({
|
|
|
50376
50385
|
runsFound: number().int().nonnegative(),
|
|
50377
50386
|
pausesFound: number().int().nonnegative(),
|
|
50378
50387
|
longestPauseMs: number().nonnegative(),
|
|
50388
|
+
/** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
|
|
50389
|
+
pulsesFound: number().int().nonnegative(),
|
|
50390
|
+
longestPulseMs: number().nonnegative(),
|
|
50379
50391
|
idleFloorW: number(),
|
|
50380
50392
|
noiseCeilingW: number(),
|
|
50381
50393
|
plateauW: number(),
|
|
@@ -56242,11 +56254,7 @@ var CreateIntegrationInputSchema = object({
|
|
|
56242
56254
|
info: record(string(), unknown()).optional(),
|
|
56243
56255
|
/** `stableId` of the discovery candidate the form was seeded from (D984). */
|
|
56244
56256
|
originStableId: string().optional(),
|
|
56245
|
-
settings: record(string(), unknown()).optional()
|
|
56246
|
-
/** Keys of `settings` the form's schema declares secret (by type) — kept in
|
|
56247
|
-
* the keychain, not the table (D787). */
|
|
56248
|
-
secretKeys: array(string()).optional(),
|
|
56249
|
-
skipRestart: boolean().optional()
|
|
56257
|
+
settings: record(string(), unknown()).optional()
|
|
56250
56258
|
});
|
|
56251
56259
|
var UpdateIntegrationInputSchema = object({
|
|
56252
56260
|
id: string(),
|
|
@@ -56267,22 +56275,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
56267
56275
|
}), method(object({ id: string() }), DeleteIntegrationResultSchema, {
|
|
56268
56276
|
kind: "mutation",
|
|
56269
56277
|
auth: "admin"
|
|
56270
|
-
}), method(object({ id: string() }), record(string(), unknown()), { auth: "admin" }), method(object({
|
|
56271
|
-
id: string(),
|
|
56272
|
-
settings: record(string(), unknown()),
|
|
56273
|
-
/** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
|
|
56274
|
-
secretKeys: array(string()).optional(),
|
|
56275
|
-
/** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
|
|
56276
|
-
skipRestart: boolean().optional()
|
|
56277
|
-
}), object({ success: boolean() }), {
|
|
56278
|
-
kind: "mutation",
|
|
56279
|
-
auth: "admin"
|
|
56280
|
-
}), method(object({ id: string() }), object({
|
|
56281
|
-
rows: number().int().nonnegative(),
|
|
56282
|
-
secrets: number().int().nonnegative()
|
|
56283
|
-
}), {
|
|
56284
|
-
kind: "mutation",
|
|
56285
|
-
auth: "admin"
|
|
56286
56278
|
}), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
|
|
56287
56279
|
addonId: string(),
|
|
56288
56280
|
settings: record(string(), unknown())
|
|
@@ -59259,6 +59251,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
|
|
|
59259
59251
|
}), {
|
|
59260
59252
|
kind: "mutation",
|
|
59261
59253
|
auth: "admin"
|
|
59254
|
+
}), method(object({ integrationId: string().min(1) }), record(string(), unknown()), { auth: "admin" }), method(object({ integrationId: string().min(1) }), object({
|
|
59255
|
+
rows: number().int().nonnegative(),
|
|
59256
|
+
secrets: number().int().nonnegative()
|
|
59257
|
+
}), {
|
|
59258
|
+
kind: "mutation",
|
|
59259
|
+
auth: "admin"
|
|
59260
|
+
}), method(object({
|
|
59261
|
+
integrationId: string().min(1),
|
|
59262
|
+
patch: record(string(), unknown())
|
|
59263
|
+
}), object({ written: boolean() }), {
|
|
59264
|
+
kind: "mutation",
|
|
59265
|
+
auth: "admin"
|
|
59266
|
+
}), method(object({
|
|
59267
|
+
integrationId: string().min(1),
|
|
59268
|
+
keys: array(string().min(1))
|
|
59269
|
+
}), object({
|
|
59270
|
+
present: boolean(),
|
|
59271
|
+
removed: record(string(), unknown())
|
|
59272
|
+
}), {
|
|
59273
|
+
kind: "mutation",
|
|
59274
|
+
auth: "admin"
|
|
59262
59275
|
});
|
|
59263
59276
|
method(object({
|
|
59264
59277
|
sourceUrl: string(),
|
|
@@ -80677,11 +80690,15 @@ discriminatedUnion("kind", [object({
|
|
|
80677
80690
|
* 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
|
|
80678
80691
|
* near F. A device that is not near one level most of the time has no floor.
|
|
80679
80692
|
* 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
|
|
80680
|
-
* 3.
|
|
80681
|
-
*
|
|
80693
|
+
* 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
|
|
80694
|
+
* display waking): it is neither a run nor a pause. Among the remaining
|
|
80695
|
+
* episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
|
|
80696
|
+
* two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
|
|
80697
|
+
* a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
|
|
80698
|
+
* is no run.
|
|
80682
80699
|
* 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
|
|
80683
|
-
* grid a person would type; stop dwell covers the longest pause
|
|
80684
|
-
* covers the longest standby blip above T.
|
|
80700
|
+
* grid a person would type; stop dwell covers the longest pause and the
|
|
80701
|
+
* kind's floor; start dwell covers the longest pulse and standby blip above T.
|
|
80685
80702
|
* 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
|
|
80686
80703
|
* run must hold exactly one true interval and nothing may flap outside.
|
|
80687
80704
|
*/
|
|
@@ -80692,6 +80709,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
|
|
|
80692
80709
|
30 * SECOND_MS;
|
|
80693
80710
|
60 * SECOND_MS;
|
|
80694
80711
|
20 * MINUTE_MS$1;
|
|
80712
|
+
90 * SECOND_MS;
|
|
80713
|
+
30 * MINUTE_MS$1;
|
|
80714
|
+
10 * MINUTE_MS$1;
|
|
80715
|
+
DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
|
|
80695
80716
|
10 * SECOND_MS;
|
|
80696
80717
|
10 * SECOND_MS;
|
|
80697
80718
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
@@ -85976,13 +85997,6 @@ Object.freeze({
|
|
|
85976
85997
|
access: "create",
|
|
85977
85998
|
role: "admin"
|
|
85978
85999
|
},
|
|
85979
|
-
"integrations.clearSettings": {
|
|
85980
|
-
capName: "integrations",
|
|
85981
|
-
capScope: "system",
|
|
85982
|
-
addonId: null,
|
|
85983
|
-
access: "delete",
|
|
85984
|
-
role: "admin"
|
|
85985
|
-
},
|
|
85986
86000
|
"integrations.create": {
|
|
85987
86001
|
capName: "integrations",
|
|
85988
86002
|
capScope: "system",
|
|
@@ -86018,13 +86032,6 @@ Object.freeze({
|
|
|
86018
86032
|
access: "view",
|
|
86019
86033
|
role: "admin"
|
|
86020
86034
|
},
|
|
86021
|
-
"integrations.getSettings": {
|
|
86022
|
-
capName: "integrations",
|
|
86023
|
-
capScope: "system",
|
|
86024
|
-
addonId: null,
|
|
86025
|
-
access: "view",
|
|
86026
|
-
role: "admin"
|
|
86027
|
-
},
|
|
86028
86035
|
"integrations.list": {
|
|
86029
86036
|
capName: "integrations",
|
|
86030
86037
|
capScope: "system",
|
|
@@ -86032,13 +86039,6 @@ Object.freeze({
|
|
|
86032
86039
|
access: "view",
|
|
86033
86040
|
role: "admin"
|
|
86034
86041
|
},
|
|
86035
|
-
"integrations.setSettings": {
|
|
86036
|
-
capName: "integrations",
|
|
86037
|
-
capScope: "system",
|
|
86038
|
-
addonId: null,
|
|
86039
|
-
access: "create",
|
|
86040
|
-
role: "admin"
|
|
86041
|
-
},
|
|
86042
86042
|
"integrations.testConnection": {
|
|
86043
86043
|
capName: "integrations",
|
|
86044
86044
|
capScope: "system",
|
|
@@ -87033,6 +87033,13 @@ Object.freeze({
|
|
|
87033
87033
|
access: "view",
|
|
87034
87034
|
role: "admin"
|
|
87035
87035
|
},
|
|
87036
|
+
"migrations.clearLegacyIntegrationRows": {
|
|
87037
|
+
capName: "migrations",
|
|
87038
|
+
capScope: "system",
|
|
87039
|
+
addonId: null,
|
|
87040
|
+
access: "delete",
|
|
87041
|
+
role: "admin"
|
|
87042
|
+
},
|
|
87036
87043
|
"migrations.declareOwner": {
|
|
87037
87044
|
capName: "migrations",
|
|
87038
87045
|
capScope: "system",
|
|
@@ -87040,6 +87047,13 @@ Object.freeze({
|
|
|
87040
87047
|
access: "create",
|
|
87041
87048
|
role: "admin"
|
|
87042
87049
|
},
|
|
87050
|
+
"migrations.deleteLegacyIntegrationRowKeys": {
|
|
87051
|
+
capName: "migrations",
|
|
87052
|
+
capScope: "system",
|
|
87053
|
+
addonId: null,
|
|
87054
|
+
access: "delete",
|
|
87055
|
+
role: "admin"
|
|
87056
|
+
},
|
|
87043
87057
|
"migrations.dryRun": {
|
|
87044
87058
|
capName: "migrations",
|
|
87045
87059
|
capScope: "system",
|
|
@@ -87075,6 +87089,20 @@ Object.freeze({
|
|
|
87075
87089
|
access: "create",
|
|
87076
87090
|
role: "admin"
|
|
87077
87091
|
},
|
|
87092
|
+
"migrations.patchLegacyIntegrationRows": {
|
|
87093
|
+
capName: "migrations",
|
|
87094
|
+
capScope: "system",
|
|
87095
|
+
addonId: null,
|
|
87096
|
+
access: "create",
|
|
87097
|
+
role: "admin"
|
|
87098
|
+
},
|
|
87099
|
+
"migrations.readLegacyIntegrationRows": {
|
|
87100
|
+
capName: "migrations",
|
|
87101
|
+
capScope: "system",
|
|
87102
|
+
addonId: null,
|
|
87103
|
+
access: "view",
|
|
87104
|
+
role: "admin"
|
|
87105
|
+
},
|
|
87078
87106
|
"migrations.restorePreMigration": {
|
|
87079
87107
|
capName: "migrations",
|
|
87080
87108
|
capScope: "system",
|
|
@@ -105323,6 +105351,7 @@ var EcowittProviderAddon = class extends BaseDeviceProvider {
|
|
|
105323
105351
|
if (records === void 0) throw new Error("provider-ecowitt: ctx.records is required (hub-only addon)");
|
|
105324
105352
|
const rowsPorts = integrationRowsPortsOverApi({
|
|
105325
105353
|
api: defaultIntegrationApiOver(this.ctx.api),
|
|
105354
|
+
secrets: this.ctx.secrets ?? null,
|
|
105326
105355
|
records: records.kind({
|
|
105327
105356
|
name: ecowittConnectionsEntryKind.name,
|
|
105328
105357
|
declaration: ecowittConnectionsEntryKind.declaration,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-ecowitt",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.156",
|
|
4
4
|
"description": "Ecowitt weather-station device-provider addon for CamStack — wraps the @apocaliss92/nodewitt local-poll / push client",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
}
|
|
64
64
|
],
|
|
65
65
|
"requires": {
|
|
66
|
-
"server": ">=1.2.
|
|
66
|
+
"server": ">=1.2.770"
|
|
67
67
|
}
|
|
68
68
|
},
|
|
69
69
|
"files": [
|