@camstack/addon-provider-rtsp 1.2.150 → 1.2.151
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 +95 -65
- package/dist/addon.mjs +95 -65
- 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
|
+
## [1.2.151] - 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
|
## [1.2.150] - 2026-11-04
|
|
11
17
|
|
|
12
18
|
### Changed
|
package/dist/addon.js
CHANGED
|
@@ -6005,7 +6005,7 @@ var ZodIssueCode = {
|
|
|
6005
6005
|
var ZodFirstPartyTypeKind;
|
|
6006
6006
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6007
6007
|
//#endregion
|
|
6008
|
-
//#region ../types/dist/sleep-
|
|
6008
|
+
//#region ../types/dist/sleep-9TIHFj1w.mjs
|
|
6009
6009
|
/**
|
|
6010
6010
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6011
6011
|
* window to float samples (D455).
|
|
@@ -7949,10 +7949,9 @@ var BaseAddon = class {
|
|
|
7949
7949
|
*
|
|
7950
7950
|
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
7951
7951
|
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
7952
|
-
* SHAPE of the form only — the values live
|
|
7953
|
-
* unchanged (`integrations.setSettings` for an account integration).
|
|
7952
|
+
* SHAPE of the form only — the values live on the instance record.
|
|
7954
7953
|
*/
|
|
7955
|
-
async
|
|
7954
|
+
async integrationFormSchema(_instance) {
|
|
7956
7955
|
return null;
|
|
7957
7956
|
}
|
|
7958
7957
|
/**
|
|
@@ -7998,7 +7997,7 @@ var BaseAddon = class {
|
|
|
7998
7997
|
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
7999
7998
|
*/
|
|
8000
7999
|
async getIntegrationFormSchema(instance, nodeId) {
|
|
8001
|
-
const scoped = await this.
|
|
8000
|
+
const scoped = await this.integrationFormSchema(instance);
|
|
8002
8001
|
if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
|
|
8003
8002
|
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
8004
8003
|
}
|
|
@@ -9288,6 +9287,7 @@ function defineEntryKind(name, spec) {
|
|
|
9288
9287
|
class: "config",
|
|
9289
9288
|
writeTrigger: spec.writeTrigger ?? "an operator adds or edits an entry in the entries UI",
|
|
9290
9289
|
retention: { none: "an entry goes only when the operator deletes it" },
|
|
9290
|
+
...spec.maxDataBytes === void 0 ? {} : { maxDataBytes: spec.maxDataBytes },
|
|
9291
9291
|
...spec.database === void 0 ? {} : { database: spec.database },
|
|
9292
9292
|
...spec.indexes === void 0 ? {} : { indexes: spec.indexes },
|
|
9293
9293
|
...spec.secretArrayKeys === void 0 ? {} : { secretArrayKeys: spec.secretArrayKeys },
|
|
@@ -12046,7 +12046,7 @@ function maskUrlCredentials(rawUrl) {
|
|
|
12046
12046
|
}
|
|
12047
12047
|
}
|
|
12048
12048
|
//#endregion
|
|
12049
|
-
//#region ../types/dist/composition-
|
|
12049
|
+
//#region ../types/dist/composition-pOHbTzRB.mjs
|
|
12050
12050
|
/**
|
|
12051
12051
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
12052
12052
|
*
|
|
@@ -14754,20 +14754,28 @@ async function moveIntegrationRowsToRecords(ports, spec) {
|
|
|
14754
14754
|
};
|
|
14755
14755
|
}
|
|
14756
14756
|
/**
|
|
14757
|
-
* The addon-side ports of `moveIntegrationRowsToRecords` (planning#416)
|
|
14758
|
-
* from its own process, so the
|
|
14759
|
-
* `
|
|
14760
|
-
*
|
|
14761
|
-
*
|
|
14762
|
-
|
|
14757
|
+
* The addon-side ports of `moveIntegrationRowsToRecords` (planning#416). An addon runs the move
|
|
14758
|
+
* from its own process, so the leftover rows are reached through the migration-only door
|
|
14759
|
+
* (`migrations.readLegacyIntegrationRows` / `clearLegacyIntegrationRows`) on the hub's connection.
|
|
14760
|
+
* The door returns markers. This process is the owner, so it resolves and releases them with
|
|
14761
|
+
* `resolveSecretMarkers` — the same call the old settings door used — and only then asks the
|
|
14762
|
+
* door to delete the rows. The addon's own record kind is its records handle.
|
|
14763
|
+
*/
|
|
14764
|
+
async function resolvedRows(stored, secrets) {
|
|
14765
|
+
if (secrets === null) return stored;
|
|
14766
|
+
const { value, unresolved } = await resolveSecretMarkers(stored, secrets);
|
|
14767
|
+
if (unresolved.length > 0) throw new Error(`${unresolved.length} secret(s) cannot be read from the keychain`);
|
|
14768
|
+
return value;
|
|
14769
|
+
}
|
|
14763
14770
|
function integrationRowsPortsOverApi(deps) {
|
|
14771
|
+
const secrets = deps.secrets ?? null;
|
|
14764
14772
|
return {
|
|
14765
14773
|
warn: (message) => deps.log.warn(message),
|
|
14766
14774
|
listIntegrations: async (addonId) => (await deps.api.list()).filter((i) => i.addonId === addonId).map((i) => ({
|
|
14767
14775
|
id: i.id,
|
|
14768
14776
|
name: i.name
|
|
14769
14777
|
})),
|
|
14770
|
-
readRows: (integrationId) => deps.api.
|
|
14778
|
+
readRows: async (integrationId) => resolvedRows(await deps.api.readLegacyIntegrationRows({ integrationId }), secrets),
|
|
14771
14779
|
putRecord: async (id, body) => {
|
|
14772
14780
|
if (await deps.records.get(id) !== null) return "exists";
|
|
14773
14781
|
try {
|
|
@@ -14786,7 +14794,9 @@ function integrationRowsPortsOverApi(deps) {
|
|
|
14786
14794
|
await deps.records.delete(id);
|
|
14787
14795
|
},
|
|
14788
14796
|
clearRows: async (integrationId) => {
|
|
14789
|
-
await deps.api.
|
|
14797
|
+
const refs = collectSecretMarkerRefs(await deps.api.readLegacyIntegrationRows({ integrationId }));
|
|
14798
|
+
if (refs.length > 0 && secrets !== null) await secrets.delete(refs);
|
|
14799
|
+
await deps.api.clearLegacyIntegrationRows({ integrationId });
|
|
14790
14800
|
}
|
|
14791
14801
|
};
|
|
14792
14802
|
}
|
|
@@ -14876,14 +14886,14 @@ async function claimDevicesToDefaultIntegration(ports, spec) {
|
|
|
14876
14886
|
* 2. `claim-devices` (tolerate): `claimDevicesToDefaultIntegration`; with no integration to claim
|
|
14877
14887
|
* to it fails and is retried on the next boot.
|
|
14878
14888
|
*
|
|
14879
|
-
* Both run in the addon process through the hub API (`ctx.api`)
|
|
14880
|
-
*
|
|
14881
|
-
* from the record, not from the rows.
|
|
14889
|
+
* Both run in the addon process through the hub API (`ctx.api`). The leftover rows are read
|
|
14890
|
+
* through the migration-only door, which answers empty once the store is gone.
|
|
14882
14891
|
*/
|
|
14883
14892
|
function defaultIntegrationPortsOver(deps) {
|
|
14884
14893
|
return {
|
|
14885
14894
|
...integrationRowsPortsOverApi({
|
|
14886
14895
|
api: deps.api,
|
|
14896
|
+
...deps.secrets !== void 0 ? { secrets: deps.secrets } : {},
|
|
14887
14897
|
records: deps.records.kind({
|
|
14888
14898
|
name: deps.kind.name,
|
|
14889
14899
|
declaration: deps.kind.declaration,
|
|
@@ -14983,8 +14993,8 @@ function defaultIntegrationMigrations(spec) {
|
|
|
14983
14993
|
function defaultIntegrationApiOver(api) {
|
|
14984
14994
|
return {
|
|
14985
14995
|
list: () => api.integrations.list.query(),
|
|
14986
|
-
|
|
14987
|
-
|
|
14996
|
+
readLegacyIntegrationRows: (input) => api.migrations.readLegacyIntegrationRows.query(input),
|
|
14997
|
+
clearLegacyIntegrationRows: (input) => api.migrations.clearLegacyIntegrationRows.mutate(input),
|
|
14988
14998
|
listDevices: (addonId) => api.deviceManager.listAll.query({
|
|
14989
14999
|
addonId,
|
|
14990
15000
|
projection: "slim"
|
|
@@ -50623,6 +50633,9 @@ var RunningProposalEvidenceSchema = object({
|
|
|
50623
50633
|
runsFound: number().int().nonnegative(),
|
|
50624
50634
|
pausesFound: number().int().nonnegative(),
|
|
50625
50635
|
longestPauseMs: number().nonnegative(),
|
|
50636
|
+
/** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
|
|
50637
|
+
pulsesFound: number().int().nonnegative(),
|
|
50638
|
+
longestPulseMs: number().nonnegative(),
|
|
50626
50639
|
idleFloorW: number(),
|
|
50627
50640
|
noiseCeilingW: number(),
|
|
50628
50641
|
plateauW: number(),
|
|
@@ -56451,11 +56464,7 @@ var CreateIntegrationInputSchema = object({
|
|
|
56451
56464
|
info: record(string(), unknown()).optional(),
|
|
56452
56465
|
/** `stableId` of the discovery candidate the form was seeded from (D984). */
|
|
56453
56466
|
originStableId: string().optional(),
|
|
56454
|
-
settings: record(string(), unknown()).optional()
|
|
56455
|
-
/** Keys of `settings` the form's schema declares secret (by type) — kept in
|
|
56456
|
-
* the keychain, not the table (D787). */
|
|
56457
|
-
secretKeys: array(string()).optional(),
|
|
56458
|
-
skipRestart: boolean().optional()
|
|
56467
|
+
settings: record(string(), unknown()).optional()
|
|
56459
56468
|
});
|
|
56460
56469
|
var UpdateIntegrationInputSchema = object({
|
|
56461
56470
|
id: string(),
|
|
@@ -56476,22 +56485,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
56476
56485
|
}), method(object({ id: string() }), DeleteIntegrationResultSchema, {
|
|
56477
56486
|
kind: "mutation",
|
|
56478
56487
|
auth: "admin"
|
|
56479
|
-
}), method(object({ id: string() }), record(string(), unknown()), { auth: "admin" }), method(object({
|
|
56480
|
-
id: string(),
|
|
56481
|
-
settings: record(string(), unknown()),
|
|
56482
|
-
/** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
|
|
56483
|
-
secretKeys: array(string()).optional(),
|
|
56484
|
-
/** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
|
|
56485
|
-
skipRestart: boolean().optional()
|
|
56486
|
-
}), object({ success: boolean() }), {
|
|
56487
|
-
kind: "mutation",
|
|
56488
|
-
auth: "admin"
|
|
56489
|
-
}), method(object({ id: string() }), object({
|
|
56490
|
-
rows: number().int().nonnegative(),
|
|
56491
|
-
secrets: number().int().nonnegative()
|
|
56492
|
-
}), {
|
|
56493
|
-
kind: "mutation",
|
|
56494
|
-
auth: "admin"
|
|
56495
56488
|
}), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
|
|
56496
56489
|
addonId: string(),
|
|
56497
56490
|
settings: record(string(), unknown())
|
|
@@ -59468,6 +59461,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
|
|
|
59468
59461
|
}), {
|
|
59469
59462
|
kind: "mutation",
|
|
59470
59463
|
auth: "admin"
|
|
59464
|
+
}), method(object({ integrationId: string().min(1) }), record(string(), unknown()), { auth: "admin" }), method(object({ integrationId: string().min(1) }), object({
|
|
59465
|
+
rows: number().int().nonnegative(),
|
|
59466
|
+
secrets: number().int().nonnegative()
|
|
59467
|
+
}), {
|
|
59468
|
+
kind: "mutation",
|
|
59469
|
+
auth: "admin"
|
|
59470
|
+
}), method(object({
|
|
59471
|
+
integrationId: string().min(1),
|
|
59472
|
+
patch: record(string(), unknown())
|
|
59473
|
+
}), object({ written: boolean() }), {
|
|
59474
|
+
kind: "mutation",
|
|
59475
|
+
auth: "admin"
|
|
59476
|
+
}), method(object({
|
|
59477
|
+
integrationId: string().min(1),
|
|
59478
|
+
keys: array(string().min(1))
|
|
59479
|
+
}), object({
|
|
59480
|
+
present: boolean(),
|
|
59481
|
+
removed: record(string(), unknown())
|
|
59482
|
+
}), {
|
|
59483
|
+
kind: "mutation",
|
|
59484
|
+
auth: "admin"
|
|
59471
59485
|
});
|
|
59472
59486
|
method(object({
|
|
59473
59487
|
sourceUrl: string(),
|
|
@@ -80898,11 +80912,15 @@ discriminatedUnion("kind", [object({
|
|
|
80898
80912
|
* 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
|
|
80899
80913
|
* near F. A device that is not near one level most of the time has no floor.
|
|
80900
80914
|
* 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
|
|
80901
|
-
* 3.
|
|
80902
|
-
*
|
|
80915
|
+
* 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
|
|
80916
|
+
* display waking): it is neither a run nor a pause. Among the remaining
|
|
80917
|
+
* episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
|
|
80918
|
+
* two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
|
|
80919
|
+
* a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
|
|
80920
|
+
* is no run.
|
|
80903
80921
|
* 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
|
|
80904
|
-
* grid a person would type; stop dwell covers the longest pause
|
|
80905
|
-
* covers the longest standby blip above T.
|
|
80922
|
+
* grid a person would type; stop dwell covers the longest pause and the
|
|
80923
|
+
* kind's floor; start dwell covers the longest pulse and standby blip above T.
|
|
80906
80924
|
* 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
|
|
80907
80925
|
* run must hold exactly one true interval and nothing may flap outside.
|
|
80908
80926
|
*/
|
|
@@ -80913,6 +80931,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
|
|
|
80913
80931
|
30 * SECOND_MS;
|
|
80914
80932
|
60 * SECOND_MS;
|
|
80915
80933
|
20 * MINUTE_MS$1;
|
|
80934
|
+
90 * SECOND_MS;
|
|
80935
|
+
30 * MINUTE_MS$1;
|
|
80936
|
+
10 * MINUTE_MS$1;
|
|
80937
|
+
DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
|
|
80916
80938
|
10 * SECOND_MS;
|
|
80917
80939
|
10 * SECOND_MS;
|
|
80918
80940
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
@@ -86197,13 +86219,6 @@ Object.freeze({
|
|
|
86197
86219
|
access: "create",
|
|
86198
86220
|
role: "admin"
|
|
86199
86221
|
},
|
|
86200
|
-
"integrations.clearSettings": {
|
|
86201
|
-
capName: "integrations",
|
|
86202
|
-
capScope: "system",
|
|
86203
|
-
addonId: null,
|
|
86204
|
-
access: "delete",
|
|
86205
|
-
role: "admin"
|
|
86206
|
-
},
|
|
86207
86222
|
"integrations.create": {
|
|
86208
86223
|
capName: "integrations",
|
|
86209
86224
|
capScope: "system",
|
|
@@ -86239,13 +86254,6 @@ Object.freeze({
|
|
|
86239
86254
|
access: "view",
|
|
86240
86255
|
role: "admin"
|
|
86241
86256
|
},
|
|
86242
|
-
"integrations.getSettings": {
|
|
86243
|
-
capName: "integrations",
|
|
86244
|
-
capScope: "system",
|
|
86245
|
-
addonId: null,
|
|
86246
|
-
access: "view",
|
|
86247
|
-
role: "admin"
|
|
86248
|
-
},
|
|
86249
86257
|
"integrations.list": {
|
|
86250
86258
|
capName: "integrations",
|
|
86251
86259
|
capScope: "system",
|
|
@@ -86253,13 +86261,6 @@ Object.freeze({
|
|
|
86253
86261
|
access: "view",
|
|
86254
86262
|
role: "admin"
|
|
86255
86263
|
},
|
|
86256
|
-
"integrations.setSettings": {
|
|
86257
|
-
capName: "integrations",
|
|
86258
|
-
capScope: "system",
|
|
86259
|
-
addonId: null,
|
|
86260
|
-
access: "create",
|
|
86261
|
-
role: "admin"
|
|
86262
|
-
},
|
|
86263
86264
|
"integrations.testConnection": {
|
|
86264
86265
|
capName: "integrations",
|
|
86265
86266
|
capScope: "system",
|
|
@@ -87254,6 +87255,13 @@ Object.freeze({
|
|
|
87254
87255
|
access: "view",
|
|
87255
87256
|
role: "admin"
|
|
87256
87257
|
},
|
|
87258
|
+
"migrations.clearLegacyIntegrationRows": {
|
|
87259
|
+
capName: "migrations",
|
|
87260
|
+
capScope: "system",
|
|
87261
|
+
addonId: null,
|
|
87262
|
+
access: "delete",
|
|
87263
|
+
role: "admin"
|
|
87264
|
+
},
|
|
87257
87265
|
"migrations.declareOwner": {
|
|
87258
87266
|
capName: "migrations",
|
|
87259
87267
|
capScope: "system",
|
|
@@ -87261,6 +87269,13 @@ Object.freeze({
|
|
|
87261
87269
|
access: "create",
|
|
87262
87270
|
role: "admin"
|
|
87263
87271
|
},
|
|
87272
|
+
"migrations.deleteLegacyIntegrationRowKeys": {
|
|
87273
|
+
capName: "migrations",
|
|
87274
|
+
capScope: "system",
|
|
87275
|
+
addonId: null,
|
|
87276
|
+
access: "delete",
|
|
87277
|
+
role: "admin"
|
|
87278
|
+
},
|
|
87264
87279
|
"migrations.dryRun": {
|
|
87265
87280
|
capName: "migrations",
|
|
87266
87281
|
capScope: "system",
|
|
@@ -87296,6 +87311,20 @@ Object.freeze({
|
|
|
87296
87311
|
access: "create",
|
|
87297
87312
|
role: "admin"
|
|
87298
87313
|
},
|
|
87314
|
+
"migrations.patchLegacyIntegrationRows": {
|
|
87315
|
+
capName: "migrations",
|
|
87316
|
+
capScope: "system",
|
|
87317
|
+
addonId: null,
|
|
87318
|
+
access: "create",
|
|
87319
|
+
role: "admin"
|
|
87320
|
+
},
|
|
87321
|
+
"migrations.readLegacyIntegrationRows": {
|
|
87322
|
+
capName: "migrations",
|
|
87323
|
+
capScope: "system",
|
|
87324
|
+
addonId: null,
|
|
87325
|
+
access: "view",
|
|
87326
|
+
role: "admin"
|
|
87327
|
+
},
|
|
87299
87328
|
"migrations.restorePreMigration": {
|
|
87300
87329
|
capName: "migrations",
|
|
87301
87330
|
capScope: "system",
|
|
@@ -98215,6 +98244,7 @@ var RtspProviderAddon = class extends BaseDeviceProvider {
|
|
|
98215
98244
|
date: "2026-11-04"
|
|
98216
98245
|
}), defaultIntegrationPortsOver({
|
|
98217
98246
|
api: defaultIntegrationApiOver(this.ctx.api),
|
|
98247
|
+
secrets: this.ctx.secrets ?? null,
|
|
98218
98248
|
records,
|
|
98219
98249
|
kind: rtspConnectionsEntryKind,
|
|
98220
98250
|
info: (message) => this.ctx.logger.info(message),
|
package/dist/addon.mjs
CHANGED
|
@@ -5981,7 +5981,7 @@ var ZodIssueCode = {
|
|
|
5981
5981
|
var ZodFirstPartyTypeKind;
|
|
5982
5982
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5983
5983
|
//#endregion
|
|
5984
|
-
//#region ../types/dist/sleep-
|
|
5984
|
+
//#region ../types/dist/sleep-9TIHFj1w.mjs
|
|
5985
5985
|
/**
|
|
5986
5986
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5987
5987
|
* window to float samples (D455).
|
|
@@ -7925,10 +7925,9 @@ var BaseAddon = class {
|
|
|
7925
7925
|
*
|
|
7926
7926
|
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
7927
7927
|
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
7928
|
-
* SHAPE of the form only — the values live
|
|
7929
|
-
* unchanged (`integrations.setSettings` for an account integration).
|
|
7928
|
+
* SHAPE of the form only — the values live on the instance record.
|
|
7930
7929
|
*/
|
|
7931
|
-
async
|
|
7930
|
+
async integrationFormSchema(_instance) {
|
|
7932
7931
|
return null;
|
|
7933
7932
|
}
|
|
7934
7933
|
/**
|
|
@@ -7974,7 +7973,7 @@ var BaseAddon = class {
|
|
|
7974
7973
|
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
7975
7974
|
*/
|
|
7976
7975
|
async getIntegrationFormSchema(instance, nodeId) {
|
|
7977
|
-
const scoped = await this.
|
|
7976
|
+
const scoped = await this.integrationFormSchema(instance);
|
|
7978
7977
|
if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
|
|
7979
7978
|
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
7980
7979
|
}
|
|
@@ -9264,6 +9263,7 @@ function defineEntryKind(name, spec) {
|
|
|
9264
9263
|
class: "config",
|
|
9265
9264
|
writeTrigger: spec.writeTrigger ?? "an operator adds or edits an entry in the entries UI",
|
|
9266
9265
|
retention: { none: "an entry goes only when the operator deletes it" },
|
|
9266
|
+
...spec.maxDataBytes === void 0 ? {} : { maxDataBytes: spec.maxDataBytes },
|
|
9267
9267
|
...spec.database === void 0 ? {} : { database: spec.database },
|
|
9268
9268
|
...spec.indexes === void 0 ? {} : { indexes: spec.indexes },
|
|
9269
9269
|
...spec.secretArrayKeys === void 0 ? {} : { secretArrayKeys: spec.secretArrayKeys },
|
|
@@ -12022,7 +12022,7 @@ function maskUrlCredentials(rawUrl) {
|
|
|
12022
12022
|
}
|
|
12023
12023
|
}
|
|
12024
12024
|
//#endregion
|
|
12025
|
-
//#region ../types/dist/composition-
|
|
12025
|
+
//#region ../types/dist/composition-pOHbTzRB.mjs
|
|
12026
12026
|
/**
|
|
12027
12027
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
12028
12028
|
*
|
|
@@ -14730,20 +14730,28 @@ async function moveIntegrationRowsToRecords(ports, spec) {
|
|
|
14730
14730
|
};
|
|
14731
14731
|
}
|
|
14732
14732
|
/**
|
|
14733
|
-
* The addon-side ports of `moveIntegrationRowsToRecords` (planning#416)
|
|
14734
|
-
* from its own process, so the
|
|
14735
|
-
* `
|
|
14736
|
-
*
|
|
14737
|
-
*
|
|
14738
|
-
|
|
14733
|
+
* The addon-side ports of `moveIntegrationRowsToRecords` (planning#416). An addon runs the move
|
|
14734
|
+
* from its own process, so the leftover rows are reached through the migration-only door
|
|
14735
|
+
* (`migrations.readLegacyIntegrationRows` / `clearLegacyIntegrationRows`) on the hub's connection.
|
|
14736
|
+
* The door returns markers. This process is the owner, so it resolves and releases them with
|
|
14737
|
+
* `resolveSecretMarkers` — the same call the old settings door used — and only then asks the
|
|
14738
|
+
* door to delete the rows. The addon's own record kind is its records handle.
|
|
14739
|
+
*/
|
|
14740
|
+
async function resolvedRows(stored, secrets) {
|
|
14741
|
+
if (secrets === null) return stored;
|
|
14742
|
+
const { value, unresolved } = await resolveSecretMarkers(stored, secrets);
|
|
14743
|
+
if (unresolved.length > 0) throw new Error(`${unresolved.length} secret(s) cannot be read from the keychain`);
|
|
14744
|
+
return value;
|
|
14745
|
+
}
|
|
14739
14746
|
function integrationRowsPortsOverApi(deps) {
|
|
14747
|
+
const secrets = deps.secrets ?? null;
|
|
14740
14748
|
return {
|
|
14741
14749
|
warn: (message) => deps.log.warn(message),
|
|
14742
14750
|
listIntegrations: async (addonId) => (await deps.api.list()).filter((i) => i.addonId === addonId).map((i) => ({
|
|
14743
14751
|
id: i.id,
|
|
14744
14752
|
name: i.name
|
|
14745
14753
|
})),
|
|
14746
|
-
readRows: (integrationId) => deps.api.
|
|
14754
|
+
readRows: async (integrationId) => resolvedRows(await deps.api.readLegacyIntegrationRows({ integrationId }), secrets),
|
|
14747
14755
|
putRecord: async (id, body) => {
|
|
14748
14756
|
if (await deps.records.get(id) !== null) return "exists";
|
|
14749
14757
|
try {
|
|
@@ -14762,7 +14770,9 @@ function integrationRowsPortsOverApi(deps) {
|
|
|
14762
14770
|
await deps.records.delete(id);
|
|
14763
14771
|
},
|
|
14764
14772
|
clearRows: async (integrationId) => {
|
|
14765
|
-
await deps.api.
|
|
14773
|
+
const refs = collectSecretMarkerRefs(await deps.api.readLegacyIntegrationRows({ integrationId }));
|
|
14774
|
+
if (refs.length > 0 && secrets !== null) await secrets.delete(refs);
|
|
14775
|
+
await deps.api.clearLegacyIntegrationRows({ integrationId });
|
|
14766
14776
|
}
|
|
14767
14777
|
};
|
|
14768
14778
|
}
|
|
@@ -14852,14 +14862,14 @@ async function claimDevicesToDefaultIntegration(ports, spec) {
|
|
|
14852
14862
|
* 2. `claim-devices` (tolerate): `claimDevicesToDefaultIntegration`; with no integration to claim
|
|
14853
14863
|
* to it fails and is retried on the next boot.
|
|
14854
14864
|
*
|
|
14855
|
-
* Both run in the addon process through the hub API (`ctx.api`)
|
|
14856
|
-
*
|
|
14857
|
-
* from the record, not from the rows.
|
|
14865
|
+
* Both run in the addon process through the hub API (`ctx.api`). The leftover rows are read
|
|
14866
|
+
* through the migration-only door, which answers empty once the store is gone.
|
|
14858
14867
|
*/
|
|
14859
14868
|
function defaultIntegrationPortsOver(deps) {
|
|
14860
14869
|
return {
|
|
14861
14870
|
...integrationRowsPortsOverApi({
|
|
14862
14871
|
api: deps.api,
|
|
14872
|
+
...deps.secrets !== void 0 ? { secrets: deps.secrets } : {},
|
|
14863
14873
|
records: deps.records.kind({
|
|
14864
14874
|
name: deps.kind.name,
|
|
14865
14875
|
declaration: deps.kind.declaration,
|
|
@@ -14959,8 +14969,8 @@ function defaultIntegrationMigrations(spec) {
|
|
|
14959
14969
|
function defaultIntegrationApiOver(api) {
|
|
14960
14970
|
return {
|
|
14961
14971
|
list: () => api.integrations.list.query(),
|
|
14962
|
-
|
|
14963
|
-
|
|
14972
|
+
readLegacyIntegrationRows: (input) => api.migrations.readLegacyIntegrationRows.query(input),
|
|
14973
|
+
clearLegacyIntegrationRows: (input) => api.migrations.clearLegacyIntegrationRows.mutate(input),
|
|
14964
14974
|
listDevices: (addonId) => api.deviceManager.listAll.query({
|
|
14965
14975
|
addonId,
|
|
14966
14976
|
projection: "slim"
|
|
@@ -50599,6 +50609,9 @@ var RunningProposalEvidenceSchema = object({
|
|
|
50599
50609
|
runsFound: number().int().nonnegative(),
|
|
50600
50610
|
pausesFound: number().int().nonnegative(),
|
|
50601
50611
|
longestPauseMs: number().nonnegative(),
|
|
50612
|
+
/** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
|
|
50613
|
+
pulsesFound: number().int().nonnegative(),
|
|
50614
|
+
longestPulseMs: number().nonnegative(),
|
|
50602
50615
|
idleFloorW: number(),
|
|
50603
50616
|
noiseCeilingW: number(),
|
|
50604
50617
|
plateauW: number(),
|
|
@@ -56427,11 +56440,7 @@ var CreateIntegrationInputSchema = object({
|
|
|
56427
56440
|
info: record(string(), unknown()).optional(),
|
|
56428
56441
|
/** `stableId` of the discovery candidate the form was seeded from (D984). */
|
|
56429
56442
|
originStableId: string().optional(),
|
|
56430
|
-
settings: record(string(), unknown()).optional()
|
|
56431
|
-
/** Keys of `settings` the form's schema declares secret (by type) — kept in
|
|
56432
|
-
* the keychain, not the table (D787). */
|
|
56433
|
-
secretKeys: array(string()).optional(),
|
|
56434
|
-
skipRestart: boolean().optional()
|
|
56443
|
+
settings: record(string(), unknown()).optional()
|
|
56435
56444
|
});
|
|
56436
56445
|
var UpdateIntegrationInputSchema = object({
|
|
56437
56446
|
id: string(),
|
|
@@ -56452,22 +56461,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
56452
56461
|
}), method(object({ id: string() }), DeleteIntegrationResultSchema, {
|
|
56453
56462
|
kind: "mutation",
|
|
56454
56463
|
auth: "admin"
|
|
56455
|
-
}), method(object({ id: string() }), record(string(), unknown()), { auth: "admin" }), method(object({
|
|
56456
|
-
id: string(),
|
|
56457
|
-
settings: record(string(), unknown()),
|
|
56458
|
-
/** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
|
|
56459
|
-
secretKeys: array(string()).optional(),
|
|
56460
|
-
/** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
|
|
56461
|
-
skipRestart: boolean().optional()
|
|
56462
|
-
}), object({ success: boolean() }), {
|
|
56463
|
-
kind: "mutation",
|
|
56464
|
-
auth: "admin"
|
|
56465
|
-
}), method(object({ id: string() }), object({
|
|
56466
|
-
rows: number().int().nonnegative(),
|
|
56467
|
-
secrets: number().int().nonnegative()
|
|
56468
|
-
}), {
|
|
56469
|
-
kind: "mutation",
|
|
56470
|
-
auth: "admin"
|
|
56471
56464
|
}), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
|
|
56472
56465
|
addonId: string(),
|
|
56473
56466
|
settings: record(string(), unknown())
|
|
@@ -59444,6 +59437,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
|
|
|
59444
59437
|
}), {
|
|
59445
59438
|
kind: "mutation",
|
|
59446
59439
|
auth: "admin"
|
|
59440
|
+
}), method(object({ integrationId: string().min(1) }), record(string(), unknown()), { auth: "admin" }), method(object({ integrationId: string().min(1) }), object({
|
|
59441
|
+
rows: number().int().nonnegative(),
|
|
59442
|
+
secrets: number().int().nonnegative()
|
|
59443
|
+
}), {
|
|
59444
|
+
kind: "mutation",
|
|
59445
|
+
auth: "admin"
|
|
59446
|
+
}), method(object({
|
|
59447
|
+
integrationId: string().min(1),
|
|
59448
|
+
patch: record(string(), unknown())
|
|
59449
|
+
}), object({ written: boolean() }), {
|
|
59450
|
+
kind: "mutation",
|
|
59451
|
+
auth: "admin"
|
|
59452
|
+
}), method(object({
|
|
59453
|
+
integrationId: string().min(1),
|
|
59454
|
+
keys: array(string().min(1))
|
|
59455
|
+
}), object({
|
|
59456
|
+
present: boolean(),
|
|
59457
|
+
removed: record(string(), unknown())
|
|
59458
|
+
}), {
|
|
59459
|
+
kind: "mutation",
|
|
59460
|
+
auth: "admin"
|
|
59447
59461
|
});
|
|
59448
59462
|
method(object({
|
|
59449
59463
|
sourceUrl: string(),
|
|
@@ -80874,11 +80888,15 @@ discriminatedUnion("kind", [object({
|
|
|
80874
80888
|
* 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
|
|
80875
80889
|
* near F. A device that is not near one level most of the time has no floor.
|
|
80876
80890
|
* 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
|
|
80877
|
-
* 3.
|
|
80878
|
-
*
|
|
80891
|
+
* 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
|
|
80892
|
+
* display waking): it is neither a run nor a pause. Among the remaining
|
|
80893
|
+
* episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
|
|
80894
|
+
* two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
|
|
80895
|
+
* a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
|
|
80896
|
+
* is no run.
|
|
80879
80897
|
* 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
|
|
80880
|
-
* grid a person would type; stop dwell covers the longest pause
|
|
80881
|
-
* covers the longest standby blip above T.
|
|
80898
|
+
* grid a person would type; stop dwell covers the longest pause and the
|
|
80899
|
+
* kind's floor; start dwell covers the longest pulse and standby blip above T.
|
|
80882
80900
|
* 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
|
|
80883
80901
|
* run must hold exactly one true interval and nothing may flap outside.
|
|
80884
80902
|
*/
|
|
@@ -80889,6 +80907,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
|
|
|
80889
80907
|
30 * SECOND_MS;
|
|
80890
80908
|
60 * SECOND_MS;
|
|
80891
80909
|
20 * MINUTE_MS$1;
|
|
80910
|
+
90 * SECOND_MS;
|
|
80911
|
+
30 * MINUTE_MS$1;
|
|
80912
|
+
10 * MINUTE_MS$1;
|
|
80913
|
+
DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
|
|
80892
80914
|
10 * SECOND_MS;
|
|
80893
80915
|
10 * SECOND_MS;
|
|
80894
80916
|
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
@@ -86173,13 +86195,6 @@ Object.freeze({
|
|
|
86173
86195
|
access: "create",
|
|
86174
86196
|
role: "admin"
|
|
86175
86197
|
},
|
|
86176
|
-
"integrations.clearSettings": {
|
|
86177
|
-
capName: "integrations",
|
|
86178
|
-
capScope: "system",
|
|
86179
|
-
addonId: null,
|
|
86180
|
-
access: "delete",
|
|
86181
|
-
role: "admin"
|
|
86182
|
-
},
|
|
86183
86198
|
"integrations.create": {
|
|
86184
86199
|
capName: "integrations",
|
|
86185
86200
|
capScope: "system",
|
|
@@ -86215,13 +86230,6 @@ Object.freeze({
|
|
|
86215
86230
|
access: "view",
|
|
86216
86231
|
role: "admin"
|
|
86217
86232
|
},
|
|
86218
|
-
"integrations.getSettings": {
|
|
86219
|
-
capName: "integrations",
|
|
86220
|
-
capScope: "system",
|
|
86221
|
-
addonId: null,
|
|
86222
|
-
access: "view",
|
|
86223
|
-
role: "admin"
|
|
86224
|
-
},
|
|
86225
86233
|
"integrations.list": {
|
|
86226
86234
|
capName: "integrations",
|
|
86227
86235
|
capScope: "system",
|
|
@@ -86229,13 +86237,6 @@ Object.freeze({
|
|
|
86229
86237
|
access: "view",
|
|
86230
86238
|
role: "admin"
|
|
86231
86239
|
},
|
|
86232
|
-
"integrations.setSettings": {
|
|
86233
|
-
capName: "integrations",
|
|
86234
|
-
capScope: "system",
|
|
86235
|
-
addonId: null,
|
|
86236
|
-
access: "create",
|
|
86237
|
-
role: "admin"
|
|
86238
|
-
},
|
|
86239
86240
|
"integrations.testConnection": {
|
|
86240
86241
|
capName: "integrations",
|
|
86241
86242
|
capScope: "system",
|
|
@@ -87230,6 +87231,13 @@ Object.freeze({
|
|
|
87230
87231
|
access: "view",
|
|
87231
87232
|
role: "admin"
|
|
87232
87233
|
},
|
|
87234
|
+
"migrations.clearLegacyIntegrationRows": {
|
|
87235
|
+
capName: "migrations",
|
|
87236
|
+
capScope: "system",
|
|
87237
|
+
addonId: null,
|
|
87238
|
+
access: "delete",
|
|
87239
|
+
role: "admin"
|
|
87240
|
+
},
|
|
87233
87241
|
"migrations.declareOwner": {
|
|
87234
87242
|
capName: "migrations",
|
|
87235
87243
|
capScope: "system",
|
|
@@ -87237,6 +87245,13 @@ Object.freeze({
|
|
|
87237
87245
|
access: "create",
|
|
87238
87246
|
role: "admin"
|
|
87239
87247
|
},
|
|
87248
|
+
"migrations.deleteLegacyIntegrationRowKeys": {
|
|
87249
|
+
capName: "migrations",
|
|
87250
|
+
capScope: "system",
|
|
87251
|
+
addonId: null,
|
|
87252
|
+
access: "delete",
|
|
87253
|
+
role: "admin"
|
|
87254
|
+
},
|
|
87240
87255
|
"migrations.dryRun": {
|
|
87241
87256
|
capName: "migrations",
|
|
87242
87257
|
capScope: "system",
|
|
@@ -87272,6 +87287,20 @@ Object.freeze({
|
|
|
87272
87287
|
access: "create",
|
|
87273
87288
|
role: "admin"
|
|
87274
87289
|
},
|
|
87290
|
+
"migrations.patchLegacyIntegrationRows": {
|
|
87291
|
+
capName: "migrations",
|
|
87292
|
+
capScope: "system",
|
|
87293
|
+
addonId: null,
|
|
87294
|
+
access: "create",
|
|
87295
|
+
role: "admin"
|
|
87296
|
+
},
|
|
87297
|
+
"migrations.readLegacyIntegrationRows": {
|
|
87298
|
+
capName: "migrations",
|
|
87299
|
+
capScope: "system",
|
|
87300
|
+
addonId: null,
|
|
87301
|
+
access: "view",
|
|
87302
|
+
role: "admin"
|
|
87303
|
+
},
|
|
87275
87304
|
"migrations.restorePreMigration": {
|
|
87276
87305
|
capName: "migrations",
|
|
87277
87306
|
capScope: "system",
|
|
@@ -98191,6 +98220,7 @@ var RtspProviderAddon = class extends BaseDeviceProvider {
|
|
|
98191
98220
|
date: "2026-11-04"
|
|
98192
98221
|
}), defaultIntegrationPortsOver({
|
|
98193
98222
|
api: defaultIntegrationApiOver(this.ctx.api),
|
|
98223
|
+
secrets: this.ctx.secrets ?? null,
|
|
98194
98224
|
records,
|
|
98195
98225
|
kind: rtspConnectionsEntryKind,
|
|
98196
98226
|
info: (message) => this.ctx.logger.info(message),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-rtsp",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.151",
|
|
4
4
|
"description": "Generic RTSP camera device provider addon for CamStack",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
}
|
|
63
63
|
],
|
|
64
64
|
"requires": {
|
|
65
|
-
"server": ">=1.2.
|
|
65
|
+
"server": ">=1.2.770"
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
68
|
"files": [
|