@camstack/addon-provider-amcrest 0.2.165 → 0.2.166
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 -64
- package/dist/addon.mjs +94 -64
- 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.166] - 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.165] - 2026-11-04
|
|
11
17
|
|
|
12
18
|
### Changed
|
package/dist/addon.js
CHANGED
|
@@ -6015,7 +6015,7 @@ var ZodIssueCode = {
|
|
|
6015
6015
|
var ZodFirstPartyTypeKind;
|
|
6016
6016
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6017
6017
|
//#endregion
|
|
6018
|
-
//#region ../types/dist/sleep-
|
|
6018
|
+
//#region ../types/dist/sleep-9TIHFj1w.mjs
|
|
6019
6019
|
/**
|
|
6020
6020
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6021
6021
|
* window to float samples (D455).
|
|
@@ -7959,10 +7959,9 @@ var BaseAddon = class {
|
|
|
7959
7959
|
*
|
|
7960
7960
|
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
7961
7961
|
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
7962
|
-
* SHAPE of the form only — the values live
|
|
7963
|
-
* unchanged (`integrations.setSettings` for an account integration).
|
|
7962
|
+
* SHAPE of the form only — the values live on the instance record.
|
|
7964
7963
|
*/
|
|
7965
|
-
async
|
|
7964
|
+
async integrationFormSchema(_instance) {
|
|
7966
7965
|
return null;
|
|
7967
7966
|
}
|
|
7968
7967
|
/**
|
|
@@ -8008,7 +8007,7 @@ var BaseAddon = class {
|
|
|
8008
8007
|
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
8009
8008
|
*/
|
|
8010
8009
|
async getIntegrationFormSchema(instance, nodeId) {
|
|
8011
|
-
const scoped = await this.
|
|
8010
|
+
const scoped = await this.integrationFormSchema(instance);
|
|
8012
8011
|
if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
|
|
8013
8012
|
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
8014
8013
|
}
|
|
@@ -9298,6 +9297,7 @@ function defineEntryKind(name, spec) {
|
|
|
9298
9297
|
class: "config",
|
|
9299
9298
|
writeTrigger: spec.writeTrigger ?? "an operator adds or edits an entry in the entries UI",
|
|
9300
9299
|
retention: { none: "an entry goes only when the operator deletes it" },
|
|
9300
|
+
...spec.maxDataBytes === void 0 ? {} : { maxDataBytes: spec.maxDataBytes },
|
|
9301
9301
|
...spec.database === void 0 ? {} : { database: spec.database },
|
|
9302
9302
|
...spec.indexes === void 0 ? {} : { indexes: spec.indexes },
|
|
9303
9303
|
...spec.secretArrayKeys === void 0 ? {} : { secretArrayKeys: spec.secretArrayKeys },
|
|
@@ -11981,7 +11981,7 @@ function userError(code, params, englishFallback) {
|
|
|
11981
11981
|
return new CamstackError(code, params, englishFallback);
|
|
11982
11982
|
}
|
|
11983
11983
|
//#endregion
|
|
11984
|
-
//#region ../types/dist/composition-
|
|
11984
|
+
//#region ../types/dist/composition-pOHbTzRB.mjs
|
|
11985
11985
|
/**
|
|
11986
11986
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11987
11987
|
*
|
|
@@ -14709,20 +14709,28 @@ async function moveIntegrationRowsToRecords(ports, spec) {
|
|
|
14709
14709
|
};
|
|
14710
14710
|
}
|
|
14711
14711
|
/**
|
|
14712
|
-
* The addon-side ports of `moveIntegrationRowsToRecords` (planning#416)
|
|
14713
|
-
* from its own process, so the
|
|
14714
|
-
* `
|
|
14715
|
-
*
|
|
14716
|
-
*
|
|
14712
|
+
* The addon-side ports of `moveIntegrationRowsToRecords` (planning#416). An addon runs the move
|
|
14713
|
+
* from its own process, so the leftover rows are reached through the migration-only door
|
|
14714
|
+
* (`migrations.readLegacyIntegrationRows` / `clearLegacyIntegrationRows`) on the hub's connection.
|
|
14715
|
+
* The door returns markers. This process is the owner, so it resolves and releases them with
|
|
14716
|
+
* `resolveSecretMarkers` — the same call the old settings door used — and only then asks the
|
|
14717
|
+
* door to delete the rows. The addon's own record kind is its records handle.
|
|
14717
14718
|
*/
|
|
14719
|
+
async function resolvedRows(stored, secrets) {
|
|
14720
|
+
if (secrets === null) return stored;
|
|
14721
|
+
const { value, unresolved } = await resolveSecretMarkers(stored, secrets);
|
|
14722
|
+
if (unresolved.length > 0) throw new Error(`${unresolved.length} secret(s) cannot be read from the keychain`);
|
|
14723
|
+
return value;
|
|
14724
|
+
}
|
|
14718
14725
|
function integrationRowsPortsOverApi(deps) {
|
|
14726
|
+
const secrets = deps.secrets ?? null;
|
|
14719
14727
|
return {
|
|
14720
14728
|
warn: (message) => deps.log.warn(message),
|
|
14721
14729
|
listIntegrations: async (addonId) => (await deps.api.list()).filter((i) => i.addonId === addonId).map((i) => ({
|
|
14722
14730
|
id: i.id,
|
|
14723
14731
|
name: i.name
|
|
14724
14732
|
})),
|
|
14725
|
-
readRows: (integrationId) => deps.api.
|
|
14733
|
+
readRows: async (integrationId) => resolvedRows(await deps.api.readLegacyIntegrationRows({ integrationId }), secrets),
|
|
14726
14734
|
putRecord: async (id, body) => {
|
|
14727
14735
|
if (await deps.records.get(id) !== null) return "exists";
|
|
14728
14736
|
try {
|
|
@@ -14741,7 +14749,9 @@ function integrationRowsPortsOverApi(deps) {
|
|
|
14741
14749
|
await deps.records.delete(id);
|
|
14742
14750
|
},
|
|
14743
14751
|
clearRows: async (integrationId) => {
|
|
14744
|
-
await deps.api.
|
|
14752
|
+
const refs = collectSecretMarkerRefs(await deps.api.readLegacyIntegrationRows({ integrationId }));
|
|
14753
|
+
if (refs.length > 0 && secrets !== null) await secrets.delete(refs);
|
|
14754
|
+
await deps.api.clearLegacyIntegrationRows({ integrationId });
|
|
14745
14755
|
}
|
|
14746
14756
|
};
|
|
14747
14757
|
}
|
|
@@ -14831,14 +14841,14 @@ async function claimDevicesToDefaultIntegration(ports, spec) {
|
|
|
14831
14841
|
* 2. `claim-devices` (tolerate): `claimDevicesToDefaultIntegration`; with no integration to claim
|
|
14832
14842
|
* to it fails and is retried on the next boot.
|
|
14833
14843
|
*
|
|
14834
|
-
* Both run in the addon process through the hub API (`ctx.api`)
|
|
14835
|
-
*
|
|
14836
|
-
* from the record, not from the rows.
|
|
14844
|
+
* Both run in the addon process through the hub API (`ctx.api`). The leftover rows are read
|
|
14845
|
+
* through the migration-only door, which answers empty once the store is gone.
|
|
14837
14846
|
*/
|
|
14838
14847
|
function defaultIntegrationPortsOver(deps) {
|
|
14839
14848
|
return {
|
|
14840
14849
|
...integrationRowsPortsOverApi({
|
|
14841
14850
|
api: deps.api,
|
|
14851
|
+
...deps.secrets !== void 0 ? { secrets: deps.secrets } : {},
|
|
14842
14852
|
records: deps.records.kind({
|
|
14843
14853
|
name: deps.kind.name,
|
|
14844
14854
|
declaration: deps.kind.declaration,
|
|
@@ -14938,8 +14948,8 @@ function defaultIntegrationMigrations(spec) {
|
|
|
14938
14948
|
function defaultIntegrationApiOver(api) {
|
|
14939
14949
|
return {
|
|
14940
14950
|
list: () => api.integrations.list.query(),
|
|
14941
|
-
|
|
14942
|
-
|
|
14951
|
+
readLegacyIntegrationRows: (input) => api.migrations.readLegacyIntegrationRows.query(input),
|
|
14952
|
+
clearLegacyIntegrationRows: (input) => api.migrations.clearLegacyIntegrationRows.mutate(input),
|
|
14943
14953
|
listDevices: (addonId) => api.deviceManager.listAll.query({
|
|
14944
14954
|
addonId,
|
|
14945
14955
|
projection: "slim"
|
|
@@ -50556,6 +50566,9 @@ var RunningProposalEvidenceSchema = object({
|
|
|
50556
50566
|
runsFound: number().int().nonnegative(),
|
|
50557
50567
|
pausesFound: number().int().nonnegative(),
|
|
50558
50568
|
longestPauseMs: number().nonnegative(),
|
|
50569
|
+
/** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
|
|
50570
|
+
pulsesFound: number().int().nonnegative(),
|
|
50571
|
+
longestPulseMs: number().nonnegative(),
|
|
50559
50572
|
idleFloorW: number(),
|
|
50560
50573
|
noiseCeilingW: number(),
|
|
50561
50574
|
plateauW: number(),
|
|
@@ -56405,11 +56418,7 @@ var CreateIntegrationInputSchema = object({
|
|
|
56405
56418
|
info: record(string(), unknown()).optional(),
|
|
56406
56419
|
/** `stableId` of the discovery candidate the form was seeded from (D984). */
|
|
56407
56420
|
originStableId: string().optional(),
|
|
56408
|
-
settings: record(string(), unknown()).optional()
|
|
56409
|
-
/** Keys of `settings` the form's schema declares secret (by type) — kept in
|
|
56410
|
-
* the keychain, not the table (D787). */
|
|
56411
|
-
secretKeys: array(string()).optional(),
|
|
56412
|
-
skipRestart: boolean().optional()
|
|
56421
|
+
settings: record(string(), unknown()).optional()
|
|
56413
56422
|
});
|
|
56414
56423
|
var UpdateIntegrationInputSchema = object({
|
|
56415
56424
|
id: string(),
|
|
@@ -56430,22 +56439,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
56430
56439
|
}), method(object({ id: string() }), DeleteIntegrationResultSchema, {
|
|
56431
56440
|
kind: "mutation",
|
|
56432
56441
|
auth: "admin"
|
|
56433
|
-
}), method(object({ id: string() }), record(string(), unknown()), { auth: "admin" }), method(object({
|
|
56434
|
-
id: string(),
|
|
56435
|
-
settings: record(string(), unknown()),
|
|
56436
|
-
/** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
|
|
56437
|
-
secretKeys: array(string()).optional(),
|
|
56438
|
-
/** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
|
|
56439
|
-
skipRestart: boolean().optional()
|
|
56440
|
-
}), object({ success: boolean() }), {
|
|
56441
|
-
kind: "mutation",
|
|
56442
|
-
auth: "admin"
|
|
56443
|
-
}), method(object({ id: string() }), object({
|
|
56444
|
-
rows: number().int().nonnegative(),
|
|
56445
|
-
secrets: number().int().nonnegative()
|
|
56446
|
-
}), {
|
|
56447
|
-
kind: "mutation",
|
|
56448
|
-
auth: "admin"
|
|
56449
56442
|
}), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
|
|
56450
56443
|
addonId: string(),
|
|
56451
56444
|
settings: record(string(), unknown())
|
|
@@ -59422,6 +59415,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
|
|
|
59422
59415
|
}), {
|
|
59423
59416
|
kind: "mutation",
|
|
59424
59417
|
auth: "admin"
|
|
59418
|
+
}), method(object({ integrationId: string().min(1) }), record(string(), unknown()), { auth: "admin" }), method(object({ integrationId: string().min(1) }), object({
|
|
59419
|
+
rows: number().int().nonnegative(),
|
|
59420
|
+
secrets: number().int().nonnegative()
|
|
59421
|
+
}), {
|
|
59422
|
+
kind: "mutation",
|
|
59423
|
+
auth: "admin"
|
|
59424
|
+
}), method(object({
|
|
59425
|
+
integrationId: string().min(1),
|
|
59426
|
+
patch: record(string(), unknown())
|
|
59427
|
+
}), object({ written: boolean() }), {
|
|
59428
|
+
kind: "mutation",
|
|
59429
|
+
auth: "admin"
|
|
59430
|
+
}), method(object({
|
|
59431
|
+
integrationId: string().min(1),
|
|
59432
|
+
keys: array(string().min(1))
|
|
59433
|
+
}), object({
|
|
59434
|
+
present: boolean(),
|
|
59435
|
+
removed: record(string(), unknown())
|
|
59436
|
+
}), {
|
|
59437
|
+
kind: "mutation",
|
|
59438
|
+
auth: "admin"
|
|
59425
59439
|
});
|
|
59426
59440
|
method(object({
|
|
59427
59441
|
sourceUrl: string(),
|
|
@@ -81815,11 +81829,15 @@ discriminatedUnion("kind", [object({
|
|
|
81815
81829
|
* 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
|
|
81816
81830
|
* near F. A device that is not near one level most of the time has no floor.
|
|
81817
81831
|
* 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
|
|
81818
|
-
* 3.
|
|
81819
|
-
*
|
|
81832
|
+
* 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
|
|
81833
|
+
* display waking): it is neither a run nor a pause. Among the remaining
|
|
81834
|
+
* episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
|
|
81835
|
+
* two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
|
|
81836
|
+
* a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
|
|
81837
|
+
* is no run.
|
|
81820
81838
|
* 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
|
|
81821
|
-
* grid a person would type; stop dwell covers the longest pause
|
|
81822
|
-
* covers the longest standby blip above T.
|
|
81839
|
+
* grid a person would type; stop dwell covers the longest pause and the
|
|
81840
|
+
* kind's floor; start dwell covers the longest pulse and standby blip above T.
|
|
81823
81841
|
* 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
|
|
81824
81842
|
* run must hold exactly one true interval and nothing may flap outside.
|
|
81825
81843
|
*/
|
|
@@ -81830,6 +81848,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
|
|
|
81830
81848
|
30 * SECOND_MS;
|
|
81831
81849
|
60 * SECOND_MS;
|
|
81832
81850
|
20 * MINUTE_MS$1;
|
|
81851
|
+
90 * SECOND_MS;
|
|
81852
|
+
30 * MINUTE_MS$1;
|
|
81853
|
+
10 * MINUTE_MS$1;
|
|
81854
|
+
DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
|
|
81833
81855
|
10 * SECOND_MS;
|
|
81834
81856
|
10 * SECOND_MS;
|
|
81835
81857
|
/**
|
|
@@ -87251,13 +87273,6 @@ Object.freeze({
|
|
|
87251
87273
|
access: "create",
|
|
87252
87274
|
role: "admin"
|
|
87253
87275
|
},
|
|
87254
|
-
"integrations.clearSettings": {
|
|
87255
|
-
capName: "integrations",
|
|
87256
|
-
capScope: "system",
|
|
87257
|
-
addonId: null,
|
|
87258
|
-
access: "delete",
|
|
87259
|
-
role: "admin"
|
|
87260
|
-
},
|
|
87261
87276
|
"integrations.create": {
|
|
87262
87277
|
capName: "integrations",
|
|
87263
87278
|
capScope: "system",
|
|
@@ -87293,13 +87308,6 @@ Object.freeze({
|
|
|
87293
87308
|
access: "view",
|
|
87294
87309
|
role: "admin"
|
|
87295
87310
|
},
|
|
87296
|
-
"integrations.getSettings": {
|
|
87297
|
-
capName: "integrations",
|
|
87298
|
-
capScope: "system",
|
|
87299
|
-
addonId: null,
|
|
87300
|
-
access: "view",
|
|
87301
|
-
role: "admin"
|
|
87302
|
-
},
|
|
87303
87311
|
"integrations.list": {
|
|
87304
87312
|
capName: "integrations",
|
|
87305
87313
|
capScope: "system",
|
|
@@ -87307,13 +87315,6 @@ Object.freeze({
|
|
|
87307
87315
|
access: "view",
|
|
87308
87316
|
role: "admin"
|
|
87309
87317
|
},
|
|
87310
|
-
"integrations.setSettings": {
|
|
87311
|
-
capName: "integrations",
|
|
87312
|
-
capScope: "system",
|
|
87313
|
-
addonId: null,
|
|
87314
|
-
access: "create",
|
|
87315
|
-
role: "admin"
|
|
87316
|
-
},
|
|
87317
87318
|
"integrations.testConnection": {
|
|
87318
87319
|
capName: "integrations",
|
|
87319
87320
|
capScope: "system",
|
|
@@ -88308,6 +88309,13 @@ Object.freeze({
|
|
|
88308
88309
|
access: "view",
|
|
88309
88310
|
role: "admin"
|
|
88310
88311
|
},
|
|
88312
|
+
"migrations.clearLegacyIntegrationRows": {
|
|
88313
|
+
capName: "migrations",
|
|
88314
|
+
capScope: "system",
|
|
88315
|
+
addonId: null,
|
|
88316
|
+
access: "delete",
|
|
88317
|
+
role: "admin"
|
|
88318
|
+
},
|
|
88311
88319
|
"migrations.declareOwner": {
|
|
88312
88320
|
capName: "migrations",
|
|
88313
88321
|
capScope: "system",
|
|
@@ -88315,6 +88323,13 @@ Object.freeze({
|
|
|
88315
88323
|
access: "create",
|
|
88316
88324
|
role: "admin"
|
|
88317
88325
|
},
|
|
88326
|
+
"migrations.deleteLegacyIntegrationRowKeys": {
|
|
88327
|
+
capName: "migrations",
|
|
88328
|
+
capScope: "system",
|
|
88329
|
+
addonId: null,
|
|
88330
|
+
access: "delete",
|
|
88331
|
+
role: "admin"
|
|
88332
|
+
},
|
|
88318
88333
|
"migrations.dryRun": {
|
|
88319
88334
|
capName: "migrations",
|
|
88320
88335
|
capScope: "system",
|
|
@@ -88350,6 +88365,20 @@ Object.freeze({
|
|
|
88350
88365
|
access: "create",
|
|
88351
88366
|
role: "admin"
|
|
88352
88367
|
},
|
|
88368
|
+
"migrations.patchLegacyIntegrationRows": {
|
|
88369
|
+
capName: "migrations",
|
|
88370
|
+
capScope: "system",
|
|
88371
|
+
addonId: null,
|
|
88372
|
+
access: "create",
|
|
88373
|
+
role: "admin"
|
|
88374
|
+
},
|
|
88375
|
+
"migrations.readLegacyIntegrationRows": {
|
|
88376
|
+
capName: "migrations",
|
|
88377
|
+
capScope: "system",
|
|
88378
|
+
addonId: null,
|
|
88379
|
+
access: "view",
|
|
88380
|
+
role: "admin"
|
|
88381
|
+
},
|
|
88353
88382
|
"migrations.restorePreMigration": {
|
|
88354
88383
|
capName: "migrations",
|
|
88355
88384
|
capScope: "system",
|
|
@@ -106886,6 +106915,7 @@ var AmcrestProviderAddon = class extends BaseDeviceProvider {
|
|
|
106886
106915
|
date: "2026-11-04"
|
|
106887
106916
|
}), defaultIntegrationPortsOver({
|
|
106888
106917
|
api: defaultIntegrationApiOver(this.ctx.api),
|
|
106918
|
+
secrets: this.ctx.secrets ?? null,
|
|
106889
106919
|
records,
|
|
106890
106920
|
kind: amcrestConnectionsEntryKind,
|
|
106891
106921
|
info: (message) => this.ctx.logger.info(message),
|
package/dist/addon.mjs
CHANGED
|
@@ -5990,7 +5990,7 @@ var ZodIssueCode = {
|
|
|
5990
5990
|
var ZodFirstPartyTypeKind;
|
|
5991
5991
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5992
5992
|
//#endregion
|
|
5993
|
-
//#region ../types/dist/sleep-
|
|
5993
|
+
//#region ../types/dist/sleep-9TIHFj1w.mjs
|
|
5994
5994
|
/**
|
|
5995
5995
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5996
5996
|
* window to float samples (D455).
|
|
@@ -7934,10 +7934,9 @@ var BaseAddon = class {
|
|
|
7934
7934
|
*
|
|
7935
7935
|
* Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
|
|
7936
7936
|
* needs its connection fields, the default integration the addon's own sections. It is the
|
|
7937
|
-
* SHAPE of the form only — the values live
|
|
7938
|
-
* unchanged (`integrations.setSettings` for an account integration).
|
|
7937
|
+
* SHAPE of the form only — the values live on the instance record.
|
|
7939
7938
|
*/
|
|
7940
|
-
async
|
|
7939
|
+
async integrationFormSchema(_instance) {
|
|
7941
7940
|
return null;
|
|
7942
7941
|
}
|
|
7943
7942
|
/**
|
|
@@ -7983,7 +7982,7 @@ var BaseAddon = class {
|
|
|
7983
7982
|
* per-instance schema when it declares one, else its global schema (what they always showed).
|
|
7984
7983
|
*/
|
|
7985
7984
|
async getIntegrationFormSchema(instance, nodeId) {
|
|
7986
|
-
const scoped = await this.
|
|
7985
|
+
const scoped = await this.integrationFormSchema(instance);
|
|
7987
7986
|
if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
|
|
7988
7987
|
return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
|
|
7989
7988
|
}
|
|
@@ -9273,6 +9272,7 @@ function defineEntryKind(name, spec) {
|
|
|
9273
9272
|
class: "config",
|
|
9274
9273
|
writeTrigger: spec.writeTrigger ?? "an operator adds or edits an entry in the entries UI",
|
|
9275
9274
|
retention: { none: "an entry goes only when the operator deletes it" },
|
|
9275
|
+
...spec.maxDataBytes === void 0 ? {} : { maxDataBytes: spec.maxDataBytes },
|
|
9276
9276
|
...spec.database === void 0 ? {} : { database: spec.database },
|
|
9277
9277
|
...spec.indexes === void 0 ? {} : { indexes: spec.indexes },
|
|
9278
9278
|
...spec.secretArrayKeys === void 0 ? {} : { secretArrayKeys: spec.secretArrayKeys },
|
|
@@ -11956,7 +11956,7 @@ function userError(code, params, englishFallback) {
|
|
|
11956
11956
|
return new CamstackError(code, params, englishFallback);
|
|
11957
11957
|
}
|
|
11958
11958
|
//#endregion
|
|
11959
|
-
//#region ../types/dist/composition-
|
|
11959
|
+
//#region ../types/dist/composition-pOHbTzRB.mjs
|
|
11960
11960
|
/**
|
|
11961
11961
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11962
11962
|
*
|
|
@@ -14684,20 +14684,28 @@ async function moveIntegrationRowsToRecords(ports, spec) {
|
|
|
14684
14684
|
};
|
|
14685
14685
|
}
|
|
14686
14686
|
/**
|
|
14687
|
-
* The addon-side ports of `moveIntegrationRowsToRecords` (planning#416)
|
|
14688
|
-
* from its own process, so the
|
|
14689
|
-
* `
|
|
14690
|
-
*
|
|
14691
|
-
*
|
|
14687
|
+
* The addon-side ports of `moveIntegrationRowsToRecords` (planning#416). An addon runs the move
|
|
14688
|
+
* from its own process, so the leftover rows are reached through the migration-only door
|
|
14689
|
+
* (`migrations.readLegacyIntegrationRows` / `clearLegacyIntegrationRows`) on the hub's connection.
|
|
14690
|
+
* The door returns markers. This process is the owner, so it resolves and releases them with
|
|
14691
|
+
* `resolveSecretMarkers` — the same call the old settings door used — and only then asks the
|
|
14692
|
+
* door to delete the rows. The addon's own record kind is its records handle.
|
|
14692
14693
|
*/
|
|
14694
|
+
async function resolvedRows(stored, secrets) {
|
|
14695
|
+
if (secrets === null) return stored;
|
|
14696
|
+
const { value, unresolved } = await resolveSecretMarkers(stored, secrets);
|
|
14697
|
+
if (unresolved.length > 0) throw new Error(`${unresolved.length} secret(s) cannot be read from the keychain`);
|
|
14698
|
+
return value;
|
|
14699
|
+
}
|
|
14693
14700
|
function integrationRowsPortsOverApi(deps) {
|
|
14701
|
+
const secrets = deps.secrets ?? null;
|
|
14694
14702
|
return {
|
|
14695
14703
|
warn: (message) => deps.log.warn(message),
|
|
14696
14704
|
listIntegrations: async (addonId) => (await deps.api.list()).filter((i) => i.addonId === addonId).map((i) => ({
|
|
14697
14705
|
id: i.id,
|
|
14698
14706
|
name: i.name
|
|
14699
14707
|
})),
|
|
14700
|
-
readRows: (integrationId) => deps.api.
|
|
14708
|
+
readRows: async (integrationId) => resolvedRows(await deps.api.readLegacyIntegrationRows({ integrationId }), secrets),
|
|
14701
14709
|
putRecord: async (id, body) => {
|
|
14702
14710
|
if (await deps.records.get(id) !== null) return "exists";
|
|
14703
14711
|
try {
|
|
@@ -14716,7 +14724,9 @@ function integrationRowsPortsOverApi(deps) {
|
|
|
14716
14724
|
await deps.records.delete(id);
|
|
14717
14725
|
},
|
|
14718
14726
|
clearRows: async (integrationId) => {
|
|
14719
|
-
await deps.api.
|
|
14727
|
+
const refs = collectSecretMarkerRefs(await deps.api.readLegacyIntegrationRows({ integrationId }));
|
|
14728
|
+
if (refs.length > 0 && secrets !== null) await secrets.delete(refs);
|
|
14729
|
+
await deps.api.clearLegacyIntegrationRows({ integrationId });
|
|
14720
14730
|
}
|
|
14721
14731
|
};
|
|
14722
14732
|
}
|
|
@@ -14806,14 +14816,14 @@ async function claimDevicesToDefaultIntegration(ports, spec) {
|
|
|
14806
14816
|
* 2. `claim-devices` (tolerate): `claimDevicesToDefaultIntegration`; with no integration to claim
|
|
14807
14817
|
* to it fails and is retried on the next boot.
|
|
14808
14818
|
*
|
|
14809
|
-
* Both run in the addon process through the hub API (`ctx.api`)
|
|
14810
|
-
*
|
|
14811
|
-
* from the record, not from the rows.
|
|
14819
|
+
* Both run in the addon process through the hub API (`ctx.api`). The leftover rows are read
|
|
14820
|
+
* through the migration-only door, which answers empty once the store is gone.
|
|
14812
14821
|
*/
|
|
14813
14822
|
function defaultIntegrationPortsOver(deps) {
|
|
14814
14823
|
return {
|
|
14815
14824
|
...integrationRowsPortsOverApi({
|
|
14816
14825
|
api: deps.api,
|
|
14826
|
+
...deps.secrets !== void 0 ? { secrets: deps.secrets } : {},
|
|
14817
14827
|
records: deps.records.kind({
|
|
14818
14828
|
name: deps.kind.name,
|
|
14819
14829
|
declaration: deps.kind.declaration,
|
|
@@ -14913,8 +14923,8 @@ function defaultIntegrationMigrations(spec) {
|
|
|
14913
14923
|
function defaultIntegrationApiOver(api) {
|
|
14914
14924
|
return {
|
|
14915
14925
|
list: () => api.integrations.list.query(),
|
|
14916
|
-
|
|
14917
|
-
|
|
14926
|
+
readLegacyIntegrationRows: (input) => api.migrations.readLegacyIntegrationRows.query(input),
|
|
14927
|
+
clearLegacyIntegrationRows: (input) => api.migrations.clearLegacyIntegrationRows.mutate(input),
|
|
14918
14928
|
listDevices: (addonId) => api.deviceManager.listAll.query({
|
|
14919
14929
|
addonId,
|
|
14920
14930
|
projection: "slim"
|
|
@@ -50531,6 +50541,9 @@ var RunningProposalEvidenceSchema = object({
|
|
|
50531
50541
|
runsFound: number().int().nonnegative(),
|
|
50532
50542
|
pausesFound: number().int().nonnegative(),
|
|
50533
50543
|
longestPauseMs: number().nonnegative(),
|
|
50544
|
+
/** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
|
|
50545
|
+
pulsesFound: number().int().nonnegative(),
|
|
50546
|
+
longestPulseMs: number().nonnegative(),
|
|
50534
50547
|
idleFloorW: number(),
|
|
50535
50548
|
noiseCeilingW: number(),
|
|
50536
50549
|
plateauW: number(),
|
|
@@ -56380,11 +56393,7 @@ var CreateIntegrationInputSchema = object({
|
|
|
56380
56393
|
info: record(string(), unknown()).optional(),
|
|
56381
56394
|
/** `stableId` of the discovery candidate the form was seeded from (D984). */
|
|
56382
56395
|
originStableId: string().optional(),
|
|
56383
|
-
settings: record(string(), unknown()).optional()
|
|
56384
|
-
/** Keys of `settings` the form's schema declares secret (by type) — kept in
|
|
56385
|
-
* the keychain, not the table (D787). */
|
|
56386
|
-
secretKeys: array(string()).optional(),
|
|
56387
|
-
skipRestart: boolean().optional()
|
|
56396
|
+
settings: record(string(), unknown()).optional()
|
|
56388
56397
|
});
|
|
56389
56398
|
var UpdateIntegrationInputSchema = object({
|
|
56390
56399
|
id: string(),
|
|
@@ -56405,22 +56414,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
|
|
|
56405
56414
|
}), method(object({ id: string() }), DeleteIntegrationResultSchema, {
|
|
56406
56415
|
kind: "mutation",
|
|
56407
56416
|
auth: "admin"
|
|
56408
|
-
}), method(object({ id: string() }), record(string(), unknown()), { auth: "admin" }), method(object({
|
|
56409
|
-
id: string(),
|
|
56410
|
-
settings: record(string(), unknown()),
|
|
56411
|
-
/** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
|
|
56412
|
-
secretKeys: array(string()).optional(),
|
|
56413
|
-
/** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
|
|
56414
|
-
skipRestart: boolean().optional()
|
|
56415
|
-
}), object({ success: boolean() }), {
|
|
56416
|
-
kind: "mutation",
|
|
56417
|
-
auth: "admin"
|
|
56418
|
-
}), method(object({ id: string() }), object({
|
|
56419
|
-
rows: number().int().nonnegative(),
|
|
56420
|
-
secrets: number().int().nonnegative()
|
|
56421
|
-
}), {
|
|
56422
|
-
kind: "mutation",
|
|
56423
|
-
auth: "admin"
|
|
56424
56417
|
}), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
|
|
56425
56418
|
addonId: string(),
|
|
56426
56419
|
settings: record(string(), unknown())
|
|
@@ -59397,6 +59390,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
|
|
|
59397
59390
|
}), {
|
|
59398
59391
|
kind: "mutation",
|
|
59399
59392
|
auth: "admin"
|
|
59393
|
+
}), method(object({ integrationId: string().min(1) }), record(string(), unknown()), { auth: "admin" }), method(object({ integrationId: string().min(1) }), object({
|
|
59394
|
+
rows: number().int().nonnegative(),
|
|
59395
|
+
secrets: number().int().nonnegative()
|
|
59396
|
+
}), {
|
|
59397
|
+
kind: "mutation",
|
|
59398
|
+
auth: "admin"
|
|
59399
|
+
}), method(object({
|
|
59400
|
+
integrationId: string().min(1),
|
|
59401
|
+
patch: record(string(), unknown())
|
|
59402
|
+
}), object({ written: boolean() }), {
|
|
59403
|
+
kind: "mutation",
|
|
59404
|
+
auth: "admin"
|
|
59405
|
+
}), method(object({
|
|
59406
|
+
integrationId: string().min(1),
|
|
59407
|
+
keys: array(string().min(1))
|
|
59408
|
+
}), object({
|
|
59409
|
+
present: boolean(),
|
|
59410
|
+
removed: record(string(), unknown())
|
|
59411
|
+
}), {
|
|
59412
|
+
kind: "mutation",
|
|
59413
|
+
auth: "admin"
|
|
59400
59414
|
});
|
|
59401
59415
|
method(object({
|
|
59402
59416
|
sourceUrl: string(),
|
|
@@ -81790,11 +81804,15 @@ discriminatedUnion("kind", [object({
|
|
|
81790
81804
|
* 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
|
|
81791
81805
|
* near F. A device that is not near one level most of the time has no floor.
|
|
81792
81806
|
* 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
|
|
81793
|
-
* 3.
|
|
81794
|
-
*
|
|
81807
|
+
* 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
|
|
81808
|
+
* display waking): it is neither a run nor a pause. Among the remaining
|
|
81809
|
+
* episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
|
|
81810
|
+
* two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
|
|
81811
|
+
* a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
|
|
81812
|
+
* is no run.
|
|
81795
81813
|
* 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
|
|
81796
|
-
* grid a person would type; stop dwell covers the longest pause
|
|
81797
|
-
* covers the longest standby blip above T.
|
|
81814
|
+
* grid a person would type; stop dwell covers the longest pause and the
|
|
81815
|
+
* kind's floor; start dwell covers the longest pulse and standby blip above T.
|
|
81798
81816
|
* 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
|
|
81799
81817
|
* run must hold exactly one true interval and nothing may flap outside.
|
|
81800
81818
|
*/
|
|
@@ -81805,6 +81823,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
|
|
|
81805
81823
|
30 * SECOND_MS;
|
|
81806
81824
|
60 * SECOND_MS;
|
|
81807
81825
|
20 * MINUTE_MS$1;
|
|
81826
|
+
90 * SECOND_MS;
|
|
81827
|
+
30 * MINUTE_MS$1;
|
|
81828
|
+
10 * MINUTE_MS$1;
|
|
81829
|
+
DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
|
|
81808
81830
|
10 * SECOND_MS;
|
|
81809
81831
|
10 * SECOND_MS;
|
|
81810
81832
|
/**
|
|
@@ -87226,13 +87248,6 @@ Object.freeze({
|
|
|
87226
87248
|
access: "create",
|
|
87227
87249
|
role: "admin"
|
|
87228
87250
|
},
|
|
87229
|
-
"integrations.clearSettings": {
|
|
87230
|
-
capName: "integrations",
|
|
87231
|
-
capScope: "system",
|
|
87232
|
-
addonId: null,
|
|
87233
|
-
access: "delete",
|
|
87234
|
-
role: "admin"
|
|
87235
|
-
},
|
|
87236
87251
|
"integrations.create": {
|
|
87237
87252
|
capName: "integrations",
|
|
87238
87253
|
capScope: "system",
|
|
@@ -87268,13 +87283,6 @@ Object.freeze({
|
|
|
87268
87283
|
access: "view",
|
|
87269
87284
|
role: "admin"
|
|
87270
87285
|
},
|
|
87271
|
-
"integrations.getSettings": {
|
|
87272
|
-
capName: "integrations",
|
|
87273
|
-
capScope: "system",
|
|
87274
|
-
addonId: null,
|
|
87275
|
-
access: "view",
|
|
87276
|
-
role: "admin"
|
|
87277
|
-
},
|
|
87278
87286
|
"integrations.list": {
|
|
87279
87287
|
capName: "integrations",
|
|
87280
87288
|
capScope: "system",
|
|
@@ -87282,13 +87290,6 @@ Object.freeze({
|
|
|
87282
87290
|
access: "view",
|
|
87283
87291
|
role: "admin"
|
|
87284
87292
|
},
|
|
87285
|
-
"integrations.setSettings": {
|
|
87286
|
-
capName: "integrations",
|
|
87287
|
-
capScope: "system",
|
|
87288
|
-
addonId: null,
|
|
87289
|
-
access: "create",
|
|
87290
|
-
role: "admin"
|
|
87291
|
-
},
|
|
87292
87293
|
"integrations.testConnection": {
|
|
87293
87294
|
capName: "integrations",
|
|
87294
87295
|
capScope: "system",
|
|
@@ -88283,6 +88284,13 @@ Object.freeze({
|
|
|
88283
88284
|
access: "view",
|
|
88284
88285
|
role: "admin"
|
|
88285
88286
|
},
|
|
88287
|
+
"migrations.clearLegacyIntegrationRows": {
|
|
88288
|
+
capName: "migrations",
|
|
88289
|
+
capScope: "system",
|
|
88290
|
+
addonId: null,
|
|
88291
|
+
access: "delete",
|
|
88292
|
+
role: "admin"
|
|
88293
|
+
},
|
|
88286
88294
|
"migrations.declareOwner": {
|
|
88287
88295
|
capName: "migrations",
|
|
88288
88296
|
capScope: "system",
|
|
@@ -88290,6 +88298,13 @@ Object.freeze({
|
|
|
88290
88298
|
access: "create",
|
|
88291
88299
|
role: "admin"
|
|
88292
88300
|
},
|
|
88301
|
+
"migrations.deleteLegacyIntegrationRowKeys": {
|
|
88302
|
+
capName: "migrations",
|
|
88303
|
+
capScope: "system",
|
|
88304
|
+
addonId: null,
|
|
88305
|
+
access: "delete",
|
|
88306
|
+
role: "admin"
|
|
88307
|
+
},
|
|
88293
88308
|
"migrations.dryRun": {
|
|
88294
88309
|
capName: "migrations",
|
|
88295
88310
|
capScope: "system",
|
|
@@ -88325,6 +88340,20 @@ Object.freeze({
|
|
|
88325
88340
|
access: "create",
|
|
88326
88341
|
role: "admin"
|
|
88327
88342
|
},
|
|
88343
|
+
"migrations.patchLegacyIntegrationRows": {
|
|
88344
|
+
capName: "migrations",
|
|
88345
|
+
capScope: "system",
|
|
88346
|
+
addonId: null,
|
|
88347
|
+
access: "create",
|
|
88348
|
+
role: "admin"
|
|
88349
|
+
},
|
|
88350
|
+
"migrations.readLegacyIntegrationRows": {
|
|
88351
|
+
capName: "migrations",
|
|
88352
|
+
capScope: "system",
|
|
88353
|
+
addonId: null,
|
|
88354
|
+
access: "view",
|
|
88355
|
+
role: "admin"
|
|
88356
|
+
},
|
|
88328
88357
|
"migrations.restorePreMigration": {
|
|
88329
88358
|
capName: "migrations",
|
|
88330
88359
|
capScope: "system",
|
|
@@ -106861,6 +106890,7 @@ var AmcrestProviderAddon = class extends BaseDeviceProvider {
|
|
|
106861
106890
|
date: "2026-11-04"
|
|
106862
106891
|
}), defaultIntegrationPortsOver({
|
|
106863
106892
|
api: defaultIntegrationApiOver(this.ctx.api),
|
|
106893
|
+
secrets: this.ctx.secrets ?? null,
|
|
106864
106894
|
records,
|
|
106865
106895
|
kind: amcrestConnectionsEntryKind,
|
|
106866
106896
|
info: (message) => this.ctx.logger.info(message),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-amcrest",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.166",
|
|
4
4
|
"description": "Amcrest/Dahua camera device provider addon for CamStack — Dahua CGI over HTTP(S) with digest auth (snapshot, RTSP catalog, PTZ, image/day-night config)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"onvif"
|
|
86
86
|
],
|
|
87
87
|
"requires": {
|
|
88
|
-
"server": ">=1.2.
|
|
88
|
+
"server": ">=1.2.770"
|
|
89
89
|
}
|
|
90
90
|
},
|
|
91
91
|
"files": [
|