@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,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { S as backdatedNotBefore, _ as NameConstraints, a as KeyUsageFlags, c as Pkcs10CertificateRequest, d as SubjectKeyIdentifierExtension, f as X509Certificate$1, g as GeneralSubtrees, h as GeneralSubtree, i as Extension, l as Pkcs10CertificateRequestGenerator, m as cryptoProvider, n as BasicConstraintsExtension, o as KeyUsagesExtension, p as X509CertificateGenerator, r as ExtendedKeyUsageExtension, s as PemConverter, t as AuthorityKeyIdentifierExtension, u as SubjectAlternativeNameExtension, v as GeneralName, x as AsnConvert } from "./x509.es-DK__ETIe.mjs";
|
|
2
2
|
import { X509Certificate, createHash, createPrivateKey, randomBytes, webcrypto } from "node:crypto";
|
|
3
3
|
import { writeOwnerOnlyFileSync } from "@camstack/types/node";
|
|
4
4
|
import { isIP } from "node:net";
|
|
@@ -99,6 +99,188 @@ function getProcessAgentHttpsNames() {
|
|
|
99
99
|
return value !== null && typeof value === "object" && typeof Reflect.get(value, "takenByOthers") === "function" ? value : null;
|
|
100
100
|
}
|
|
101
101
|
//#endregion
|
|
102
|
+
//#region src/tls/cert-name-constraints.ts
|
|
103
|
+
/**
|
|
104
|
+
* Name constraints of the hub's generated local CA (D873).
|
|
105
|
+
*
|
|
106
|
+
* An unconstrained private CA vouches for EVERY site on the internet to any
|
|
107
|
+
* device that trusts it, so a leaked CA key would let its holder impersonate
|
|
108
|
+
* a bank. The generated CA therefore carries a CRITICAL `nameConstraints`
|
|
109
|
+
* extension (RFC 5280 4.2.1.10) that limits what it can ever certify to the
|
|
110
|
+
* private address space and local-only names. A verifier that does not
|
|
111
|
+
* understand a critical extension must reject the certificate, so the
|
|
112
|
+
* constraint cannot be silently ignored by a conforming client.
|
|
113
|
+
*
|
|
114
|
+
* Pure: no filesystem, no clock. `cert-issue.ts` embeds the extension,
|
|
115
|
+
* `cert-manager.ts` filters leaf names through {@link permitsIdentity}.
|
|
116
|
+
*/
|
|
117
|
+
/** `id-ce-nameConstraints`. */
|
|
118
|
+
var NAME_CONSTRAINTS_OID = "2.5.29.30";
|
|
119
|
+
/** The address space the generated CA may certify. 100.64.0.0/10 is CGNAT, which Tailscale hands out. Loopback is for the hub's own `127.0.0.1` / `::1` SANs. */
|
|
120
|
+
var PERMITTED_IP_RANGES = [
|
|
121
|
+
"10.0.0.0/8",
|
|
122
|
+
"172.16.0.0/12",
|
|
123
|
+
"192.168.0.0/16",
|
|
124
|
+
"100.64.0.0/10",
|
|
125
|
+
"127.0.0.0/8",
|
|
126
|
+
"fc00::/7",
|
|
127
|
+
"::1/128"
|
|
128
|
+
];
|
|
129
|
+
/**
|
|
130
|
+
* Local-only DNS suffixes: none of them is delegated in public DNS. A leading
|
|
131
|
+
* dot permits every name under the suffix and not the suffix itself.
|
|
132
|
+
*/
|
|
133
|
+
var PERMITTED_DNS_SUFFIXES = [
|
|
134
|
+
".local",
|
|
135
|
+
".lan",
|
|
136
|
+
".home.arpa",
|
|
137
|
+
".internal",
|
|
138
|
+
".localdomain",
|
|
139
|
+
"localhost"
|
|
140
|
+
];
|
|
141
|
+
var LABEL_RE = /^(?!-)[a-z0-9-]{1,63}(?<!-)$/i;
|
|
142
|
+
/** A name that cannot collide with public DNS: a single label, or under a local-only suffix. */
|
|
143
|
+
function isLocalOnlyHostname(name) {
|
|
144
|
+
const lower = name.toLowerCase();
|
|
145
|
+
if (lower.length === 0 || lower.length > 253) return false;
|
|
146
|
+
if (!lower.includes(".")) return LABEL_RE.test(lower);
|
|
147
|
+
if (!PERMITTED_DNS_SUFFIXES.some((suffix) => suffix.startsWith(".") && lower.endsWith(suffix))) return false;
|
|
148
|
+
return lower.split(".").every((label) => LABEL_RE.test(label));
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* The constraint set for a new CA. `hostnames` are the hub's own local-only
|
|
152
|
+
* names at creation time (a single-label OS hostname has no suffix to hide
|
|
153
|
+
* under), added as exact entries; anything that could collide with public DNS
|
|
154
|
+
* is dropped here, never constrained in.
|
|
155
|
+
*/
|
|
156
|
+
function buildNameConstraintSet(hostnames) {
|
|
157
|
+
const dns = new Set(PERMITTED_DNS_SUFFIXES);
|
|
158
|
+
for (const name of hostnames) {
|
|
159
|
+
const lower = name.trim().toLowerCase();
|
|
160
|
+
if (isIP(lower) === 0 && isLocalOnlyHostname(lower)) dns.add(lower);
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
ipRanges: PERMITTED_IP_RANGES,
|
|
164
|
+
dnsNames: [...dns],
|
|
165
|
+
critical: true
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/** The `nameConstraints` extension for a CA: permitted subtrees only, marked critical. */
|
|
169
|
+
function createNameConstraintsExtension(set) {
|
|
170
|
+
const subtrees = [...set.ipRanges.map((range) => new GeneralSubtree({ base: new GeneralName({ iPAddress: range }) })), ...set.dnsNames.map((name) => new GeneralSubtree({ base: new GeneralName({ dNSName: name }) }))];
|
|
171
|
+
const value = AsnConvert.serialize(new NameConstraints({ permittedSubtrees: new GeneralSubtrees(subtrees) }));
|
|
172
|
+
return new Extension(NAME_CONSTRAINTS_OID, set.critical, value);
|
|
173
|
+
}
|
|
174
|
+
/** The CA's constraint set, or `null` when the certificate carries no `nameConstraints`. */
|
|
175
|
+
function readNameConstraints(cert) {
|
|
176
|
+
const ext = cert.extensions.find((e) => e.type === NAME_CONSTRAINTS_OID);
|
|
177
|
+
if (ext === void 0) return null;
|
|
178
|
+
const parsed = AsnConvert.parse(ext.value, NameConstraints);
|
|
179
|
+
const ipRanges = [];
|
|
180
|
+
const dnsNames = [];
|
|
181
|
+
for (const subtree of parsed.permittedSubtrees ?? []) {
|
|
182
|
+
if (subtree.base.iPAddress !== void 0) ipRanges.push(subtree.base.iPAddress);
|
|
183
|
+
if (subtree.base.dNSName !== void 0) dnsNames.push(subtree.base.dNSName.toLowerCase());
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
ipRanges,
|
|
187
|
+
dnsNames,
|
|
188
|
+
critical: ext.critical
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* True when a CA is safe to keep as the hub's anchor: constrained to a
|
|
193
|
+
* non-empty permitted set AND marked critical. A non-critical constraint is
|
|
194
|
+
* ignored by clients that do not know the extension, which is the same as none.
|
|
195
|
+
*/
|
|
196
|
+
function isConstrainedCa(cert) {
|
|
197
|
+
const set = readNameConstraints(cert);
|
|
198
|
+
return set !== null && set.critical && (set.ipRanges.length > 0 || set.dnsNames.length > 0);
|
|
199
|
+
}
|
|
200
|
+
function ipv4ToBigInt(address) {
|
|
201
|
+
return address.split(".").reduce((acc, octet) => acc << 8n | BigInt(Number(octet)), 0n);
|
|
202
|
+
}
|
|
203
|
+
function ipv6ToBigInt(address) {
|
|
204
|
+
const mapped = /^(.*:)(\d+\.\d+\.\d+\.\d+)$/.exec(address);
|
|
205
|
+
let text = address;
|
|
206
|
+
if (mapped !== null) {
|
|
207
|
+
const v4 = ipv4ToBigInt(mapped[2] ?? "0.0.0.0");
|
|
208
|
+
text = `${mapped[1] ?? ""}${(v4 >> 16n & 65535n).toString(16)}:${(v4 & 65535n).toString(16)}`;
|
|
209
|
+
}
|
|
210
|
+
const halves = text.split("::");
|
|
211
|
+
if (halves.length > 2) return null;
|
|
212
|
+
const head = (halves[0] ?? "") === "" ? [] : (halves[0] ?? "").split(":");
|
|
213
|
+
const tail = halves.length === 2 && (halves[1] ?? "") !== "" ? (halves[1] ?? "").split(":") : [];
|
|
214
|
+
const fill = halves.length === 2 ? 8 - head.length - tail.length : 0;
|
|
215
|
+
if (fill < 0 || halves.length === 1 && head.length !== 8) return null;
|
|
216
|
+
return [
|
|
217
|
+
...head,
|
|
218
|
+
...Array(fill).fill("0"),
|
|
219
|
+
...tail
|
|
220
|
+
].reduce((acc, group) => acc << 16n | BigInt(Number.parseInt(group, 16)), 0n);
|
|
221
|
+
}
|
|
222
|
+
function toBigInt(address) {
|
|
223
|
+
const family = isIP(address);
|
|
224
|
+
if (family === 4) return {
|
|
225
|
+
value: ipv4ToBigInt(address),
|
|
226
|
+
bits: 32
|
|
227
|
+
};
|
|
228
|
+
if (family === 6) {
|
|
229
|
+
const value = ipv6ToBigInt(address);
|
|
230
|
+
return value === null ? null : {
|
|
231
|
+
value,
|
|
232
|
+
bits: 128
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
function ipInRange(address, range) {
|
|
238
|
+
const [base, prefixText] = range.split("/");
|
|
239
|
+
if (base === void 0 || prefixText === void 0) return false;
|
|
240
|
+
const target = toBigInt(address);
|
|
241
|
+
const net = toBigInt(base);
|
|
242
|
+
const prefix = Number(prefixText);
|
|
243
|
+
if (target === null || net === null || target.bits !== net.bits) return false;
|
|
244
|
+
if (!Number.isInteger(prefix) || prefix < 0 || prefix > net.bits) return false;
|
|
245
|
+
const shift = BigInt(net.bits - prefix);
|
|
246
|
+
return target.value >> shift === net.value >> shift;
|
|
247
|
+
}
|
|
248
|
+
/** RFC 5280 DNS matching: a leading dot is a strict subtree, a bare name is itself and everything under it. */
|
|
249
|
+
function dnsPermitted(name, constraint) {
|
|
250
|
+
const lower = name.toLowerCase();
|
|
251
|
+
if (constraint.startsWith(".")) return lower.endsWith(constraint);
|
|
252
|
+
return lower === constraint || lower.endsWith(`.${constraint}`);
|
|
253
|
+
}
|
|
254
|
+
/** Is this SAN value (an IP literal or a DNS name) inside the permitted set? */
|
|
255
|
+
function permitsName(set, value) {
|
|
256
|
+
if (isIP(value) !== 0) return set.ipRanges.some((range) => ipInRange(value, range));
|
|
257
|
+
return set.dnsNames.some((constraint) => dnsPermitted(value, constraint));
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* The part of an identity the CA is allowed to certify. A leaf naming
|
|
261
|
+
* anything outside the constraints makes the WHOLE chain fail validation in
|
|
262
|
+
* OpenSSL, so such names are dropped (and reported), never signed. The
|
|
263
|
+
* required lists shrink the same way: otherwise a name the CA cannot certify
|
|
264
|
+
* would count as a permanent SAN gap and reissue the leaf on every boot.
|
|
265
|
+
*/
|
|
266
|
+
function permitsIdentity(set, identity) {
|
|
267
|
+
const dropped = /* @__PURE__ */ new Set();
|
|
268
|
+
const keep = (values) => values.filter((value) => {
|
|
269
|
+
if (permitsName(set, value)) return true;
|
|
270
|
+
dropped.add(value);
|
|
271
|
+
return false;
|
|
272
|
+
});
|
|
273
|
+
return {
|
|
274
|
+
identity: {
|
|
275
|
+
dnsNames: keep(identity.dnsNames),
|
|
276
|
+
ipAddresses: keep(identity.ipAddresses),
|
|
277
|
+
requiredDnsNames: keep(identity.requiredDnsNames),
|
|
278
|
+
requiredIpAddresses: keep(identity.requiredIpAddresses)
|
|
279
|
+
},
|
|
280
|
+
dropped: [...dropped]
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
//#endregion
|
|
102
284
|
//#region src/tls/cert-evaluation.ts
|
|
103
285
|
/**
|
|
104
286
|
* The regeneration rule (D227), as a pure function.
|
|
@@ -127,7 +309,8 @@ var REASONS_REQUIRING_NEW_CA = [
|
|
|
127
309
|
"missing",
|
|
128
310
|
"unreadable",
|
|
129
311
|
"no-local-ca",
|
|
130
|
-
"ca-expiring"
|
|
312
|
+
"ca-expiring",
|
|
313
|
+
"ca-unconstrained"
|
|
131
314
|
];
|
|
132
315
|
function reasonRequiresNewCa(reason) {
|
|
133
316
|
return REASONS_REQUIRING_NEW_CA.includes(reason);
|
|
@@ -139,6 +322,14 @@ function parse(pem) {
|
|
|
139
322
|
return null;
|
|
140
323
|
}
|
|
141
324
|
}
|
|
325
|
+
/** A root without a CRITICAL name constraint (every pre-D873 install) can vouch for any site. */
|
|
326
|
+
function caIsUnconstrained(caPem) {
|
|
327
|
+
try {
|
|
328
|
+
return !isConstrainedCa(new X509Certificate$1(caPem));
|
|
329
|
+
} catch {
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
142
333
|
function daysBetween(from, to) {
|
|
143
334
|
return (to.getTime() - from.getTime()) / MS_PER_DAY$1;
|
|
144
335
|
}
|
|
@@ -169,6 +360,7 @@ function evaluateExistingCert(input) {
|
|
|
169
360
|
const ca = parse(input.caPem);
|
|
170
361
|
if (leaf === null || ca === null) return "unreadable";
|
|
171
362
|
if (daysBetween(input.now, new Date(ca.validTo)) < 427) return "ca-expiring";
|
|
363
|
+
if (caIsUnconstrained(input.caPem)) return "ca-unconstrained";
|
|
172
364
|
if (!keyMatches(leaf, input.keyPem)) return "key-mismatch";
|
|
173
365
|
if (daysBetween(input.now, new Date(leaf.validTo)) < 30) return "expiring";
|
|
174
366
|
if (!hasServerAuthEku(leaf)) return "missing-server-auth-eku";
|
|
@@ -381,13 +573,18 @@ function subjectAltNames(identity) {
|
|
|
381
573
|
* A local root: 10 years, `pathlen:0` so it can sign leaves and nothing
|
|
382
574
|
* else, and **no EKU** — Apple rejects an anchor asserting
|
|
383
575
|
* `anyExtendedKeyUsage`, and a root with no EKU constrains nothing.
|
|
576
|
+
*
|
|
577
|
+
* It carries a CRITICAL `nameConstraints` extension (D873): private address
|
|
578
|
+
* ranges and local-only DNS names, plus `hostnames` (the hub's own single-label
|
|
579
|
+
* names at creation). A leaked key therefore cannot vouch for a public site.
|
|
384
580
|
*/
|
|
385
|
-
async function generateCa(now) {
|
|
581
|
+
async function generateCa(now, hostnames = []) {
|
|
386
582
|
const keys = await webcrypto.subtle.generateKey(SIGNING_ALGORITHM, true, ["sign", "verify"]);
|
|
387
583
|
const extensions = [
|
|
388
584
|
new BasicConstraintsExtension(true, 0, true),
|
|
389
585
|
new KeyUsagesExtension(KeyUsageFlags.keyCertSign | KeyUsageFlags.cRLSign, true),
|
|
390
|
-
await SubjectKeyIdentifierExtension.create(keys.publicKey)
|
|
586
|
+
await SubjectKeyIdentifierExtension.create(keys.publicKey),
|
|
587
|
+
createNameConstraintsExtension(buildNameConstraintSet(hostnames))
|
|
391
588
|
];
|
|
392
589
|
const cert = await X509CertificateGenerator.createSelfSigned({
|
|
393
590
|
serialNumber: freshSerial(),
|
|
@@ -650,14 +847,6 @@ function describeHttpsLeaf(certPem) {
|
|
|
650
847
|
notAfter: Date.parse(x509.validTo)
|
|
651
848
|
};
|
|
652
849
|
}
|
|
653
|
-
var LOCAL_SUFFIXES = [
|
|
654
|
-
".local",
|
|
655
|
-
".lan",
|
|
656
|
-
".home.arpa",
|
|
657
|
-
".internal",
|
|
658
|
-
".localdomain"
|
|
659
|
-
];
|
|
660
|
-
var LABEL_RE = /^(?!-)[a-z0-9-]{1,63}(?<!-)$/i;
|
|
661
850
|
/** Private-network IPv4/IPv6: RFC 1918, CGNAT (Tailscale), link-local, ULA. */
|
|
662
851
|
function isPrivateAddress(address) {
|
|
663
852
|
const family = isIP(address);
|
|
@@ -675,14 +864,6 @@ function isPrivateAddress(address) {
|
|
|
675
864
|
function isContainerBridgeAddress(address) {
|
|
676
865
|
return /^172\.17\.\d{1,3}\.\d{1,3}$/.test(address);
|
|
677
866
|
}
|
|
678
|
-
/** A name that cannot collide with public DNS. */
|
|
679
|
-
function isLocalOnlyHostname(name) {
|
|
680
|
-
const lower = name.toLowerCase();
|
|
681
|
-
if (lower.length === 0 || lower.length > 253) return false;
|
|
682
|
-
if (!lower.includes(".")) return LABEL_RE.test(lower);
|
|
683
|
-
if (!LOCAL_SUFFIXES.some((suffix) => lower.endsWith(suffix))) return false;
|
|
684
|
-
return lower.split(".").every((label) => LABEL_RE.test(label));
|
|
685
|
-
}
|
|
686
867
|
/**
|
|
687
868
|
* The names the hub will sign for `nodeId`: its node id and the address of its live mesh
|
|
688
869
|
* socket - nothing the agent says about itself. `excluded` holds every name already taken
|
|
@@ -735,14 +916,21 @@ async function issueAgentHttpsLeaf(input) {
|
|
|
735
916
|
if (!existsSync(caCertPath) || !existsSync(caKeyPath)) throw new Error("the hub has no local CA to sign with (no tls/camstack-ca.crt + key)");
|
|
736
917
|
const excluded = new Set(input.takenByOthers ?? []);
|
|
737
918
|
if (existsSync(hubLeafPath)) for (const name of certificateNames(readFileSync(hubLeafPath, "utf8"))) excluded.add(name);
|
|
738
|
-
const
|
|
919
|
+
const ca = await loadCa(readFileSync(caCertPath, "utf8"), readFileSync(caKeyPath, "utf8"));
|
|
920
|
+
const policy = acceptAgentSans({
|
|
739
921
|
nodeId: input.nodeId,
|
|
740
922
|
observedAddress: input.observedAddress,
|
|
741
923
|
excluded,
|
|
742
924
|
...input.reportedNames !== void 0 ? { reported: input.reportedNames } : {}
|
|
743
925
|
});
|
|
926
|
+
const constraints = readNameConstraints(ca.cert);
|
|
927
|
+
const constrained = constraints === null ? null : permitsIdentity(constraints, policy.identity);
|
|
928
|
+
const sans = constrained === null ? policy : {
|
|
929
|
+
identity: constrained.identity,
|
|
930
|
+
accepted: policy.accepted.filter((name) => !constrained.dropped.includes(name)),
|
|
931
|
+
rejected: [...policy.rejected, ...constrained.dropped.map((name) => `${name} (outside the local CA's name constraints)`)]
|
|
932
|
+
};
|
|
744
933
|
if (sans.accepted.length === 0) throw new Error(`no name of node '${input.nodeId}' can be certified (${sans.rejected.join("; ") || "nothing offered"})`);
|
|
745
|
-
const ca = await loadCa(readFileSync(caCertPath, "utf8"), readFileSync(caKeyPath, "utf8"));
|
|
746
934
|
return {
|
|
747
935
|
certPem: await issueLeafFromCsr(ca, input.csrPem, sans.identity, input.nodeId, 397, input.now ?? /* @__PURE__ */ new Date()),
|
|
748
936
|
caCertPem: ca.certPem,
|
|
@@ -755,4 +943,4 @@ function pemDigest(pem) {
|
|
|
755
943
|
return createHash("sha256").update(pem).digest("hex").slice(0, 16);
|
|
756
944
|
}
|
|
757
945
|
//#endregion
|
|
758
|
-
export {
|
|
946
|
+
export { isConstrainedCa as A, MAX_LEAF_VALIDITY_DAYS as C, PERMITTED_DNS_SUFFIXES as D, reasonRequiresNewCa as E, AGENT_HTTPS_NAMES_COLLECTION as F, AGENT_HTTPS_NAMES_COLUMNS as I, AgentHttpsNames as L, permitsIdentity as M, permitsName as N, PERMITTED_IP_RANGES as O, readNameConstraints as P, getProcessAgentHttpsNames as R, LEAF_RENEWAL_WINDOW_DAYS as S, evaluateExistingCert as T, issueLeaf as _, collectAgentNames as a, systemHostFacts as b, installAgentHttps as c, issueAgentHttpsLeaf as d, loadAgentHttps as f, generateCa as g, CA_COMMON_NAME as h, certificateNames as i, isLocalOnlyHostname as j, buildNameConstraintSet as k, isContainerBridgeAddress as l, pinnedHttpsCaFingerprint as m, acceptAgentSans as n, createAgentHttpsRequest as o, pemDigest as p, agentHttpsPaths as r, describeHttpsLeaf as s, AgentHttpsInstallError as t, isPrivateAddress as u, loadCa as v, SERVER_AUTH_OID as w, CA_VALIDITY_DAYS as x, collectCertIdentity as y, setProcessAgentHttpsNames as z };
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BKhlcYz6.js");
|
|
7
7
|
const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
|
|
8
8
|
let node_crypto = require("node:crypto");
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ar as errMsg, Si as EventCategory, it as addonPagesCapability, jr as BaseAddon } from "../../dist-9fcsrFU3.mjs";
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BKhlcYz6.js");
|
|
7
7
|
const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
|
|
8
8
|
let node_crypto = require("node:crypto");
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ar as errMsg, Si as EventCategory, jr as BaseAddon, ot as addonWidgetsCapability } from "../../dist-9fcsrFU3.mjs";
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BKhlcYz6.js");
|
|
7
7
|
//#region src/builtins/alerts/device-label.ts
|
|
8
8
|
/**
|
|
9
9
|
* Operator-facing device label for alert messages.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ar as errMsg, Si as EventCategory, i as AlertSchema, jr as BaseAddon, qr as createEvent, st as alertsCapability } from "../../dist-9fcsrFU3.mjs";
|
|
2
2
|
//#region src/builtins/alerts/device-label.ts
|
|
3
3
|
/**
|
|
4
4
|
* Operator-facing device label for alert messages.
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BKhlcYz6.js");
|
|
7
7
|
//#region src/builtins/autotrack/autotrack-config.ts
|
|
8
8
|
var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
|
|
9
9
|
deadZoneFraction: .5,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ar as errMsg, M as FIRST_LEVEL_MACRO_CLASSES, Pn as ptzAutotrackCapability, Si as EventCategory, jr as BaseAddon, ni as isEvent, ut as bareAddonId } from "../../dist-9fcsrFU3.mjs";
|
|
2
2
|
//#region src/builtins/autotrack/autotrack-config.ts
|
|
3
3
|
var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
|
|
4
4
|
deadZoneFraction: .5,
|
|
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
7
|
-
const require_restore_archive = require("../../restore-archive-
|
|
6
|
+
const require_dist = require("../../dist-BKhlcYz6.js");
|
|
7
|
+
const require_restore_archive = require("../../restore-archive-49aZwkp8.js");
|
|
8
8
|
let node_crypto = require("node:crypto");
|
|
9
9
|
let node_fs_promises = require("node:fs/promises");
|
|
10
10
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as BackupSnapshotRefusedError, d as ENCRYPTED_BACKUP_SUFFIX, f as generateBackupKeyPair, i as BackupCancelledError, l as BackupKeyFormatError, m as parseBackupSecretKey, n as precheckRestoreKey, o as DEFAULT_BACKUP_DATABASES, p as parseBackupPublicKey, r as prepareRestoreArchive, s as SystemBackupService } from "../../restore-archive-
|
|
1
|
+
import { Si as EventCategory, bn as mayWriteToLocation, jr as BaseAddon, lt as backupCapability, rr as storageOccupancyCapability, si as nodePin, vi as toNodeId } from "../../dist-9fcsrFU3.mjs";
|
|
2
|
+
import { a as BackupSnapshotRefusedError, d as ENCRYPTED_BACKUP_SUFFIX, f as generateBackupKeyPair, i as BackupCancelledError, l as BackupKeyFormatError, m as parseBackupSecretKey, n as precheckRestoreKey, o as DEFAULT_BACKUP_DATABASES, p as parseBackupPublicKey, r as prepareRestoreArchive, s as SystemBackupService } from "../../restore-archive-DgvDecXM.mjs";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import * as fsp from "node:fs/promises";
|
|
5
5
|
import * as path$1 from "node:path";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BKhlcYz6.js");
|
|
7
7
|
const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
|
|
8
8
|
let zod = require("zod");
|
|
9
9
|
//#region src/builtins/calendars/calendar-color.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { g as CalendarPreferencesSchema, gt as calendarsCapability, jr as BaseAddon } from "../../dist-9fcsrFU3.mjs";
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region src/builtins/calendars/calendar-color.ts
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BKhlcYz6.js");
|
|
7
7
|
let zod = require("zod");
|
|
8
8
|
let _camstack_types_node = require("@camstack/types/node");
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as DeclaredDevices,
|
|
1
|
+
import { A as DeclaredDevices, Ar as errMsg, Dr as DeviceFeature, H as MOTION_CLOSE_AFTER_MS, Qn as snapshotCapability, Si as EventCategory, _t as cameraGridLayoutCapability, ar as streamCatalogCapability, ei as hydrateSchema, gr as buildFfmpegArgs, jr as BaseAddon, jt as declarationOwnerNodeId, kr as DeviceType, o as BaseDevice, qr as createEvent, w as DERIVED_CAMERA_SILENCED_CAP_NAMES, wn as motionCapability, xn as memoizePinnedFfmpeg } from "../../dist-9fcsrFU3.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { FfmpegProcess } from "@camstack/types/node";
|
|
4
4
|
import { join } from "node:path";
|
|
@@ -3,8 +3,8 @@ 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 require_composition_sources = require("../../composition-sources-
|
|
6
|
+
const require_dist = require("../../dist-BKhlcYz6.js");
|
|
7
|
+
const require_composition_sources = require("../../composition-sources-cBG8fBTu.js");
|
|
8
8
|
let zod = require("zod");
|
|
9
9
|
//#region src/builtins/shared/device-state-changed.ts
|
|
10
10
|
/** Structural narrowing helper for untrusted bus payloads. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as DeclaredDevices,
|
|
2
|
-
import { n as normalizedNativeOwner } from "../../composition-sources-
|
|
1
|
+
import { A as DeclaredDevices, Ar as errMsg, Cr as compositionSourceKey, Er as toExpressionValue, Si as EventCategory, Sr as compositionSliceKey, Tr as disarmRoseMemory, Wt as evaluateCompositionField, _r as cloneStatefulExpressionMemory, br as compositionFeatureEnabled, bt as composerCapability, f as COMPOSED_ITEM_FIXED_FIELDS, ft as buildCapabilityLookup, hr as COMPOSER_ADDON_ID, jn as planComposition, jr as BaseAddon, kr as DeviceType, o as BaseDevice, qr as createEvent, qt as expressionContainsBuiltinCall, r as ALL_CAPABILITY_DEFINITIONS, vr as composedDeviceRef, wr as createStatefulExpressionMemory, xr as compositionItemFieldPath, xt as compositionFieldKey, yr as composedDeviceStableId } from "../../dist-9fcsrFU3.mjs";
|
|
2
|
+
import { n as normalizedNativeOwner } from "../../composition-sources-CS0D7imL.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region src/builtins/shared/device-state-changed.ts
|
|
5
5
|
/** Structural narrowing helper for untrusted bus payloads. */
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BKhlcYz6.js");
|
|
7
7
|
const require_formatter = require("../../formatter-DqAKDlvN.js");
|
|
8
8
|
//#region src/builtins/console-logging/console-destination.ts
|
|
9
9
|
var LEVEL_RANK = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { gn as logDestinationCapability, jr as BaseAddon } from "../../dist-9fcsrFU3.mjs";
|
|
2
2
|
import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
|
|
3
3
|
//#region src/builtins/console-logging/console-destination.ts
|
|
4
4
|
var LEVEL_RANK = {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* keeps any values the UI already wrote.
|
|
9
9
|
*
|
|
10
10
|
* On every patch the same values are mirrored into the block addon's
|
|
11
|
-
* `addon-settings`
|
|
11
|
+
* `addon-settings` rows so a running script reads them the same way any
|
|
12
12
|
* addon does: `ctx.settings.readAddonStore()`.
|
|
13
13
|
*/
|
|
14
14
|
import type { SettingsStoreClient } from "@camstack/types";
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("../../dist-
|
|
4
|
-
const require_composition_sources = require("../../composition-sources-
|
|
3
|
+
const require_dist = require("../../dist-BKhlcYz6.js");
|
|
4
|
+
const require_composition_sources = require("../../composition-sources-cBG8fBTu.js");
|
|
5
|
+
const require_prefix_range = require("../../prefix-range-D_KueXbQ.js");
|
|
6
|
+
const require_prefix_walk = require("../../prefix-walk-Dv6MLZlM.js");
|
|
5
7
|
let node_crypto = require("node:crypto");
|
|
6
8
|
let _camstack_types_node = require("@camstack/types/node");
|
|
7
9
|
let node_fs_promises = require("node:fs/promises");
|
|
@@ -490,6 +492,72 @@ var BlockSupervisor = class {
|
|
|
490
492
|
}
|
|
491
493
|
};
|
|
492
494
|
//#endregion
|
|
495
|
+
//#region src/kernel/addon-settings-store.ts
|
|
496
|
+
/** The collection every addon's settings share. Named nowhere else (with sections' own module). */
|
|
497
|
+
var ADDON_SETTINGS_COLLECTION = "addon-settings";
|
|
498
|
+
function createAddonSettingsStore(door, addonId) {
|
|
499
|
+
const prefix = `${addonId}.`;
|
|
500
|
+
const message = (err) => err instanceof Error ? err.message : String(err);
|
|
501
|
+
return {
|
|
502
|
+
async read() {
|
|
503
|
+
try {
|
|
504
|
+
const value = await require_prefix_walk.loadPrefixed(door, ADDON_SETTINGS_COLLECTION, prefix);
|
|
505
|
+
return Object.keys(value).length === 0 ? { kind: "absent" } : {
|
|
506
|
+
kind: "present",
|
|
507
|
+
value
|
|
508
|
+
};
|
|
509
|
+
} catch (err) {
|
|
510
|
+
return {
|
|
511
|
+
kind: "unreadable",
|
|
512
|
+
error: message(err)
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
},
|
|
516
|
+
async readKey(key) {
|
|
517
|
+
try {
|
|
518
|
+
const row = await door.get({
|
|
519
|
+
collection: ADDON_SETTINGS_COLLECTION,
|
|
520
|
+
key: `${prefix}${key}`
|
|
521
|
+
});
|
|
522
|
+
return row === void 0 || row === null ? { kind: "absent" } : {
|
|
523
|
+
kind: "present",
|
|
524
|
+
value: require_prefix_walk.unwrapStoredValue(row)
|
|
525
|
+
};
|
|
526
|
+
} catch (err) {
|
|
527
|
+
return {
|
|
528
|
+
kind: "unreadable",
|
|
529
|
+
error: message(err)
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
async merge(patch) {
|
|
534
|
+
const records = [];
|
|
535
|
+
const removed = [];
|
|
536
|
+
for (const [key, value] of Object.entries(patch)) if (value === void 0) removed.push(`${prefix}${key}`);
|
|
537
|
+
else records.push({
|
|
538
|
+
id: `${prefix}${key}`,
|
|
539
|
+
data: {
|
|
540
|
+
addonId,
|
|
541
|
+
key,
|
|
542
|
+
value
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
if (records.length === 0 && removed.length === 0) return;
|
|
546
|
+
if (require_prefix_range.prefixRange(prefix) === null) throw new Error(`addon settings: "${addonId}" cannot be expressed as an id range`);
|
|
547
|
+
await door.transact({ ops: [...removed.length > 0 ? [{
|
|
548
|
+
op: "deleteWhere",
|
|
549
|
+
collection: ADDON_SETTINGS_COLLECTION,
|
|
550
|
+
filter: { whereIn: { id: removed } }
|
|
551
|
+
}] : [], ...records.length > 0 ? [{
|
|
552
|
+
op: "upsertMany",
|
|
553
|
+
collection: ADDON_SETTINGS_COLLECTION,
|
|
554
|
+
conflict: ["id"],
|
|
555
|
+
records
|
|
556
|
+
}] : []] });
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
//#endregion
|
|
493
561
|
//#region src/builtins/core-blocks/block-settings-store.ts
|
|
494
562
|
/**
|
|
495
563
|
* @durable class=config owner=core-blocks
|
|
@@ -550,15 +618,12 @@ var BlockSettingsStore = class {
|
|
|
550
618
|
});
|
|
551
619
|
}
|
|
552
620
|
async mirrorToBlockAddon(blockId, values) {
|
|
553
|
-
const
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
value: values
|
|
560
|
-
});
|
|
561
|
-
} catch {}
|
|
621
|
+
const store = this.store;
|
|
622
|
+
await createAddonSettingsStore({
|
|
623
|
+
query: (input) => store.query.query(input),
|
|
624
|
+
get: (input) => store.get.query(input),
|
|
625
|
+
transact: (input) => store.transact.mutate(input)
|
|
626
|
+
}, require_dist.coreBlockAddonId(blockId)).merge(values);
|
|
562
627
|
}
|
|
563
628
|
};
|
|
564
629
|
//#endregion
|
|
@@ -2273,6 +2338,7 @@ exports.CoreBlocksAddon = CoreBlocksAddon;
|
|
|
2273
2338
|
exports.blockAddonId = blockAddonId;
|
|
2274
2339
|
exports.blockIdFromAddonId = blockIdFromAddonId;
|
|
2275
2340
|
exports.compileBlock = compileBlock;
|
|
2341
|
+
exports.createAddonSettingsStore = createAddonSettingsStore;
|
|
2276
2342
|
exports.extractSettingsSchema = extractSettingsSchema;
|
|
2277
2343
|
exports.loadBlockTypeDefs = loadBlockTypeDefs;
|
|
2278
2344
|
exports.materializeBlock = materializeBlock;
|