@camstack/system 1.2.438 → 1.2.440
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/dist/addon-runner.js +743 -79
- package/dist/addon-runner.mjs +743 -79
- package/dist/addon-utils.js +1 -1
- package/dist/addon-utils.mjs +1 -1
- package/dist/{agent-https-BZIwS4xF.js → agent-https-DlpTMDqA.js} +252 -22
- package/dist/{agent-https-BPfHrI4c.mjs → agent-https-U0d4uvn2.mjs} +211 -23
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/autotrack/index.js +1 -1
- package/dist/builtins/autotrack/index.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
- package/dist/builtins/calendars/calendars.addon.js +1 -1
- package/dist/builtins/calendars/calendars.addon.mjs +1 -1
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/composer/composer.addon.js +2 -2
- package/dist/builtins/composer/composer.addon.mjs +2 -2
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/block-settings-store.d.ts +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +77 -11
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +77 -12
- package/dist/builtins/core-blocks/index.mjs +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +197 -60
- package/dist/builtins/device-manager/device-manager.addon.mjs +196 -61
- package/dist/builtins/device-manager/device-removal-hooks.d.ts +0 -11
- package/dist/builtins/device-manager/device-tombstone-store.d.ts +12 -2
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/keychain/index.js +29 -11
- package/dist/builtins/keychain/index.mjs +29 -11
- package/dist/builtins/keychain/keychain-service.d.ts +8 -0
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +2 -2
- package/dist/builtins/local-auth/local-auth.addon.mjs +2 -2
- package/dist/builtins/local-network/local-network.addon.js +7 -2
- package/dist/builtins/local-network/local-network.addon.mjs +7 -2
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/index.js +1 -1
- package/dist/builtins/sqlite-storage/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +38 -7
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +69 -3
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +69 -3
- package/dist/builtins/sqlite-storage/storage-admin-provider.d.ts +31 -0
- package/dist/builtins/storage-orchestrator/hub-settings-forward.d.ts +3 -3
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +4 -4
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +4 -4
- package/dist/builtins/system-config/system-config.addon.js +4 -4
- package/dist/builtins/system-config/system-config.addon.mjs +285 -285
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{composition-sources-DpHGCjdL.mjs → composition-sources-CS0D7imL.mjs} +1 -1
- package/dist/{composition-sources-DI3Z83vG.js → composition-sources-cBG8fBTu.js} +1 -1
- package/dist/{constants-DQK705Sb.mjs → constants-CIzPjw7L.mjs} +1 -1
- package/dist/{constants-wkcn5Ij3.js → constants-CRI3QzT4.js} +1 -1
- package/dist/{device-ca-DvIZjXIl.mjs → device-ca-DLKXYseS.mjs} +2 -2
- package/dist/{device-ca-BSvkXqyI.js → device-ca-DNHjts4_.js} +2 -2
- package/dist/{dist-Dc8GKC5H.mjs → dist-9fcsrFU3.mjs} +271 -32
- package/dist/{dist-GgG-7amw.js → dist-BKhlcYz6.js} +288 -31
- package/dist/file-host-worker.js +1 -1
- package/dist/file-host-worker.mjs +1 -1
- package/dist/{hub-mdns-ciao-CBLvq2oj.js → hub-mdns-ciao-3Zc9G9MS.js} +377 -69
- package/dist/{hub-mdns-ciao-DMlQTdPU.mjs → hub-mdns-ciao-Dy2YjRqC.mjs} +344 -72
- package/dist/index.js +372 -339
- package/dist/index.mjs +361 -341
- package/dist/kernel/addon-settings-store.d.ts +43 -0
- package/dist/kernel/config-manager.d.ts +0 -19
- package/dist/kernel/device-settings-store.d.ts +74 -0
- package/dist/kernel/legacy-blob-guard.d.ts +58 -0
- package/dist/kernel/moleculer/runner-addon-settings.d.ts +34 -0
- package/dist/kernel/moleculer/runner-device-settings.d.ts +39 -0
- package/dist/kernel/prefix-walk.d.ts +39 -0
- package/dist/kernel/sections-store.d.ts +20 -0
- package/dist/kernel/settings-door-view.d.ts +2 -2
- package/dist/kernel/settings-view-types.d.ts +5 -30
- package/dist/kernel/store-settings-view.d.ts +0 -3
- package/dist/{lib-NNxHSOIE.js → lib-8oZrELLm.js} +1 -1
- package/dist/{lib-BeGzVQcd.mjs → lib-DK38ompL.mjs} +1 -1
- package/dist/prefix-range-D_KueXbQ.js +27 -0
- package/dist/prefix-range-Dl0znowN.mjs +22 -0
- package/dist/prefix-walk-DAOBSyH1.mjs +88 -0
- package/dist/prefix-walk-Dv6MLZlM.js +99 -0
- package/dist/{restore-archive-CTRz8v9o.js → restore-archive-49aZwkp8.js} +1 -1
- package/dist/{restore-archive-DPg9duVY.mjs → restore-archive-DgvDecXM.mjs} +82 -82
- package/dist/{retired-settings-keys-Is0zO8gX.mjs → retired-settings-keys-Bhwe4ymb.mjs} +2 -2
- package/dist/{retired-settings-keys-Dr_4lfKu.js → retired-settings-keys-D_VwZiDt.js} +10 -4
- package/dist/tls/agent-https.d.ts +2 -2
- package/dist/tls/boot-tls.d.ts +6 -0
- package/dist/tls/cert-evaluation.d.ts +1 -1
- package/dist/tls/cert-issue.d.ts +5 -1
- package/dist/tls/cert-manager.d.ts +18 -0
- package/dist/tls/cert-name-constraints.d.ts +53 -0
- package/dist/tls/index.d.ts +5 -4
- package/dist/tls/tls-actions.d.ts +27 -7
- package/dist/tls/tls-status.d.ts +22 -0
- package/dist/tls/uploaded-cert.d.ts +36 -4
- package/dist/{wal-maintenance-Bx3lcVA7.mjs → wal-maintenance-BZGmF-3U.mjs} +0 -0
- package/dist/{wal-maintenance-mjB2i-VR.js → wal-maintenance-C041zn6V.js} +0 -0
- package/dist/{x509.es-r7Ht1thA.js → x509.es-C4cOo48M.js} +36 -0
- package/dist/{x509.es-CDvj67p1.mjs → x509.es-DK__ETIe.mjs} +1 -1
- package/package.json +7 -2
- package/dist/{custom-action-registry-Bf_YnagS.js → custom-action-registry-BKmoaqG0.js} +1 -1
- package/dist/{custom-action-registry-BQnbN0DP.mjs → custom-action-registry-CyUuhATc.mjs} +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { A as DeclaredDevices,
|
|
2
|
-
import { t as describeCompositionSources } from "../../composition-sources-
|
|
1
|
+
import { A as DeclaredDevices, Ar as errMsg, Bn as resolveCoreBlockFiles, Cr as compositionSourceKey, Ct as coreBlockAddonId, Dt as coreBlocksCapability, Et as coreBlockSourceKind, Ft as describeComposableCaps, In as replacedFieldKeys, St as compositionSourceRefs, Tn as normalizeCoreBlockWrite, Tt as coreBlockIdFromAddonId, ei as hydrateSchema, ft as buildCapabilityLookup, h as CORE_BLOCK_ADDON_PREFIX, jn as planComposition, jr as BaseAddon, lr as validateComposition, m as CORE_BLOCKS_ADDON_ID, p as COMPOSER_RUNNER_ID, r as ALL_CAPABILITY_DEFINITIONS, v as CoreBlockSchema, vr as composedDeviceRef, wt as coreBlockComposition, zn as resolveCoreBlockEntry } from "../../dist-9fcsrFU3.mjs";
|
|
2
|
+
import { t as describeCompositionSources } from "../../composition-sources-CS0D7imL.mjs";
|
|
3
|
+
import { t as prefixRange } from "../../prefix-range-Dl0znowN.mjs";
|
|
4
|
+
import { n as unwrapStoredValue, t as loadPrefixed } from "../../prefix-walk-DAOBSyH1.mjs";
|
|
3
5
|
import { createRequire } from "node:module";
|
|
4
6
|
import { randomUUID } from "node:crypto";
|
|
5
7
|
import { customizationBlockName } from "@camstack/types/node";
|
|
@@ -485,6 +487,72 @@ var BlockSupervisor = class {
|
|
|
485
487
|
}
|
|
486
488
|
};
|
|
487
489
|
//#endregion
|
|
490
|
+
//#region src/kernel/addon-settings-store.ts
|
|
491
|
+
/** The collection every addon's settings share. Named nowhere else (with sections' own module). */
|
|
492
|
+
var ADDON_SETTINGS_COLLECTION = "addon-settings";
|
|
493
|
+
function createAddonSettingsStore(door, addonId) {
|
|
494
|
+
const prefix = `${addonId}.`;
|
|
495
|
+
const message = (err) => err instanceof Error ? err.message : String(err);
|
|
496
|
+
return {
|
|
497
|
+
async read() {
|
|
498
|
+
try {
|
|
499
|
+
const value = await loadPrefixed(door, ADDON_SETTINGS_COLLECTION, prefix);
|
|
500
|
+
return Object.keys(value).length === 0 ? { kind: "absent" } : {
|
|
501
|
+
kind: "present",
|
|
502
|
+
value
|
|
503
|
+
};
|
|
504
|
+
} catch (err) {
|
|
505
|
+
return {
|
|
506
|
+
kind: "unreadable",
|
|
507
|
+
error: message(err)
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
async readKey(key) {
|
|
512
|
+
try {
|
|
513
|
+
const row = await door.get({
|
|
514
|
+
collection: ADDON_SETTINGS_COLLECTION,
|
|
515
|
+
key: `${prefix}${key}`
|
|
516
|
+
});
|
|
517
|
+
return row === void 0 || row === null ? { kind: "absent" } : {
|
|
518
|
+
kind: "present",
|
|
519
|
+
value: unwrapStoredValue(row)
|
|
520
|
+
};
|
|
521
|
+
} catch (err) {
|
|
522
|
+
return {
|
|
523
|
+
kind: "unreadable",
|
|
524
|
+
error: message(err)
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
},
|
|
528
|
+
async merge(patch) {
|
|
529
|
+
const records = [];
|
|
530
|
+
const removed = [];
|
|
531
|
+
for (const [key, value] of Object.entries(patch)) if (value === void 0) removed.push(`${prefix}${key}`);
|
|
532
|
+
else records.push({
|
|
533
|
+
id: `${prefix}${key}`,
|
|
534
|
+
data: {
|
|
535
|
+
addonId,
|
|
536
|
+
key,
|
|
537
|
+
value
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
if (records.length === 0 && removed.length === 0) return;
|
|
541
|
+
if (prefixRange(prefix) === null) throw new Error(`addon settings: "${addonId}" cannot be expressed as an id range`);
|
|
542
|
+
await door.transact({ ops: [...removed.length > 0 ? [{
|
|
543
|
+
op: "deleteWhere",
|
|
544
|
+
collection: ADDON_SETTINGS_COLLECTION,
|
|
545
|
+
filter: { whereIn: { id: removed } }
|
|
546
|
+
}] : [], ...records.length > 0 ? [{
|
|
547
|
+
op: "upsertMany",
|
|
548
|
+
collection: ADDON_SETTINGS_COLLECTION,
|
|
549
|
+
conflict: ["id"],
|
|
550
|
+
records
|
|
551
|
+
}] : []] });
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
//#endregion
|
|
488
556
|
//#region src/builtins/core-blocks/block-settings-store.ts
|
|
489
557
|
/**
|
|
490
558
|
* @durable class=config owner=core-blocks
|
|
@@ -545,15 +613,12 @@ var BlockSettingsStore = class {
|
|
|
545
613
|
});
|
|
546
614
|
}
|
|
547
615
|
async mirrorToBlockAddon(blockId, values) {
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
value: values
|
|
555
|
-
});
|
|
556
|
-
} catch {}
|
|
616
|
+
const store = this.store;
|
|
617
|
+
await createAddonSettingsStore({
|
|
618
|
+
query: (input) => store.query.query(input),
|
|
619
|
+
get: (input) => store.get.query(input),
|
|
620
|
+
transact: (input) => store.transact.mutate(input)
|
|
621
|
+
}, coreBlockAddonId(blockId)).merge(values);
|
|
557
622
|
}
|
|
558
623
|
};
|
|
559
624
|
//#endregion
|
|
@@ -2258,4 +2323,4 @@ async function loadTranspiler(logger) {
|
|
|
2258
2323
|
}
|
|
2259
2324
|
}
|
|
2260
2325
|
//#endregion
|
|
2261
|
-
export { CoreBlocksAddon, loadBlockTypeDefs as a,
|
|
2326
|
+
export { CoreBlocksAddon, loadBlockTypeDefs as a, createAddonSettingsStore as c, blockAddonId as d, blockIdFromAddonId as f, compileBlock as i, BlockSupervisor as l, removeBlockPackage as m, CORE_BLOCKS_COLLECTION as n, BlockSettingsStore as o, materializeBlock as p, CoreBlockStore as r, CORE_BLOCK_SETTINGS_COLLECTION as s, extractSettingsSchema as t, BLOCK_ADDON_PREFIX as u };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { CoreBlocksAddon, a as loadBlockTypeDefs,
|
|
1
|
+
import { CoreBlocksAddon, a as loadBlockTypeDefs, d as blockAddonId, f as blockIdFromAddonId, i as compileBlock, l as BlockSupervisor, m as removeBlockPackage, n as CORE_BLOCKS_COLLECTION, o as BlockSettingsStore, p as materializeBlock, r as CoreBlockStore, s as CORE_BLOCK_SETTINGS_COLLECTION, t as extractSettingsSchema, u as BLOCK_ADDON_PREFIX } from "./core-blocks.addon.mjs";
|
|
2
2
|
export { BLOCK_ADDON_PREFIX, BlockSettingsStore, BlockSupervisor, CORE_BLOCKS_COLLECTION, CORE_BLOCK_SETTINGS_COLLECTION, CoreBlockStore, CoreBlocksAddon, CoreBlocksAddon as default, blockAddonId, blockIdFromAddonId, compileBlock, extractSettingsSchema, loadBlockTypeDefs, materializeBlock, removeBlockPackage };
|
|
@@ -3,8 +3,10 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
7
|
-
const
|
|
6
|
+
const require_dist = require("../../dist-BKhlcYz6.js");
|
|
7
|
+
const require_prefix_range = require("../../prefix-range-D_KueXbQ.js");
|
|
8
|
+
const require_prefix_walk = require("../../prefix-walk-Dv6MLZlM.js");
|
|
9
|
+
const require_retired_settings_keys = require("../../retired-settings-keys-D_VwZiDt.js");
|
|
8
10
|
let zod = require("zod");
|
|
9
11
|
let node_crypto = require("node:crypto");
|
|
10
12
|
let _camstack_types_node = require("@camstack/types/node");
|
|
@@ -2730,30 +2732,13 @@ async function listPersistedByAddon(pctx, input) {
|
|
|
2730
2732
|
return saved;
|
|
2731
2733
|
}
|
|
2732
2734
|
/**
|
|
2733
|
-
* Every requested device's persisted config
|
|
2734
|
-
*
|
|
2735
|
-
*
|
|
2736
|
-
* One call when the view can batch (the in-process door, which keys
|
|
2737
|
-
* `addon-device-settings` by `<addonId>:<deviceId>.` and answers a whole addon
|
|
2738
|
-
* with one indexed range scan). Otherwise the per-device form, unchanged — a
|
|
2739
|
-
* fallback and not a silent downgrade: `readDeviceStoreBatch` is optional
|
|
2740
|
-
* precisely because a forked addon's view has nothing to batch, and refusing
|
|
2741
|
-
* would break the only implementation that cannot comply.
|
|
2742
|
-
*
|
|
2743
|
-
* A read that THROWS yields `{}` for that device rather than failing the whole
|
|
2744
|
-
* listing: one unreadable settings row must not make the fleet unlistable.
|
|
2735
|
+
* Every requested device's persisted config in ONE store round trip (D870). A
|
|
2736
|
+
* store that cannot be asked THROWS and the listing fails with it: an
|
|
2737
|
+
* unreadable row is not a device with no settings (D49).
|
|
2745
2738
|
*/
|
|
2746
2739
|
async function readDeviceConfigs(pctx, deviceIds) {
|
|
2747
2740
|
if (deviceIds.length === 0) return /* @__PURE__ */ new Map();
|
|
2748
|
-
|
|
2749
|
-
if (batch !== void 0) return batch.call(pctx.settings, deviceIds);
|
|
2750
|
-
const out = /* @__PURE__ */ new Map();
|
|
2751
|
-
for (const id of deviceIds) try {
|
|
2752
|
-
out.set(id, await pctx.settings.readDeviceStore(id));
|
|
2753
|
-
} catch {
|
|
2754
|
-
out.set(id, {});
|
|
2755
|
-
}
|
|
2756
|
-
return out;
|
|
2741
|
+
return pctx.settings.readDeviceStoreBatch(deviceIds);
|
|
2757
2742
|
}
|
|
2758
2743
|
async function listAll(pctx, input) {
|
|
2759
2744
|
const ownerFilter = Reflect.get(input, "addonId");
|
|
@@ -4856,6 +4841,170 @@ function createDeviceManagerExtensionProvider(pctx) {
|
|
|
4856
4841
|
});
|
|
4857
4842
|
}
|
|
4858
4843
|
//#endregion
|
|
4844
|
+
//#region src/kernel/device-settings-store.ts
|
|
4845
|
+
/** The collection every addon's per-device settings share. Named nowhere else. */
|
|
4846
|
+
var DEVICE_SETTINGS_COLLECTION = "addon-device-settings";
|
|
4847
|
+
function scopeOf(addonId, deviceId) {
|
|
4848
|
+
return `${addonId}:${String(deviceId)}.`;
|
|
4849
|
+
}
|
|
4850
|
+
function assertDeviceId(deviceId) {
|
|
4851
|
+
if (!Number.isInteger(deviceId) || deviceId <= 0) throw new Error(`device settings: "${String(deviceId)}" is not a device id`);
|
|
4852
|
+
}
|
|
4853
|
+
function deviceIdOfSuffix(suffix) {
|
|
4854
|
+
const dot = suffix.indexOf(".");
|
|
4855
|
+
if (dot <= 0) return null;
|
|
4856
|
+
const id = Number(suffix.slice(0, dot));
|
|
4857
|
+
return Number.isInteger(id) && id > 0 ? id : null;
|
|
4858
|
+
}
|
|
4859
|
+
/** Every field row of one device scope, or a throw. */
|
|
4860
|
+
async function readScope(door, addonId, deviceId) {
|
|
4861
|
+
return require_prefix_walk.loadPrefixed(door, DEVICE_SETTINGS_COLLECTION, scopeOf(addonId, deviceId));
|
|
4862
|
+
}
|
|
4863
|
+
function createDeviceSettingsStore(door, addonId) {
|
|
4864
|
+
return {
|
|
4865
|
+
async read(deviceId) {
|
|
4866
|
+
try {
|
|
4867
|
+
assertDeviceId(deviceId);
|
|
4868
|
+
const value = await readScope(door, addonId, deviceId);
|
|
4869
|
+
return Object.keys(value).length === 0 ? { kind: "absent" } : {
|
|
4870
|
+
kind: "present",
|
|
4871
|
+
value
|
|
4872
|
+
};
|
|
4873
|
+
} catch (err) {
|
|
4874
|
+
return {
|
|
4875
|
+
kind: "unreadable",
|
|
4876
|
+
error: err instanceof Error ? err.message : String(err)
|
|
4877
|
+
};
|
|
4878
|
+
}
|
|
4879
|
+
},
|
|
4880
|
+
async readBatch(deviceIds) {
|
|
4881
|
+
const out = /* @__PURE__ */ new Map();
|
|
4882
|
+
if (deviceIds.length === 0) return out;
|
|
4883
|
+
for (const id of deviceIds) out.set(id, {});
|
|
4884
|
+
const wanted = new Set(deviceIds);
|
|
4885
|
+
const all = await require_prefix_walk.loadPrefixed(door, DEVICE_SETTINGS_COLLECTION, `${addonId}:`);
|
|
4886
|
+
for (const [suffix, value] of Object.entries(all)) {
|
|
4887
|
+
const id = deviceIdOfSuffix(suffix);
|
|
4888
|
+
if (id === null || !wanted.has(id)) continue;
|
|
4889
|
+
const blob = out.get(id);
|
|
4890
|
+
if (blob !== void 0) blob[suffix.slice(suffix.indexOf(".") + 1)] = value;
|
|
4891
|
+
}
|
|
4892
|
+
return out;
|
|
4893
|
+
},
|
|
4894
|
+
async listIds() {
|
|
4895
|
+
const all = await require_prefix_walk.loadPrefixed(door, DEVICE_SETTINGS_COLLECTION, `${addonId}:`, () => null);
|
|
4896
|
+
const ids = /* @__PURE__ */ new Set();
|
|
4897
|
+
for (const suffix of Object.keys(all)) {
|
|
4898
|
+
const id = deviceIdOfSuffix(suffix);
|
|
4899
|
+
if (id !== null) ids.add(id);
|
|
4900
|
+
}
|
|
4901
|
+
return [...ids].toSorted((a, b) => a - b);
|
|
4902
|
+
},
|
|
4903
|
+
async merge(deviceId, patch) {
|
|
4904
|
+
assertDeviceId(deviceId);
|
|
4905
|
+
const scope = scopeOf(addonId, deviceId);
|
|
4906
|
+
const records = [];
|
|
4907
|
+
const removed = [];
|
|
4908
|
+
for (const [key, value] of Object.entries(patch)) if (value === void 0) removed.push(`${scope}${key}`);
|
|
4909
|
+
else records.push({
|
|
4910
|
+
id: `${scope}${key}`,
|
|
4911
|
+
data: {
|
|
4912
|
+
addonId,
|
|
4913
|
+
deviceId: String(deviceId),
|
|
4914
|
+
key,
|
|
4915
|
+
value
|
|
4916
|
+
}
|
|
4917
|
+
});
|
|
4918
|
+
if (records.length === 0 && removed.length === 0) return;
|
|
4919
|
+
await door.transact({ ops: [...removed.length > 0 ? [{
|
|
4920
|
+
op: "deleteWhere",
|
|
4921
|
+
collection: DEVICE_SETTINGS_COLLECTION,
|
|
4922
|
+
filter: { whereIn: { id: removed } }
|
|
4923
|
+
}] : [], ...records.length > 0 ? [{
|
|
4924
|
+
op: "upsertMany",
|
|
4925
|
+
collection: DEVICE_SETTINGS_COLLECTION,
|
|
4926
|
+
conflict: ["id"],
|
|
4927
|
+
records
|
|
4928
|
+
}] : []] });
|
|
4929
|
+
},
|
|
4930
|
+
async clear(deviceId) {
|
|
4931
|
+
assertDeviceId(deviceId);
|
|
4932
|
+
const range = require_prefix_range.prefixRange(scopeOf(addonId, deviceId));
|
|
4933
|
+
if (range === null) throw new Error(`device settings: no id range for addon "${addonId}"`);
|
|
4934
|
+
await door.deleteWhere({
|
|
4935
|
+
collection: DEVICE_SETTINGS_COLLECTION,
|
|
4936
|
+
filter: { whereBetween: { id: [range.lo, range.hi] } }
|
|
4937
|
+
});
|
|
4938
|
+
}
|
|
4939
|
+
};
|
|
4940
|
+
}
|
|
4941
|
+
/** The `Record` form of a read: `{}` for a store that answered with no row, a THROW for one that did not. */
|
|
4942
|
+
async function readDeviceOrThrow(store, deviceId) {
|
|
4943
|
+
const read = await store.read(deviceId);
|
|
4944
|
+
switch (read.kind) {
|
|
4945
|
+
case "present": return { ...read.value };
|
|
4946
|
+
case "absent": return {};
|
|
4947
|
+
case "unreadable": throw new Error(`device settings of ${String(deviceId)} could not be read: ${read.error}`);
|
|
4948
|
+
}
|
|
4949
|
+
}
|
|
4950
|
+
/**
|
|
4951
|
+
* Remove a device's rows for EVERY addon, in one statement (D865's central
|
|
4952
|
+
* delete). Matched on the device id each row carries, so no addon needs a
|
|
4953
|
+
* handler. Returns how many rows went.
|
|
4954
|
+
*/
|
|
4955
|
+
async function clearDeviceSettings(door, deviceId) {
|
|
4956
|
+
assertDeviceId(deviceId);
|
|
4957
|
+
const { deleted } = await door.deleteWhere({
|
|
4958
|
+
collection: DEVICE_SETTINGS_COLLECTION,
|
|
4959
|
+
filter: { where: { deviceId: String(deviceId) } }
|
|
4960
|
+
});
|
|
4961
|
+
return deleted;
|
|
4962
|
+
}
|
|
4963
|
+
/** Rows one page of the scope walk asks for. */
|
|
4964
|
+
var SCOPE_PAGE_ROWS = 1e3;
|
|
4965
|
+
/** Pages the walk may take before it refuses (a bound, never a silent cut). */
|
|
4966
|
+
var SCOPE_PAGE_BUDGET = 512;
|
|
4967
|
+
/** Above every id: ids are ASCII. */
|
|
4968
|
+
var SCOPE_TAIL = "";
|
|
4969
|
+
/**
|
|
4970
|
+
* Every (addon, device) pair holding rows, across all addons - the admin
|
|
4971
|
+
* "deleted devices" listing. A keyset walk by primary key (never one query cut
|
|
4972
|
+
* at a row cap): a read that cannot be completed THROWS.
|
|
4973
|
+
*/
|
|
4974
|
+
async function listDeviceSettingsScopes(door) {
|
|
4975
|
+
const seen = /* @__PURE__ */ new Map();
|
|
4976
|
+
let cursor = "";
|
|
4977
|
+
for (let page = 0;; page++) {
|
|
4978
|
+
if (page >= SCOPE_PAGE_BUDGET) throw new Error(`device settings scopes: more than ${SCOPE_PAGE_BUDGET} pages - refusing a partial list`);
|
|
4979
|
+
const rows = await door.query({
|
|
4980
|
+
collection: DEVICE_SETTINGS_COLLECTION,
|
|
4981
|
+
filter: {
|
|
4982
|
+
whereBetween: { id: [cursor, SCOPE_TAIL] },
|
|
4983
|
+
orderBy: {
|
|
4984
|
+
field: "id",
|
|
4985
|
+
direction: "asc"
|
|
4986
|
+
},
|
|
4987
|
+
limit: SCOPE_PAGE_ROWS
|
|
4988
|
+
}
|
|
4989
|
+
});
|
|
4990
|
+
for (const row of rows) {
|
|
4991
|
+
const addonId = row.data["addonId"];
|
|
4992
|
+
const raw = row.data["deviceId"];
|
|
4993
|
+
if (typeof addonId !== "string" || typeof raw !== "string") continue;
|
|
4994
|
+
const deviceId = Number(raw);
|
|
4995
|
+
if (!Number.isInteger(deviceId) || deviceId <= 0) continue;
|
|
4996
|
+
seen.set(`${addonId}:${deviceId}`, {
|
|
4997
|
+
deviceId,
|
|
4998
|
+
addonId
|
|
4999
|
+
});
|
|
5000
|
+
}
|
|
5001
|
+
const last = rows[rows.length - 1];
|
|
5002
|
+
if (rows.length < SCOPE_PAGE_ROWS || last === void 0) return [...seen.values()];
|
|
5003
|
+
if (last.id === cursor) throw new Error(`device settings scopes: no progress at "${last.id}"`);
|
|
5004
|
+
cursor = last.id;
|
|
5005
|
+
}
|
|
5006
|
+
}
|
|
5007
|
+
//#endregion
|
|
4859
5008
|
//#region src/builtins/device-manager/migration-refused.ts
|
|
4860
5009
|
/**
|
|
4861
5010
|
* A migration step that REFUSED with nothing moved.
|
|
@@ -5788,41 +5937,16 @@ async function cleanupDeletedDevicesData(deps, input) {
|
|
|
5788
5937
|
unreachable: [...unreachable]
|
|
5789
5938
|
};
|
|
5790
5939
|
}
|
|
5791
|
-
/** The settings-store collection every addon's per-device settings share. */
|
|
5792
|
-
var ADDON_DEVICE_SETTINGS_COLLECTION = "addon-device-settings";
|
|
5793
|
-
/** The engine's hard ceiling on one read; a result this long may be a truncated one. */
|
|
5794
|
-
var SCOPE_READ_LIMIT = 2e4;
|
|
5795
5940
|
/** Scope access over the settings store; undefined when the store is unavailable. */
|
|
5796
5941
|
function settingsScopes(store) {
|
|
5797
5942
|
if (store === void 0) return void 0;
|
|
5943
|
+
const door = {
|
|
5944
|
+
query: (input) => store.query.query(input),
|
|
5945
|
+
deleteWhere: (input) => store.deleteWhere.mutate(input)
|
|
5946
|
+
};
|
|
5798
5947
|
return {
|
|
5799
|
-
list:
|
|
5800
|
-
|
|
5801
|
-
collection: ADDON_DEVICE_SETTINGS_COLLECTION,
|
|
5802
|
-
filter: { limit: SCOPE_READ_LIMIT }
|
|
5803
|
-
});
|
|
5804
|
-
if (rows.length >= SCOPE_READ_LIMIT) throw new Error(`the settings read returned ${rows.length} rows — possibly truncated`);
|
|
5805
|
-
const seen = /* @__PURE__ */ new Map();
|
|
5806
|
-
for (const row of rows) {
|
|
5807
|
-
const addonId = row.data["addonId"];
|
|
5808
|
-
const raw = row.data["deviceId"];
|
|
5809
|
-
if (typeof addonId !== "string" || typeof raw !== "string") continue;
|
|
5810
|
-
const deviceId = Number(raw);
|
|
5811
|
-
if (!Number.isInteger(deviceId) || deviceId <= 0) continue;
|
|
5812
|
-
seen.set(`${addonId}:${deviceId}`, {
|
|
5813
|
-
deviceId,
|
|
5814
|
-
addonId
|
|
5815
|
-
});
|
|
5816
|
-
}
|
|
5817
|
-
return [...seen.values()];
|
|
5818
|
-
},
|
|
5819
|
-
clear: async (deviceId) => {
|
|
5820
|
-
const { deleted } = await store.deleteWhere.mutate({
|
|
5821
|
-
collection: ADDON_DEVICE_SETTINGS_COLLECTION,
|
|
5822
|
-
filter: { where: { deviceId: String(deviceId) } }
|
|
5823
|
-
});
|
|
5824
|
-
return deleted;
|
|
5825
|
-
}
|
|
5948
|
+
list: () => listDeviceSettingsScopes(door),
|
|
5949
|
+
clear: (deviceId) => clearDeviceSettings(door, deviceId)
|
|
5826
5950
|
};
|
|
5827
5951
|
}
|
|
5828
5952
|
//#endregion
|
|
@@ -6267,11 +6391,7 @@ function removalSteps(pctx, deviceId, providerAddonId, deletedAt) {
|
|
|
6267
6391
|
run: async () => {
|
|
6268
6392
|
const api = pctx.host.ctx.api?.settingsStore;
|
|
6269
6393
|
if (api === void 0) throw new Error("settings-store api not available");
|
|
6270
|
-
|
|
6271
|
-
collection: "addon-device-settings",
|
|
6272
|
-
filter: { where: { deviceId: String(deviceId) } }
|
|
6273
|
-
});
|
|
6274
|
-
return deleted;
|
|
6394
|
+
return clearDeviceSettings({ deleteWhere: (input) => api.deleteWhere.mutate(input) }, deviceId);
|
|
6275
6395
|
}
|
|
6276
6396
|
},
|
|
6277
6397
|
{
|
|
@@ -8740,7 +8860,17 @@ var DeviceTombstoneStore = class {
|
|
|
8740
8860
|
this.now = opts.now ?? (() => Date.now());
|
|
8741
8861
|
this.retentionMs = opts.retentionMs ?? 7776e6;
|
|
8742
8862
|
}
|
|
8743
|
-
/**
|
|
8863
|
+
/**
|
|
8864
|
+
* Declare the collection now. Idempotent; a rejection is not latched.
|
|
8865
|
+
*
|
|
8866
|
+
* Called at device-manager init (D871) so the table exists on a hub that has
|
|
8867
|
+
* not deleted a device yet. It used to be declared only by the first
|
|
8868
|
+
* `record` / `listSince`, i.e. by the first delete or by an implementer's
|
|
8869
|
+
* reconcile — so a hub whose implementers had not been redeployed, and where
|
|
8870
|
+
* nothing was deleted, never had the table, and the census read that as
|
|
8871
|
+
* "D865 is not running". A DECLARATION only: nothing is read, written or
|
|
8872
|
+
* purged here.
|
|
8873
|
+
*/
|
|
8744
8874
|
declare() {
|
|
8745
8875
|
if (this.declared !== null) return this.declared;
|
|
8746
8876
|
const run = this.backend.declareCollection({
|
|
@@ -10738,6 +10868,11 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
|
|
|
10738
10868
|
backend: deviceRowBackendOf(settingsStoreApi),
|
|
10739
10869
|
logger: this.ctx.logger.child("tombstones")
|
|
10740
10870
|
});
|
|
10871
|
+
try {
|
|
10872
|
+
await tombstones.declare();
|
|
10873
|
+
} catch (err) {
|
|
10874
|
+
this.ctx.logger.warn("device tombstones collection not declared at init — retried on first use", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
10875
|
+
}
|
|
10741
10876
|
this.staleWrapperActivations.checkOnce(() => readBindingsStore(this.bindingsDeps));
|
|
10742
10877
|
try {
|
|
10743
10878
|
await require_retired_settings_keys.purgeRetiredSettingsRows(deviceRows.retiredRowStore(), this.ctx.logger.child("RetiredRows"));
|
|
@@ -11074,5 +11209,7 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
|
|
|
11074
11209
|
//#endregion
|
|
11075
11210
|
exports.DeviceManagerAddon = DeviceManagerAddon;
|
|
11076
11211
|
exports.default = DeviceManagerAddon;
|
|
11212
|
+
exports.createDeviceSettingsStore = createDeviceSettingsStore;
|
|
11077
11213
|
exports.mergeAggregates = mergeAggregates;
|
|
11214
|
+
exports.readDeviceOrThrow = readDeviceOrThrow;
|
|
11078
11215
|
exports.setWrapperActive = setWrapperActive;
|