@camstack/addon-matter-broker 0.2.156 → 0.2.157
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 +94 -58
- package/dist/addon.mjs +94 -58
- 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.157] - 2026-11-05
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- A Matter integration links to its fabric through the fabric record
|
|
15
|
+
|
|
10
16
|
## [0.2.156] - 2026-11-04
|
|
11
17
|
|
|
12
18
|
### Changed
|
package/dist/addon.js
CHANGED
|
@@ -5995,7 +5995,7 @@ var ZodIssueCode = {
|
|
|
5995
5995
|
var ZodFirstPartyTypeKind;
|
|
5996
5996
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5997
5997
|
//#endregion
|
|
5998
|
-
//#region ../types/dist/sleep-
|
|
5998
|
+
//#region ../types/dist/sleep-9TIHFj1w.mjs
|
|
5999
5999
|
/**
|
|
6000
6000
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6001
6001
|
* window to float samples (D455).
|
|
@@ -6595,7 +6595,7 @@ var NOT_RUN = {
|
|
|
6595
6595
|
* throws: an unreachable or refusing engine is logged and reported `declared: false`,
|
|
6596
6596
|
* because the hub (and this addon's boot) must not hang on a migration.
|
|
6597
6597
|
*/
|
|
6598
|
-
async function runAddonMigrations(host, migrations, logger) {
|
|
6598
|
+
async function runAddonMigrations(host, migrations, logger, options = {}) {
|
|
6599
6599
|
const first = migrations[0];
|
|
6600
6600
|
if (first === void 0) return NOT_RUN;
|
|
6601
6601
|
const owner = first.meta.owner;
|
|
@@ -6624,7 +6624,9 @@ async function runAddonMigrations(host, migrations, logger) {
|
|
|
6624
6624
|
else if (status === "blocked") blocked.push(id);
|
|
6625
6625
|
else skipped.push(id);
|
|
6626
6626
|
};
|
|
6627
|
+
const selected = options.only === void 0 ? null : new Set(options.only);
|
|
6627
6628
|
for (const step of declaration.steps) {
|
|
6629
|
+
if (selected !== null && !selected.has(step.id)) continue;
|
|
6628
6630
|
const bound = byId.get(step.id);
|
|
6629
6631
|
if (bound === void 0 || step.action === "skip") {
|
|
6630
6632
|
skipped.push(step.id);
|
|
@@ -7784,14 +7786,18 @@ var BaseAddon = class {
|
|
|
7784
7786
|
* nothing; the boot continues. A migration that FAILED (or was blocked by one)
|
|
7785
7787
|
* and declares `onFailure: 'block-owner'` makes this throw, so the addon does not
|
|
7786
7788
|
* serve data whose shape it cannot trust; `tolerate` migrations never do.
|
|
7789
|
+
*
|
|
7790
|
+
* ALWAYS pass the whole catalogue; a phase that must run only some of it passes
|
|
7791
|
+
* `{ only: [ids] }` — never a filtered catalogue (the engine would judge the
|
|
7792
|
+
* omitted applied ids "newer").
|
|
7787
7793
|
*/
|
|
7788
|
-
async runMigrations(migrations) {
|
|
7794
|
+
async runMigrations(migrations, options) {
|
|
7789
7795
|
const api = this.ctx.api.migrations;
|
|
7790
7796
|
const report = await runAddonMigrations({
|
|
7791
7797
|
declareOwner: (input) => api.declareOwner.mutate(input),
|
|
7792
7798
|
startMigration: (input) => api.startMigration.mutate(input),
|
|
7793
7799
|
finishMigration: (input) => api.finishMigration.mutate(input)
|
|
7794
|
-
}, migrations, this.ctx.logger);
|
|
7800
|
+
}, migrations, this.ctx.logger, options);
|
|
7795
7801
|
if (report.blockOwner.length > 0) throw new AddonMigrationsBlockedError(report.blockOwner);
|
|
7796
7802
|
return report;
|
|
7797
7803
|
}
|
|
@@ -7933,10 +7939,9 @@ var BaseAddon = class {
|
|
|
7933
7939
|
*
|
|
7934
7940
|
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
7935
7941
|
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
7936
|
-
* SHAPE of the form only — the values live
|
|
7937
|
-
* unchanged (`integrations.setSettings` for an account integration).
|
|
7942
|
+
* SHAPE of the form only — the values live on the instance record.
|
|
7938
7943
|
*/
|
|
7939
|
-
async
|
|
7944
|
+
async integrationFormSchema(_instance) {
|
|
7940
7945
|
return null;
|
|
7941
7946
|
}
|
|
7942
7947
|
/**
|
|
@@ -7982,7 +7987,7 @@ var BaseAddon = class {
|
|
|
7982
7987
|
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
7983
7988
|
*/
|
|
7984
7989
|
async getIntegrationFormSchema(instance, nodeId) {
|
|
7985
|
-
const scoped = await this.
|
|
7990
|
+
const scoped = await this.integrationFormSchema(instance);
|
|
7986
7991
|
if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
|
|
7987
7992
|
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
7988
7993
|
}
|
|
@@ -9256,6 +9261,7 @@ function defineEntryKind(name, spec) {
|
|
|
9256
9261
|
class: "config",
|
|
9257
9262
|
writeTrigger: spec.writeTrigger ?? "an operator adds or edits an entry in the entries UI",
|
|
9258
9263
|
retention: { none: "an entry goes only when the operator deletes it" },
|
|
9264
|
+
...spec.maxDataBytes === void 0 ? {} : { maxDataBytes: spec.maxDataBytes },
|
|
9259
9265
|
...spec.database === void 0 ? {} : { database: spec.database },
|
|
9260
9266
|
...spec.indexes === void 0 ? {} : { indexes: spec.indexes },
|
|
9261
9267
|
...spec.secretArrayKeys === void 0 ? {} : { secretArrayKeys: spec.secretArrayKeys },
|
|
@@ -11925,7 +11931,7 @@ object({
|
|
|
11925
11931
|
params: record(string$2(), union([string$2(), number()])).optional()
|
|
11926
11932
|
});
|
|
11927
11933
|
//#endregion
|
|
11928
|
-
//#region ../types/dist/composition-
|
|
11934
|
+
//#region ../types/dist/composition-pOHbTzRB.mjs
|
|
11929
11935
|
/**
|
|
11930
11936
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11931
11937
|
*
|
|
@@ -14506,7 +14512,13 @@ var MigrationLedgerEntrySchema = object({
|
|
|
14506
14512
|
* joined by the engine from the catalogues it knows this boot. Absent when no
|
|
14507
14513
|
* catalogue lists the id (a newer database).
|
|
14508
14514
|
*/
|
|
14509
|
-
meta: MigrationMetaSchema.optional()
|
|
14515
|
+
meta: MigrationMetaSchema.optional(),
|
|
14516
|
+
/**
|
|
14517
|
+
* Set when this is an applied row of an addon owner whose catalogue the answering
|
|
14518
|
+
* process has not loaded (the owner has not declared yet): the row is applied, the
|
|
14519
|
+
* process just cannot judge it. Never `skipped-newer` — that needs the owner loaded.
|
|
14520
|
+
*/
|
|
14521
|
+
ownerNotLoaded: boolean().optional()
|
|
14510
14522
|
});
|
|
14511
14523
|
/** A catalogued migration that is not applied, with where it stands. */
|
|
14512
14524
|
var MigrationPendingEntrySchema = object({
|
|
@@ -50241,6 +50253,9 @@ var RunningProposalEvidenceSchema = object({
|
|
|
50241
50253
|
runsFound: number().int().nonnegative(),
|
|
50242
50254
|
pausesFound: number().int().nonnegative(),
|
|
50243
50255
|
longestPauseMs: number().nonnegative(),
|
|
50256
|
+
/** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
|
|
50257
|
+
pulsesFound: number().int().nonnegative(),
|
|
50258
|
+
longestPulseMs: number().nonnegative(),
|
|
50244
50259
|
idleFloorW: number(),
|
|
50245
50260
|
noiseCeilingW: number(),
|
|
50246
50261
|
plateauW: number(),
|
|
@@ -56086,11 +56101,7 @@ var CreateIntegrationInputSchema = object({
|
|
|
56086
56101
|
info: record(string$2(), unknown()).optional(),
|
|
56087
56102
|
/** `stableId` of the discovery candidate the form was seeded from (D984). */
|
|
56088
56103
|
originStableId: string$2().optional(),
|
|
56089
|
-
settings: record(string$2(), unknown()).optional()
|
|
56090
|
-
/** Keys of `settings` the form's schema declares secret (by type) — kept in
|
|
56091
|
-
* the keychain, not the table (D787). */
|
|
56092
|
-
secretKeys: array(string$2()).optional(),
|
|
56093
|
-
skipRestart: boolean().optional()
|
|
56104
|
+
settings: record(string$2(), unknown()).optional()
|
|
56094
56105
|
});
|
|
56095
56106
|
var UpdateIntegrationInputSchema = object({
|
|
56096
56107
|
id: string$2(),
|
|
@@ -56111,16 +56122,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string$2
|
|
|
56111
56122
|
}), method(object({ id: string$2() }), DeleteIntegrationResultSchema, {
|
|
56112
56123
|
kind: "mutation",
|
|
56113
56124
|
auth: "admin"
|
|
56114
|
-
}), method(object({ id: string$2() }), record(string$2(), unknown()), { auth: "admin" }), method(object({
|
|
56115
|
-
id: string$2(),
|
|
56116
|
-
settings: record(string$2(), unknown()),
|
|
56117
|
-
/** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
|
|
56118
|
-
secretKeys: array(string$2()).optional(),
|
|
56119
|
-
/** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
|
|
56120
|
-
skipRestart: boolean().optional()
|
|
56121
|
-
}), object({ success: boolean() }), {
|
|
56122
|
-
kind: "mutation",
|
|
56123
|
-
auth: "admin"
|
|
56124
56125
|
}), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
|
|
56125
56126
|
addonId: string$2(),
|
|
56126
56127
|
settings: record(string$2(), unknown())
|
|
@@ -59097,6 +59098,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
|
|
|
59097
59098
|
}), {
|
|
59098
59099
|
kind: "mutation",
|
|
59099
59100
|
auth: "admin"
|
|
59101
|
+
}), method(object({ integrationId: string$2().min(1) }), record(string$2(), unknown()), { auth: "admin" }), method(object({ integrationId: string$2().min(1) }), object({
|
|
59102
|
+
rows: number().int().nonnegative(),
|
|
59103
|
+
secrets: number().int().nonnegative()
|
|
59104
|
+
}), {
|
|
59105
|
+
kind: "mutation",
|
|
59106
|
+
auth: "admin"
|
|
59107
|
+
}), method(object({
|
|
59108
|
+
integrationId: string$2().min(1),
|
|
59109
|
+
patch: record(string$2(), unknown())
|
|
59110
|
+
}), object({ written: boolean() }), {
|
|
59111
|
+
kind: "mutation",
|
|
59112
|
+
auth: "admin"
|
|
59113
|
+
}), method(object({
|
|
59114
|
+
integrationId: string$2().min(1),
|
|
59115
|
+
keys: array(string$2().min(1))
|
|
59116
|
+
}), object({
|
|
59117
|
+
present: boolean(),
|
|
59118
|
+
removed: record(string$2(), unknown())
|
|
59119
|
+
}), {
|
|
59120
|
+
kind: "mutation",
|
|
59121
|
+
auth: "admin"
|
|
59100
59122
|
});
|
|
59101
59123
|
method(object({
|
|
59102
59124
|
sourceUrl: string$2(),
|
|
@@ -80423,11 +80445,15 @@ discriminatedUnion("kind", [object({
|
|
|
80423
80445
|
* 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
|
|
80424
80446
|
* near F. A device that is not near one level most of the time has no floor.
|
|
80425
80447
|
* 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
|
|
80426
|
-
* 3.
|
|
80427
|
-
*
|
|
80448
|
+
* 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
|
|
80449
|
+
* display waking): it is neither a run nor a pause. Among the remaining
|
|
80450
|
+
* episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
|
|
80451
|
+
* two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
|
|
80452
|
+
* a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
|
|
80453
|
+
* is no run.
|
|
80428
80454
|
* 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
|
|
80429
|
-
* grid a person would type; stop dwell covers the longest pause
|
|
80430
|
-
* covers the longest standby blip above T.
|
|
80455
|
+
* grid a person would type; stop dwell covers the longest pause and the
|
|
80456
|
+
* kind's floor; start dwell covers the longest pulse and standby blip above T.
|
|
80431
80457
|
* 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
|
|
80432
80458
|
* run must hold exactly one true interval and nothing may flap outside.
|
|
80433
80459
|
*/
|
|
@@ -80438,6 +80464,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
|
|
|
80438
80464
|
30 * SECOND_MS;
|
|
80439
80465
|
60 * SECOND_MS;
|
|
80440
80466
|
20 * MINUTE_MS$1;
|
|
80467
|
+
90 * SECOND_MS;
|
|
80468
|
+
30 * MINUTE_MS$1;
|
|
80469
|
+
10 * MINUTE_MS$1;
|
|
80470
|
+
DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
|
|
80441
80471
|
10 * SECOND_MS;
|
|
80442
80472
|
10 * SECOND_MS;
|
|
80443
80473
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
@@ -85757,13 +85787,6 @@ Object.freeze({
|
|
|
85757
85787
|
access: "view",
|
|
85758
85788
|
role: "admin"
|
|
85759
85789
|
},
|
|
85760
|
-
"integrations.getSettings": {
|
|
85761
|
-
capName: "integrations",
|
|
85762
|
-
capScope: "system",
|
|
85763
|
-
addonId: null,
|
|
85764
|
-
access: "view",
|
|
85765
|
-
role: "admin"
|
|
85766
|
-
},
|
|
85767
85790
|
"integrations.list": {
|
|
85768
85791
|
capName: "integrations",
|
|
85769
85792
|
capScope: "system",
|
|
@@ -85771,13 +85794,6 @@ Object.freeze({
|
|
|
85771
85794
|
access: "view",
|
|
85772
85795
|
role: "admin"
|
|
85773
85796
|
},
|
|
85774
|
-
"integrations.setSettings": {
|
|
85775
|
-
capName: "integrations",
|
|
85776
|
-
capScope: "system",
|
|
85777
|
-
addonId: null,
|
|
85778
|
-
access: "create",
|
|
85779
|
-
role: "admin"
|
|
85780
|
-
},
|
|
85781
85797
|
"integrations.testConnection": {
|
|
85782
85798
|
capName: "integrations",
|
|
85783
85799
|
capScope: "system",
|
|
@@ -86772,6 +86788,13 @@ Object.freeze({
|
|
|
86772
86788
|
access: "view",
|
|
86773
86789
|
role: "admin"
|
|
86774
86790
|
},
|
|
86791
|
+
"migrations.clearLegacyIntegrationRows": {
|
|
86792
|
+
capName: "migrations",
|
|
86793
|
+
capScope: "system",
|
|
86794
|
+
addonId: null,
|
|
86795
|
+
access: "delete",
|
|
86796
|
+
role: "admin"
|
|
86797
|
+
},
|
|
86775
86798
|
"migrations.declareOwner": {
|
|
86776
86799
|
capName: "migrations",
|
|
86777
86800
|
capScope: "system",
|
|
@@ -86779,6 +86802,13 @@ Object.freeze({
|
|
|
86779
86802
|
access: "create",
|
|
86780
86803
|
role: "admin"
|
|
86781
86804
|
},
|
|
86805
|
+
"migrations.deleteLegacyIntegrationRowKeys": {
|
|
86806
|
+
capName: "migrations",
|
|
86807
|
+
capScope: "system",
|
|
86808
|
+
addonId: null,
|
|
86809
|
+
access: "delete",
|
|
86810
|
+
role: "admin"
|
|
86811
|
+
},
|
|
86782
86812
|
"migrations.dryRun": {
|
|
86783
86813
|
capName: "migrations",
|
|
86784
86814
|
capScope: "system",
|
|
@@ -86814,6 +86844,20 @@ Object.freeze({
|
|
|
86814
86844
|
access: "create",
|
|
86815
86845
|
role: "admin"
|
|
86816
86846
|
},
|
|
86847
|
+
"migrations.patchLegacyIntegrationRows": {
|
|
86848
|
+
capName: "migrations",
|
|
86849
|
+
capScope: "system",
|
|
86850
|
+
addonId: null,
|
|
86851
|
+
access: "create",
|
|
86852
|
+
role: "admin"
|
|
86853
|
+
},
|
|
86854
|
+
"migrations.readLegacyIntegrationRows": {
|
|
86855
|
+
capName: "migrations",
|
|
86856
|
+
capScope: "system",
|
|
86857
|
+
addonId: null,
|
|
86858
|
+
access: "view",
|
|
86859
|
+
role: "admin"
|
|
86860
|
+
},
|
|
86817
86861
|
"migrations.restorePreMigration": {
|
|
86818
86862
|
capName: "migrations",
|
|
86819
86863
|
capScope: "system",
|
|
@@ -209100,18 +209144,10 @@ var MatterBrokerAddon = class extends BaseDeviceProvider {
|
|
|
209100
209144
|
try {
|
|
209101
209145
|
const mine = (await this.ctx.api.integrations.list.query()).filter((i) => i.addonId === this.ctx.id);
|
|
209102
209146
|
const surviving = new Set(mine.map((i) => i.id));
|
|
209103
|
-
for (const
|
|
209104
|
-
const
|
|
209105
|
-
|
|
209106
|
-
|
|
209107
|
-
if (!this.activeBrokers.some((b) => b.id === brokerId)) {
|
|
209108
|
-
this.ctx.logger.warn("Matter integration→broker: linked broker not found", { meta: {
|
|
209109
|
-
integrationId: integration.id,
|
|
209110
|
-
brokerId
|
|
209111
|
-
} });
|
|
209112
|
-
continue;
|
|
209113
|
-
}
|
|
209114
|
-
this.requireRegistry().linkIntegration(integration.id, brokerId);
|
|
209147
|
+
for (const broker of this.activeBrokers) {
|
|
209148
|
+
const integrationId = broker.integrationId;
|
|
209149
|
+
if (integrationId === void 0 || !surviving.has(integrationId)) continue;
|
|
209150
|
+
this.requireRegistry().linkIntegration(integrationId, broker.id);
|
|
209115
209151
|
}
|
|
209116
209152
|
const toRemove = this.activeBrokers.filter((b) => b.integrationId !== void 0 && !surviving.has(b.integrationId)).map((b) => b.id);
|
|
209117
209153
|
if (toRemove.length === 0) return;
|
|
@@ -209152,9 +209188,9 @@ var MatterBrokerAddon = class extends BaseDeviceProvider {
|
|
|
209152
209188
|
},
|
|
209153
209189
|
logger: this.ctx.logger,
|
|
209154
209190
|
getBrokerIdForIntegration: async (id) => {
|
|
209155
|
-
const
|
|
209156
|
-
if (
|
|
209157
|
-
return
|
|
209191
|
+
const broker = this.activeBrokers.find((entry) => entry.integrationId === id);
|
|
209192
|
+
if (broker === void 0) throw new Error(`integration ${id} has no linked brokerId`);
|
|
209193
|
+
return broker.id;
|
|
209158
209194
|
},
|
|
209159
209195
|
listAdoptedMatter: async () => {
|
|
209160
209196
|
const reg = this.ctx.kernel.deviceRegistry;
|
package/dist/addon.mjs
CHANGED
|
@@ -5993,7 +5993,7 @@ var ZodIssueCode = {
|
|
|
5993
5993
|
var ZodFirstPartyTypeKind;
|
|
5994
5994
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5995
5995
|
//#endregion
|
|
5996
|
-
//#region ../types/dist/sleep-
|
|
5996
|
+
//#region ../types/dist/sleep-9TIHFj1w.mjs
|
|
5997
5997
|
/**
|
|
5998
5998
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5999
5999
|
* window to float samples (D455).
|
|
@@ -6593,7 +6593,7 @@ var NOT_RUN = {
|
|
|
6593
6593
|
* throws: an unreachable or refusing engine is logged and reported `declared: false`,
|
|
6594
6594
|
* because the hub (and this addon's boot) must not hang on a migration.
|
|
6595
6595
|
*/
|
|
6596
|
-
async function runAddonMigrations(host, migrations, logger) {
|
|
6596
|
+
async function runAddonMigrations(host, migrations, logger, options = {}) {
|
|
6597
6597
|
const first = migrations[0];
|
|
6598
6598
|
if (first === void 0) return NOT_RUN;
|
|
6599
6599
|
const owner = first.meta.owner;
|
|
@@ -6622,7 +6622,9 @@ async function runAddonMigrations(host, migrations, logger) {
|
|
|
6622
6622
|
else if (status === "blocked") blocked.push(id);
|
|
6623
6623
|
else skipped.push(id);
|
|
6624
6624
|
};
|
|
6625
|
+
const selected = options.only === void 0 ? null : new Set(options.only);
|
|
6625
6626
|
for (const step of declaration.steps) {
|
|
6627
|
+
if (selected !== null && !selected.has(step.id)) continue;
|
|
6626
6628
|
const bound = byId.get(step.id);
|
|
6627
6629
|
if (bound === void 0 || step.action === "skip") {
|
|
6628
6630
|
skipped.push(step.id);
|
|
@@ -7782,14 +7784,18 @@ var BaseAddon = class {
|
|
|
7782
7784
|
* nothing; the boot continues. A migration that FAILED (or was blocked by one)
|
|
7783
7785
|
* and declares `onFailure: 'block-owner'` makes this throw, so the addon does not
|
|
7784
7786
|
* serve data whose shape it cannot trust; `tolerate` migrations never do.
|
|
7787
|
+
*
|
|
7788
|
+
* ALWAYS pass the whole catalogue; a phase that must run only some of it passes
|
|
7789
|
+
* `{ only: [ids] }` — never a filtered catalogue (the engine would judge the
|
|
7790
|
+
* omitted applied ids "newer").
|
|
7785
7791
|
*/
|
|
7786
|
-
async runMigrations(migrations) {
|
|
7792
|
+
async runMigrations(migrations, options) {
|
|
7787
7793
|
const api = this.ctx.api.migrations;
|
|
7788
7794
|
const report = await runAddonMigrations({
|
|
7789
7795
|
declareOwner: (input) => api.declareOwner.mutate(input),
|
|
7790
7796
|
startMigration: (input) => api.startMigration.mutate(input),
|
|
7791
7797
|
finishMigration: (input) => api.finishMigration.mutate(input)
|
|
7792
|
-
}, migrations, this.ctx.logger);
|
|
7798
|
+
}, migrations, this.ctx.logger, options);
|
|
7793
7799
|
if (report.blockOwner.length > 0) throw new AddonMigrationsBlockedError(report.blockOwner);
|
|
7794
7800
|
return report;
|
|
7795
7801
|
}
|
|
@@ -7931,10 +7937,9 @@ var BaseAddon = class {
|
|
|
7931
7937
|
*
|
|
7932
7938
|
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
7933
7939
|
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
7934
|
-
* SHAPE of the form only — the values live
|
|
7935
|
-
* unchanged (`integrations.setSettings` for an account integration).
|
|
7940
|
+
* SHAPE of the form only — the values live on the instance record.
|
|
7936
7941
|
*/
|
|
7937
|
-
async
|
|
7942
|
+
async integrationFormSchema(_instance) {
|
|
7938
7943
|
return null;
|
|
7939
7944
|
}
|
|
7940
7945
|
/**
|
|
@@ -7980,7 +7985,7 @@ var BaseAddon = class {
|
|
|
7980
7985
|
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
7981
7986
|
*/
|
|
7982
7987
|
async getIntegrationFormSchema(instance, nodeId) {
|
|
7983
|
-
const scoped = await this.
|
|
7988
|
+
const scoped = await this.integrationFormSchema(instance);
|
|
7984
7989
|
if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
|
|
7985
7990
|
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
7986
7991
|
}
|
|
@@ -9254,6 +9259,7 @@ function defineEntryKind(name, spec) {
|
|
|
9254
9259
|
class: "config",
|
|
9255
9260
|
writeTrigger: spec.writeTrigger ?? "an operator adds or edits an entry in the entries UI",
|
|
9256
9261
|
retention: { none: "an entry goes only when the operator deletes it" },
|
|
9262
|
+
...spec.maxDataBytes === void 0 ? {} : { maxDataBytes: spec.maxDataBytes },
|
|
9257
9263
|
...spec.database === void 0 ? {} : { database: spec.database },
|
|
9258
9264
|
...spec.indexes === void 0 ? {} : { indexes: spec.indexes },
|
|
9259
9265
|
...spec.secretArrayKeys === void 0 ? {} : { secretArrayKeys: spec.secretArrayKeys },
|
|
@@ -11923,7 +11929,7 @@ object({
|
|
|
11923
11929
|
params: record(string$2(), union([string$2(), number()])).optional()
|
|
11924
11930
|
});
|
|
11925
11931
|
//#endregion
|
|
11926
|
-
//#region ../types/dist/composition-
|
|
11932
|
+
//#region ../types/dist/composition-pOHbTzRB.mjs
|
|
11927
11933
|
/**
|
|
11928
11934
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11929
11935
|
*
|
|
@@ -14504,7 +14510,13 @@ var MigrationLedgerEntrySchema = object({
|
|
|
14504
14510
|
* joined by the engine from the catalogues it knows this boot. Absent when no
|
|
14505
14511
|
* catalogue lists the id (a newer database).
|
|
14506
14512
|
*/
|
|
14507
|
-
meta: MigrationMetaSchema.optional()
|
|
14513
|
+
meta: MigrationMetaSchema.optional(),
|
|
14514
|
+
/**
|
|
14515
|
+
* Set when this is an applied row of an addon owner whose catalogue the answering
|
|
14516
|
+
* process has not loaded (the owner has not declared yet): the row is applied, the
|
|
14517
|
+
* process just cannot judge it. Never `skipped-newer` — that needs the owner loaded.
|
|
14518
|
+
*/
|
|
14519
|
+
ownerNotLoaded: boolean().optional()
|
|
14508
14520
|
});
|
|
14509
14521
|
/** A catalogued migration that is not applied, with where it stands. */
|
|
14510
14522
|
var MigrationPendingEntrySchema = object({
|
|
@@ -50239,6 +50251,9 @@ var RunningProposalEvidenceSchema = object({
|
|
|
50239
50251
|
runsFound: number().int().nonnegative(),
|
|
50240
50252
|
pausesFound: number().int().nonnegative(),
|
|
50241
50253
|
longestPauseMs: number().nonnegative(),
|
|
50254
|
+
/** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
|
|
50255
|
+
pulsesFound: number().int().nonnegative(),
|
|
50256
|
+
longestPulseMs: number().nonnegative(),
|
|
50242
50257
|
idleFloorW: number(),
|
|
50243
50258
|
noiseCeilingW: number(),
|
|
50244
50259
|
plateauW: number(),
|
|
@@ -56084,11 +56099,7 @@ var CreateIntegrationInputSchema = object({
|
|
|
56084
56099
|
info: record(string$2(), unknown()).optional(),
|
|
56085
56100
|
/** `stableId` of the discovery candidate the form was seeded from (D984). */
|
|
56086
56101
|
originStableId: string$2().optional(),
|
|
56087
|
-
settings: record(string$2(), unknown()).optional()
|
|
56088
|
-
/** Keys of `settings` the form's schema declares secret (by type) — kept in
|
|
56089
|
-
* the keychain, not the table (D787). */
|
|
56090
|
-
secretKeys: array(string$2()).optional(),
|
|
56091
|
-
skipRestart: boolean().optional()
|
|
56102
|
+
settings: record(string$2(), unknown()).optional()
|
|
56092
56103
|
});
|
|
56093
56104
|
var UpdateIntegrationInputSchema = object({
|
|
56094
56105
|
id: string$2(),
|
|
@@ -56109,16 +56120,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string$2
|
|
|
56109
56120
|
}), method(object({ id: string$2() }), DeleteIntegrationResultSchema, {
|
|
56110
56121
|
kind: "mutation",
|
|
56111
56122
|
auth: "admin"
|
|
56112
|
-
}), method(object({ id: string$2() }), record(string$2(), unknown()), { auth: "admin" }), method(object({
|
|
56113
|
-
id: string$2(),
|
|
56114
|
-
settings: record(string$2(), unknown()),
|
|
56115
|
-
/** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
|
|
56116
|
-
secretKeys: array(string$2()).optional(),
|
|
56117
|
-
/** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
|
|
56118
|
-
skipRestart: boolean().optional()
|
|
56119
|
-
}), object({ success: boolean() }), {
|
|
56120
|
-
kind: "mutation",
|
|
56121
|
-
auth: "admin"
|
|
56122
56123
|
}), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
|
|
56123
56124
|
addonId: string$2(),
|
|
56124
56125
|
settings: record(string$2(), unknown())
|
|
@@ -59095,6 +59096,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
|
|
|
59095
59096
|
}), {
|
|
59096
59097
|
kind: "mutation",
|
|
59097
59098
|
auth: "admin"
|
|
59099
|
+
}), method(object({ integrationId: string$2().min(1) }), record(string$2(), unknown()), { auth: "admin" }), method(object({ integrationId: string$2().min(1) }), object({
|
|
59100
|
+
rows: number().int().nonnegative(),
|
|
59101
|
+
secrets: number().int().nonnegative()
|
|
59102
|
+
}), {
|
|
59103
|
+
kind: "mutation",
|
|
59104
|
+
auth: "admin"
|
|
59105
|
+
}), method(object({
|
|
59106
|
+
integrationId: string$2().min(1),
|
|
59107
|
+
patch: record(string$2(), unknown())
|
|
59108
|
+
}), object({ written: boolean() }), {
|
|
59109
|
+
kind: "mutation",
|
|
59110
|
+
auth: "admin"
|
|
59111
|
+
}), method(object({
|
|
59112
|
+
integrationId: string$2().min(1),
|
|
59113
|
+
keys: array(string$2().min(1))
|
|
59114
|
+
}), object({
|
|
59115
|
+
present: boolean(),
|
|
59116
|
+
removed: record(string$2(), unknown())
|
|
59117
|
+
}), {
|
|
59118
|
+
kind: "mutation",
|
|
59119
|
+
auth: "admin"
|
|
59098
59120
|
});
|
|
59099
59121
|
method(object({
|
|
59100
59122
|
sourceUrl: string$2(),
|
|
@@ -80421,11 +80443,15 @@ discriminatedUnion("kind", [object({
|
|
|
80421
80443
|
* 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
|
|
80422
80444
|
* near F. A device that is not near one level most of the time has no floor.
|
|
80423
80445
|
* 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
|
|
80424
|
-
* 3.
|
|
80425
|
-
*
|
|
80446
|
+
* 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
|
|
80447
|
+
* display waking): it is neither a run nor a pause. Among the remaining
|
|
80448
|
+
* episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
|
|
80449
|
+
* two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
|
|
80450
|
+
* a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
|
|
80451
|
+
* is no run.
|
|
80426
80452
|
* 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
|
|
80427
|
-
* grid a person would type; stop dwell covers the longest pause
|
|
80428
|
-
* covers the longest standby blip above T.
|
|
80453
|
+
* grid a person would type; stop dwell covers the longest pause and the
|
|
80454
|
+
* kind's floor; start dwell covers the longest pulse and standby blip above T.
|
|
80429
80455
|
* 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
|
|
80430
80456
|
* run must hold exactly one true interval and nothing may flap outside.
|
|
80431
80457
|
*/
|
|
@@ -80436,6 +80462,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
|
|
|
80436
80462
|
30 * SECOND_MS;
|
|
80437
80463
|
60 * SECOND_MS;
|
|
80438
80464
|
20 * MINUTE_MS$1;
|
|
80465
|
+
90 * SECOND_MS;
|
|
80466
|
+
30 * MINUTE_MS$1;
|
|
80467
|
+
10 * MINUTE_MS$1;
|
|
80468
|
+
DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
|
|
80439
80469
|
10 * SECOND_MS;
|
|
80440
80470
|
10 * SECOND_MS;
|
|
80441
80471
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
@@ -85755,13 +85785,6 @@ Object.freeze({
|
|
|
85755
85785
|
access: "view",
|
|
85756
85786
|
role: "admin"
|
|
85757
85787
|
},
|
|
85758
|
-
"integrations.getSettings": {
|
|
85759
|
-
capName: "integrations",
|
|
85760
|
-
capScope: "system",
|
|
85761
|
-
addonId: null,
|
|
85762
|
-
access: "view",
|
|
85763
|
-
role: "admin"
|
|
85764
|
-
},
|
|
85765
85788
|
"integrations.list": {
|
|
85766
85789
|
capName: "integrations",
|
|
85767
85790
|
capScope: "system",
|
|
@@ -85769,13 +85792,6 @@ Object.freeze({
|
|
|
85769
85792
|
access: "view",
|
|
85770
85793
|
role: "admin"
|
|
85771
85794
|
},
|
|
85772
|
-
"integrations.setSettings": {
|
|
85773
|
-
capName: "integrations",
|
|
85774
|
-
capScope: "system",
|
|
85775
|
-
addonId: null,
|
|
85776
|
-
access: "create",
|
|
85777
|
-
role: "admin"
|
|
85778
|
-
},
|
|
85779
85795
|
"integrations.testConnection": {
|
|
85780
85796
|
capName: "integrations",
|
|
85781
85797
|
capScope: "system",
|
|
@@ -86770,6 +86786,13 @@ Object.freeze({
|
|
|
86770
86786
|
access: "view",
|
|
86771
86787
|
role: "admin"
|
|
86772
86788
|
},
|
|
86789
|
+
"migrations.clearLegacyIntegrationRows": {
|
|
86790
|
+
capName: "migrations",
|
|
86791
|
+
capScope: "system",
|
|
86792
|
+
addonId: null,
|
|
86793
|
+
access: "delete",
|
|
86794
|
+
role: "admin"
|
|
86795
|
+
},
|
|
86773
86796
|
"migrations.declareOwner": {
|
|
86774
86797
|
capName: "migrations",
|
|
86775
86798
|
capScope: "system",
|
|
@@ -86777,6 +86800,13 @@ Object.freeze({
|
|
|
86777
86800
|
access: "create",
|
|
86778
86801
|
role: "admin"
|
|
86779
86802
|
},
|
|
86803
|
+
"migrations.deleteLegacyIntegrationRowKeys": {
|
|
86804
|
+
capName: "migrations",
|
|
86805
|
+
capScope: "system",
|
|
86806
|
+
addonId: null,
|
|
86807
|
+
access: "delete",
|
|
86808
|
+
role: "admin"
|
|
86809
|
+
},
|
|
86780
86810
|
"migrations.dryRun": {
|
|
86781
86811
|
capName: "migrations",
|
|
86782
86812
|
capScope: "system",
|
|
@@ -86812,6 +86842,20 @@ Object.freeze({
|
|
|
86812
86842
|
access: "create",
|
|
86813
86843
|
role: "admin"
|
|
86814
86844
|
},
|
|
86845
|
+
"migrations.patchLegacyIntegrationRows": {
|
|
86846
|
+
capName: "migrations",
|
|
86847
|
+
capScope: "system",
|
|
86848
|
+
addonId: null,
|
|
86849
|
+
access: "create",
|
|
86850
|
+
role: "admin"
|
|
86851
|
+
},
|
|
86852
|
+
"migrations.readLegacyIntegrationRows": {
|
|
86853
|
+
capName: "migrations",
|
|
86854
|
+
capScope: "system",
|
|
86855
|
+
addonId: null,
|
|
86856
|
+
access: "view",
|
|
86857
|
+
role: "admin"
|
|
86858
|
+
},
|
|
86815
86859
|
"migrations.restorePreMigration": {
|
|
86816
86860
|
capName: "migrations",
|
|
86817
86861
|
capScope: "system",
|
|
@@ -209098,18 +209142,10 @@ var MatterBrokerAddon = class extends BaseDeviceProvider {
|
|
|
209098
209142
|
try {
|
|
209099
209143
|
const mine = (await this.ctx.api.integrations.list.query()).filter((i) => i.addonId === this.ctx.id);
|
|
209100
209144
|
const surviving = new Set(mine.map((i) => i.id));
|
|
209101
|
-
for (const
|
|
209102
|
-
const
|
|
209103
|
-
|
|
209104
|
-
|
|
209105
|
-
if (!this.activeBrokers.some((b) => b.id === brokerId)) {
|
|
209106
|
-
this.ctx.logger.warn("Matter integration→broker: linked broker not found", { meta: {
|
|
209107
|
-
integrationId: integration.id,
|
|
209108
|
-
brokerId
|
|
209109
|
-
} });
|
|
209110
|
-
continue;
|
|
209111
|
-
}
|
|
209112
|
-
this.requireRegistry().linkIntegration(integration.id, brokerId);
|
|
209145
|
+
for (const broker of this.activeBrokers) {
|
|
209146
|
+
const integrationId = broker.integrationId;
|
|
209147
|
+
if (integrationId === void 0 || !surviving.has(integrationId)) continue;
|
|
209148
|
+
this.requireRegistry().linkIntegration(integrationId, broker.id);
|
|
209113
209149
|
}
|
|
209114
209150
|
const toRemove = this.activeBrokers.filter((b) => b.integrationId !== void 0 && !surviving.has(b.integrationId)).map((b) => b.id);
|
|
209115
209151
|
if (toRemove.length === 0) return;
|
|
@@ -209150,9 +209186,9 @@ var MatterBrokerAddon = class extends BaseDeviceProvider {
|
|
|
209150
209186
|
},
|
|
209151
209187
|
logger: this.ctx.logger,
|
|
209152
209188
|
getBrokerIdForIntegration: async (id) => {
|
|
209153
|
-
const
|
|
209154
|
-
if (
|
|
209155
|
-
return
|
|
209189
|
+
const broker = this.activeBrokers.find((entry) => entry.integrationId === id);
|
|
209190
|
+
if (broker === void 0) throw new Error(`integration ${id} has no linked brokerId`);
|
|
209191
|
+
return broker.id;
|
|
209156
209192
|
},
|
|
209157
209193
|
listAdoptedMatter: async () => {
|
|
209158
209194
|
const reg = this.ctx.kernel.deviceRegistry;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-matter-broker",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.157",
|
|
4
4
|
"description": "Matter broker addon for CamStack — owns a Matter fabric (commissioning + the long-lived controller) via the matter.js controller and brokers commissioned Matter nodes into CamStack",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
}
|
|
66
66
|
],
|
|
67
67
|
"requires": {
|
|
68
|
-
"server": ">=1.2.
|
|
68
|
+
"server": ">=1.2.770"
|
|
69
69
|
}
|
|
70
70
|
},
|
|
71
71
|
"files": [
|